diff --git a/front/app/src/app/views/base-view/list/list.component.html b/front/app/src/app/views/base-view/list/list.component.html
index 514d337a..99f92f3e 100644
--- a/front/app/src/app/views/base-view/list/list.component.html
+++ b/front/app/src/app/views/base-view/list/list.component.html
@@ -2,6 +2,7 @@
[resource]="this.resource"
[schema]="this.schema"
[columns]="this.columns"
+ [filters]="this.filters"
(result)="this.flashService.success($event)"
(error)="this.flashService.error($event)">
\ No newline at end of file
diff --git a/front/app/src/app/views/base-view/list/list.component.ts b/front/app/src/app/views/base-view/list/list.component.ts
index 9d50abaf..56fea308 100644
--- a/front/app/src/app/views/base-view/list/list.component.ts
+++ b/front/app/src/app/views/base-view/list/list.component.ts
@@ -9,6 +9,7 @@ export class BaseCrudListComponent {
@Input() resource: string = "";
@Input() columns: string[] = [];
@Input() schema: string | undefined;
+ @Input() filters: string[] = [];
constructor(
public flashService: FlashmessagesService
diff --git a/front/app/src/app/views/base-view/templates/list.template.html b/front/app/src/app/views/base-view/templates/list.template.html
index 3b9cc863..f0b7ec17 100644
--- a/front/app/src/app/views/base-view/templates/list.template.html
+++ b/front/app/src/app/views/base-view/templates/list.template.html
@@ -1,5 +1,6 @@
+ [columns]="this.columns"
+ [filters]="this.filters">
\ No newline at end of file
diff --git a/front/app/src/common/crud/crud-formly-jsonschema.service.ts b/front/app/src/common/crud/crud-formly-jsonschema.service.ts
index 275bb4da..cdbe25df 100644
--- a/front/app/src/common/crud/crud-formly-jsonschema.service.ts
+++ b/front/app/src/common/crud/crud-formly-jsonschema.service.ts
@@ -55,6 +55,8 @@ export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions {
field.type = "richtext";
} else if (schema.type == "string" && schema.format == "signature-link") {
field.type = "signature-link";
+ } else if (field.type == "enum" && field.props.multiple) {
+ field.type = 'multicheckbox';
}
if (schema.hasOwnProperty('props')) {
diff --git a/front/app/src/common/crud/crud.module.ts b/front/app/src/common/crud/crud.module.ts
index 7b9ab6c7..a5eb39e7 100644
--- a/front/app/src/common/crud/crud.module.ts
+++ b/front/app/src/common/crud/crud.module.ts
@@ -28,12 +28,14 @@ import { DictionaryService } from "./types/dictionary.service";
import { RichtextTypeComponent } from "./types/richtext.type";
import { SignatureLinkTypeComponent } from "@common/crud/types/signature-link.type";
import { ClipboardModule } from '@angular/cdk/clipboard';
+import {FilterListComponent} from "@common/crud/list/filter-list.component";
@NgModule({
declarations: [
CardComponent,
ListComponent,
+ FilterListComponent,
ObjectTypeComponent,
DatetimeTypeComponent,
DateTypeComponent,
diff --git a/front/app/src/common/crud/jsonschemas.service.ts b/front/app/src/common/crud/jsonschemas.service.ts
index 271020b2..de3a2efb 100644
--- a/front/app/src/common/crud/jsonschemas.service.ts
+++ b/front/app/src/common/crud/jsonschemas.service.ts
@@ -206,6 +206,21 @@ export class JsonschemasService {
path.substring(pointFirstPosition + 1)
);
}
+
+ get_property_by_path(resource: JSONSchema7, path: string): JSONSchema7 {
+ const pointFirstPosition = path.indexOf('.')
+ if (pointFirstPosition == -1) {
+ return this.get_descendant(resource, path);
+ }
+
+ return this.get_property_by_path(
+ this.get_descendant(
+ resource,
+ path.substring(0, pointFirstPosition)
+ ),
+ path.substring(pointFirstPosition + 1)
+ );
+ }
}
export interface Schema {
diff --git a/front/app/src/common/crud/list/filter-list.component.ts b/front/app/src/common/crud/list/filter-list.component.ts
new file mode 100644
index 00000000..9e69fedd
--- /dev/null
+++ b/front/app/src/common/crud/list/filter-list.component.ts
@@ -0,0 +1,88 @@
+import {Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {JSONSchema7} from "json-schema";
+import {JsonschemasService} from "@common/crud/jsonschemas.service"
+import {FormGroup} from "@angular/forms";
+import {FormlyFieldConfig} from "@ngx-formly/core";
+import {CrudFormlyJsonschemaService} from "@common/crud/crud-formly-jsonschema.service";
+
+@Component({
+ selector: 'crud-list-filter-list',
+ template: `
+
+ `,
+})
+export class FilterListComponent implements OnInit {
+ @Input() filters: string[] = [];
+ @Input() schema = "";
+
+ @Output() filterChange: EventEmitter<{[key: string]: any}> = new EventEmitter();
+
+ form = new FormGroup({});
+ fields: FormlyFieldConfig[] = [];
+
+ searchTerms = {}
+
+ public fieldJson = {
+ components: {},
+ type: "object",
+ properties: {},
+ }
+
+ constructor(private jsonSchemasService: JsonschemasService,
+ private formlyJsonschema: CrudFormlyJsonschemaService,) { }
+
+ ngOnInit() {
+ this.jsonSchemasService.getUpdateResource(this.schema!).subscribe({
+ next: (schema: any) => this.getFilterDefinition(schema),
+ error: (err) => console.log(err) /*this.error.emit("Error loading the schema:" + err)*/
+ });
+ }
+
+ getFilterDefinition(schema: JSONSchema7) {
+ const properties: {[key: string]: JSONSchema7} = {}
+ for (let filter of this.filters) {
+ if (this.jsonSchemasService.path_exists(schema, filter)) {
+ let prop = this.jsonSchemasService.get_property_by_path(schema, filter)
+ if (prop.hasOwnProperty('allOf')) {
+ // @ts-ignore
+ prop = schema.components.schemas[prop.allOf![0]['$ref'].replace('#/components/schemas/', '')];
+ prop.type = "array";
+ prop.items = {"type": "string", "enum": prop.enum};
+ }
+
+ if (prop.hasOwnProperty('readOnly') && prop.readOnly) {
+ prop.readOnly = false
+ }
+ properties[filter] = prop;
+ }
+ }
+ // @ts-ignore
+ this.fieldJson.components = schema.components;
+ this.fieldJson.properties = properties;
+
+ // @ts-ignore
+ this.fields = [this.formlyJsonschema.toFieldConfig(this.fieldJson)]
+ }
+
+ onModelChange(event: {[key: string]: any}) {
+ for (let p_name in event) {
+ // @ts-ignore
+ let p = this.fieldJson.properties[p_name]
+ if (p.type == "array" && !Array.isArray(p.items)) {
+ let value = []
+ for (let key in event[p_name]) {
+ if (event[p_name][key]) {
+ value.push(key)
+ }
+ }
+
+ if (value.length == 0 || value.length == p.items.enum.length) {
+ delete event[p_name];
+ } else {
+ event[p_name] = value;
+ }
+ }
+ }
+ this.filterChange.next(event);
+ }
+}
diff --git a/front/app/src/common/crud/list/list.component.html b/front/app/src/common/crud/list/list.component.html
index 25bf5009..a806a7a4 100644
--- a/front/app/src/common/crud/list/list.component.html
+++ b/front/app/src/common/crud/list/list.component.html
@@ -13,6 +13,9 @@
[(ngModel)]="searchTerm"
/>
+
+
+
Loading...
diff --git a/front/app/src/common/crud/list/list.component.ts b/front/app/src/common/crud/list/list.component.ts
index 3989c594..7d281935 100644
--- a/front/app/src/common/crud/list/list.component.ts
+++ b/front/app/src/common/crud/list/list.component.ts
@@ -13,6 +13,7 @@ interface State {
searchTerm: string;
sortColumn: SortColumn;
sortDirection: SortDirection;
+ searchFilters: {[key: string]: any}
}
@Component({
@@ -23,6 +24,7 @@ interface State {
export class ListComponent implements OnInit {
@Input() resource: string = "";
@Input() columns: string[] = [];
+ @Input() filters: string[] = [];
@Input() schema: string | undefined;
@Output() error: EventEmitter = new EventEmitter();
@@ -43,6 +45,7 @@ export class ListComponent implements OnInit {
searchTerm: '',
sortColumn: '_id',
sortDirection: 'asc',
+ searchFilters: {}
};
constructor(private service: CrudService,
@@ -93,6 +96,13 @@ export class ListComponent implements OnInit {
this._loading$.next(true);
let sortBy = new SortBy(this.sortColumn, this.sortDirection)
let filters = this.searchTerm ? [new Filters('fulltext', 'eq', this.searchTerm)] : [];
+ for (let f in this.searchFilters) {
+ if (Array.isArray(this.searchFilters[f])) {
+ filters.push(new Filters(f, 'in', this.searchFilters[f]))
+ } else {
+ filters.push(new Filters(f, 'eq', this.searchFilters[f]))
+ }
+ }
this.service.getList(this.resource, this.page, this.pageSize, [sortBy], filters).subscribe({
next: (data: any) => {
@@ -107,6 +117,10 @@ export class ListComponent implements OnInit {
});
}
+ onFilterChange(event: any) {
+ this.searchFilters = event;
+ }
+
onSort({ column, direction }: any) {
// resetting other headers
this.headers.forEach((header) => {
@@ -151,6 +165,9 @@ export class ListComponent implements OnInit {
get searchTerm() {
return this._state.searchTerm;
}
+ get searchFilters() {
+ return this._state.searchFilters;
+ }
set page(page: number) {
this._set({ page });
@@ -161,6 +178,9 @@ export class ListComponent implements OnInit {
set searchTerm(searchTerm: string) {
this._set({ searchTerm });
}
+ set searchFilters(searchFilters: {[key: string]: any}) {
+ this._set({ searchFilters });
+ }
set sortColumn(sortColumn: SortColumn) {
this._set({ sortColumn });
}