diff --git a/demo-shell/src/app.config.json b/demo-shell/src/app.config.json
index 490fe38e22..21d4f81841 100644
--- a/demo-shell/src/app.config.json
+++ b/demo-shell/src/app.config.json
@@ -53,6 +53,8 @@
}
],
"search": {
+ "include": ["path", "allowableOperations"],
+ "fields": [],
"filterQueries": [
{ "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" },
{ "query": "NOT cm:creator:System" }
@@ -78,85 +80,62 @@
"query": {
"categories": [
{
- "id": "broken",
- "name": "Broken Facet",
- "enabled": false,
- "expanded": false,
- "component": {
- "selector": "text",
- "settings": {
- "field": "fieldname"
+ "id": "queryName",
+ "name": "Name",
+ "enabled": true,
+ "expanded": true,
+ "component": {
+ "selector": "text",
+ "settings": {
+ "pattern": "cm:name:'(.*?)'",
+ "field": "cm:name",
+ "placeholder": "Enter the name"
+ }
+ }
+ },
+ {
+ "id": "contentSize",
+ "name": "Content Size",
+ "enabled": true,
+ "component": {
+ "selector": "slider",
+ "settings": {
+ "field": "cm:content.size",
+ "min": 0,
+ "max": 18,
+ "step": 1,
+ "thumbLabel": true
+ }
+ }
+ },
+ {
+ "id": "contentSizeRange",
+ "name": "Content Size (range)",
+ "enabled": true,
+ "component": {
+ "selector": "number-range",
+ "settings": {
+ "field": "cm:content.size"
+ }
+ }
+ },
+ {
+ "id": "queryType",
+ "name": "Type",
+ "enabled": true,
+ "component": {
+ "selector": "radio",
+ "settings": {
+ "field": null,
+ "options": [
+ { "name": "None", "value": "", "default": true },
+ { "name": "All", "value": "TYPE:'cm:folder' OR TYPE:'cm:content'" },
+ { "name": "Folder", "value": "TYPE:'cm:folder'" },
+ { "name": "Document", "value": "TYPE:'cm:content'" }
+ ]
+ }
}
}
- },
- {
- "id": "queryName",
- "name": "Name",
- "enabled": true,
- "expanded": true,
- "component": {
- "selector": "text",
- "settings": {
- "pattern": "cm:name:'(.*?)'",
- "field": "cm:name",
- "placeholder": "Enter the name"
- }
- }
- },
- {
- "id": "queryFields",
- "name": "Fields",
- "enabled": true,
- "expanded": false,
- "component": {
- "selector": "fields",
- "settings": {
- "field": null,
- "options": [
- { "name": "Name", "value": "name", "fields": ["name"], "default": true },
- { "name": "File Size", "value": "content.sizeInBytes", "fields": ["content"], "default": true },
- { "name": "Modified On", "value": "modifiedAt", "fields": ["modifiedAt"], "default": true },
- { "name": "Modified By", "value": "modifiedByUser.displayName", "fields": ["modifiedByUser"], "default": true }
- ]
- }
- }
- },
- {
- "id": "queryType",
- "name": "Type",
- "enabled": true,
- "expanded": false,
- "component": {
- "selector": "radio",
- "settings": {
- "field": null,
- "options": [
- { "name": "None", "value": "", "default": true },
- { "name": "All", "value": "TYPE:'cm:folder' OR TYPE:'cm:content'" },
- { "name": "Folder", "value": "TYPE:'cm:folder'" },
- { "name": "Document", "value": "TYPE:'cm:content'" }
- ]
- }
- }
- },
- {
- "id": "queryLocations",
- "name": "Locations",
- "enabled": true,
- "expanded": false,
- "component": {
- "selector": "scope-locations",
- "settings": {
- "field": null,
- "options": [
- { "name": "Default", "value": "nodes", "default": true },
- { "name": "Nodes", "value": "nodes" },
- { "name": "Deleted Nodes", "value": "deleted-nodes" },
- { "name": "Versions", "value": "versions" }
- ]
- }
- }
- }
]
}
},
diff --git a/lib/config/export-check/export-2.3.0.json b/lib/config/export-check/export-2.3.0.json
index 3f05565614..8746233cc9 100644
--- a/lib/config/export-check/export-2.3.0.json
+++ b/lib/config/export-check/export-2.3.0.json
@@ -5109,7 +5109,8 @@
"character": 8,
"fileName": "lib/content-services/search/components/search-widget-container/search-widgets.module.ts"
},
- "name": "SearchFieldsComponent"
+ "name": "SearchFieldsComponent",
+ "skipError": true
},
{
"position": {
@@ -5173,7 +5174,8 @@
"character": 8,
"fileName": "lib/content-services/search/components/search-widget-container/search-widgets.module.ts"
},
- "name": "SearchScopeLocationsComponent"
+ "name": "SearchScopeLocationsComponent",
+ "skipError": true
},
{
"position": {
@@ -6455,4 +6457,4 @@
},
"name": "WidgetComponent"
}
-]
\ No newline at end of file
+]
diff --git a/lib/content-services/i18n/en.json b/lib/content-services/i18n/en.json
index abbb8eedc7..ace61f1fc2 100644
--- a/lib/content-services/i18n/en.json
+++ b/lib/content-services/i18n/en.json
@@ -165,6 +165,16 @@
"MODIFIED_AT": "Modified at"
}
},
+ "FILTER": {
+ "ACTIONS": {
+ "CLEAR": "Clear",
+ "APPLY": "Apply"
+ },
+ "RANGE": {
+ "FROM": "From",
+ "TO": "To"
+ }
+ },
"ICONS": {
"ft_ic_raster_image": "Image file",
"ft_ic_pdf": "PDF document",
diff --git a/lib/content-services/material.module.ts b/lib/content-services/material.module.ts
index 272db886c1..c5ea70d2dc 100644
--- a/lib/content-services/material.module.ts
+++ b/lib/content-services/material.module.ts
@@ -34,7 +34,8 @@ import {
MatCheckboxModule,
MatDatepickerModule,
MatSlideToggleModule,
- MatRadioModule
+ MatRadioModule,
+ MatSliderModule
} from '@angular/material';
export function modules() {
@@ -56,7 +57,8 @@ export function modules() {
MatCheckboxModule,
MatDatepickerModule,
MatSlideToggleModule,
- MatRadioModule
+ MatRadioModule,
+ MatSliderModule
];
}
diff --git a/lib/content-services/search/components/search-fields/search-fields.component.html b/lib/content-services/search/components/search-fields/search-fields.component.html
deleted file mode 100644
index 8dd4a54b35..0000000000
--- a/lib/content-services/search/components/search-fields/search-fields.component.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
- {{ option.name }}
-
diff --git a/lib/content-services/search/components/search-fields/search-fields.component.scss b/lib/content-services/search/components/search-fields/search-fields.component.scss
deleted file mode 100644
index bb65a956fb..0000000000
--- a/lib/content-services/search/components/search-fields/search-fields.component.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.adf-search-fields {
- display: flex;
- flex-direction: column;
-
- .mat-checkbox {
- margin: 5px;
- }
-}
diff --git a/lib/content-services/search/components/search-fields/search-fields.component.ts b/lib/content-services/search/components/search-fields/search-fields.component.ts
deleted file mode 100644
index 688c915a96..0000000000
--- a/lib/content-services/search/components/search-fields/search-fields.component.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*!
- * @license
- * Copyright 2016 Alfresco Software, Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { Component, ViewEncapsulation, OnInit, Input } from '@angular/core';
-import { MatCheckboxChange } from '@angular/material';
-
-import { SearchWidget } from '../../search-widget.interface';
-import { SearchWidgetSettings } from '../../search-widget-settings.interface';
-import { SearchQueryBuilderService } from '../../search-query-builder.service';
-
-@Component({
- selector: 'adf-search-fields',
- templateUrl: './search-fields.component.html',
- styleUrls: ['./search-fields.component.scss'],
- encapsulation: ViewEncapsulation.None,
- host: { class: 'adf-search-fields' }
-})
-export class SearchFieldsComponent implements SearchWidget, OnInit {
-
- @Input()
- value: string;
-
- id: string;
- settings: SearchWidgetSettings;
- context: SearchQueryBuilderService;
-
- ngOnInit() {
- const defaultOptions = (this.settings.options || [])
- .filter(opt => opt.default)
- .map(opt => {
- opt.checked = true;
- return opt;
- });
-
- if (defaultOptions.length > 0) {
- this.flush(defaultOptions);
- }
- }
-
- changeHandler(event: MatCheckboxChange, option: any) {
- option.checked = event.checked;
- this.flush(this.settings.options);
- }
-
- flush(opts: any[] = []) {
- const checkedValues = opts
- .filter(v => v.checked)
- .map(v => v.fields)
- .reduce((prev, curr) => {
- return prev.concat(curr);
- }, []);
-
- this.context.fields[this.id] = checkedValues;
- this.context.update();
- }
-}
diff --git a/lib/content-services/search/components/search-filter/search-filter.service.ts b/lib/content-services/search/components/search-filter/search-filter.service.ts
index d56c31b104..c1010939aa 100644
--- a/lib/content-services/search/components/search-filter/search-filter.service.ts
+++ b/lib/content-services/search/components/search-filter/search-filter.service.ts
@@ -18,8 +18,8 @@
import { Injectable, Type } from '@angular/core';
import { SearchTextComponent } from '../search-text/search-text.component';
import { SearchRadioComponent } from '../search-radio/search-radio.component';
-import { SearchFieldsComponent } from '../search-fields/search-fields.component';
-import { SearchScopeLocationsComponent } from '../search-scope-locations/search-scope-locations.component';
+import { SearchSliderComponent } from '../search-slider/search-slider.component';
+import { SearchNumberRangeComponent } from '../search-number-range/search-number-range.component';
@Injectable()
export class SearchFilterService {
@@ -30,8 +30,8 @@ export class SearchFilterService {
widgets: { [id: string]: Type<{}> } = {
'text': SearchTextComponent,
'radio': SearchRadioComponent,
- 'fields': SearchFieldsComponent,
- 'scope-locations': SearchScopeLocationsComponent
+ 'slider': SearchSliderComponent,
+ 'number-range': SearchNumberRangeComponent
};
}
diff --git a/lib/content-services/search/components/search-number-range/search-number-range.component.html b/lib/content-services/search/components/search-number-range/search-number-range.component.html
new file mode 100644
index 0000000000..6a25a88bed
--- /dev/null
+++ b/lib/content-services/search/components/search-number-range/search-number-range.component.html
@@ -0,0 +1,27 @@
+
diff --git a/lib/content-services/search/components/search-number-range/search-number-range.component.scss b/lib/content-services/search/components/search-number-range/search-number-range.component.scss
new file mode 100644
index 0000000000..c4437f1597
--- /dev/null
+++ b/lib/content-services/search/components/search-number-range/search-number-range.component.scss
@@ -0,0 +1,8 @@
+.adf-search-number-range > form {
+ display: inline-flex;
+ flex-direction: column;
+
+ .mat-button {
+ text-transform: uppercase;
+ }
+}
diff --git a/lib/content-services/search/components/search-number-range/search-number-range.component.spec.ts b/lib/content-services/search/components/search-number-range/search-number-range.component.spec.ts
new file mode 100644
index 0000000000..0a1f6e7893
--- /dev/null
+++ b/lib/content-services/search/components/search-number-range/search-number-range.component.spec.ts
@@ -0,0 +1,88 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { SearchNumberRangeComponent } from './search-number-range.component';
+
+describe('SearchNumberRangeComponent', () => {
+
+ let component: SearchNumberRangeComponent;
+
+ beforeEach(() => {
+ component = new SearchNumberRangeComponent();
+ });
+
+ it('should setup form elements on init', () => {
+ component.ngOnInit();
+ expect(component.form).toBeDefined();
+ expect(component.to).toBeDefined();
+ expect(component.form).toBeDefined();
+ });
+
+ it('should reset form', () => {
+ component.ngOnInit();
+ component.form.reset({ from: '10', to: '20' });
+ component.reset();
+
+ expect(component.from.value).toEqual('');
+ expect(component.to.value).toEqual('');
+ expect(component.form.value).toEqual({ from: '', to: '' });
+ });
+
+ it('should update query builder on reset', () => {
+ const context: any = {
+ queryFragments: {
+ contentSize: 'query'
+ },
+ update() {}
+ };
+
+ component.id = 'contentSize';
+ component.context = context;
+
+ spyOn(context, 'update').and.stub();
+
+ component.ngOnInit();
+ component.reset();
+
+ expect(context.queryFragments.contentSize).toEqual('');
+ expect(context.update).toHaveBeenCalled();
+ });
+
+ it('should update query builder on value changes', () => {
+ const context: any = {
+ queryFragments: {},
+ update() {}
+ };
+
+ component.id = 'contentSize';
+ component.context = context;
+ component.settings = { field: 'cm:content.size' };
+
+ spyOn(context, 'update').and.stub();
+
+ component.ngOnInit();
+ component.apply({
+ from: '10',
+ to: '20'
+ }, true);
+
+ const expectedQuery = 'cm:content.size:[10 TO 20]';
+ expect(context.queryFragments[component.id]).toEqual(expectedQuery);
+ expect(context.update).toHaveBeenCalled();
+ });
+
+});
diff --git a/lib/content-services/search/components/search-number-range/search-number-range.component.ts b/lib/content-services/search/components/search-number-range/search-number-range.component.ts
new file mode 100644
index 0000000000..ca9a9229bd
--- /dev/null
+++ b/lib/content-services/search/components/search-number-range/search-number-range.component.ts
@@ -0,0 +1,77 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { OnInit, Component, ViewEncapsulation } from '@angular/core';
+import { FormControl, Validators, FormGroup } from '@angular/forms';
+import { SearchWidget } from '../../search-widget.interface';
+import { SearchWidgetSettings } from '../../search-widget-settings.interface';
+import { SearchQueryBuilderService } from '../../search-query-builder.service';
+import { LiveErrorStateMatcher } from '../../forms/live-error-state-matcher';
+
+@Component({
+ selector: 'adf-search-number-range',
+ templateUrl: './search-number-range.component.html',
+ styleUrls: ['./search-number-range.component.scss'],
+ encapsulation: ViewEncapsulation.None,
+ host: { class: 'adf-search-number-range' }
+})
+export class SearchNumberRangeComponent implements SearchWidget, OnInit {
+
+ from: FormControl;
+ to: FormControl;
+
+ form: FormGroup;
+ matcher = new LiveErrorStateMatcher();
+
+ id: string;
+ settings?: SearchWidgetSettings;
+ context?: SearchQueryBuilderService;
+
+ ngOnInit(): void {
+ const validators = Validators.compose([
+ Validators.required,
+ Validators.pattern(/^-?(0|[1-9]\d*)?$/)
+ ]);
+
+ this.from = new FormControl('', validators);
+ this.to = new FormControl('', validators);
+
+ this.form = new FormGroup({
+ from: this.from,
+ to: this.to
+ });
+ }
+
+ apply(model: { from: string, to: string }, isValid: boolean) {
+ if (isValid && this.id && this.context && this.settings && this.settings.field) {
+ this.context.queryFragments[this.id] = `${this.settings.field}:[${model.from} TO ${model.to}]`;
+ this.context.update();
+ }
+ }
+
+ reset() {
+ this.form.reset({
+ from: '',
+ to: ''
+ });
+
+ if (this.id && this.context) {
+ this.context.queryFragments[this.id] = '';
+ this.context.update();
+ }
+ }
+}
diff --git a/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.html b/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.html
deleted file mode 100644
index 17cfe5077f..0000000000
--- a/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- {{option.name}}
-
-
-
diff --git a/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.ts b/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.ts
deleted file mode 100644
index 06051ce4ec..0000000000
--- a/lib/content-services/search/components/search-scope-locations/search-scope-locations.component.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*!
- * @license
- * Copyright 2016 Alfresco Software, Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { Component, ViewEncapsulation, OnInit, Input } from '@angular/core';
-import { MatSelectChange } from '@angular/material';
-
-import { SearchWidget } from '../../search-widget.interface';
-import { SearchWidgetSettings } from '../../search-widget-settings.interface';
-import { SearchQueryBuilderService } from '../../search-query-builder.service';
-
-@Component({
- selector: 'adf-search-scope-locations',
- templateUrl: './search-scope-locations.component.html',
- encapsulation: ViewEncapsulation.None,
- host: { class: 'adf-search-scope-locations' }
-})
-export class SearchScopeLocationsComponent implements SearchWidget, OnInit {
-
- @Input()
- value: string;
-
- id: string;
- settings: SearchWidgetSettings;
- context: SearchQueryBuilderService;
-
- ngOnInit() {
-
- const defaultSelection = (this.settings.options || []).find(opt => opt.default);
- if (defaultSelection) {
- this.flush(defaultSelection.value);
- }
- }
-
- changeHandler(event: MatSelectChange) {
- this.flush(event.value);
- }
-
- flush(value: string) {
- this.value = value;
- this.context.scope.locations = value;
- this.context.update();
- }
-}
diff --git a/lib/content-services/search/components/search-slider/search-slider.component.html b/lib/content-services/search/components/search-slider/search-slider.component.html
new file mode 100644
index 0000000000..adb5aecf52
--- /dev/null
+++ b/lib/content-services/search/components/search-slider/search-slider.component.html
@@ -0,0 +1,8 @@
+
+
diff --git a/lib/content-services/search/components/search-slider/search-slider.component.scss b/lib/content-services/search/components/search-slider/search-slider.component.scss
new file mode 100644
index 0000000000..2f05890816
--- /dev/null
+++ b/lib/content-services/search/components/search-slider/search-slider.component.scss
@@ -0,0 +1,5 @@
+.adf-search-slider {
+ .mat-slider {
+ width: 100%;
+ }
+}
diff --git a/lib/content-services/search/components/search-slider/search-slider.component.spec.ts b/lib/content-services/search/components/search-slider/search-slider.component.spec.ts
new file mode 100644
index 0000000000..cdad747c2c
--- /dev/null
+++ b/lib/content-services/search/components/search-slider/search-slider.component.spec.ts
@@ -0,0 +1,73 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { MatSliderChange } from '@angular/material';
+import { SearchSliderComponent } from './search-slider.component';
+
+describe('SearchSliderComponent', () => {
+
+ let component: SearchSliderComponent;
+
+ beforeEach(() => {
+ component = new SearchSliderComponent();
+ });
+
+ it('should setup slider from settings', () => {
+ const settings: any = {
+ min: 10,
+ max: 100,
+ step: 2,
+ thumbLabel: true
+ };
+
+ component.settings = settings;
+ component.ngOnInit();
+
+ expect(component.min).toEqual(settings.min);
+ expect(component.max).toEqual(settings.max);
+ expect(component.step).toEqual(settings.step);
+ expect(component.thumbLabel).toEqual(settings.thumbLabel);
+ });
+
+ it('should update value on slider change', () => {
+ component.onChangedHandler( { value: 10 });
+ expect(component.value).toEqual(10);
+
+ component.onChangedHandler( { value: 20 });
+ expect(component.value).toEqual(20);
+ });
+
+ it('should update its query part on slider change', () => {
+ const context: any = {
+ queryFragments: {},
+ update() {}
+ };
+
+ spyOn(context, 'update').and.stub();
+
+ component.context = context;
+ component.id = 'contentSize';
+ component.settings = { field: 'cm:content.size' };
+
+ component.onChangedHandler( { value: 10 });
+
+ const expectedQuery = 'cm:content.size:[0 TO 10]';
+ expect(context.queryFragments[component.id]).toEqual(expectedQuery);
+ expect(context.update).toHaveBeenCalled();
+ });
+
+});
diff --git a/lib/content-services/search/components/search-slider/search-slider.component.ts b/lib/content-services/search/components/search-slider/search-slider.component.ts
new file mode 100644
index 0000000000..bbe29b4e0e
--- /dev/null
+++ b/lib/content-services/search/components/search-slider/search-slider.component.ts
@@ -0,0 +1,69 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component, ViewEncapsulation, OnInit } from '@angular/core';
+import { SearchWidget } from '../../search-widget.interface';
+import { SearchWidgetSettings } from '../../search-widget-settings.interface';
+import { SearchQueryBuilderService } from '../../search-query-builder.service';
+import { MatSliderChange } from '@angular/material';
+
+@Component({
+ selector: 'adf-search-slider',
+ templateUrl: './search-slider.component.html',
+ styleUrls: ['./search-slider.component.scss'],
+ encapsulation: ViewEncapsulation.None,
+ host: { class: 'adf-search-slider' }
+})
+export class SearchSliderComponent implements SearchWidget, OnInit {
+
+ id: string;
+ settings: SearchWidgetSettings;
+ context: SearchQueryBuilderService;
+ step: number;
+ min: number;
+ max: number;
+ thumbLabel = false;
+ value: number;
+
+ ngOnInit() {
+ if (this.settings) {
+ if (this.settings.hasOwnProperty('min')) {
+ this.min = this.settings['min'];
+ }
+
+ if (this.settings.hasOwnProperty('max')) {
+ this.max = this.settings['max'];
+ }
+
+ if (this.settings.hasOwnProperty('step')) {
+ this.step = this.settings['step'];
+ }
+
+ this.thumbLabel = this.settings['thumbLabel'] ? true : false;
+ }
+ }
+
+ onChangedHandler(event: MatSliderChange) {
+ this.value = event.value;
+
+ if (this.id && this.context && this.settings && this.settings.field) {
+ this.context.queryFragments[this.id] = `${this.settings.field}:[0 TO ${this.value}]`;
+ this.context.update();
+ }
+ }
+
+}
diff --git a/lib/content-services/search/forms/live-error-state-matcher.ts b/lib/content-services/search/forms/live-error-state-matcher.ts
new file mode 100644
index 0000000000..4257d4afa6
--- /dev/null
+++ b/lib/content-services/search/forms/live-error-state-matcher.ts
@@ -0,0 +1,28 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ErrorStateMatcher } from '@angular/material';
+import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';
+
+export class LiveErrorStateMatcher implements ErrorStateMatcher {
+
+ isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
+ const isSubmitted = form && form.submitted;
+ return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
+ }
+
+}
diff --git a/lib/content-services/search/search-configuration.interface.ts b/lib/content-services/search/search-configuration.interface.ts
index ed6a406bd2..30948fcf8f 100644
--- a/lib/content-services/search/search-configuration.interface.ts
+++ b/lib/content-services/search/search-configuration.interface.ts
@@ -21,13 +21,11 @@ import { FacetField } from './facet-field.interface';
import { SearchCategory } from './search-category.interface';
export interface SearchConfiguration {
+ include?: Array;
+ fields?: Array;
query?: {
categories: Array
};
- limits?: {
- permissionEvaluationTime?: number;
- permissionEvaluationCount?: number;
- };
filterQueries?: Array;
facetQueries?: Array;
facetFields?: {
diff --git a/lib/content-services/search/search-query-builder.service.spec.ts b/lib/content-services/search/search-query-builder.service.spec.ts
index ce757edc0e..52f75332a1 100644
--- a/lib/content-services/search/search-query-builder.service.spec.ts
+++ b/lib/content-services/search/search-query-builder.service.spec.ts
@@ -69,13 +69,6 @@ describe('SearchQueryBuilder', () => {
expect(builder.filterQueries[1].query).toBe('query2');
});
- it('should setup default location scope', () => {
- const builder = new SearchQueryBuilderService(buildConfig({}), null);
-
- expect(builder.scope).toBeDefined();
- expect(builder.scope.locations).toBeNull();
- });
-
it('should add new filter query', () => {
const builder = new SearchQueryBuilderService(buildConfig({}), null);
@@ -237,6 +230,7 @@ describe('SearchQueryBuilder', () => {
it('should build query with custom fields', () => {
const config: SearchConfiguration = {
+ fields: ['field1', 'field2'],
query: {
categories: [
{ id: 'cat1', enabled: true },
@@ -247,15 +241,14 @@ describe('SearchQueryBuilder', () => {
const builder = new SearchQueryBuilderService(buildConfig(config), null);
builder.queryFragments['cat1'] = 'cm:name:test';
- builder.fields['cat1'] = ['field1', 'field3'];
- builder.fields['cat2'] = ['field2', 'field3'];
const compiled = builder.buildQuery();
- expect(compiled.fields).toEqual(['field1', 'field3', 'field2']);
+ expect(compiled.fields).toEqual(['field1', 'field2']);
});
it('should build query with empty custom fields', () => {
const config: SearchConfiguration = {
+ fields: [],
query: {
categories: [
{ id: 'cat1', enabled: true },
@@ -266,8 +259,6 @@ describe('SearchQueryBuilder', () => {
const builder = new SearchQueryBuilderService(buildConfig(config), null);
builder.queryFragments['cat1'] = 'cm:name:test';
- builder.fields['cat1'] = [];
- builder.fields['cat2'] = null;
const compiled = builder.buildQuery();
expect(compiled.fields).toEqual([]);
@@ -330,41 +321,6 @@ describe('SearchQueryBuilder', () => {
expect(compiled.facetFields).toEqual(config.facetFields);
});
- it('should build query with custom limits', () => {
- const config: SearchConfiguration = {
- query: {
- categories: [
- { id: 'cat1', enabled: true }
- ]
- },
- limits: {
- permissionEvaluationCount: 100,
- permissionEvaluationTime: 100
- }
- };
- const builder = new SearchQueryBuilderService(buildConfig(config), null);
- builder.queryFragments['cat1'] = 'cm:name:test';
-
- const compiled = builder.buildQuery();
- expect(compiled.limits).toEqual(config.limits);
- });
-
- it('should build query with custom scope', () => {
- const config: SearchConfiguration = {
- query: {
- categories: [
- { id: 'cat1', enabled: true }
- ]
- }
- };
- const builder = new SearchQueryBuilderService(buildConfig(config), null);
- builder.queryFragments['cat1'] = 'cm:name:test';
- builder.scope.locations = 'custom';
-
- const compiled = builder.buildQuery();
- expect(compiled.scope.locations).toEqual('custom');
- });
-
it('should use pagination settings', () => {
const config: SearchConfiguration = {
query: {
diff --git a/lib/content-services/search/search-query-builder.service.ts b/lib/content-services/search/search-query-builder.service.ts
index dd2cb58ebf..8ad60f1c26 100644
--- a/lib/content-services/search/search-query-builder.service.ts
+++ b/lib/content-services/search/search-query-builder.service.ts
@@ -33,8 +33,6 @@ export class SearchQueryBuilderService {
categories: Array = [];
queryFragments: { [id: string]: string } = {};
- fields: { [id: string]: string[] } = {};
- scope: { locations?: string };
filterQueries: FilterQuery[] = [];
ranges: { [id: string]: SearchRange } = {};
paging: { maxItems?: number; skipCount?: number } = null;
@@ -52,9 +50,6 @@ export class SearchQueryBuilderService {
}
this.filterQueries = this.config.filterQueries || [];
- this.scope = {
- locations: null
- };
}
addFilterQuery(query: string): void {
@@ -93,7 +88,6 @@ export class SearchQueryBuilderService {
buildQuery(): QueryBody {
let query = '';
- const fields: string[] = [];
this.categories.forEach(facet => {
const customQuery = this.queryFragments[facet.id];
@@ -103,17 +97,13 @@ export class SearchQueryBuilderService {
}
query += `(${customQuery})`;
}
-
- const customFields = this.fields[facet.id];
- if (customFields && customFields.length > 0) {
- for (const field of customFields) {
- if (!fields.includes(field)) {
- fields.push(field);
- }
- }
- }
});
+ const include = this.config.include || [];
+ if (include.length === 0) {
+ include.push('path', 'allowableOperations');
+ }
+
if (query) {
const result: QueryBody = {
@@ -121,14 +111,12 @@ export class SearchQueryBuilderService {
query: query,
language: 'afts'
},
- include: ['path', 'allowableOperations'],
- fields: fields,
+ include: include,
paging: this.paging,
+ fields: this.config.fields,
filterQueries: this.filterQueries,
facetQueries: this.config.facetQueries,
- facetFields: this.config.facetFields,
- limits: this.config.limits,
- scope: this.scope
+ facetFields: this.config.facetFields
};
return result;
diff --git a/lib/content-services/search/search.module.ts b/lib/content-services/search/search.module.ts
index 8e0d3d846a..59663158fb 100644
--- a/lib/content-services/search/search.module.ts
+++ b/lib/content-services/search/search.module.ts
@@ -33,8 +33,8 @@ import { SearchFilterComponent } from './components/search-filter/search-filter.
import { SearchChipListComponent } from './components/search-chip-list/search-chip-list.component';
import { SearchTextComponent } from './components/search-text/search-text.component';
import { SearchRadioComponent } from './components/search-radio/search-radio.component';
-import { SearchFieldsComponent } from './components/search-fields/search-fields.component';
-import { SearchScopeLocationsComponent } from './components/search-scope-locations/search-scope-locations.component';
+import { SearchSliderComponent } from './components/search-slider/search-slider.component';
+import { SearchNumberRangeComponent } from './components/search-number-range/search-number-range.component';
export const ALFRESCO_SEARCH_DIRECTIVES: any[] = [
SearchComponent,
@@ -59,23 +59,23 @@ export const ALFRESCO_SEARCH_DIRECTIVES: any[] = [
SearchWidgetContainerComponent,
SearchTextComponent,
SearchRadioComponent,
- SearchFieldsComponent,
- SearchScopeLocationsComponent
+ SearchSliderComponent,
+ SearchNumberRangeComponent
],
exports: [
...ALFRESCO_SEARCH_DIRECTIVES,
SearchWidgetContainerComponent,
SearchTextComponent,
SearchRadioComponent,
- SearchFieldsComponent,
- SearchScopeLocationsComponent
+ SearchSliderComponent,
+ SearchNumberRangeComponent
],
entryComponents: [
SearchWidgetContainerComponent,
SearchTextComponent,
SearchRadioComponent,
- SearchFieldsComponent,
- SearchScopeLocationsComponent
+ SearchSliderComponent,
+ SearchNumberRangeComponent
]
})
export class SearchModule {}
diff --git a/lib/core/app-config/schema.json b/lib/core/app-config/schema.json
index 48956b2cdb..711c7650d6 100644
--- a/lib/core/app-config/schema.json
+++ b/lib/core/app-config/schema.json
@@ -481,12 +481,16 @@
"description": "Search configuration parameters",
"type": "object",
"properties": {
- "limits": {
- "description": "The limits element limits the time and resources used for query execution. Limits applied to the query go to the database.",
- "type": "object",
- "properties": {
- "permissionEvaluationTime": { "type": "integer" },
- "permissionEvaluationCount": { "type": "integer" }
+ "include": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "fields": {
+ "type": "array",
+ "items": {
+ "type": "string"
}
},
"filterQueries": {