mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-2914] support for number range patterns (#3282)
* support for number range patterns * fix memory leak for tag actions
This commit is contained in:
committed by
Eugenio Romano
parent
f63614e964
commit
3a3acd23ff
@@ -132,7 +132,8 @@
|
|||||||
"component": {
|
"component": {
|
||||||
"selector": "number-range",
|
"selector": "number-range",
|
||||||
"settings": {
|
"settings": {
|
||||||
"field": "cm:content.size"
|
"field": "cm:content.size",
|
||||||
|
"format": "[{FROM} TO {TO}]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -326,7 +326,8 @@ Provides ability to select a range between two Numbers based on the particular `
|
|||||||
"component": {
|
"component": {
|
||||||
"selector": "number-range",
|
"selector": "number-range",
|
||||||
"settings": {
|
"settings": {
|
||||||
"field": "cm:content.size"
|
"field": "cm:content.size",
|
||||||
|
"format": "[{FROM} TO {TO}]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,6 +338,42 @@ Provides ability to select a range between two Numbers based on the particular `
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
#### Widget Settings
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| field | string | Field to to use |
|
||||||
|
| format | string | Value format. Uses string substitution to allow all sorts of [range queries](https://docs.alfresco.com/5.2/concepts/rm-searchsyntax-ranges.html). |
|
||||||
|
|
||||||
|
#### Range query format
|
||||||
|
|
||||||
|
For more details on the range search format please refer to the "[Search for ranges](https://docs.alfresco.com/5.2/concepts/rm-searchsyntax-ranges.html)" article.
|
||||||
|
|
||||||
|
The widget uses `{FROM}` and `{TO}` values together with the required target format of the query.
|
||||||
|
You can use any type of the query pattern, the widget automatically substitutes the values, for example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"settings": {
|
||||||
|
"field": "cm:content.size",
|
||||||
|
"format": "[{FROM} TO {TO}]"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The format above may result in the following query at runtime:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cm:content.size:[0 TO 100]
|
||||||
|
```
|
||||||
|
|
||||||
|
Other format examples:
|
||||||
|
|
||||||
|
| Format | Example |
|
||||||
|
| --- | --- |
|
||||||
|
| `[{FROM} TO {TO}]` | `[0 TO 5]` |
|
||||||
|
| `<{FROM} TO {TO}]` | `<0 TO 5]` |
|
||||||
|
| `[{FROM} TO {TO}>` | `[0 TO 5>` |
|
||||||
|
| `<{FROM} TO {TO}>` | `<0 TO 5>` |
|
||||||
|
|
||||||
### Radio List Widget
|
### Radio List Widget
|
||||||
|
|
||||||
Provides you with a list of radio-boxes, each backed by a particular query fragment.
|
Provides you with a list of radio-boxes, each backed by a particular query fragment.
|
||||||
|
@@ -85,4 +85,43 @@ describe('SearchNumberRangeComponent', () => {
|
|||||||
expect(context.update).toHaveBeenCalled();
|
expect(context.update).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fetch format from the settings', () => {
|
||||||
|
component.settings = {
|
||||||
|
field: 'cm:content.size',
|
||||||
|
format: '<{FROM} TO {TO}>'
|
||||||
|
};
|
||||||
|
component.ngOnInit();
|
||||||
|
|
||||||
|
expect(component.field).toEqual('cm:content.size');
|
||||||
|
expect(component.format).toEqual('<{FROM} TO {TO}>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use default format if not provided', () => {
|
||||||
|
component.settings = {
|
||||||
|
field: 'cm:content.size'
|
||||||
|
};
|
||||||
|
component.ngOnInit();
|
||||||
|
|
||||||
|
expect(component.field).toEqual('cm:content.size');
|
||||||
|
expect(component.format).toEqual('[{FROM} TO {TO}]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should format value based on the current pattern', () => {
|
||||||
|
const context: any = {
|
||||||
|
queryFragments: {},
|
||||||
|
update() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.id = 'range1';
|
||||||
|
component.settings = {
|
||||||
|
field: 'cm:content.size',
|
||||||
|
format: '<{FROM} TO {TO}>'
|
||||||
|
};
|
||||||
|
component.context = context;
|
||||||
|
component.ngOnInit();
|
||||||
|
|
||||||
|
component.apply({ from: '0', to: '100' }, true);
|
||||||
|
expect(context.queryFragments['range1']).toEqual('cm:content.size:<0 TO 100>');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -41,7 +41,16 @@ export class SearchNumberRangeComponent implements SearchWidget, OnInit {
|
|||||||
settings?: SearchWidgetSettings;
|
settings?: SearchWidgetSettings;
|
||||||
context?: SearchQueryBuilderService;
|
context?: SearchQueryBuilderService;
|
||||||
|
|
||||||
|
field: string;
|
||||||
|
format = '[{FROM} TO {TO}]';
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
if (this.settings) {
|
||||||
|
this.field = this.settings.field;
|
||||||
|
this.format = this.settings.format || '[{FROM} TO {TO}]';
|
||||||
|
}
|
||||||
|
|
||||||
const validators = Validators.compose([
|
const validators = Validators.compose([
|
||||||
Validators.required,
|
Validators.required,
|
||||||
Validators.pattern(/^-?(0|[1-9]\d*)?$/)
|
Validators.pattern(/^-?(0|[1-9]\d*)?$/)
|
||||||
@@ -57,12 +66,30 @@ export class SearchNumberRangeComponent implements SearchWidget, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply(model: { from: string, to: string }, isValid: boolean) {
|
apply(model: { from: string, to: string }, isValid: boolean) {
|
||||||
if (isValid && this.id && this.context && this.settings && this.settings.field) {
|
if (isValid && this.id && this.context && this.field) {
|
||||||
this.context.queryFragments[this.id] = `${this.settings.field}:[${model.from} TO ${model.to}]`;
|
const map = new Map<string, string>();
|
||||||
|
map.set('FROM', model.from);
|
||||||
|
map.set('TO', model.to);
|
||||||
|
|
||||||
|
const value = this.formatString(this.format, map);
|
||||||
|
const query = `${this.field}:${value}`;
|
||||||
|
|
||||||
|
this.context.queryFragments[this.id] = query;
|
||||||
this.context.update();
|
this.context.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private formatString(str: string, map: Map<string, string>): string {
|
||||||
|
let result = str;
|
||||||
|
|
||||||
|
map.forEach((value, key) => {
|
||||||
|
const expr = new RegExp('{' + key + '}', 'gm');
|
||||||
|
result = result.replace(expr, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.form.reset({
|
this.form.reset({
|
||||||
from: '',
|
from: '',
|
||||||
|
@@ -192,13 +192,14 @@ describe('TagActionsComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add tag should be disabled by default', (done) => {
|
it('Add tag should be disabled by default', () => {
|
||||||
component.nodeId = 'fake-node-id';
|
component.nodeId = 'fake-node-id';
|
||||||
component.newTagName = 'fake-tag-name';
|
component.newTagName = 'fake-tag-name';
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
let addButton: any = element.querySelector('#add-tag');
|
let addButton: any = element.querySelector('#add-tag');
|
||||||
expect(addButton.disabled).toEqual(true);
|
expect(addButton.disabled).toEqual(true);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add tag should return an error if the tag is already present', (done) => {
|
it('Add tag should return an error if the tag is already present', (done) => {
|
||||||
|
@@ -16,8 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { TranslationService } from '@alfresco/adf-core';
|
import { TranslationService } from '@alfresco/adf-core';
|
||||||
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { TagService } from './services/tag.service';
|
import { TagService } from './services/tag.service';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -30,7 +31,7 @@ import { TagService } from './services/tag.service';
|
|||||||
styleUrls: ['./tag-actions.component.scss'],
|
styleUrls: ['./tag-actions.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class TagActionsComponent implements OnChanges {
|
export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
|
||||||
|
|
||||||
/** The identifier of a node. */
|
/** The identifier of a node. */
|
||||||
@Input()
|
@Input()
|
||||||
@@ -49,23 +50,31 @@ export class TagActionsComponent implements OnChanges {
|
|||||||
result = new EventEmitter();
|
result = new EventEmitter();
|
||||||
|
|
||||||
newTagName: string;
|
newTagName: string;
|
||||||
|
|
||||||
tagsEntries: any;
|
tagsEntries: any;
|
||||||
|
|
||||||
errorMsg: string;
|
errorMsg: string;
|
||||||
|
|
||||||
disableAddTag: boolean = true;
|
disableAddTag: boolean = true;
|
||||||
|
|
||||||
constructor(private tagService: TagService, private translateService: TranslationService) {
|
private subscriptions: Subscription[] = [];
|
||||||
this.tagService.refresh.subscribe(() => {
|
|
||||||
this.refreshTag();
|
constructor(private tagService: TagService, private translateService: TranslationService) {}
|
||||||
});
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.tagService.refresh.subscribe(() => {
|
||||||
|
this.refreshTag();
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
return this.refreshTag();
|
return this.refreshTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
|
||||||
refreshTag() {
|
refreshTag() {
|
||||||
if (this.nodeId) {
|
if (this.nodeId) {
|
||||||
this.tagService.getTagsByNodeId(this.nodeId).subscribe((data) => {
|
this.tagService.getTagsByNodeId(this.nodeId).subscribe((data) => {
|
||||||
|
Reference in New Issue
Block a user