namirasoft-account-react 1.5.20 → 1.5.21

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.
Files changed (139) hide show
  1. package/.env.template +15 -15
  2. package/SKILL.md +514 -514
  3. package/config-overrides.js +72 -72
  4. package/dist/App.d.ts +1 -1
  5. package/dist/Router.d.ts +1 -1
  6. package/dist/UseParams.d.ts +1 -1
  7. package/dist/components/NSAAccessListDialog.d.ts +2 -2
  8. package/dist/components/NSAAccessListDialog.module.css +71 -71
  9. package/dist/components/NSABoxSecret.d.ts +1 -1
  10. package/dist/components/NSABoxSecret.module.css +23 -23
  11. package/dist/components/NSAMasterMenu.d.ts +1 -1
  12. package/dist/components/NSAMasterMenu.module.css +250 -250
  13. package/dist/components/NSAMasterMenuItem.d.ts +1 -1
  14. package/dist/components/NSAMessageListDialog.d.ts +1 -1
  15. package/dist/components/NSAMessageListDialog.module.css +99 -99
  16. package/dist/components/NSANavigationGuard.d.ts +1 -1
  17. package/dist/components/NSAProductListDialog.d.ts +1 -1
  18. package/dist/components/NSAProductListDialog.module.css +44 -44
  19. package/dist/components/NSATaskBar.d.ts +1 -1
  20. package/dist/components/NSATaskBar.module.css +57 -57
  21. package/dist/components/NSAUserDialog.d.ts +1 -1
  22. package/dist/components/NSAUserDialog.module.css +67 -67
  23. package/dist/components/NSAWorkspaceListDialog.d.ts +1 -1
  24. package/dist/components/NSAWorkspaceListDialog.module.css +41 -41
  25. package/dist/components/NSFBoxCategoryScope.d.ts +1 -1
  26. package/dist/components/NSFBoxField.d.ts +1 -1
  27. package/dist/components/NSFBoxSlot.d.ts +1 -1
  28. package/dist/components/NSFBoxWrapper.d.ts +1 -1
  29. package/dist/components/NSLabelSecret.d.ts +1 -1
  30. package/dist/components/quickfilter/NSAFilterBoxEnum.module.css +44 -44
  31. package/dist/components/quickfilter/NSAQuickFilterBar.d.ts +1 -1
  32. package/dist/components/quickfilter/NSAQuickFilterBar.module.css +19 -19
  33. package/dist/components/quickfilter/NSAQuickFilterDialog.d.ts +1 -1
  34. package/dist/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  35. package/dist/layouts/NSALayout.d.ts +1 -1
  36. package/dist/layouts/NSASectionEdit.d.ts +1 -1
  37. package/dist/layouts/NSASectionEditTabPage.d.ts +1 -1
  38. package/dist/layouts/NSASectionEditTabPage.module.css +4 -4
  39. package/dist/layouts/NSASectionList.d.ts +1 -1
  40. package/dist/layouts/NSASectionList.module.css +31 -31
  41. package/dist/layouts/NSASectionView.d.ts +1 -1
  42. package/dist/layouts/NSASectionViewTabMore.d.ts +1 -1
  43. package/dist/layouts/NSASectionViewTabPage.d.ts +1 -1
  44. package/dist/layouts/NSASectionViewTabPage.module.css +47 -47
  45. package/dist/pages/NSAConsentPage.module.css +26 -26
  46. package/dist/pages/NSAEmailVerificationPage.d.ts +1 -1
  47. package/dist/pages/NSAHomePage.d.ts +1 -1
  48. package/dist/pages/NSAHomePage.module.css +41 -41
  49. package/dist/pages/NSALoginPage.d.ts +1 -1
  50. package/dist/pages/NSALoginPage.module.css +26 -26
  51. package/dist/pages/NSAPhoneVerificationPage.d.ts +1 -1
  52. package/dist/pages/NSAVerificationPage.d.ts +1 -1
  53. package/dist/pages/NSAVerificationPage.module.css +31 -31
  54. package/package.json +95 -95
  55. package/public/index.html +21 -21
  56. package/src/App.tsx +19 -19
  57. package/src/CTFRow.ts +7 -7
  58. package/src/FieldCacheService.tsx +84 -84
  59. package/src/IEntityInfo.ts +33 -33
  60. package/src/NSACacheService.ts +120 -120
  61. package/src/NSAFilterOperators.ts +92 -92
  62. package/src/NSARouterMaker.tsx +140 -140
  63. package/src/NSARouterMakerProps.ts +23 -23
  64. package/src/NSARouterMakerResult.ts +24 -24
  65. package/src/NSFRouterMaker.tsx +35 -35
  66. package/src/NSFRouterProps.ts +7 -7
  67. package/src/NSFRoutes.ts +30 -30
  68. package/src/Router.tsx +48 -48
  69. package/src/UseParams.tsx +17 -17
  70. package/src/components/NSAAccessListDialog.module.css +71 -71
  71. package/src/components/NSAAccessListDialog.tsx +178 -178
  72. package/src/components/NSABoxSecret.module.css +23 -23
  73. package/src/components/NSABoxSecret.tsx +264 -264
  74. package/src/components/NSAMasterMenu.module.css +250 -250
  75. package/src/components/NSAMasterMenu.tsx +169 -169
  76. package/src/components/NSAMasterMenuItem.tsx +250 -250
  77. package/src/components/NSAMessageListDialog.module.css +99 -99
  78. package/src/components/NSAMessageListDialog.tsx +142 -142
  79. package/src/components/NSANavigationGuard.tsx +79 -79
  80. package/src/components/NSAProductListDialog.module.css +44 -44
  81. package/src/components/NSAProductListDialog.tsx +88 -88
  82. package/src/components/NSATable.tsx +494 -494
  83. package/src/components/NSATaskBar.module.css +57 -57
  84. package/src/components/NSATaskBar.tsx +193 -193
  85. package/src/components/NSAUserDialog.module.css +67 -67
  86. package/src/components/NSAUserDialog.tsx +122 -122
  87. package/src/components/NSAWorkspaceListDialog.module.css +41 -41
  88. package/src/components/NSAWorkspaceListDialog.tsx +147 -147
  89. package/src/components/NSFBoxCategoryScope.tsx +52 -52
  90. package/src/components/NSFBoxField.tsx +37 -37
  91. package/src/components/NSFBoxSlot.tsx +71 -71
  92. package/src/components/NSFBoxWrapper.tsx +69 -69
  93. package/src/components/NSLabelSecret.tsx +37 -37
  94. package/src/components/quickfilter/NSAFilterBoxBase.tsx +89 -89
  95. package/src/components/quickfilter/NSAFilterBoxBoolean.tsx +66 -66
  96. package/src/components/quickfilter/NSAFilterBoxDate.tsx +110 -110
  97. package/src/components/quickfilter/NSAFilterBoxDateTime.tsx +110 -110
  98. package/src/components/quickfilter/NSAFilterBoxEnum.module.css +44 -44
  99. package/src/components/quickfilter/NSAFilterBoxEnum.tsx +79 -79
  100. package/src/components/quickfilter/NSAFilterBoxNumber.tsx +145 -145
  101. package/src/components/quickfilter/NSAFilterBoxString.tsx +83 -83
  102. package/src/components/quickfilter/NSAFilterBoxTime.tsx +106 -106
  103. package/src/components/quickfilter/NSAQuickFilterBar.module.css +19 -19
  104. package/src/components/quickfilter/NSAQuickFilterBar.tsx +142 -142
  105. package/src/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  106. package/src/components/quickfilter/NSAQuickFilterDialog.tsx +260 -260
  107. package/src/css.d.ts +13 -13
  108. package/src/formatters/SecretFormatter.tsx +24 -24
  109. package/src/index.tsx +26 -26
  110. package/src/layouts/Actions.ts +146 -146
  111. package/src/layouts/CFTUtil.ts +18 -18
  112. package/src/layouts/NSALayout.tsx +744 -744
  113. package/src/layouts/NSALayout_Field.ts +125 -125
  114. package/src/layouts/NSASectionEdit.tsx +281 -281
  115. package/src/layouts/NSASectionEditTabPage.module.css +4 -4
  116. package/src/layouts/NSASectionEditTabPage.tsx +256 -256
  117. package/src/layouts/NSASectionList.module.css +31 -31
  118. package/src/layouts/NSASectionList.tsx +147 -147
  119. package/src/layouts/NSASectionView.tsx +98 -98
  120. package/src/layouts/NSASectionViewTabMore.tsx +78 -78
  121. package/src/layouts/NSASectionViewTabPage.module.css +47 -47
  122. package/src/layouts/NSASectionViewTabPage.tsx +399 -399
  123. package/src/main.ts +52 -52
  124. package/src/pages/NSAConsentPage.module.css +26 -26
  125. package/src/pages/NSAConsentPage.tsx +120 -120
  126. package/src/pages/NSAEmailVerificationPage.tsx +30 -30
  127. package/src/pages/NSAHomePage.module.css +41 -41
  128. package/src/pages/NSAHomePage.tsx +124 -124
  129. package/src/pages/NSALoginPage.module.css +26 -26
  130. package/src/pages/NSALoginPage.tsx +87 -87
  131. package/src/pages/NSAPhoneVerificationPage.tsx +94 -94
  132. package/src/pages/NSAVerificationPage.module.css +31 -31
  133. package/src/pages/NSAVerificationPage.tsx +185 -185
  134. package/src/pages/NSFCategoryEditPage.tsx +87 -87
  135. package/src/pages/NSFCategoryListPage.tsx +23 -23
  136. package/src/pages/NSFCategoryViewPage.tsx +23 -23
  137. package/src/pages/NSFEntities.ts +58 -58
  138. package/src/pages/PaymentRequired.tsx +80 -80
  139. package/tsconfig.json +43 -43
@@ -1,495 +1,495 @@
1
- import { EncodingOperation, FilterItem, FilterItemColumnType, NamingConvention, ObjectService, SearchOperation, SortItem } from "namirasoft-core";
2
- import { EntityResolveResponseRow } from "namirasoft-field";
3
- import { FilterItemColumnTypeBuilder, VariableType } from "namirasoft-schema";
4
- import { IBaseComponentProps, NSButtonProps, NSFilterBox, NSFilterBoxItems, NSFilterBoxProps_Table, NSSpace, NSSpaceSizeType, NSTable, TableColumnInfo, TableRowInfo } from "namirasoft-site-react";
5
- import { Component, ReactNode, createRef } from "react";
6
- import { IEntityInfo } from "../IEntityInfo";
7
- import { NSACacheService } from "../NSACacheService";
8
- import { NSAQuickFilterBar } from "./quickfilter/NSAQuickFilterBar";
9
- import { NSAQuickFilterDialog, QuickFilterConfig } from "./quickfilter/NSAQuickFilterDialog";
10
-
11
- export interface NSATableUIProps<RowType>
12
- {
13
- getRowAttributes?: (row_value: RowType, row_index: number, res: { rows: RowType[]; count: number; } | null) => { [key: string]: any };
14
- getColumnAttributes?: (column: TableColumnInfo) => { [key: string]: any };
15
- getCellFormattedValue?: (value: any, column: TableColumnInfo, row: TableRowInfo<RowType>) => any;
16
- search_box?: {
17
- exclude?: {
18
- show?: {
19
- table?: (table: string) => boolean;
20
- column?: (table: string, column: string) => boolean;
21
- },
22
- load_value?: (table: string, column: string) => boolean;
23
- }
24
- };
25
- }
26
-
27
- export interface NSATableProps<RowType extends { id: string }, RowTypeInput = RowType> extends IBaseComponentProps
28
- {
29
- entity: IEntityInfo<RowType, RowTypeInput>;
30
- ctf: {
31
- enabled: boolean;
32
- rows: EntityResolveResponseRow | null;
33
- };
34
- url: { getQuery(name: string, base64?: boolean, remove?: boolean): string };
35
- ui?: NSATableUIProps<RowType>;
36
- checkbox?: boolean;
37
- buttons?: NSButtonProps[];
38
- onSelectionChanged?: () => void;
39
- }
40
-
41
- interface NSATableState<RowType>
42
- {
43
- res: { rows: RowType[]; count: number; } | null;
44
- visible_column_keys: string[];
45
- quick_filter_configs: QuickFilterConfig[];
46
- show_quick_filter_dialog: boolean;
47
- filter_revision: number;
48
- }
49
-
50
- export class NSATable<RowType extends { id: string }, RowTypeInput = RowType>
51
- extends Component<NSATableProps<RowType, RowTypeInput>, NSATableState<RowType>>
52
- {
53
- public NSTable_Main = createRef<NSTable<RowType>>();
54
- public NSFilterBox_Top = createRef<NSFilterBox>();
55
- public NSAQuickFilterBar_Ref = createRef<NSAQuickFilterBar>();
56
-
57
- constructor(props: NSATableProps<RowType, RowTypeInput>)
58
- {
59
- super(props);
60
-
61
- let quick_filter_configs = NSACacheService.loadQuickFilters(props.entity.name);
62
- if (quick_filter_configs.length === 0)
63
- quick_filter_configs = this.buildDefaultQuickFilters();
64
- this.state = {
65
- res: null,
66
- visible_column_keys: [],
67
- quick_filter_configs,
68
- show_quick_filter_dialog: false,
69
- filter_revision: 0,
70
- };
71
- }
72
-
73
- override componentDidMount()
74
- {
75
- const visible = this.NSTable_Main.current?.getVisibleColumns() ?? [];
76
- if (visible.length > 0)
77
- this.setState({ visible_column_keys: visible.map(v => v.table + "." + v.column) });
78
-
79
- this.setState(prev => ({ filter_revision: prev.filter_revision + 1 }));
80
- }
81
-
82
- private getColumns(): TableColumnInfo[]
83
- {
84
- let columns = Object.values(this.props.entity.client.getColumns()).flat();
85
- columns.forEach(col =>
86
- {
87
- col.text = NamingConvention.auto.convert(col.text, NamingConvention.Pascal_Case_Space);
88
- });
89
- return columns;
90
- }
91
-
92
- private buildDefaultQuickFilters(): QuickFilterConfig[]
93
- {
94
- const getDefaults = this.props.entity.client.getQuickFilters;
95
- if (!getDefaults)
96
- return [];
97
-
98
- const columns = this.getColumns();
99
- const ans: QuickFilterConfig[] = [];
100
- for (const def of getDefaults())
101
- {
102
- const col = columns.find(c => c.name === def.column);
103
- if (!col)
104
- continue;
105
- const columnType = new ObjectService(col.type).getEnum(VariableType, VariableType.Any);
106
- ans.push({
107
- id: `default-${col.table.name}-${col.name}`,
108
- column: {
109
- table: { name: col.table.name, text: col.table.text },
110
- name: col.name,
111
- text: col.text,
112
- type: col.type,
113
- columnType,
114
- },
115
- operatorName: (def as { operator?: string }).operator,
116
- });
117
- }
118
- return ans;
119
- }
120
-
121
- private filterItemTypeConverter(type: string): FilterItemColumnType
122
- {
123
- let t = new ObjectService(type).getEnum(VariableType, VariableType.Any);
124
- let builder = new FilterItemColumnTypeBuilder(t);
125
- return builder.runSynch(() => { }) ?? FilterItemColumnType.Unknown;
126
- }
127
-
128
- private getIncomingFilterItems(): FilterItem[] | undefined
129
- {
130
- try
131
- {
132
- let encoded = this.props.url.getQuery("filters");
133
- if (encoded)
134
- return FilterItem.decode(encoded) ?? undefined;
135
- } catch (error)
136
- {
137
- }
138
- return undefined;
139
- }
140
-
141
- private itemMatchesQuickFilter(item: FilterItem): boolean
142
- {
143
- return this.state.quick_filter_configs.some(c =>
144
- c.column.table.name === item.table.name && c.column.name === item.column.name);
145
- }
146
- private getIncomingBoxItems(): FilterItem[] | undefined
147
- {
148
- let items = this.getIncomingFilterItems();
149
- if (!items)
150
- return undefined;
151
- return items.filter(i => !this.itemMatchesQuickFilter(i));
152
- }
153
- private getIncomingQuickItems(): FilterItem[]
154
- {
155
- let items = this.getIncomingFilterItems();
156
- if (!items)
157
- return [];
158
- return items.filter(i => this.itemMatchesQuickFilter(i));
159
- }
160
-
161
- private encodeFilters(items: FilterItem[]): string
162
- {
163
- let command = items.map(item =>
164
- {
165
- let key = item.operator.name.replace(/\s+/g, "").toLowerCase();
166
- let values = item.values.map(v => (v ?? "").toString().replace(/;/g, "\\;"));
167
- return [item.table.name, item.column.name, item.not ? "1" : "0", key, ...values].join(";");
168
- }).join(";");
169
- return EncodingOperation.Base64Encode(command);
170
- }
171
-
172
- private syncQueryFromFilters()
173
- {
174
- let items = this.getFilterItems();
175
- let url = new URL(window.location.href);
176
- let encoded = items.length > 0 ? this.encodeFilters(items) : "";
177
- if (encoded)
178
- url.searchParams.set("filters", encoded);
179
- else
180
- url.searchParams.delete("filters");
181
- window.history.replaceState({}, "", url.toString());
182
- }
183
-
184
- public reload(page: number | null, size: number | null): Promise<void> | undefined
185
- {
186
- return this.NSTable_Main.current?.reload(page, size);
187
- }
188
- public getSelectedIDs(): string[]
189
- {
190
- return this.NSTable_Main.current?.getSelectedIDs() ?? [];
191
- }
192
- public getSelectedRows(): RowType[]
193
- {
194
- return this.NSTable_Main.current?.getSelectedRows() ?? [];
195
- }
196
- public setSelectedIDs(ids: string[], rows: RowType[], callback?: () => void)
197
- {
198
- this.NSTable_Main.current?.setSelectedIDs(ids, rows, callback);
199
- }
200
- public getSortItems(): SortItem[]
201
- {
202
- return this.NSTable_Main.current?.getSortItems() ?? [];
203
- }
204
- public setSortItems(items: SortItem[] | null)
205
- {
206
- this.NSTable_Main.current?.setSortItems(items);
207
- }
208
- public getVisibleColumns(): { table: string, column: string }[]
209
- {
210
- return this.NSTable_Main.current?.getVisibleColumns() ?? [];
211
- }
212
- public setVisibleColumns(visible_columns: { table: string, column: string }[])
213
- {
214
- this.NSTable_Main.current?.setVisibleColumns(visible_columns);
215
- }
216
- public getFilterBoxItems(): FilterItem[]
217
- {
218
- return this.NSFilterBox_Top.current?.getFilterItems() ?? [];
219
- }
220
- public getQuickFilterItems(): FilterItem[]
221
- {
222
- return this.NSAQuickFilterBar_Ref.current?.getFilterItems() ?? [];
223
- }
224
- public getFilterItems(): FilterItem[]
225
- {
226
- return [...this.getFilterBoxItems(), ...this.getQuickFilterItems()];
227
- }
228
-
229
- private reloadFromFilters()
230
- {
231
- this.syncQueryFromFilters();
232
- this.NSTable_Main.current?.setSelectedIDs([], []);
233
- this.NSTable_Main.current?.reload(null, null);
234
- }
235
-
236
- private onFilterBoxChanged = () =>
237
- {
238
- this.reloadFromFilters();
239
- this.setState(prev => ({ filter_revision: prev.filter_revision + 1 }));
240
- };
241
-
242
- private buildButtons(): NSButtonProps[]
243
- {
244
- const buttons: NSButtonProps[] = [
245
- {
246
- title: "",
247
- icon: { src: "https://static.namirasoft.com/image/concept/sliders/blue.svg", alt: "filter" },
248
- attributes: { title: "Quick Filters" },
249
- onClick: {
250
- action: () => this.setState({ show_quick_filter_dialog: true }),
251
- showLoading: false,
252
- },
253
- },
254
- ];
255
- return [...buttons, ...(this.props.buttons ?? [])];
256
- }
257
-
258
- private renderFilterHeader(): ReactNode
259
- {
260
- return (
261
- <NSFilterBox
262
- ref={this.NSFilterBox_Top}
263
- filterItems={this.getIncomingBoxItems()}
264
- getTables={() =>
265
- {
266
- return this.props.entity.tables.map(table =>
267
- {
268
- let columns = table.table.getColumns().map(c => ({ id: c.name, ...c, type: this.filterItemTypeConverter(c.type) }));
269
- columns = columns.filter(c =>
270
- {
271
- if (this.props.ui?.search_box?.exclude?.show?.column)
272
- if (this.props.ui?.search_box?.exclude.show?.column(table.table.name, c.name))
273
- return false;
274
- return true;
275
- });
276
- return { name: table.table.name, text: table.table.text, columns, required: table.required };
277
- }).filter(t =>
278
- {
279
- if (this.props.ui?.search_box?.exclude?.show?.table)
280
- if (this.props.ui?.search_box?.exclude.show.table(t.name))
281
- return false;
282
- return true;
283
- });
284
- }}
285
- getMoreTables={async () =>
286
- {
287
- let ans: NSFilterBoxProps_Table[] = [];
288
- if (this.props.ctf.enabled)
289
- try
290
- {
291
- if (this.props.ctf.rows?.fields)
292
- if (this.props.ctf.rows.fields.length > 0)
293
- {
294
- let name = this.props.entity.name + "_field";
295
- ans.push({
296
- name,
297
- text: "Fields",
298
- columns: [{
299
- id: "field_id",
300
- name: "field_id",
301
- text: "ID",
302
- type: FilterItemColumnType.Unknown,
303
- getValues: async (search) =>
304
- {
305
- return this.props.ctf.rows?.fields?.filter(c => SearchOperation.match(c.id, search)).map(c => { return { value: c.id, title: c.id } }) ?? [];
306
- }
307
- }, {
308
- id: "field_name",
309
- name: "field_id",
310
- text: "Name",
311
- type: FilterItemColumnType.Unknown,
312
- getValues: async (search) =>
313
- {
314
- return this.props.ctf.rows?.fields?.filter(c => SearchOperation.match(c.name, search)).map(c => { return { value: c.id, title: c.name } }) ?? [];
315
- }
316
- }, {
317
- id: "field_value",
318
- name: "value",
319
- text: "Value",
320
- type: FilterItemColumnType.Unknown
321
- },
322
- ...this.props.ctf.rows?.fields.map(f =>
323
- {
324
- return {
325
- id: f.id,
326
- name: f.id,
327
- text: f.name,
328
- type: this.filterItemTypeConverter(f.type.type.type),
329
- getValues: async (search: string) =>
330
- {
331
- let values = await this.props.entity.server.value_list(name, "value", search, f.id, null);
332
- return values.map(v => { return { value: v, title: v } });
333
- }
334
- };
335
- }),],
336
- required: false
337
- });
338
- }
339
-
340
- if (this.props.ctf.rows?.categories)
341
- if (this.props.ctf.rows?.categories.length > 0)
342
- ans.push({
343
- name: this.props.entity.name + "_category",
344
- text: "Categories",
345
- columns: [{
346
- id: "category_id",
347
- name: "category_id",
348
- text: "ID",
349
- type: FilterItemColumnType.Unknown,
350
- getValues: async (search) =>
351
- {
352
- return this.props.ctf.rows?.categories?.filter(c => SearchOperation.match(c.id, search)).map(c => { return { value: c.id, title: c.id } }) ?? [];
353
- }
354
- }, {
355
- id: "category_name",
356
- name: "category_id",
357
- text: "Name",
358
- type: FilterItemColumnType.Unknown,
359
- getValues: async (search) =>
360
- {
361
- return this.props.ctf.rows?.categories?.filter(c => SearchOperation.match(c.name, search)).map(c => { return { value: c.id, title: c.name } }) ?? [];
362
- }
363
- }],
364
- required: false
365
- });
366
-
367
- } catch (error)
368
- {
369
- }
370
- // todo add tags
371
- return ans;
372
- }}
373
- getValues={async (table, column, value) =>
374
- {
375
- if (this.props.ui?.search_box?.exclude?.load_value)
376
- if (this.props.ui?.search_box?.exclude?.load_value(table.name, column.name))
377
- return [];
378
- if (column.type === FilterItemColumnType.Boolean)
379
- {
380
- const col = this.getColumns().find(c => c.table.name === table.name && c.name === column.name);
381
- return [true, false].map(b =>
382
- {
383
- const formatted = col ? col.formatter.format(b, col, { value: {} } as any, true) : null;
384
- return { value: String(b), title: formatted != null ? String(formatted) : String(b) };
385
- });
386
- }
387
- let values = await this.props.entity.server.value_list(table.name, column.name, value, null, null);
388
- return values.map(v => { return { value: v, title: v } });
389
- }}
390
- onChanged={this.onFilterBoxChanged}
391
- />
392
- );
393
- }
394
-
395
- private getOrderedColumns(): TableColumnInfo[]
396
- {
397
- const all = this.getColumns();
398
- const vk = this.state.visible_column_keys;
399
- if (vk.length === 0)
400
- return all;
401
- const ordered = vk.map(k => all.find(c => c.table.name + "." + c.name === k)).filter((c): c is TableColumnInfo => !!c);
402
- const rest = all.filter(c => !vk.includes(c.table.name + "." + c.name));
403
- return [...ordered, ...rest];
404
- }
405
-
406
- override render(): ReactNode
407
- {
408
- const filterBoxItems = this.NSFilterBox_Top.current?.getFilterItems() ?? [];
409
- const filterChips = filterBoxItems.length > 0 && (
410
- <>
411
- <NSFilterBoxItems
412
- filterItems={filterBoxItems}
413
- onClearFilterItems={() => this.NSFilterBox_Top.current?.setFilterItems([])}
414
- onRemoveFilterItem={(item) => this.NSFilterBox_Top.current?.removeFilterItem(item)}
415
- />
416
- <NSSpace size={NSSpaceSizeType.MINI} />
417
- </>
418
- );
419
-
420
- const quickFilterBar = this.state.quick_filter_configs.length > 0 && (
421
- <NSAQuickFilterBar
422
- key={this.state.quick_filter_configs.map(c => c.id).join("-")}
423
- ref={this.NSAQuickFilterBar_Ref}
424
- configs={this.state.quick_filter_configs}
425
- initialItems={this.getIncomingQuickItems()}
426
- getValues={async (tableName, columnName, search) =>
427
- {
428
- const values = await this.props.entity.server.value_list(tableName, columnName, search, null, null);
429
- const col = this.getColumns().find(c => c.table.name === tableName && c.name === columnName);
430
- return values.map(v =>
431
- {
432
- const formatted = col ? col.formatter.format(v, col, { value: {} } as any, true) : null;
433
- return { value: v, title: formatted != null ? String(formatted) : v };
434
- });
435
- }}
436
- onChanged={() => this.reloadFromFilters()}
437
- />
438
- );
439
-
440
- return (
441
- <>
442
- <NSTable<RowType>
443
- id={this.props.id}
444
- classList={this.props.classList}
445
- style={this.props.style}
446
- ref={this.NSTable_Main}
447
- name={NamingConvention.lower_case_dash.convert(this.props.entity.name, NamingConvention.Pascal_Case_Space)}
448
- checkbox={this.props.checkbox ?? true}
449
- headerChildren={this.renderFilterHeader()}
450
- buttons={this.buildButtons()}
451
- columns={this.getOrderedColumns()}
452
- getRows={async (page, size, sorts) =>
453
- {
454
- let res: { rows: RowType[], count: number } = { rows: [], count: 0 };
455
- if (this.props.entity.server.list)
456
- res = await this.props.entity.server.list(this.getFilterItems(), page, size, sorts, null);
457
- this.setState({ res });
458
- return res;
459
- }}
460
- getRowKey={(row) => row.value.id.toString()}
461
- sort={{
462
- onSort: () => { this.NSTable_Main.current?.reload(null, null); },
463
- }}
464
- getRowAttributes={(row_value, row_index) => this.props.ui?.getRowAttributes?.(row_value, row_index, this.state.res) ?? {}}
465
- getColumnAttributes={this.props.ui?.getColumnAttributes}
466
- getCellFormattedValue={this.props.ui?.getCellFormattedValue}
467
- onVisibleColumnsChanged={(visible_columns) => this.setState({ visible_column_keys: visible_columns.map(c => c.table + "." + c.column) })}
468
- onSelectedIDsChanged={() => this.props.onSelectionChanged?.()}
469
- >
470
- {filterChips}
471
- {quickFilterBar}
472
- </NSTable>
473
- {
474
- this.state.show_quick_filter_dialog &&
475
- <NSAQuickFilterDialog
476
- configs={this.state.quick_filter_configs}
477
- getColumns={() => this.getColumns()}
478
- typeConverter={(type: string) => new ObjectService(type).getEnum(VariableType, VariableType.Any)}
479
- onSave={configs =>
480
- {
481
- NSACacheService.saveQuickFilters(this.props.entity.name, configs);
482
- this.setState({ quick_filter_configs: configs }, () => this.reloadFromFilters());
483
- }}
484
- onConfirm={configs =>
485
- {
486
- NSACacheService.saveQuickFilters(this.props.entity.name, configs);
487
- this.setState({ quick_filter_configs: configs, show_quick_filter_dialog: false }, () => this.reloadFromFilters());
488
- }}
489
- onClose={() => this.setState({ show_quick_filter_dialog: false })}
490
- />
491
- }
492
- </>
493
- );
494
- }
1
+ import { EncodingOperation, FilterItem, FilterItemColumnType, NamingConvention, ObjectService, SearchOperation, SortItem } from "namirasoft-core";
2
+ import { EntityResolveResponseRow } from "namirasoft-field";
3
+ import { FilterItemColumnTypeBuilder, VariableType } from "namirasoft-schema";
4
+ import { IBaseComponentProps, NSButtonProps, NSFilterBox, NSFilterBoxItems, NSFilterBoxProps_Table, NSSpace, NSSpaceSizeType, NSTable, TableColumnInfo, TableRowInfo } from "namirasoft-site-react";
5
+ import { Component, ReactNode, createRef } from "react";
6
+ import { IEntityInfo } from "../IEntityInfo";
7
+ import { NSACacheService } from "../NSACacheService";
8
+ import { NSAQuickFilterBar } from "./quickfilter/NSAQuickFilterBar";
9
+ import { NSAQuickFilterDialog, QuickFilterConfig } from "./quickfilter/NSAQuickFilterDialog";
10
+
11
+ export interface NSATableUIProps<RowType>
12
+ {
13
+ getRowAttributes?: (row_value: RowType, row_index: number, res: { rows: RowType[]; count: number; } | null) => { [key: string]: any };
14
+ getColumnAttributes?: (column: TableColumnInfo) => { [key: string]: any };
15
+ getCellFormattedValue?: (value: any, column: TableColumnInfo, row: TableRowInfo<RowType>) => any;
16
+ search_box?: {
17
+ exclude?: {
18
+ show?: {
19
+ table?: (table: string) => boolean;
20
+ column?: (table: string, column: string) => boolean;
21
+ },
22
+ load_value?: (table: string, column: string) => boolean;
23
+ }
24
+ };
25
+ }
26
+
27
+ export interface NSATableProps<RowType extends { id: string }, RowTypeInput = RowType> extends IBaseComponentProps
28
+ {
29
+ entity: IEntityInfo<RowType, RowTypeInput>;
30
+ ctf: {
31
+ enabled: boolean;
32
+ rows: EntityResolveResponseRow | null;
33
+ };
34
+ url: { getQuery(name: string, base64?: boolean, remove?: boolean): string };
35
+ ui?: NSATableUIProps<RowType>;
36
+ checkbox?: boolean;
37
+ buttons?: NSButtonProps[];
38
+ onSelectionChanged?: () => void;
39
+ }
40
+
41
+ interface NSATableState<RowType>
42
+ {
43
+ res: { rows: RowType[]; count: number; } | null;
44
+ visible_column_keys: string[];
45
+ quick_filter_configs: QuickFilterConfig[];
46
+ show_quick_filter_dialog: boolean;
47
+ filter_revision: number;
48
+ }
49
+
50
+ export class NSATable<RowType extends { id: string }, RowTypeInput = RowType>
51
+ extends Component<NSATableProps<RowType, RowTypeInput>, NSATableState<RowType>>
52
+ {
53
+ public NSTable_Main = createRef<NSTable<RowType>>();
54
+ public NSFilterBox_Top = createRef<NSFilterBox>();
55
+ public NSAQuickFilterBar_Ref = createRef<NSAQuickFilterBar>();
56
+
57
+ constructor(props: NSATableProps<RowType, RowTypeInput>)
58
+ {
59
+ super(props);
60
+
61
+ let quick_filter_configs = NSACacheService.loadQuickFilters(props.entity.name);
62
+ if (quick_filter_configs.length === 0)
63
+ quick_filter_configs = this.buildDefaultQuickFilters();
64
+ this.state = {
65
+ res: null,
66
+ visible_column_keys: [],
67
+ quick_filter_configs,
68
+ show_quick_filter_dialog: false,
69
+ filter_revision: 0,
70
+ };
71
+ }
72
+
73
+ override componentDidMount()
74
+ {
75
+ const visible = this.NSTable_Main.current?.getVisibleColumns() ?? [];
76
+ if (visible.length > 0)
77
+ this.setState({ visible_column_keys: visible.map(v => v.table + "." + v.column) });
78
+
79
+ this.setState(prev => ({ filter_revision: prev.filter_revision + 1 }));
80
+ }
81
+
82
+ private getColumns(): TableColumnInfo[]
83
+ {
84
+ let columns = Object.values(this.props.entity.client.getColumns()).flat();
85
+ columns.forEach(col =>
86
+ {
87
+ col.text = NamingConvention.auto.convert(col.text, NamingConvention.Pascal_Case_Space);
88
+ });
89
+ return columns;
90
+ }
91
+
92
+ private buildDefaultQuickFilters(): QuickFilterConfig[]
93
+ {
94
+ const getDefaults = this.props.entity.client.getQuickFilters;
95
+ if (!getDefaults)
96
+ return [];
97
+
98
+ const columns = this.getColumns();
99
+ const ans: QuickFilterConfig[] = [];
100
+ for (const def of getDefaults())
101
+ {
102
+ const col = columns.find(c => c.name === def.column);
103
+ if (!col)
104
+ continue;
105
+ const columnType = new ObjectService(col.type).getEnum(VariableType, VariableType.Any);
106
+ ans.push({
107
+ id: `default-${col.table.name}-${col.name}`,
108
+ column: {
109
+ table: { name: col.table.name, text: col.table.text },
110
+ name: col.name,
111
+ text: col.text,
112
+ type: col.type,
113
+ columnType,
114
+ },
115
+ operatorName: (def as { operator?: string }).operator,
116
+ });
117
+ }
118
+ return ans;
119
+ }
120
+
121
+ private filterItemTypeConverter(type: string): FilterItemColumnType
122
+ {
123
+ let t = new ObjectService(type).getEnum(VariableType, VariableType.Any);
124
+ let builder = new FilterItemColumnTypeBuilder(t);
125
+ return builder.runSynch(() => { }) ?? FilterItemColumnType.Unknown;
126
+ }
127
+
128
+ private getIncomingFilterItems(): FilterItem[] | undefined
129
+ {
130
+ try
131
+ {
132
+ let encoded = this.props.url.getQuery("filters");
133
+ if (encoded)
134
+ return FilterItem.decode(encoded) ?? undefined;
135
+ } catch (error)
136
+ {
137
+ }
138
+ return undefined;
139
+ }
140
+
141
+ private itemMatchesQuickFilter(item: FilterItem): boolean
142
+ {
143
+ return this.state.quick_filter_configs.some(c =>
144
+ c.column.table.name === item.table.name && c.column.name === item.column.name);
145
+ }
146
+ private getIncomingBoxItems(): FilterItem[] | undefined
147
+ {
148
+ let items = this.getIncomingFilterItems();
149
+ if (!items)
150
+ return undefined;
151
+ return items.filter(i => !this.itemMatchesQuickFilter(i));
152
+ }
153
+ private getIncomingQuickItems(): FilterItem[]
154
+ {
155
+ let items = this.getIncomingFilterItems();
156
+ if (!items)
157
+ return [];
158
+ return items.filter(i => this.itemMatchesQuickFilter(i));
159
+ }
160
+
161
+ private encodeFilters(items: FilterItem[]): string
162
+ {
163
+ let command = items.map(item =>
164
+ {
165
+ let key = item.operator.name.replace(/\s+/g, "").toLowerCase();
166
+ let values = item.values.map(v => (v ?? "").toString().replace(/;/g, "\\;"));
167
+ return [item.table.name, item.column.name, item.not ? "1" : "0", key, ...values].join(";");
168
+ }).join(";");
169
+ return EncodingOperation.Base64Encode(command);
170
+ }
171
+
172
+ private syncQueryFromFilters()
173
+ {
174
+ let items = this.getFilterItems();
175
+ let url = new URL(window.location.href);
176
+ let encoded = items.length > 0 ? this.encodeFilters(items) : "";
177
+ if (encoded)
178
+ url.searchParams.set("filters", encoded);
179
+ else
180
+ url.searchParams.delete("filters");
181
+ window.history.replaceState({}, "", url.toString());
182
+ }
183
+
184
+ public reload(page: number | null, size: number | null): Promise<void> | undefined
185
+ {
186
+ return this.NSTable_Main.current?.reload(page, size);
187
+ }
188
+ public getSelectedIDs(): string[]
189
+ {
190
+ return this.NSTable_Main.current?.getSelectedIDs() ?? [];
191
+ }
192
+ public getSelectedRows(): RowType[]
193
+ {
194
+ return this.NSTable_Main.current?.getSelectedRows() ?? [];
195
+ }
196
+ public setSelectedIDs(ids: string[], rows: RowType[], callback?: () => void)
197
+ {
198
+ this.NSTable_Main.current?.setSelectedIDs(ids, rows, callback);
199
+ }
200
+ public getSortItems(): SortItem[]
201
+ {
202
+ return this.NSTable_Main.current?.getSortItems() ?? [];
203
+ }
204
+ public setSortItems(items: SortItem[] | null)
205
+ {
206
+ this.NSTable_Main.current?.setSortItems(items);
207
+ }
208
+ public getVisibleColumns(): { table: string, column: string }[]
209
+ {
210
+ return this.NSTable_Main.current?.getVisibleColumns() ?? [];
211
+ }
212
+ public setVisibleColumns(visible_columns: { table: string, column: string }[])
213
+ {
214
+ this.NSTable_Main.current?.setVisibleColumns(visible_columns);
215
+ }
216
+ public getFilterBoxItems(): FilterItem[]
217
+ {
218
+ return this.NSFilterBox_Top.current?.getFilterItems() ?? [];
219
+ }
220
+ public getQuickFilterItems(): FilterItem[]
221
+ {
222
+ return this.NSAQuickFilterBar_Ref.current?.getFilterItems() ?? [];
223
+ }
224
+ public getFilterItems(): FilterItem[]
225
+ {
226
+ return [...this.getFilterBoxItems(), ...this.getQuickFilterItems()];
227
+ }
228
+
229
+ private reloadFromFilters()
230
+ {
231
+ this.syncQueryFromFilters();
232
+ this.NSTable_Main.current?.setSelectedIDs([], []);
233
+ this.NSTable_Main.current?.reload(null, null);
234
+ }
235
+
236
+ private onFilterBoxChanged = () =>
237
+ {
238
+ this.reloadFromFilters();
239
+ this.setState(prev => ({ filter_revision: prev.filter_revision + 1 }));
240
+ };
241
+
242
+ private buildButtons(): NSButtonProps[]
243
+ {
244
+ const buttons: NSButtonProps[] = [
245
+ {
246
+ title: "",
247
+ icon: { src: "https://static.namirasoft.com/image/concept/sliders/blue.svg", alt: "filter" },
248
+ attributes: { title: "Quick Filters" },
249
+ onClick: {
250
+ action: () => this.setState({ show_quick_filter_dialog: true }),
251
+ showLoading: false,
252
+ },
253
+ },
254
+ ];
255
+ return [...buttons, ...(this.props.buttons ?? [])];
256
+ }
257
+
258
+ private renderFilterHeader(): ReactNode
259
+ {
260
+ return (
261
+ <NSFilterBox
262
+ ref={this.NSFilterBox_Top}
263
+ filterItems={this.getIncomingBoxItems()}
264
+ getTables={() =>
265
+ {
266
+ return this.props.entity.tables.map(table =>
267
+ {
268
+ let columns = table.table.getColumns().map(c => ({ id: c.name, ...c, type: this.filterItemTypeConverter(c.type) }));
269
+ columns = columns.filter(c =>
270
+ {
271
+ if (this.props.ui?.search_box?.exclude?.show?.column)
272
+ if (this.props.ui?.search_box?.exclude.show?.column(table.table.name, c.name))
273
+ return false;
274
+ return true;
275
+ });
276
+ return { name: table.table.name, text: table.table.text, columns, required: table.required };
277
+ }).filter(t =>
278
+ {
279
+ if (this.props.ui?.search_box?.exclude?.show?.table)
280
+ if (this.props.ui?.search_box?.exclude.show.table(t.name))
281
+ return false;
282
+ return true;
283
+ });
284
+ }}
285
+ getMoreTables={async () =>
286
+ {
287
+ let ans: NSFilterBoxProps_Table[] = [];
288
+ if (this.props.ctf.enabled)
289
+ try
290
+ {
291
+ if (this.props.ctf.rows?.fields)
292
+ if (this.props.ctf.rows.fields.length > 0)
293
+ {
294
+ let name = this.props.entity.name + "_field";
295
+ ans.push({
296
+ name,
297
+ text: "Fields",
298
+ columns: [{
299
+ id: "field_id",
300
+ name: "field_id",
301
+ text: "ID",
302
+ type: FilterItemColumnType.Unknown,
303
+ getValues: async (search) =>
304
+ {
305
+ return this.props.ctf.rows?.fields?.filter(c => SearchOperation.match(c.id, search)).map(c => { return { value: c.id, title: c.id } }) ?? [];
306
+ }
307
+ }, {
308
+ id: "field_name",
309
+ name: "field_id",
310
+ text: "Name",
311
+ type: FilterItemColumnType.Unknown,
312
+ getValues: async (search) =>
313
+ {
314
+ return this.props.ctf.rows?.fields?.filter(c => SearchOperation.match(c.name, search)).map(c => { return { value: c.id, title: c.name } }) ?? [];
315
+ }
316
+ }, {
317
+ id: "field_value",
318
+ name: "value",
319
+ text: "Value",
320
+ type: FilterItemColumnType.Unknown
321
+ },
322
+ ...this.props.ctf.rows?.fields.map(f =>
323
+ {
324
+ return {
325
+ id: f.id,
326
+ name: f.id,
327
+ text: f.name,
328
+ type: this.filterItemTypeConverter(f.type.type.type),
329
+ getValues: async (search: string) =>
330
+ {
331
+ let values = await this.props.entity.server.value_list(name, "value", search, f.id, null);
332
+ return values.map(v => { return { value: v, title: v } });
333
+ }
334
+ };
335
+ }),],
336
+ required: false
337
+ });
338
+ }
339
+
340
+ if (this.props.ctf.rows?.categories)
341
+ if (this.props.ctf.rows?.categories.length > 0)
342
+ ans.push({
343
+ name: this.props.entity.name + "_category",
344
+ text: "Categories",
345
+ columns: [{
346
+ id: "category_id",
347
+ name: "category_id",
348
+ text: "ID",
349
+ type: FilterItemColumnType.Unknown,
350
+ getValues: async (search) =>
351
+ {
352
+ return this.props.ctf.rows?.categories?.filter(c => SearchOperation.match(c.id, search)).map(c => { return { value: c.id, title: c.id } }) ?? [];
353
+ }
354
+ }, {
355
+ id: "category_name",
356
+ name: "category_id",
357
+ text: "Name",
358
+ type: FilterItemColumnType.Unknown,
359
+ getValues: async (search) =>
360
+ {
361
+ return this.props.ctf.rows?.categories?.filter(c => SearchOperation.match(c.name, search)).map(c => { return { value: c.id, title: c.name } }) ?? [];
362
+ }
363
+ }],
364
+ required: false
365
+ });
366
+
367
+ } catch (error)
368
+ {
369
+ }
370
+ // todo add tags
371
+ return ans;
372
+ }}
373
+ getValues={async (table, column, value) =>
374
+ {
375
+ if (this.props.ui?.search_box?.exclude?.load_value)
376
+ if (this.props.ui?.search_box?.exclude?.load_value(table.name, column.name))
377
+ return [];
378
+ if (column.type === FilterItemColumnType.Boolean)
379
+ {
380
+ const col = this.getColumns().find(c => c.table.name === table.name && c.name === column.name);
381
+ return [true, false].map(b =>
382
+ {
383
+ const formatted = col ? col.formatter.format(b, col, { value: {} } as any, true) : null;
384
+ return { value: String(b), title: formatted != null ? String(formatted) : String(b) };
385
+ });
386
+ }
387
+ let values = await this.props.entity.server.value_list(table.name, column.name, value, null, null);
388
+ return values.map(v => { return { value: v, title: v } });
389
+ }}
390
+ onChanged={this.onFilterBoxChanged}
391
+ />
392
+ );
393
+ }
394
+
395
+ private getOrderedColumns(): TableColumnInfo[]
396
+ {
397
+ const all = this.getColumns();
398
+ const vk = this.state.visible_column_keys;
399
+ if (vk.length === 0)
400
+ return all;
401
+ const ordered = vk.map(k => all.find(c => c.table.name + "." + c.name === k)).filter((c): c is TableColumnInfo => !!c);
402
+ const rest = all.filter(c => !vk.includes(c.table.name + "." + c.name));
403
+ return [...ordered, ...rest];
404
+ }
405
+
406
+ override render(): ReactNode
407
+ {
408
+ const filterBoxItems = this.NSFilterBox_Top.current?.getFilterItems() ?? [];
409
+ const filterChips = filterBoxItems.length > 0 && (
410
+ <>
411
+ <NSFilterBoxItems
412
+ filterItems={filterBoxItems}
413
+ onClearFilterItems={() => this.NSFilterBox_Top.current?.setFilterItems([])}
414
+ onRemoveFilterItem={(item) => this.NSFilterBox_Top.current?.removeFilterItem(item)}
415
+ />
416
+ <NSSpace size={NSSpaceSizeType.MINI} />
417
+ </>
418
+ );
419
+
420
+ const quickFilterBar = this.state.quick_filter_configs.length > 0 && (
421
+ <NSAQuickFilterBar
422
+ key={this.state.quick_filter_configs.map(c => c.id).join("-")}
423
+ ref={this.NSAQuickFilterBar_Ref}
424
+ configs={this.state.quick_filter_configs}
425
+ initialItems={this.getIncomingQuickItems()}
426
+ getValues={async (tableName, columnName, search) =>
427
+ {
428
+ const values = await this.props.entity.server.value_list(tableName, columnName, search, null, null);
429
+ const col = this.getColumns().find(c => c.table.name === tableName && c.name === columnName);
430
+ return values.map(v =>
431
+ {
432
+ const formatted = col ? col.formatter.format(v, col, { value: {} } as any, true) : null;
433
+ return { value: v, title: formatted != null ? String(formatted) : v };
434
+ });
435
+ }}
436
+ onChanged={() => this.reloadFromFilters()}
437
+ />
438
+ );
439
+
440
+ return (
441
+ <>
442
+ <NSTable<RowType>
443
+ id={this.props.id}
444
+ classList={this.props.classList}
445
+ style={this.props.style}
446
+ ref={this.NSTable_Main}
447
+ name={NamingConvention.lower_case_dash.convert(this.props.entity.name, NamingConvention.Pascal_Case_Space)}
448
+ checkbox={this.props.checkbox ?? true}
449
+ headerChildren={this.renderFilterHeader()}
450
+ buttons={this.buildButtons()}
451
+ columns={this.getOrderedColumns()}
452
+ getRows={async (page, size, sorts) =>
453
+ {
454
+ let res: { rows: RowType[], count: number } = { rows: [], count: 0 };
455
+ if (this.props.entity.server.list)
456
+ res = await this.props.entity.server.list(this.getFilterItems(), page, size, sorts, null);
457
+ this.setState({ res });
458
+ return res;
459
+ }}
460
+ getRowKey={(row) => row.value.id.toString()}
461
+ sort={{
462
+ onSort: () => { this.NSTable_Main.current?.reload(null, null); },
463
+ }}
464
+ getRowAttributes={(row_value, row_index) => this.props.ui?.getRowAttributes?.(row_value, row_index, this.state.res) ?? {}}
465
+ getColumnAttributes={this.props.ui?.getColumnAttributes}
466
+ getCellFormattedValue={this.props.ui?.getCellFormattedValue}
467
+ onVisibleColumnsChanged={(visible_columns) => this.setState({ visible_column_keys: visible_columns.map(c => c.table + "." + c.column) })}
468
+ onSelectedIDsChanged={() => this.props.onSelectionChanged?.()}
469
+ >
470
+ {filterChips}
471
+ {quickFilterBar}
472
+ </NSTable>
473
+ {
474
+ this.state.show_quick_filter_dialog &&
475
+ <NSAQuickFilterDialog
476
+ configs={this.state.quick_filter_configs}
477
+ getColumns={() => this.getColumns()}
478
+ typeConverter={(type: string) => new ObjectService(type).getEnum(VariableType, VariableType.Any)}
479
+ onSave={configs =>
480
+ {
481
+ NSACacheService.saveQuickFilters(this.props.entity.name, configs);
482
+ this.setState({ quick_filter_configs: configs }, () => this.reloadFromFilters());
483
+ }}
484
+ onConfirm={configs =>
485
+ {
486
+ NSACacheService.saveQuickFilters(this.props.entity.name, configs);
487
+ this.setState({ quick_filter_configs: configs, show_quick_filter_dialog: false }, () => this.reloadFromFilters());
488
+ }}
489
+ onClose={() => this.setState({ show_quick_filter_dialog: false })}
490
+ />
491
+ }
492
+ </>
493
+ );
494
+ }
495
495
  }