namirasoft-account-react 1.5.37 → 1.5.39

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 (147) 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/FieldCacheService.js +4 -0
  6. package/dist/FieldCacheService.js.map +1 -1
  7. package/dist/NSARouterMaker.js +1 -1
  8. package/dist/NSARouterMaker.js.map +1 -1
  9. package/dist/Router.d.ts +1 -1
  10. package/dist/UseParams.d.ts +1 -1
  11. package/dist/components/NSAAccessListDialog.d.ts +2 -2
  12. package/dist/components/NSAAccessListDialog.module.css +71 -71
  13. package/dist/components/NSABoxSecret.d.ts +1 -1
  14. package/dist/components/NSABoxSecret.module.css +23 -23
  15. package/dist/components/NSAMasterMenu.d.ts +1 -1
  16. package/dist/components/NSAMasterMenu.js +4 -0
  17. package/dist/components/NSAMasterMenu.js.map +1 -1
  18. package/dist/components/NSAMasterMenu.module.css +250 -250
  19. package/dist/components/NSAMasterMenuItem.d.ts +1 -1
  20. package/dist/components/NSAMessageListDialog.d.ts +1 -1
  21. package/dist/components/NSAMessageListDialog.module.css +99 -99
  22. package/dist/components/NSANavigationGuard.d.ts +1 -1
  23. package/dist/components/NSAProductListDialog.d.ts +1 -1
  24. package/dist/components/NSAProductListDialog.module.css +44 -44
  25. package/dist/components/NSATaskBar.d.ts +1 -1
  26. package/dist/components/NSATaskBar.module.css +57 -57
  27. package/dist/components/NSAUserDialog.d.ts +1 -1
  28. package/dist/components/NSAUserDialog.module.css +67 -67
  29. package/dist/components/NSAWorkspaceListDialog.d.ts +1 -1
  30. package/dist/components/NSAWorkspaceListDialog.module.css +41 -41
  31. package/dist/components/NSFBoxCategoryScope.d.ts +1 -1
  32. package/dist/components/NSFBoxField.d.ts +1 -1
  33. package/dist/components/NSFBoxSlot.d.ts +1 -1
  34. package/dist/components/NSFBoxWrapper.d.ts +1 -1
  35. package/dist/components/NSLabelSecret.d.ts +1 -1
  36. package/dist/components/quickfilter/NSAFilterBoxEnum.module.css +51 -51
  37. package/dist/components/quickfilter/NSAQuickFilterBar.d.ts +1 -1
  38. package/dist/components/quickfilter/NSAQuickFilterBar.module.css +20 -20
  39. package/dist/components/quickfilter/NSAQuickFilterDialog.d.ts +1 -1
  40. package/dist/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  41. package/dist/layouts/NSALayout.d.ts +1 -1
  42. package/dist/layouts/NSASectionEdit.d.ts +1 -1
  43. package/dist/layouts/NSASectionEditTabPage.d.ts +1 -1
  44. package/dist/layouts/NSASectionEditTabPage.module.css +4 -4
  45. package/dist/layouts/NSASectionList.d.ts +1 -1
  46. package/dist/layouts/NSASectionList.module.css +24 -24
  47. package/dist/layouts/NSASectionView.d.ts +1 -1
  48. package/dist/layouts/NSASectionViewTabMore.d.ts +1 -1
  49. package/dist/layouts/NSASectionViewTabPage.d.ts +1 -1
  50. package/dist/layouts/NSASectionViewTabPage.module.css +47 -47
  51. package/dist/pages/NSAConsentPage.module.css +26 -26
  52. package/dist/pages/NSAEmailVerificationPage.d.ts +1 -1
  53. package/dist/pages/NSAHomePage.d.ts +1 -1
  54. package/dist/pages/NSAHomePage.module.css +41 -41
  55. package/dist/pages/NSALoginPage.d.ts +1 -1
  56. package/dist/pages/NSALoginPage.module.css +26 -26
  57. package/dist/pages/NSAPhoneVerificationPage.d.ts +1 -1
  58. package/dist/pages/NSAPhoneVerificationPage.js +11 -3
  59. package/dist/pages/NSAPhoneVerificationPage.js.map +1 -1
  60. package/dist/pages/NSAVerificationPage.d.ts +1 -1
  61. package/dist/pages/NSAVerificationPage.module.css +31 -31
  62. package/package.json +94 -94
  63. package/public/index.html +21 -21
  64. package/src/App.tsx +72 -72
  65. package/src/CTFRow.ts +7 -7
  66. package/src/FieldCacheService.tsx +113 -108
  67. package/src/IEntityInfo.ts +33 -33
  68. package/src/NSACacheService.ts +126 -126
  69. package/src/NSAFilterOperators.ts +94 -94
  70. package/src/NSARouterMaker.tsx +141 -141
  71. package/src/NSARouterMakerProps.ts +23 -23
  72. package/src/NSARouterMakerResult.ts +24 -24
  73. package/src/NSFRouterMaker.tsx +35 -35
  74. package/src/NSFRouterProps.ts +7 -7
  75. package/src/NSFRoutes.ts +30 -30
  76. package/src/Router.tsx +48 -48
  77. package/src/UseParams.tsx +17 -17
  78. package/src/components/NSAAccessListDialog.module.css +71 -71
  79. package/src/components/NSAAccessListDialog.tsx +178 -178
  80. package/src/components/NSABoxSecret.module.css +23 -23
  81. package/src/components/NSABoxSecret.tsx +264 -264
  82. package/src/components/NSAMasterMenu.module.css +250 -250
  83. package/src/components/NSAMasterMenu.tsx +174 -169
  84. package/src/components/NSAMasterMenuItem.tsx +250 -250
  85. package/src/components/NSAMessageListDialog.module.css +99 -99
  86. package/src/components/NSAMessageListDialog.tsx +144 -144
  87. package/src/components/NSANavigationGuard.tsx +79 -79
  88. package/src/components/NSAProductListDialog.module.css +44 -44
  89. package/src/components/NSAProductListDialog.tsx +88 -88
  90. package/src/components/NSATable.tsx +494 -494
  91. package/src/components/NSATaskBar.module.css +57 -57
  92. package/src/components/NSATaskBar.tsx +193 -193
  93. package/src/components/NSAUserDialog.module.css +67 -67
  94. package/src/components/NSAUserDialog.tsx +122 -122
  95. package/src/components/NSAWorkspaceListDialog.module.css +41 -41
  96. package/src/components/NSAWorkspaceListDialog.tsx +147 -147
  97. package/src/components/NSFBoxCategoryScope.tsx +52 -52
  98. package/src/components/NSFBoxField.tsx +37 -37
  99. package/src/components/NSFBoxSlot.tsx +73 -73
  100. package/src/components/NSFBoxWrapper.tsx +69 -69
  101. package/src/components/NSLabelSecret.tsx +37 -37
  102. package/src/components/quickfilter/NSAFilterBoxBase.tsx +110 -110
  103. package/src/components/quickfilter/NSAFilterBoxBoolean.tsx +72 -72
  104. package/src/components/quickfilter/NSAFilterBoxDate.tsx +110 -110
  105. package/src/components/quickfilter/NSAFilterBoxDateTime.tsx +110 -110
  106. package/src/components/quickfilter/NSAFilterBoxEnum.module.css +51 -51
  107. package/src/components/quickfilter/NSAFilterBoxEnum.tsx +103 -103
  108. package/src/components/quickfilter/NSAFilterBoxNumber.tsx +145 -145
  109. package/src/components/quickfilter/NSAFilterBoxString.tsx +83 -83
  110. package/src/components/quickfilter/NSAFilterBoxTime.tsx +106 -106
  111. package/src/components/quickfilter/NSAQuickFilterBar.module.css +20 -20
  112. package/src/components/quickfilter/NSAQuickFilterBar.tsx +142 -142
  113. package/src/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  114. package/src/components/quickfilter/NSAQuickFilterDialog.tsx +297 -297
  115. package/src/css.d.ts +13 -13
  116. package/src/formatters/SecretFormatter.tsx +24 -24
  117. package/src/index.tsx +27 -27
  118. package/src/layouts/Actions.ts +146 -146
  119. package/src/layouts/CFTUtil.ts +18 -18
  120. package/src/layouts/NSALayout.tsx +750 -750
  121. package/src/layouts/NSALayout_Field.ts +125 -125
  122. package/src/layouts/NSASectionEdit.tsx +279 -279
  123. package/src/layouts/NSASectionEditTabPage.module.css +4 -4
  124. package/src/layouts/NSASectionEditTabPage.tsx +256 -256
  125. package/src/layouts/NSASectionList.module.css +24 -24
  126. package/src/layouts/NSASectionList.tsx +165 -165
  127. package/src/layouts/NSASectionView.tsx +98 -98
  128. package/src/layouts/NSASectionViewTabMore.tsx +78 -78
  129. package/src/layouts/NSASectionViewTabPage.module.css +47 -47
  130. package/src/layouts/NSASectionViewTabPage.tsx +400 -400
  131. package/src/main.ts +52 -52
  132. package/src/pages/NSAConsentPage.module.css +26 -26
  133. package/src/pages/NSAConsentPage.tsx +120 -120
  134. package/src/pages/NSAEmailVerificationPage.tsx +30 -30
  135. package/src/pages/NSAHomePage.module.css +41 -41
  136. package/src/pages/NSAHomePage.tsx +113 -113
  137. package/src/pages/NSALoginPage.module.css +26 -26
  138. package/src/pages/NSALoginPage.tsx +87 -87
  139. package/src/pages/NSAPhoneVerificationPage.tsx +106 -94
  140. package/src/pages/NSAVerificationPage.module.css +31 -31
  141. package/src/pages/NSAVerificationPage.tsx +185 -185
  142. package/src/pages/NSFCategoryEditPage.tsx +87 -87
  143. package/src/pages/NSFCategoryListPage.tsx +23 -23
  144. package/src/pages/NSFCategoryViewPage.tsx +23 -23
  145. package/src/pages/NSFEntities.ts +58 -58
  146. package/src/pages/PaymentRequired.tsx +80 -80
  147. package/tsconfig.json +43 -43
@@ -1,298 +1,298 @@
1
- import { FilterItemOperator } from "namirasoft-core";
2
- import { VariableType } from "namirasoft-schema";
3
- import { NSBoxBaseCombo, NSBoxCombo, NSBoxString, NSButton, NSButtonBlue, NSColumn, NSDialog, NSNoData, NSTitle, TableColumnInfo } from "namirasoft-site-react";
4
- import { Component, Fragment } from "react";
5
- import { NSAFilterOperators } from "../../NSAFilterOperators";
6
- import Styles from "./NSAQuickFilterDialog.module.css";
7
-
8
- export interface QuickFilterConfig
9
- {
10
- id: string;
11
- title?: string;
12
- column: {
13
- table: { name: string; text: string };
14
- name: string;
15
- text: string;
16
- type: string;
17
- columnType: VariableType;
18
- };
19
- operatorName?: string;
20
- }
21
-
22
- interface NSAQuickFilterDialogProps
23
- {
24
- configs: QuickFilterConfig[];
25
- defaults?: QuickFilterConfig[];
26
- getColumns: () => TableColumnInfo[];
27
- typeConverter: (type: string) => VariableType;
28
- onSave: (configs: QuickFilterConfig[]) => void;
29
- onConfirm: (configs: QuickFilterConfig[]) => void;
30
- onClose: () => void;
31
- }
32
-
33
- interface NSAQuickFilterDialogState
34
- {
35
- configs: QuickFilterConfig[];
36
- formMode: "add" | "edit" | null;
37
- editingId: string | null;
38
- formColumn: TableColumnInfo | null;
39
- formOperatorName: string | null;
40
- formTitle: string | null;
41
- formKey: number;
42
- }
43
-
44
- export class NSAQuickFilterDialog extends Component<NSAQuickFilterDialogProps, NSAQuickFilterDialogState>
45
- {
46
- constructor(props: NSAQuickFilterDialogProps)
47
- {
48
- super(props);
49
- this.state = {
50
- configs: [...props.configs],
51
- formMode: null,
52
- editingId: null,
53
- formColumn: null,
54
- formOperatorName: null,
55
- formTitle: null,
56
- formKey: 0,
57
- };
58
- }
59
-
60
- private openAdd = () =>
61
- {
62
- this.setState(prev => ({
63
- formMode: "add",
64
- editingId: null,
65
- formColumn: null,
66
- formOperatorName: null,
67
- formTitle: null,
68
- formKey: prev.formKey + 1,
69
- }));
70
- };
71
-
72
- private openEdit = (config: QuickFilterConfig) =>
73
- {
74
- const col = this.props.getColumns().find(
75
- c => c.table.name === config.column.table.name && c.name === config.column.name
76
- ) ?? null;
77
- this.setState(prev => ({
78
- formMode: "edit",
79
- editingId: config.id,
80
- formColumn: col,
81
- formOperatorName: config.operatorName ?? null,
82
- formTitle: config.title ?? null,
83
- formKey: prev.formKey + 1,
84
- }));
85
- };
86
-
87
- private deleteConfig = (id: string) =>
88
- {
89
- this.setState(prev => ({ configs: prev.configs.filter(c => c.id !== id) }));
90
- };
91
-
92
- private hasChanges(): boolean
93
- {
94
- return JSON.stringify(this.state.configs) !== JSON.stringify(this.props.configs);
95
- }
96
-
97
- // compares on column/operator (not id) so a manually re-added default still counts
98
- private isAtDefaults(): boolean
99
- {
100
- const key = (c: QuickFilterConfig) => `${c.column.table.name}|${c.column.name}|${c.operatorName ?? ""}|${c.title ?? ""}`;
101
- const defaults = this.props.defaults ?? [];
102
- return this.state.configs.length === defaults.length
103
- && this.state.configs.every((c, i) => key(c) === key(defaults[i]));
104
- }
105
-
106
- private resetToDefaults = () =>
107
- {
108
- this.setState({ configs: [...(this.props.defaults ?? [])] });
109
- };
110
-
111
- private saveForm = () =>
112
- {
113
- const { formColumn, formOperatorName, formTitle, formMode, editingId, configs } = this.state;
114
- if (!formColumn) return;
115
-
116
- const columnType = this.props.typeConverter(formColumn.type);
117
- const isBoolean = columnType === VariableType.Boolean;
118
-
119
- const newConfig: QuickFilterConfig = {
120
- id: formMode === "edit" && editingId ? editingId : crypto.randomUUID(),
121
- title: formTitle?.trim() || undefined,
122
- column: {
123
- table: { name: formColumn.table.name, text: formColumn.table.text },
124
- name: formColumn.name,
125
- text: formColumn.text,
126
- type: formColumn.type,
127
- columnType,
128
- },
129
- operatorName: isBoolean ? undefined : (formOperatorName ?? undefined),
130
- };
131
-
132
- const updatedConfigs = formMode === "edit" && editingId
133
- ? configs.map(c => c.id === editingId ? newConfig : c)
134
- : [...configs, newConfig];
135
-
136
- this.setState({ configs: updatedConfigs, formMode: null }, () =>
137
- {
138
- this.props.onSave(updatedConfigs);
139
- });
140
- };
141
-
142
- override render()
143
- {
144
- const { onClose, onConfirm, getColumns, typeConverter } = this.props;
145
- const { configs, formMode, formColumn, formOperatorName, formKey } = this.state;
146
-
147
- const columns = getColumns();
148
- const columnType = formColumn ? typeConverter(formColumn.type) : null;
149
- const isBoolean = columnType === VariableType.Boolean;
150
- const operators = columnType && !isBoolean ? NSAFilterOperators.getQuickFilterOperators(columnType) : [];
151
-
152
- return (
153
- <NSDialog
154
- center_dialog
155
- closeButton={{ show: true }}
156
- onClose={onClose}
157
- >
158
- <NSColumn classList={["align-items-center"]}>
159
- <NSTitle
160
- title="Quick Filters"
161
- style={{ marginBottom: 0, fontSize: 24 }}
162
- />
163
-
164
- {
165
- configs.length === 0 && !formMode &&
166
- <NSNoData lable="No quick filters defined" style={{ marginBottom: 16, fontSize: 20 }} />
167
- }
168
-
169
- {
170
- configs.length > 0 && !formMode && (
171
- <NSColumn classList={["gap-2"]}>
172
- {
173
- configs.map(cfg =>
174
- {
175
- const opLabel = cfg.operatorName
176
- ? FilterItemOperator.getByName(cfg.operatorName).name
177
- : "—";
178
- return (
179
- <div key={cfg.id} className={Styles.qf_item}>
180
- <div className={Styles.qf_item_info}>
181
- <span className={Styles.qf_item_label}>{cfg.title ?? cfg.column.text}</span>
182
- <span className={Styles.qf_item_op}>{opLabel}</span>
183
- </div>
184
- <div className={Styles.qf_item_actions}>
185
- <NSButton
186
- title=""
187
- icon={{ src: "https://static.namirasoft.com/image/concept/edit/blue.svg", alt: "edit" }}
188
- classList={[Styles.qf_item_btn]}
189
- onClick={{ action: () => this.openEdit(cfg), showLoading: false }}
190
- />
191
- <NSButton
192
- title=""
193
- icon={{ src: "https://static.namirasoft.com/image/concept/delete/blue.svg", alt: "delete" }}
194
- classList={[Styles.qf_item_btn]}
195
- onClick={{ action: () => this.deleteConfig(cfg.id), showLoading: false }}
196
- />
197
- </div>
198
- </div>
199
- );
200
- })
201
- }
202
- </NSColumn>
203
- )
204
- }
205
-
206
- {
207
- formMode &&
208
- <Fragment key={formKey}>
209
- <NSBoxString
210
- title="Title"
211
- required={false}
212
- defaultValue={this.state.formTitle ?? undefined}
213
- onChanged={e => this.setState({ formTitle: e.getValue() || null })}
214
- />
215
- <NSBoxBaseCombo<TableColumnInfo>
216
- title="Column"
217
- required
218
- defaultValue={formColumn?.name}
219
- getItems={async () => ({ count: columns.length, rows: columns })}
220
- getTitle={c => c.text}
221
- getValue={c => c.name}
222
- getSort={() => null}
223
- multiple={false}
224
- onChanged={e =>
225
- {
226
- const col = e.getDataOne();
227
- this.setState({ formColumn: col ?? null, formOperatorName: null });
228
- }}
229
- menu={{
230
- builtin: {
231
- copy: { enabled: false, getValue: () => "" }
232
- },
233
- items: []
234
- }}
235
- />
236
- <NSBoxCombo
237
- key={formColumn?.name}
238
- title="Operator"
239
- required
240
- disabled={!formColumn || isBoolean}
241
- defaultValue={formOperatorName ?? undefined}
242
- getOptions={() => operators.map(op => ({ value: NSAFilterOperators.getOperatorKey(op), title: `${op.sign} (${op.name})` }))}
243
- multiple={false}
244
- searchable={false}
245
- onChanged={e => this.setState({ formOperatorName: e.getValueOne(false) ?? null })}
246
- menu={{
247
- builtin: {
248
- copy: { enabled: false, getValue: () => "" }
249
- },
250
- items: []
251
- }}
252
- />
253
- <NSButtonBlue
254
- title="Save"
255
- onClick={{ action: this.saveForm, showLoading: false }}
256
- />
257
- <NSButton
258
- title=""
259
- icon={{ src: "https://static.namirasoft.com/image/concept/arrow/left/blue.svg", alt: "back" }}
260
- classList={[Styles.qf_back_btn]}
261
- onClick={{ action: () => this.setState({ formMode: null }), showLoading: false }}
262
- style={{ width: 40, height: 40 }}
263
- />
264
- </Fragment>
265
- }
266
-
267
- {
268
- !formMode &&
269
- <>
270
- {
271
- (this.props.defaults?.length ?? 0) > 0 && !this.isAtDefaults() &&
272
- <NSButton
273
- title=""
274
- icon={{ src: "https://static.namirasoft.com/image/concept/refresh/blue.svg", alt: "reset" }}
275
- classList={[Styles.qf_back_btn]}
276
- onClick={{ action: this.resetToDefaults, showLoading: false }}
277
- style={{ width: 40, height: 40 }}
278
- />
279
- }
280
- <NSButton
281
- title="+ Add Filter"
282
- onClick={{ action: this.openAdd, showLoading: false }}
283
- style={{ border: "1px solid #000" }}
284
- />
285
- {
286
- this.hasChanges() &&
287
- <NSButtonBlue
288
- title="Save Changes"
289
- onClick={{ action: () => onConfirm(this.state.configs), showLoading: false }}
290
- />
291
- }
292
- </>
293
- }
294
- </NSColumn>
295
- </NSDialog>
296
- );
297
- }
1
+ import { FilterItemOperator } from "namirasoft-core";
2
+ import { VariableType } from "namirasoft-schema";
3
+ import { NSBoxBaseCombo, NSBoxCombo, NSBoxString, NSButton, NSButtonBlue, NSColumn, NSDialog, NSNoData, NSTitle, TableColumnInfo } from "namirasoft-site-react";
4
+ import { Component, Fragment } from "react";
5
+ import { NSAFilterOperators } from "../../NSAFilterOperators";
6
+ import Styles from "./NSAQuickFilterDialog.module.css";
7
+
8
+ export interface QuickFilterConfig
9
+ {
10
+ id: string;
11
+ title?: string;
12
+ column: {
13
+ table: { name: string; text: string };
14
+ name: string;
15
+ text: string;
16
+ type: string;
17
+ columnType: VariableType;
18
+ };
19
+ operatorName?: string;
20
+ }
21
+
22
+ interface NSAQuickFilterDialogProps
23
+ {
24
+ configs: QuickFilterConfig[];
25
+ defaults?: QuickFilterConfig[];
26
+ getColumns: () => TableColumnInfo[];
27
+ typeConverter: (type: string) => VariableType;
28
+ onSave: (configs: QuickFilterConfig[]) => void;
29
+ onConfirm: (configs: QuickFilterConfig[]) => void;
30
+ onClose: () => void;
31
+ }
32
+
33
+ interface NSAQuickFilterDialogState
34
+ {
35
+ configs: QuickFilterConfig[];
36
+ formMode: "add" | "edit" | null;
37
+ editingId: string | null;
38
+ formColumn: TableColumnInfo | null;
39
+ formOperatorName: string | null;
40
+ formTitle: string | null;
41
+ formKey: number;
42
+ }
43
+
44
+ export class NSAQuickFilterDialog extends Component<NSAQuickFilterDialogProps, NSAQuickFilterDialogState>
45
+ {
46
+ constructor(props: NSAQuickFilterDialogProps)
47
+ {
48
+ super(props);
49
+ this.state = {
50
+ configs: [...props.configs],
51
+ formMode: null,
52
+ editingId: null,
53
+ formColumn: null,
54
+ formOperatorName: null,
55
+ formTitle: null,
56
+ formKey: 0,
57
+ };
58
+ }
59
+
60
+ private openAdd = () =>
61
+ {
62
+ this.setState(prev => ({
63
+ formMode: "add",
64
+ editingId: null,
65
+ formColumn: null,
66
+ formOperatorName: null,
67
+ formTitle: null,
68
+ formKey: prev.formKey + 1,
69
+ }));
70
+ };
71
+
72
+ private openEdit = (config: QuickFilterConfig) =>
73
+ {
74
+ const col = this.props.getColumns().find(
75
+ c => c.table.name === config.column.table.name && c.name === config.column.name
76
+ ) ?? null;
77
+ this.setState(prev => ({
78
+ formMode: "edit",
79
+ editingId: config.id,
80
+ formColumn: col,
81
+ formOperatorName: config.operatorName ?? null,
82
+ formTitle: config.title ?? null,
83
+ formKey: prev.formKey + 1,
84
+ }));
85
+ };
86
+
87
+ private deleteConfig = (id: string) =>
88
+ {
89
+ this.setState(prev => ({ configs: prev.configs.filter(c => c.id !== id) }));
90
+ };
91
+
92
+ private hasChanges(): boolean
93
+ {
94
+ return JSON.stringify(this.state.configs) !== JSON.stringify(this.props.configs);
95
+ }
96
+
97
+ // compares on column/operator (not id) so a manually re-added default still counts
98
+ private isAtDefaults(): boolean
99
+ {
100
+ const key = (c: QuickFilterConfig) => `${c.column.table.name}|${c.column.name}|${c.operatorName ?? ""}|${c.title ?? ""}`;
101
+ const defaults = this.props.defaults ?? [];
102
+ return this.state.configs.length === defaults.length
103
+ && this.state.configs.every((c, i) => key(c) === key(defaults[i]));
104
+ }
105
+
106
+ private resetToDefaults = () =>
107
+ {
108
+ this.setState({ configs: [...(this.props.defaults ?? [])] });
109
+ };
110
+
111
+ private saveForm = () =>
112
+ {
113
+ const { formColumn, formOperatorName, formTitle, formMode, editingId, configs } = this.state;
114
+ if (!formColumn) return;
115
+
116
+ const columnType = this.props.typeConverter(formColumn.type);
117
+ const isBoolean = columnType === VariableType.Boolean;
118
+
119
+ const newConfig: QuickFilterConfig = {
120
+ id: formMode === "edit" && editingId ? editingId : crypto.randomUUID(),
121
+ title: formTitle?.trim() || undefined,
122
+ column: {
123
+ table: { name: formColumn.table.name, text: formColumn.table.text },
124
+ name: formColumn.name,
125
+ text: formColumn.text,
126
+ type: formColumn.type,
127
+ columnType,
128
+ },
129
+ operatorName: isBoolean ? undefined : (formOperatorName ?? undefined),
130
+ };
131
+
132
+ const updatedConfigs = formMode === "edit" && editingId
133
+ ? configs.map(c => c.id === editingId ? newConfig : c)
134
+ : [...configs, newConfig];
135
+
136
+ this.setState({ configs: updatedConfigs, formMode: null }, () =>
137
+ {
138
+ this.props.onSave(updatedConfigs);
139
+ });
140
+ };
141
+
142
+ override render()
143
+ {
144
+ const { onClose, onConfirm, getColumns, typeConverter } = this.props;
145
+ const { configs, formMode, formColumn, formOperatorName, formKey } = this.state;
146
+
147
+ const columns = getColumns();
148
+ const columnType = formColumn ? typeConverter(formColumn.type) : null;
149
+ const isBoolean = columnType === VariableType.Boolean;
150
+ const operators = columnType && !isBoolean ? NSAFilterOperators.getQuickFilterOperators(columnType) : [];
151
+
152
+ return (
153
+ <NSDialog
154
+ center_dialog
155
+ closeButton={{ show: true }}
156
+ onClose={onClose}
157
+ >
158
+ <NSColumn classList={["align-items-center"]}>
159
+ <NSTitle
160
+ title="Quick Filters"
161
+ style={{ marginBottom: 0, fontSize: 24 }}
162
+ />
163
+
164
+ {
165
+ configs.length === 0 && !formMode &&
166
+ <NSNoData lable="No quick filters defined" style={{ marginBottom: 16, fontSize: 20 }} />
167
+ }
168
+
169
+ {
170
+ configs.length > 0 && !formMode && (
171
+ <NSColumn classList={["gap-2"]}>
172
+ {
173
+ configs.map(cfg =>
174
+ {
175
+ const opLabel = cfg.operatorName
176
+ ? FilterItemOperator.getByName(cfg.operatorName).name
177
+ : "—";
178
+ return (
179
+ <div key={cfg.id} className={Styles.qf_item}>
180
+ <div className={Styles.qf_item_info}>
181
+ <span className={Styles.qf_item_label}>{cfg.title ?? cfg.column.text}</span>
182
+ <span className={Styles.qf_item_op}>{opLabel}</span>
183
+ </div>
184
+ <div className={Styles.qf_item_actions}>
185
+ <NSButton
186
+ title=""
187
+ icon={{ src: "https://static.namirasoft.com/image/concept/edit/blue.svg", alt: "edit" }}
188
+ classList={[Styles.qf_item_btn]}
189
+ onClick={{ action: () => this.openEdit(cfg), showLoading: false }}
190
+ />
191
+ <NSButton
192
+ title=""
193
+ icon={{ src: "https://static.namirasoft.com/image/concept/delete/blue.svg", alt: "delete" }}
194
+ classList={[Styles.qf_item_btn]}
195
+ onClick={{ action: () => this.deleteConfig(cfg.id), showLoading: false }}
196
+ />
197
+ </div>
198
+ </div>
199
+ );
200
+ })
201
+ }
202
+ </NSColumn>
203
+ )
204
+ }
205
+
206
+ {
207
+ formMode &&
208
+ <Fragment key={formKey}>
209
+ <NSBoxString
210
+ title="Title"
211
+ required={false}
212
+ defaultValue={this.state.formTitle ?? undefined}
213
+ onChanged={e => this.setState({ formTitle: e.getValue() || null })}
214
+ />
215
+ <NSBoxBaseCombo<TableColumnInfo>
216
+ title="Column"
217
+ required
218
+ defaultValue={formColumn?.name}
219
+ getItems={async () => ({ count: columns.length, rows: columns })}
220
+ getTitle={c => c.text}
221
+ getValue={c => c.name}
222
+ getSort={() => null}
223
+ multiple={false}
224
+ onChanged={e =>
225
+ {
226
+ const col = e.getDataOne();
227
+ this.setState({ formColumn: col ?? null, formOperatorName: null });
228
+ }}
229
+ menu={{
230
+ builtin: {
231
+ copy: { enabled: false, getValue: () => "" }
232
+ },
233
+ items: []
234
+ }}
235
+ />
236
+ <NSBoxCombo
237
+ key={formColumn?.name}
238
+ title="Operator"
239
+ required
240
+ disabled={!formColumn || isBoolean}
241
+ defaultValue={formOperatorName ?? undefined}
242
+ getOptions={() => operators.map(op => ({ value: NSAFilterOperators.getOperatorKey(op), title: `${op.sign} (${op.name})` }))}
243
+ multiple={false}
244
+ searchable={false}
245
+ onChanged={e => this.setState({ formOperatorName: e.getValueOne(false) ?? null })}
246
+ menu={{
247
+ builtin: {
248
+ copy: { enabled: false, getValue: () => "" }
249
+ },
250
+ items: []
251
+ }}
252
+ />
253
+ <NSButtonBlue
254
+ title="Save"
255
+ onClick={{ action: this.saveForm, showLoading: false }}
256
+ />
257
+ <NSButton
258
+ title=""
259
+ icon={{ src: "https://static.namirasoft.com/image/concept/arrow/left/blue.svg", alt: "back" }}
260
+ classList={[Styles.qf_back_btn]}
261
+ onClick={{ action: () => this.setState({ formMode: null }), showLoading: false }}
262
+ style={{ width: 40, height: 40 }}
263
+ />
264
+ </Fragment>
265
+ }
266
+
267
+ {
268
+ !formMode &&
269
+ <>
270
+ {
271
+ (this.props.defaults?.length ?? 0) > 0 && !this.isAtDefaults() &&
272
+ <NSButton
273
+ title=""
274
+ icon={{ src: "https://static.namirasoft.com/image/concept/refresh/blue.svg", alt: "reset" }}
275
+ classList={[Styles.qf_back_btn]}
276
+ onClick={{ action: this.resetToDefaults, showLoading: false }}
277
+ style={{ width: 40, height: 40 }}
278
+ />
279
+ }
280
+ <NSButton
281
+ title="+ Add Filter"
282
+ onClick={{ action: this.openAdd, showLoading: false }}
283
+ style={{ border: "1px solid #000" }}
284
+ />
285
+ {
286
+ this.hasChanges() &&
287
+ <NSButtonBlue
288
+ title="Save Changes"
289
+ onClick={{ action: () => onConfirm(this.state.configs), showLoading: false }}
290
+ />
291
+ }
292
+ </>
293
+ }
294
+ </NSColumn>
295
+ </NSDialog>
296
+ );
297
+ }
298
298
  }
package/src/css.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- let css_d = "";
2
-
3
- declare module "*.module.css" {
4
- const classes: { readonly [key: string]: string };
5
- export default classes;
6
- }
7
-
8
- declare module "*.module.scss" {
9
- const classes: { readonly [key: string]: string };
10
- export default classes;
11
- }
12
-
13
- declare module "*.css";
1
+ let css_d = "";
2
+
3
+ declare module "*.module.css" {
4
+ const classes: { readonly [key: string]: string };
5
+ export default classes;
6
+ }
7
+
8
+ declare module "*.module.scss" {
9
+ const classes: { readonly [key: string]: string };
10
+ export default classes;
11
+ }
12
+
13
+ declare module "*.css";
14
14
  declare module "*.scss";