Browse Source

Minor improvements to query editor.

pull/473/head
Sebastian 7 years ago
parent
commit
bf3faa1524
  1. 2
      frontend/app/features/content/pages/contents/contents-page.component.html
  2. 2
      frontend/app/features/content/shared/contents-selector.component.html
  3. 4
      frontend/app/framework/angular/forms/date-time-editor.component.html
  4. 10
      frontend/app/framework/angular/forms/date-time-editor.component.ts
  5. 12
      frontend/app/framework/angular/forms/dropdown.component.ts
  6. 20
      frontend/app/shared/components/queries/filter-comparison.component.html
  7. 6
      frontend/app/shared/components/queries/filter-comparison.component.scss
  8. 16
      frontend/app/shared/components/queries/sorting.component.ts
  9. 2
      frontend/app/shared/components/search-form.component.ts
  10. 95
      frontend/app/shared/state/query.ts
  11. 4
      frontend/app/theme/_forms.scss

2
frontend/app/features/content/pages/contents/contents-page.component.html

@ -15,7 +15,7 @@
</button>
</div>
<div class="col pl-1">
<sqx-search-form formClass="form" placeholder="Search for content"
<sqx-search-form formClass="form" placeholder="Fulltext search"
[query]="contentsState.contentsQuery | async"
[queries]="queries"
[queryModel]="queryModel"

2
frontend/app/features/content/shared/contents-selector.component.html

@ -22,7 +22,7 @@
</button>
</div>
<div class="col pl-1">
<sqx-search-form formClass="form" placeholder="Search for content"
<sqx-search-form formClass="form" placeholder="Fulltext search"
[query]="contentsState.contentsQuery | async"
[queryModel]="queryModel"
(queryChange)="search($event)">

4
frontend/app/framework/angular/forms/date-time-editor.component.html

@ -13,12 +13,12 @@
<i class="icon-close"></i>
</button>
</div>
<div class="form-group" *ngIf="showTime && !hideDateButtons">
<div class="form-group" *ngIf="showTime && shouldShowDateButtons">
<button type="button" class="btn btn-text-secondary" [disabled]="snapshot.isDisabled" (click)="writeNow()" title="Use Now (UTC)">
Now
</button>
</div>
<div class="form-group" *ngIf="!showTime && !hideDateButtons">
<div class="form-group" *ngIf="!showTime && shouldShowDateButtons">
<button type="button" class="btn btn-text-secondary" [disabled]="snapshot.isDisabled" (click)="writeNow()" title="Use Today (UTC)">
Today
</button>

10
frontend/app/framework/angular/forms/date-time-editor.component.ts

@ -36,6 +36,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
private picker: any;
private timeValue: moment.Moment | null = null;
private dateValue: moment.Moment | null = null;
private hideDateButtonsSettings: boolean;
private suppressEvents = false;
@Input()
@ -47,13 +48,18 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
@Input()
public hideClear: boolean;
@Input()
public hideDateButtons: boolean;
@ViewChild('dateInput', { static: false })
public dateInput: ElementRef;
public timeControl = new FormControl();
public dateControl = new FormControl();
public hideDateButtons: boolean;
public get shouldShowDateButtons() {
return !this.hideDateButtonsSettings && !this.hideDateButtons;
}
public get showTime() {
return this.mode === 'DateTime';
@ -66,7 +72,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
constructor(changeDetector: ChangeDetectorRef, uiOptions: UIOptions) {
super(changeDetector, {});
this.hideDateButtons = !!uiOptions.get('hideDateButtons');
this.hideDateButtonsSettings = !!uiOptions.get('hideDateButtons');
}
public ngOnInit() {

12
frontend/app/framework/angular/forms/dropdown.component.ts

@ -107,15 +107,11 @@ export class DropdownComponent extends StatefulControlComponent<State, any[]> im
public ngAfterContentInit() {
if (this.templates.length === 1) {
this.templateItem = this.templateSelection = this.templates.first;
this.templateItem = this.templates.first;
this.templateSelection = this.templates.first;
} else {
this.templates.forEach(template => {
if (template.name === 'selection') {
this.templateSelection = template;
} else {
this.templateItem = template;
}
});
this.templateItem = this.templates.first;
this.templateSelection = this.templates.last;
}
if (this.templateItem) {

20
frontend/app/shared/components/queries/filter-comparison.component.html

@ -1,15 +1,23 @@
<div class="row no-gutters mb-1" *ngIf="fieldModel">
<div class="col-auto path">
<select class="form-control" [ngModel]="filter.path" (ngModelChange)="changePath($event)">
<option *ngFor="let fieldName of model.fields | sqxKeys" [ngValue]="fieldName">{{fieldName}}</option>
</select>
<sqx-dropdown [items]="model.fields | sqxKeys" [ngModel]="filter.path" (ngModelChange)="changePath($event)" [canSearch]="false">
<ng-template let-field="$implicit">
<div>{{model.fields[field].displayName}}</div>
<sqx-form-hint>{{model.fields[field].description}}</sqx-form-hint>
</ng-template>
<ng-template let-field="$implicit">
{{model.fields[field].displayName}}
</ng-template>
</sqx-dropdown>
</div>
<div class="col-auto pl-2">
<div class="col-auto operator pl-1">
<select class="form-control" [ngModel]="filter.op" (ngModelChange)="changeOp($event)">
<option *ngFor="let operator of fieldModel.operators" [ngValue]="operator.value">{{operator.name || operator.value}}</option>
</select>
</div>
<div class="col pl-2" *ngIf="!noValue" [ngSwitch]="fieldModel.type">
<div class="col pl-1" *ngIf="!noValue" [ngSwitch]="fieldModel.type">
<ng-container *ngSwitchCase="'boolean'">
<input type="checkbox" class="form-control"
[ngModel]="filter.value"
@ -17,12 +25,14 @@
</ng-container>
<ng-container *ngSwitchCase="'date'">
<sqx-date-time-editor mode="Date"
[hideDateButtons]="true"
[ngModel]="filter.value"
(ngModelChange)="changeValue($event)">
</sqx-date-time-editor>
</ng-container>
<ng-container *ngSwitchCase="'datetime'">
<sqx-date-time-editor mode="DateTime"
[hideDateButtons]="true"
[ngModel]="filter.value"
(ngModelChange)="changeValue($event)">
</sqx-date-time-editor>

6
frontend/app/shared/components/queries/filter-comparison.component.scss

@ -2,5 +2,9 @@
@import '_mixins';
.path {
max-width: 12rem;
width: 10rem;
}
.operator {
width: 10rem;
}

16
frontend/app/shared/components/queries/sorting.component.ts

@ -15,11 +15,19 @@ import { QueryModel, QuerySorting } from '@app/shared/internal';
<div class="row">
<div class="col">
<div class="form-inline">
<select class="form-control mr-2" [ngModel]="sorting.path" (ngModelChange)="changePath($event)">
<option *ngFor="let fieldName of model.fields | sqxKeys" [ngValue]="fieldName">{{fieldName}}</option>
</select>
<sqx-dropdown [items]="model.fields | sqxKeys" [ngModel]="sorting.path" (ngModelChange)="changePath($event)" [canSearch]="false">
<ng-template let-field="$implicit">
<div>{{model.fields[field].displayName}}</div>
<sqx-form-hint>{{model.fields[field].description}}</sqx-form-hint>
</ng-template>
<ng-template let-field="$implicit">
{{model.fields[field].displayName}}
</ng-template>
</sqx-dropdown>
<select class="form-control mr-2" [ngModel]="sorting.order" (ngModelChange)="changeOrder($event)">
<select class="form-control ml-1" [ngModel]="sorting.order" (ngModelChange)="changeOrder($event)">
<option>ascending</option>
<option>descending</option>
</select>

2
frontend/app/shared/components/search-form.component.ts

@ -56,7 +56,7 @@ export class SearchFormComponent implements OnChanges {
public saveQueryDialog = new DialogModel();
public saveQueryForm = new SaveQueryForm(this.formBuilder);
public searchDialog = new DialogModel();
public searchDialog = new DialogModel(true);
public hasFilter: boolean;

95
frontend/app/shared/state/query.ts

@ -43,11 +43,19 @@ export interface QueryFieldModel {
// Extra values.
extra?: any;
// The optional display name for the field.
displayName?: string;
// The optional description for the field.
description?: string;
}
type QueryModelFields = { [name: string]: QueryFieldModel };
export interface QueryModel {
// All available fields.
fields: { [name: string]: QueryFieldModel };
fields: QueryModelFields;
}
export type FilterNode = FilterComparison | FilterLogical;
@ -121,25 +129,25 @@ export function hasFilter(query?: Query) {
}
const EqualOperators: ReadonlyArray<FilterOperator> = [
{ name: '==', value: 'eq' },
{ name: '!=', value: 'ne' }
{ name: 'is equals to', value: 'eq' },
{ name: 'is not equals to', value: 'ne' }
];
const CompareOperator: ReadonlyArray<FilterOperator> = [
{ name: '<', value: 'lt' },
{ name: '<=', value: 'le' },
{ name: '>', value: 'gt' },
{ name: '>=', value: 'ge' }
{ name: 'is less than', value: 'lt' },
{ name: 'is less than or equals to', value: 'le' },
{ name: 'is greater than', value: 'gt' },
{ name: 'is greater than or equals to', value: 'ge' }
];
const StringOperators: ReadonlyArray<FilterOperator> = [
{ name: 'T*', value: 'startsWith' },
{ name: '*T', value: 'endsWith' },
{ name: '*T*', value: 'contains' }
{ name: 'starts with', value: 'startsWith' },
{ name: 'ends with', value: 'endsWith' },
{ name: 'contains', value: 'contains' }
];
const ArrayOperators: ReadonlyArray<FilterOperator> = [
{ value: 'empty', noValue: true }
{ value: 'is empty', noValue: true }
];
const TypeBoolean: QueryFieldModel = {
@ -177,23 +185,48 @@ const TypeTags: QueryFieldModel = {
operators: EqualOperators
};
const DEFAULT_FIELDS: QueryModelFields = {
created: {
...TypeDateTime,
displayName: 'Created',
description: 'The date time when the content item was created.'
},
createdBy: {
...TypeString,
displayName: 'Created by',
description: 'The user who created the content item.'
},
lastModified: {
...TypeDateTime,
displayName: 'Updated',
description: 'The date time when the content item was updated the last time.'
},
lastModifiedBy: {
...TypeString,
displayName: 'Updated by',
description: 'The user who updated the content item the last time.'
},
version: {
...TypeNumber,
displayName: 'Version',
description: 'The version of the content item'
}
};
export function queryModelFromSchema(schema: SchemaDetailsDto, languages: ReadonlyArray<LanguageDto>, statuses: ReadonlyArray<StatusInfo> | undefined) {
const languagesCodes = languages.map(x => x.iso2Code);
const invariantCodes = ['iv'];
const model: QueryModel = {
fields: {}
fields: { ...DEFAULT_FIELDS }
};
model.fields['created'] = TypeDateTime;
model.fields['createdBy'] = TypeString;
model.fields['lastModified'] = TypeDateTime;
model.fields['lastModifiedBy'] = TypeString;
model.fields['version'] = TypeNumber;
if (statuses) {
model.fields['status'] = { ...TypeStatus, extra: statuses };
model.fields['status'] = {
...TypeStatus,
displayName: 'Status',
description: 'The status of the content item.',
extra: statuses
};
}
for (const field of schema.fields) {
@ -216,10 +249,22 @@ export function queryModelFromSchema(schema: SchemaDetailsDto, languages: Readon
}
if (type) {
const codes = field.isLocalizable ? languagesCodes : invariantCodes;
for (const code of codes) {
model.fields[`data.${field.name}.${code}`] = type;
if (field.isLocalizable) {
for (const code of languagesCodes) {
const infos = {
displayName: `${field.displayName} (${code})`,
description: `The '${field.displayName}' field of the content item (localized).`
};
model.fields[`data.${field.name}.${code}`] = { ...type, ...infos };
}
} else {
const infos = {
displayName: field.displayName,
description: `The '${field.displayName}' field of the content item.`
};
model.fields[`data.${field.name}.iv`] = { ...type, ...infos };
}
}
}

4
frontend/app/theme/_forms.scss

@ -165,6 +165,10 @@
background: $color-theme-blue;
border: 0;
color: $color-dark-foreground;
& * {
color: $color-dark-foreground !important;
}
}
}
}

Loading…
Cancel
Save