@verisoft/ui-core 18.0.0 → 18.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -3
- package/src/index.ts +3 -1
- package/src/lib/common/constants.ts +5 -1
- package/src/lib/common/control.models.ts +14 -0
- package/src/lib/common/datasource-component.model.ts +6 -4
- package/src/lib/common/deactivate-guard.model.ts +5 -0
- package/src/lib/common/download-file.ts +20 -0
- package/src/lib/common/filter.ts +7 -0
- package/src/lib/common/icons.ts +34 -0
- package/src/lib/common/index.ts +7 -1
- package/src/lib/common/notificable-property.model.ts +5 -0
- package/src/lib/common/rxjs.spec.ts +58 -0
- package/src/lib/common/rxjs.ts +21 -0
- package/src/lib/components/action-button-group/action-button-group.model.ts +9 -10
- package/src/lib/components/action-button-group/action-button.model.ts +14 -15
- package/src/lib/components/base-form/base-form-input.component.ts +7 -1
- package/src/lib/components/base-form/base-form.component.ts +33 -6
- package/src/lib/components/base-form/directives/detail-store.directive.ts +104 -31
- package/src/lib/components/breadcrumb/breadcrumbcore.component.ts +50 -29
- package/src/lib/components/button/button.model.ts +0 -1
- package/src/lib/components/calendar/calendar.model.ts +1 -1
- package/src/lib/components/checkbox/checkbox.model.ts +1 -2
- package/src/lib/components/confirm-dialog/confirm-dialog.model.ts +22 -17
- package/src/lib/components/confirm-dialog/index.ts +1 -1
- package/src/lib/components/dropdown/dropdown.model.ts +3 -0
- package/src/lib/components/dynamic-component/dynamic-component.model.ts +2 -0
- package/src/lib/components/dynamic-component/index.ts +1 -0
- package/src/lib/components/filter/filter.model.ts +17 -0
- package/src/lib/components/filter/index.ts +1 -0
- package/src/lib/components/generic-field/generic-field.model.ts +1 -1
- package/src/lib/components/generic-form/generic-form.component.ts +33 -0
- package/src/lib/components/generic-form/index.ts +1 -0
- package/src/lib/components/header/header.model.ts +2 -2
- package/src/lib/components/icons/icons.component.ts +17 -0
- package/src/lib/components/icons/icons.model.ts +10 -0
- package/src/lib/components/icons/index.ts +2 -0
- package/src/lib/components/index.ts +4 -0
- package/src/lib/components/loader/loader.model.ts +1 -2
- package/src/lib/components/page-header/index.ts +3 -1
- package/src/lib/components/page-header/page-header.model.ts +1 -7
- package/src/lib/components/page-header/page-header.service.ts +9 -0
- package/src/lib/components/page-header/page-headercore.component.ts +40 -0
- package/src/lib/components/password/password.model.ts +14 -0
- package/src/lib/components/side-menu/directives/side-menu-service.directive.ts +31 -0
- package/src/lib/components/side-menu/index.ts +2 -1
- package/src/lib/components/side-menu/services/side-menu.service.ts +8 -4
- package/src/lib/components/side-menu/side-menu.model.ts +14 -11
- package/src/lib/components/snackbar/snackbar.model.ts +1 -2
- package/src/lib/components/stepper/stepper.model.ts +13 -3
- package/src/lib/components/switch/switch.model.ts +1 -2
- package/src/lib/components/tab-view/tab-view.model.ts +7 -4
- package/src/lib/components/table/column-configuration.ts +38 -0
- package/src/lib/components/table/index.ts +3 -1
- package/src/lib/components/table/table-builder.ts +93 -0
- package/src/lib/components/table/table-column.directive.ts +62 -0
- package/src/lib/components/table/table.models.ts +116 -44
- package/src/lib/components/textfield/textfield.model.ts +1 -1
- package/src/lib/components/tristatecheckbox/tristatecheckbox.model.ts +1 -2
- package/src/lib/directives/datasource.directive.ts +10 -10
- package/src/lib/directives/index.ts +3 -0
- package/src/lib/directives/shortcut.directive.ts +37 -0
- package/src/lib/directives/table-datasource.directive.ts +184 -0
- package/src/lib/directives/table-filter.directive.ts +69 -0
- package/src/lib/format/format.ts +74 -0
- package/src/lib/pipes/error/error.codes.ts +6 -1
- package/src/lib/pipes/helper/enumToList.pipe.ts +16 -0
- package/src/lib/pipes/index.ts +1 -2
- package/src/lib/services/confirm-dialog.service.ts +44 -0
- package/src/lib/services/index.ts +4 -0
- package/src/lib/services/leave-form.service.ts +53 -0
- package/src/lib/services/screen-size.service.ts +25 -0
- package/src/lib/services/table.service.ts +22 -0
- package/src/lib/components/table/template-column.directive.ts +0 -45
- package/src/lib/pipes/gov/gov-color.pipe.ts +0 -24
- package/src/lib/pipes/gov/gov-size.pipe.ts +0 -16
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ColumnDefinition } from "./table.models";
|
|
2
|
+
|
|
3
|
+
export class ColumnConfiguration<TEntity> {
|
|
4
|
+
private column: Partial<ColumnDefinition<TEntity>> = {};
|
|
5
|
+
|
|
6
|
+
constructor(private id: string | keyof TEntity) {
|
|
7
|
+
this.column.id = id as string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
headerName(headerName: string | ((columnId: string, index?: number) => string)): this {
|
|
11
|
+
this.column.headerName = headerName;
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
sortable(sortable: boolean): this {
|
|
16
|
+
this.column.sortable = sortable;
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
columnClass(columnClass: string): this {
|
|
21
|
+
this.column.columnClass = columnClass;
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
valueFunction(value: (row: TEntity, index?: number) => string): this {
|
|
26
|
+
this.column.value = value;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type(type: string): this {
|
|
31
|
+
this.column.type = type;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
build(): ColumnDefinition<TEntity> {
|
|
36
|
+
return this.column as ColumnDefinition<TEntity>;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { ColumnConfiguration } from './column-configuration';
|
|
3
|
+
import { ColumnDefinition } from './table.models';
|
|
4
|
+
|
|
5
|
+
@Injectable({
|
|
6
|
+
providedIn: 'root',
|
|
7
|
+
})
|
|
8
|
+
export class TableBuilder<TEntity> {
|
|
9
|
+
private columns: ColumnDefinition<TEntity>[] = [];
|
|
10
|
+
|
|
11
|
+
addColumn(
|
|
12
|
+
id: string | keyof TEntity,
|
|
13
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
14
|
+
): TableBuilder<TEntity> {
|
|
15
|
+
const columnConfig = new ColumnConfiguration<TEntity>(id);
|
|
16
|
+
config?.(columnConfig);
|
|
17
|
+
this.columns.push(columnConfig.build());
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
addTextColumn(
|
|
22
|
+
id: string | keyof TEntity,
|
|
23
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
24
|
+
): TableBuilder<TEntity> {
|
|
25
|
+
return this.addColumn(id, (x) => {
|
|
26
|
+
config?.(x);
|
|
27
|
+
x.type('text');
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
addNumberColumn(
|
|
32
|
+
id: string | keyof TEntity,
|
|
33
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
34
|
+
): TableBuilder<TEntity> {
|
|
35
|
+
return this.addColumn(id, (x) => {
|
|
36
|
+
config?.(x);
|
|
37
|
+
x.type('number').columnClass('text-end');
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
addDateColumn(
|
|
42
|
+
id: string | keyof TEntity,
|
|
43
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
44
|
+
): TableBuilder<TEntity> {
|
|
45
|
+
return this.addColumn(id, (x) => {
|
|
46
|
+
config?.(x);
|
|
47
|
+
x.type('date').valueFunction((row) => covertFromDateToUserLocale(row, id as string));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
addBooleanColumn(
|
|
52
|
+
id: string,
|
|
53
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
54
|
+
): TableBuilder<TEntity> {
|
|
55
|
+
return this.addColumn(id, (x) => {
|
|
56
|
+
config?.(x);
|
|
57
|
+
x.type('boolean');
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
addEnumColumn(
|
|
62
|
+
id: string | keyof TEntity,
|
|
63
|
+
config?: (v: ColumnConfiguration<TEntity>) => void
|
|
64
|
+
): TableBuilder<TEntity> {
|
|
65
|
+
return this.addColumn(id, (x) => {
|
|
66
|
+
config?.(x);
|
|
67
|
+
x.type('enum');
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
build(): ColumnDefinition<TEntity>[] {
|
|
72
|
+
return this.columns;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function covertFromDateToUserLocale<TEntity>(row: TEntity, id: string) {
|
|
77
|
+
const value = (row as { [key: string]: undefined | string | Date })[id];
|
|
78
|
+
if (value === undefined) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const locale = navigator.language;
|
|
83
|
+
|
|
84
|
+
if (value instanceof Date) {
|
|
85
|
+
return value.toLocaleDateString(locale);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (typeof value === 'string' && !isNaN(Date.parse(value))) {
|
|
89
|
+
return new Date(value).toLocaleDateString(locale);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ContentChild, Directive, Input, TemplateRef } from '@angular/core';
|
|
2
|
+
import { Params } from '@angular/router';
|
|
3
|
+
import { FieldAlign, FieldAlignType } from '../../common';
|
|
4
|
+
import { ColumnDefinition, ColumnProvider, ColumnVisibility, ColumnVisibilityType, TABLE_COLUMN_PROVIDER } from './table.models';
|
|
5
|
+
|
|
6
|
+
@Directive({
|
|
7
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
8
|
+
selector: 'v-table-column',
|
|
9
|
+
standalone: true,
|
|
10
|
+
providers: [
|
|
11
|
+
{
|
|
12
|
+
provide: TABLE_COLUMN_PROVIDER,
|
|
13
|
+
useExisting: TableColumnDirective,
|
|
14
|
+
multi: true,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
})
|
|
18
|
+
export class TableColumnDirective<T> implements ColumnProvider<T> {
|
|
19
|
+
@ContentChild(TemplateRef) template!:
|
|
20
|
+
TemplateRef<{ $implicit: T }>;
|
|
21
|
+
|
|
22
|
+
@Input() index = 0;
|
|
23
|
+
|
|
24
|
+
@Input() id!: string;
|
|
25
|
+
|
|
26
|
+
@Input() columnClass!: string;
|
|
27
|
+
|
|
28
|
+
@Input() sortable!: boolean;
|
|
29
|
+
|
|
30
|
+
@Input() routerLink!: (row: T) => string;
|
|
31
|
+
|
|
32
|
+
@Input() queryParams!: Params;
|
|
33
|
+
|
|
34
|
+
@Input() headerName!: ((column: string, index?: number) => string) | string;
|
|
35
|
+
|
|
36
|
+
@Input() width: string | number | undefined;
|
|
37
|
+
|
|
38
|
+
@Input() textAlign: FieldAlignType = FieldAlign.left;
|
|
39
|
+
|
|
40
|
+
@Input() format!: (row: T) => string
|
|
41
|
+
|
|
42
|
+
@Input() forceVisibility: ColumnVisibilityType = ColumnVisibility.default;
|
|
43
|
+
|
|
44
|
+
@Input() visible = true;
|
|
45
|
+
|
|
46
|
+
getDefinition(): ColumnDefinition<T> {
|
|
47
|
+
return {
|
|
48
|
+
id: this.id,
|
|
49
|
+
columnClass: this.columnClass,
|
|
50
|
+
template: this.template,
|
|
51
|
+
headerName: this.headerName,
|
|
52
|
+
routerLink: this.routerLink,
|
|
53
|
+
queryParams: this.queryParams,
|
|
54
|
+
sortable: this.sortable,
|
|
55
|
+
width: this.width,
|
|
56
|
+
format: this.format,
|
|
57
|
+
textAlign: this.textAlign,
|
|
58
|
+
forceVisibility: this.forceVisibility,
|
|
59
|
+
visible: this.visible,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { InjectionToken, TemplateRef } from '@angular/core';
|
|
1
|
+
import { EventEmitter, InjectionToken, TemplateRef } from '@angular/core';
|
|
2
2
|
import { Params } from '@angular/router';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { LazyLoadEvent, Sort, SortDirectionType } from '@verisoft/core';
|
|
4
|
+
import { v4 } from 'uuid';
|
|
5
|
+
import { FieldAlignType } from '../../common';
|
|
5
6
|
|
|
6
7
|
export const TABLE_COMPONENT_TOKEN = new InjectionToken<TableCore<any>>(
|
|
7
8
|
'TabVIewComponentToken'
|
|
@@ -11,26 +12,58 @@ export const TABLE_COLUMN_PROVIDER = new InjectionToken(
|
|
|
11
12
|
'TABLE_COLUMN_PROVIDER'
|
|
12
13
|
);
|
|
13
14
|
|
|
15
|
+
export enum TableSelectionMode {
|
|
16
|
+
single = 'single',
|
|
17
|
+
multiple = 'multiple',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export enum TableButtonSeverity {
|
|
21
|
+
success = 'success',
|
|
22
|
+
info = 'info',
|
|
23
|
+
warning = 'warning',
|
|
24
|
+
danger = 'danger',
|
|
25
|
+
help = 'help',
|
|
26
|
+
primary = 'primary',
|
|
27
|
+
secondary = 'secondary',
|
|
28
|
+
contrast = 'contrast',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum ColumnVisibility {
|
|
32
|
+
visible = 'visible',
|
|
33
|
+
hidden = 'hidden',
|
|
34
|
+
default = 'default',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type TableSelectionModeType = keyof typeof TableSelectionMode;
|
|
38
|
+
export type TableButtonSeverityType = keyof typeof TableButtonSeverity;
|
|
39
|
+
export type ColumnVisibilityType = keyof typeof ColumnVisibility;
|
|
40
|
+
|
|
14
41
|
export interface TableCore<T> {
|
|
15
42
|
sorters: Sort[];
|
|
43
|
+
columns: ColumnDefinition<T>[];
|
|
16
44
|
data: T[];
|
|
17
45
|
total: number;
|
|
46
|
+
filter: Partial<T> | undefined;
|
|
18
47
|
loading: boolean;
|
|
19
|
-
scrollHeight: string;
|
|
20
48
|
scrollable: boolean;
|
|
21
49
|
pageSize: number;
|
|
22
50
|
currentPage: number;
|
|
23
51
|
showPaginator: boolean;
|
|
24
52
|
sortMultiple: boolean;
|
|
25
53
|
lazy: boolean;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
autoIndex: boolean;
|
|
54
|
+
selection: T[];
|
|
55
|
+
selectionMode: TableSelectionModeType | undefined;
|
|
29
56
|
showPageSizePicker: boolean;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
57
|
+
entityKey: string | undefined;
|
|
58
|
+
selectionChange: EventEmitter<T[]>;
|
|
59
|
+
lazyLoad: EventEmitter<LazyLoadEvent>;
|
|
60
|
+
maximumColumnLength: number;
|
|
61
|
+
disableCustomClicks: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface TableSignal {
|
|
65
|
+
name: string,
|
|
66
|
+
symbol: symbol
|
|
34
67
|
}
|
|
35
68
|
|
|
36
69
|
export interface ActionColumnsDefinition<T> {
|
|
@@ -54,29 +87,23 @@ export interface ColumnProvider<T> {
|
|
|
54
87
|
index: number;
|
|
55
88
|
}
|
|
56
89
|
|
|
57
|
-
export enum TableButtonSeverity {
|
|
58
|
-
SUCCESS = 'success',
|
|
59
|
-
INFO = 'info',
|
|
60
|
-
WARNING = 'warning',
|
|
61
|
-
DANGER = 'danger',
|
|
62
|
-
HELP = 'help',
|
|
63
|
-
PRIMARY = 'primary',
|
|
64
|
-
SECONDARY = 'secondary',
|
|
65
|
-
CONTRAST = 'contrast',
|
|
66
|
-
}
|
|
67
|
-
|
|
68
90
|
export interface ColumnDefinition<T, _KEY = keyof T> {
|
|
69
91
|
id: string;
|
|
70
92
|
value?: (row: T, index?: number) => string;
|
|
71
|
-
headerName?: (
|
|
93
|
+
headerName?: ((columnId: string, index?: number) => string) | string;
|
|
72
94
|
icon?: string | ((row?: T | undefined) => string);
|
|
73
95
|
type?: string;
|
|
74
96
|
sortable?: boolean;
|
|
97
|
+
format?: (row: T) => string
|
|
75
98
|
routerLink?: (row: T) => string | string;
|
|
76
99
|
queryParams?: Params;
|
|
77
100
|
columnClass?: string;
|
|
78
|
-
template?: TemplateRef<T>;
|
|
101
|
+
template?: TemplateRef<{ $implicit: T }>;
|
|
79
102
|
actions?: ActionColumnsDefinition<T>[];
|
|
103
|
+
textAlign?: FieldAlignType;
|
|
104
|
+
width?: string | number;
|
|
105
|
+
forceVisibility?: ColumnVisibilityType;
|
|
106
|
+
visible?: boolean;
|
|
80
107
|
}
|
|
81
108
|
|
|
82
109
|
export function LinkRenderer<T>(text: string, href: string) {
|
|
@@ -98,30 +125,40 @@ export function Renderer<T>(fnc: (row: T) => string) {
|
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
export class ColumnModel<T> {
|
|
101
|
-
sortDirection:
|
|
102
|
-
sortColumn: Sort | undefined = undefined;
|
|
128
|
+
sortDirection: SortDirectionType | undefined = undefined;
|
|
103
129
|
columnClass?: string;
|
|
104
130
|
queryParams?: Params;
|
|
105
131
|
routerLink?: (row: T) => string | string;
|
|
106
132
|
valueGetter!: (row: T, index: number) => string;
|
|
107
|
-
headerGetter!: (
|
|
108
|
-
template?: TemplateRef<T>;
|
|
133
|
+
headerGetter!: (columnId: string, index: number) => string | string;
|
|
134
|
+
template?: TemplateRef<{ $implicit: T }>;
|
|
109
135
|
actions?: ActionColumnsDefinition<T>[];
|
|
110
136
|
sortable?: boolean;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
137
|
+
id: string;
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
139
|
+
format!: Function;
|
|
140
|
+
textAlign?: FieldAlignType;
|
|
141
|
+
width: string | undefined;
|
|
142
|
+
forceVisibility: ColumnVisibilityType = ColumnVisibility.default;
|
|
143
|
+
visible = true;
|
|
115
144
|
|
|
116
145
|
constructor(readonly configuration: ColumnDefinition<T>) {
|
|
146
|
+
this.id = this.configuration.id;
|
|
147
|
+
|
|
148
|
+
if (this.configuration.format) {
|
|
149
|
+
this.format = this.configuration.format;
|
|
150
|
+
}
|
|
151
|
+
|
|
117
152
|
if (this.configuration.value) {
|
|
118
|
-
this.valueGetter = (row, index) =>
|
|
119
|
-
this.configuration.value?.(row, index) ?? '-';
|
|
153
|
+
this.valueGetter = (row, index) => {
|
|
154
|
+
const value = this.configuration.value?.(row, index) ?? '-';
|
|
155
|
+
return this.format ? this.format(value, row) : value;
|
|
156
|
+
};
|
|
120
157
|
} else {
|
|
121
|
-
this.valueGetter = (row) =>
|
|
122
|
-
((row as { [key: string]: string })?.[
|
|
123
|
-
|
|
124
|
-
|
|
158
|
+
this.valueGetter = (row) => {
|
|
159
|
+
const value = ((row as { [key: string]: string })?.[this.configuration.id]) ?? '';
|
|
160
|
+
return this.format ? this.format(value, row) : value;
|
|
161
|
+
};
|
|
125
162
|
}
|
|
126
163
|
|
|
127
164
|
if (this.configuration.actions) {
|
|
@@ -141,10 +178,16 @@ export class ColumnModel<T> {
|
|
|
141
178
|
}
|
|
142
179
|
|
|
143
180
|
if (this.configuration.headerName) {
|
|
144
|
-
this.headerGetter = (
|
|
145
|
-
this.configuration.headerName
|
|
181
|
+
this.headerGetter = (
|
|
182
|
+
typeof this.configuration.headerName === 'string'
|
|
183
|
+
? () => this.configuration.headerName ?? ''
|
|
184
|
+
: (columnId: string, index: number) =>
|
|
185
|
+
(<(columnId: string, index?: number) => string>(
|
|
186
|
+
this.configuration.headerName
|
|
187
|
+
))?.(columnId, index) ?? this.id
|
|
188
|
+
) as (columnId: string, index: number) => string;
|
|
146
189
|
} else {
|
|
147
|
-
this.headerGetter = (
|
|
190
|
+
this.headerGetter = () => "";
|
|
148
191
|
}
|
|
149
192
|
|
|
150
193
|
if (this.configuration.queryParams) {
|
|
@@ -160,30 +203,59 @@ export class ColumnModel<T> {
|
|
|
160
203
|
} else {
|
|
161
204
|
this.sortable = true;
|
|
162
205
|
}
|
|
206
|
+
|
|
207
|
+
if (this.configuration.width){
|
|
208
|
+
this.width = typeof this.configuration.width === "number" ? this.configuration.width + 'px' : this.configuration.width;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (this.configuration.textAlign !== undefined) {
|
|
212
|
+
this.textAlign = this.configuration.textAlign;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (this.configuration.forceVisibility) {
|
|
216
|
+
this.forceVisibility = this.configuration.forceVisibility;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (this.configuration.visible !== undefined) {
|
|
220
|
+
this.visible = this.configuration.visible;
|
|
221
|
+
}
|
|
163
222
|
}
|
|
164
223
|
}
|
|
165
224
|
|
|
166
|
-
export declare type SortDirection = 'asc' | 'desc' | undefined;
|
|
167
|
-
|
|
168
225
|
export class RowModel<T> {
|
|
169
226
|
row: T;
|
|
170
227
|
index?: number;
|
|
228
|
+
id: number | string;
|
|
171
229
|
selected: boolean;
|
|
172
230
|
marked?: boolean;
|
|
173
231
|
focused?: boolean;
|
|
232
|
+
expanded: boolean;
|
|
174
233
|
fnc?: void;
|
|
234
|
+
customRoute: string | undefined;
|
|
175
235
|
|
|
176
236
|
constructor(
|
|
177
237
|
row: T,
|
|
178
238
|
selected: boolean,
|
|
239
|
+
expanded: boolean,
|
|
179
240
|
marked?: boolean,
|
|
180
241
|
index?: number,
|
|
181
|
-
fnc?: void
|
|
242
|
+
fnc?: void,
|
|
243
|
+
customRoute?: string,
|
|
244
|
+
entityKey?: string
|
|
182
245
|
) {
|
|
183
246
|
this.row = row;
|
|
247
|
+
this.id = (row as { [key: string]: string })['id'] ?? v4();
|
|
184
248
|
this.index = index;
|
|
185
249
|
this.selected = selected;
|
|
250
|
+
this.expanded = expanded;
|
|
186
251
|
this.marked = marked;
|
|
187
252
|
this.fnc = fnc;
|
|
253
|
+
this.customRoute = createCustomRoute<T>(row, entityKey, customRoute);
|
|
188
254
|
}
|
|
189
255
|
}
|
|
256
|
+
|
|
257
|
+
function createCustomRoute<T>(row: T, entityKey?: string, customRoute?: string) {
|
|
258
|
+
return customRoute && entityKey
|
|
259
|
+
? `${customRoute}/` + (row as { [key: string]: string })[entityKey]
|
|
260
|
+
: undefined;
|
|
261
|
+
}
|
|
@@ -5,5 +5,4 @@ export const TRISTATE_CHECKBOX_COMPONENT_TOKEN = new InjectionToken<TristateChec
|
|
|
5
5
|
'TristateCheckboxComponentToken'
|
|
6
6
|
);
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
export interface TristateCheckboxCore extends BaseFormCore {}
|
|
8
|
+
export type TristateCheckboxCore = BaseFormCore
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @angular-eslint/directive-selector */
|
|
2
1
|
import { HttpClient } from '@angular/common/http';
|
|
3
2
|
import {
|
|
4
3
|
ChangeDetectorRef,
|
|
@@ -35,6 +34,7 @@ import {
|
|
|
35
34
|
import {
|
|
36
35
|
DataSourceComponentModel,
|
|
37
36
|
DEFAULT_DEBOUNCE_TIME,
|
|
37
|
+
ExtendedRequestType,
|
|
38
38
|
setComponentProperties,
|
|
39
39
|
setDataToArray,
|
|
40
40
|
} from '../common';
|
|
@@ -48,10 +48,9 @@ import {
|
|
|
48
48
|
UnsubscribeComponent,
|
|
49
49
|
} from '../components';
|
|
50
50
|
|
|
51
|
-
type ExtendedRequestType<T> = RequestParams<T> & { useNewData: boolean}
|
|
52
|
-
|
|
53
51
|
@Directive({
|
|
54
52
|
selector:
|
|
53
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
55
54
|
'v-dropdown[useDatasource], v-multiselect[useDatasource], v-generic-field[useDatasource]',
|
|
56
55
|
standalone: true,
|
|
57
56
|
})
|
|
@@ -69,6 +68,8 @@ export class DatasourceDirective<T>
|
|
|
69
68
|
|
|
70
69
|
@Input() transformFn?: (data: T) => unknown;
|
|
71
70
|
|
|
71
|
+
@Input() extraFilter!: any;
|
|
72
|
+
|
|
72
73
|
get activeComponent(): DataSourceComponentModel<T> {
|
|
73
74
|
return (this.dropdownComponent ??
|
|
74
75
|
this.multiSelectComponent ??
|
|
@@ -136,6 +137,7 @@ export class DatasourceDirective<T>
|
|
|
136
137
|
offset: 0,
|
|
137
138
|
filter: {
|
|
138
139
|
[property]: value.filter ? value.filter : undefined,
|
|
140
|
+
...(this.extraFilter ?? {})
|
|
139
141
|
} as Partial<T>,
|
|
140
142
|
useNewData: true,
|
|
141
143
|
});
|
|
@@ -147,7 +149,7 @@ export class DatasourceDirective<T>
|
|
|
147
149
|
takeUntil(this.destroyed$),
|
|
148
150
|
filter(request => !this.isDataForRequestLoaded(request)),
|
|
149
151
|
map((request) => {
|
|
150
|
-
const extendedParams = normalizeRequest({ ...this.lastParameter, ...request }) as ExtendedRequestType<T>;
|
|
152
|
+
const extendedParams = normalizeRequest({ ...this.lastParameter, ...request }, DEFAULT_SEARCH_LIMIT) as ExtendedRequestType<T>;
|
|
151
153
|
extendedParams.useNewData = request.useNewData ?? false;
|
|
152
154
|
return extendedParams;
|
|
153
155
|
}),
|
|
@@ -203,8 +205,6 @@ export class DatasourceDirective<T>
|
|
|
203
205
|
this.httpClient
|
|
204
206
|
);
|
|
205
207
|
|
|
206
|
-
this.activeComponent.loading = true;
|
|
207
|
-
this.changeDetectorRef.detectChanges();
|
|
208
208
|
if (this.autoBind) {
|
|
209
209
|
this.parameters$.next({ offset: 0 });
|
|
210
210
|
}
|
|
@@ -212,22 +212,22 @@ export class DatasourceDirective<T>
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
private isDataForRequestLoaded(request: Partial<ExtendedRequestType<T>>) {
|
|
215
|
-
if (request.useNewData){
|
|
215
|
+
if (request.useNewData) {
|
|
216
216
|
return false;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
const offset = request.offset ?? 0;
|
|
220
220
|
const limit = request.limit ?? DEFAULT_SEARCH_LIMIT;
|
|
221
221
|
const options = this.activeComponent.options;
|
|
222
|
-
if (!options){
|
|
222
|
+
if (!options) {
|
|
223
223
|
return false;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
if (options.length < offset + limit) {
|
|
227
227
|
return false;
|
|
228
228
|
}
|
|
229
|
-
|
|
230
|
-
const allItemsFilled = options.slice(offset, offset + limit).every(item => item !== undefined && item != this.loadingPlaceholderItem);
|
|
229
|
+
|
|
230
|
+
const allItemsFilled = options.slice(offset, offset + limit).every(item => item !== undefined && item != this.loadingPlaceholderItem);
|
|
231
231
|
return allItemsFilled;
|
|
232
232
|
}
|
|
233
233
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Directive, HostListener, Input } from "@angular/core";
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
5
|
+
selector: 'v-button[useShortCut]',
|
|
6
|
+
exportAs: 'useShortCut',
|
|
7
|
+
standalone: true,
|
|
8
|
+
})
|
|
9
|
+
export class ButtonShortCutDirective
|
|
10
|
+
{
|
|
11
|
+
@Input() shortCutFn?: () => void;
|
|
12
|
+
@Input() shortCutKey!: string;
|
|
13
|
+
|
|
14
|
+
private keyMap: { [key: string]: boolean } = {};
|
|
15
|
+
|
|
16
|
+
@HostListener('document:keydown', ['$event'])
|
|
17
|
+
onKeyDown(event: KeyboardEvent) {
|
|
18
|
+
this.keyMap[event.key.toLowerCase()] = true;
|
|
19
|
+
this.checkShortcut();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@HostListener('document:keyup', ['$event'])
|
|
23
|
+
onKeyUp(event: KeyboardEvent) {
|
|
24
|
+
this.keyMap[event.key.toLowerCase()] = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private checkShortcut() {
|
|
28
|
+
if (this.shortCutKey && this.shortCutFn) {
|
|
29
|
+
const keys = this.shortCutKey.toLowerCase().split('+');
|
|
30
|
+
const isShortcutPressed = keys.every((key) => this.keyMap[key]);
|
|
31
|
+
if (isShortcutPressed) {
|
|
32
|
+
this.shortCutFn?.();
|
|
33
|
+
keys.forEach((key) => (this.keyMap[key] = false));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|