Adding filter display and management in Crud front
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
[resource]="this.resource"
|
[resource]="this.resource"
|
||||||
[schema]="this.schema"
|
[schema]="this.schema"
|
||||||
[columns]="this.columns"
|
[columns]="this.columns"
|
||||||
|
[filters]="this.filters"
|
||||||
(result)="this.flashService.success($event)"
|
(result)="this.flashService.success($event)"
|
||||||
(error)="this.flashService.error($event)">
|
(error)="this.flashService.error($event)">
|
||||||
</crud-list>
|
</crud-list>
|
||||||
@@ -9,6 +9,7 @@ export class BaseCrudListComponent {
|
|||||||
@Input() resource: string = "";
|
@Input() resource: string = "";
|
||||||
@Input() columns: string[] = [];
|
@Input() columns: string[] = [];
|
||||||
@Input() schema: string | undefined;
|
@Input() schema: string | undefined;
|
||||||
|
@Input() filters: string[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public flashService: FlashmessagesService
|
public flashService: FlashmessagesService
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<base-list
|
<base-list
|
||||||
[resource]="this.resource"
|
[resource]="this.resource"
|
||||||
[schema]="this.schema"
|
[schema]="this.schema"
|
||||||
[columns]="this.columns">
|
[columns]="this.columns"
|
||||||
|
[filters]="this.filters">
|
||||||
</base-list>
|
</base-list>
|
||||||
@@ -55,6 +55,8 @@ export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions {
|
|||||||
field.type = "richtext";
|
field.type = "richtext";
|
||||||
} else if (schema.type == "string" && schema.format == "signature-link") {
|
} else if (schema.type == "string" && schema.format == "signature-link") {
|
||||||
field.type = "signature-link";
|
field.type = "signature-link";
|
||||||
|
} else if (field.type == "enum" && field.props.multiple) {
|
||||||
|
field.type = 'multicheckbox';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.hasOwnProperty('props')) {
|
if (schema.hasOwnProperty('props')) {
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ import { DictionaryService } from "./types/dictionary.service";
|
|||||||
import { RichtextTypeComponent } from "./types/richtext.type";
|
import { RichtextTypeComponent } from "./types/richtext.type";
|
||||||
import { SignatureLinkTypeComponent } from "@common/crud/types/signature-link.type";
|
import { SignatureLinkTypeComponent } from "@common/crud/types/signature-link.type";
|
||||||
import { ClipboardModule } from '@angular/cdk/clipboard';
|
import { ClipboardModule } from '@angular/cdk/clipboard';
|
||||||
|
import {FilterListComponent} from "@common/crud/list/filter-list.component";
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
CardComponent,
|
CardComponent,
|
||||||
ListComponent,
|
ListComponent,
|
||||||
|
FilterListComponent,
|
||||||
ObjectTypeComponent,
|
ObjectTypeComponent,
|
||||||
DatetimeTypeComponent,
|
DatetimeTypeComponent,
|
||||||
DateTypeComponent,
|
DateTypeComponent,
|
||||||
|
|||||||
@@ -206,6 +206,21 @@ export class JsonschemasService {
|
|||||||
path.substring(pointFirstPosition + 1)
|
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 {
|
export interface Schema {
|
||||||
|
|||||||
88
front/app/src/common/crud/list/filter-list.component.ts
Normal file
88
front/app/src/common/crud/list/filter-list.component.ts
Normal file
@@ -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: `
|
||||||
|
<formly-form [form]="form" [fields]="fields" [model]="this.searchTerms" (modelChange)="onModelChange($event)"></formly-form>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
[(ngModel)]="searchTerm"
|
[(ngModel)]="searchTerm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-xs-3 col-sm-auto">
|
||||||
|
<crud-list-filter-list [filters]="this.filters" [schema]="this.schema!" (filterChange)="onFilterChange($event)"></crud-list-filter-list>
|
||||||
|
</div>
|
||||||
<span class="col col-form-label" i18n *ngIf="loading$ | async">Loading...</span>
|
<span class="col col-form-label" i18n *ngIf="loading$ | async">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive-md">
|
<div class="table-responsive-md">
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface State {
|
|||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
sortColumn: SortColumn;
|
sortColumn: SortColumn;
|
||||||
sortDirection: SortDirection;
|
sortDirection: SortDirection;
|
||||||
|
searchFilters: {[key: string]: any}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -23,6 +24,7 @@ interface State {
|
|||||||
export class ListComponent implements OnInit {
|
export class ListComponent implements OnInit {
|
||||||
@Input() resource: string = "";
|
@Input() resource: string = "";
|
||||||
@Input() columns: string[] = [];
|
@Input() columns: string[] = [];
|
||||||
|
@Input() filters: string[] = [];
|
||||||
@Input() schema: string | undefined;
|
@Input() schema: string | undefined;
|
||||||
|
|
||||||
@Output() error: EventEmitter<string> = new EventEmitter();
|
@Output() error: EventEmitter<string> = new EventEmitter();
|
||||||
@@ -43,6 +45,7 @@ export class ListComponent implements OnInit {
|
|||||||
searchTerm: '',
|
searchTerm: '',
|
||||||
sortColumn: '_id',
|
sortColumn: '_id',
|
||||||
sortDirection: 'asc',
|
sortDirection: 'asc',
|
||||||
|
searchFilters: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private service: CrudService,
|
constructor(private service: CrudService,
|
||||||
@@ -93,6 +96,13 @@ export class ListComponent implements OnInit {
|
|||||||
this._loading$.next(true);
|
this._loading$.next(true);
|
||||||
let sortBy = new SortBy(this.sortColumn, this.sortDirection)
|
let sortBy = new SortBy(this.sortColumn, this.sortDirection)
|
||||||
let filters = this.searchTerm ? [new Filters('fulltext', 'eq', this.searchTerm)] : [];
|
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({
|
this.service.getList(this.resource, this.page, this.pageSize, [sortBy], filters).subscribe({
|
||||||
next: (data: any) => {
|
next: (data: any) => {
|
||||||
@@ -107,6 +117,10 @@ export class ListComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFilterChange(event: any) {
|
||||||
|
this.searchFilters = event;
|
||||||
|
}
|
||||||
|
|
||||||
onSort({ column, direction }: any) {
|
onSort({ column, direction }: any) {
|
||||||
// resetting other headers
|
// resetting other headers
|
||||||
this.headers.forEach((header) => {
|
this.headers.forEach((header) => {
|
||||||
@@ -151,6 +165,9 @@ export class ListComponent implements OnInit {
|
|||||||
get searchTerm() {
|
get searchTerm() {
|
||||||
return this._state.searchTerm;
|
return this._state.searchTerm;
|
||||||
}
|
}
|
||||||
|
get searchFilters() {
|
||||||
|
return this._state.searchFilters;
|
||||||
|
}
|
||||||
|
|
||||||
set page(page: number) {
|
set page(page: number) {
|
||||||
this._set({ page });
|
this._set({ page });
|
||||||
@@ -161,6 +178,9 @@ export class ListComponent implements OnInit {
|
|||||||
set searchTerm(searchTerm: string) {
|
set searchTerm(searchTerm: string) {
|
||||||
this._set({ searchTerm });
|
this._set({ searchTerm });
|
||||||
}
|
}
|
||||||
|
set searchFilters(searchFilters: {[key: string]: any}) {
|
||||||
|
this._set({ searchFilters });
|
||||||
|
}
|
||||||
set sortColumn(sortColumn: SortColumn) {
|
set sortColumn(sortColumn: SortColumn) {
|
||||||
this._set({ sortColumn });
|
this._set({ sortColumn });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user