namirasoft-account-react 1.4.433 → 1.4.435

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 (133) hide show
  1. package/.env.template +15 -15
  2. package/SKILLS.md +514 -514
  3. package/config-overrides.js +72 -72
  4. package/dist/App.css +32 -0
  5. package/dist/App.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/NSAMasterMenu.d.ts +1 -1
  10. package/dist/components/NSAMasterMenu.module.css +248 -248
  11. package/dist/components/NSAMasterMenuItem.d.ts +1 -1
  12. package/dist/components/NSAMessageListDialog.d.ts +1 -1
  13. package/dist/components/NSAMessageListDialog.module.css +99 -99
  14. package/dist/components/NSANavigationGuard.d.ts +1 -1
  15. package/dist/components/NSANavigationGuard.js +12 -5
  16. package/dist/components/NSANavigationGuard.js.map +1 -1
  17. package/dist/components/NSAProductListDialog.d.ts +1 -1
  18. package/dist/components/NSAProductListDialog.module.css +44 -44
  19. package/dist/components/NSAReorderDialog.d.ts +1 -1
  20. package/dist/components/NSAReorderDialog.module.css +49 -49
  21. package/dist/components/NSASortDialog.d.ts +1 -1
  22. package/dist/components/NSATaskBar.d.ts +1 -1
  23. package/dist/components/NSATaskBar.module.css +57 -57
  24. package/dist/components/NSAUserDialog.d.ts +1 -1
  25. package/dist/components/NSAUserDialog.module.css +67 -67
  26. package/dist/components/NSAWorkspaceListDialog.d.ts +1 -1
  27. package/dist/components/NSAWorkspaceListDialog.module.css +41 -41
  28. package/dist/components/NSBoxSecret.d.ts +1 -1
  29. package/dist/components/NSBoxSecret.module.css +23 -23
  30. package/dist/components/NSLabelSecret.d.ts +1 -1
  31. package/dist/components/quickfilter/NSAFilterBoxEnum.module.css +45 -0
  32. package/dist/components/quickfilter/NSAQuickFilterBar.d.ts +1 -1
  33. package/dist/components/quickfilter/NSAQuickFilterBar.module.css +20 -0
  34. package/dist/components/quickfilter/NSAQuickFilterDialog.d.ts +1 -1
  35. package/dist/components/quickfilter/NSAQuickFilterDialog.module.css +75 -0
  36. package/dist/index.css +0 -0
  37. package/dist/layouts/NSALayout.d.ts +1 -1
  38. package/dist/layouts/NSASectionEdit.d.ts +1 -1
  39. package/dist/layouts/NSASectionEditTabPage.d.ts +1 -1
  40. package/dist/layouts/NSASectionEditTabPage.module.css +4 -4
  41. package/dist/layouts/NSASectionList.d.ts +1 -1
  42. package/dist/layouts/NSASectionList.module.css +31 -31
  43. package/dist/layouts/NSASectionView.d.ts +1 -1
  44. package/dist/layouts/NSASectionViewTabMore.d.ts +1 -1
  45. package/dist/layouts/NSASectionViewTabPage.d.ts +1 -1
  46. package/dist/layouts/NSASectionViewTabPage.module.css +47 -47
  47. package/dist/pages/NSAConsentPage.module.css +26 -26
  48. package/dist/pages/NSAEmailVerificationPage.d.ts +1 -1
  49. package/dist/pages/NSAHomePage.d.ts +1 -1
  50. package/dist/pages/NSAHomePage.module.css +41 -41
  51. package/dist/pages/NSALoginPage.d.ts +1 -1
  52. package/dist/pages/NSALoginPage.module.css +26 -26
  53. package/dist/pages/NSAPhoneVerificationPage.d.ts +1 -1
  54. package/dist/pages/NSAVerificationPage.d.ts +1 -1
  55. package/dist/pages/NSAVerificationPage.module.css +31 -31
  56. package/package.json +94 -94
  57. package/public/index.html +21 -21
  58. package/src/App.css +31 -31
  59. package/src/App.tsx +19 -19
  60. package/src/CTFRow.ts +7 -7
  61. package/src/IEntityInfo.ts +33 -33
  62. package/src/NSACacheService.ts +120 -120
  63. package/src/NSAFilterOperators.ts +92 -92
  64. package/src/NSARouterMaker.tsx +140 -140
  65. package/src/NSARouterMakerConfig.ts +15 -15
  66. package/src/NSARouterMakerProps.ts +24 -24
  67. package/src/NSATaskService.ts +122 -122
  68. package/src/Router.tsx +45 -45
  69. package/src/UseParams.tsx +18 -18
  70. package/src/components/NSAAccessListDialog.module.css +71 -71
  71. package/src/components/NSAAccessListDialog.tsx +178 -178
  72. package/src/components/NSAMasterMenu.module.css +248 -248
  73. package/src/components/NSAMasterMenu.tsx +169 -169
  74. package/src/components/NSAMasterMenuItem.tsx +250 -250
  75. package/src/components/NSAMessageListDialog.module.css +99 -99
  76. package/src/components/NSAMessageListDialog.tsx +142 -142
  77. package/src/components/NSANavigationGuard.tsx +21 -6
  78. package/src/components/NSAProductListDialog.module.css +44 -44
  79. package/src/components/NSAProductListDialog.tsx +88 -88
  80. package/src/components/NSAReorderDialog.module.css +49 -49
  81. package/src/components/NSAReorderDialog.tsx +149 -149
  82. package/src/components/NSASortDialog.tsx +117 -117
  83. package/src/components/NSATable.tsx +498 -498
  84. package/src/components/NSATaskBar.module.css +57 -57
  85. package/src/components/NSATaskBar.tsx +101 -101
  86. package/src/components/NSAUserDialog.module.css +67 -67
  87. package/src/components/NSAUserDialog.tsx +122 -122
  88. package/src/components/NSAWorkspaceListDialog.module.css +41 -41
  89. package/src/components/NSAWorkspaceListDialog.tsx +147 -147
  90. package/src/components/NSBoxSecret.module.css +23 -23
  91. package/src/components/NSBoxSecret.tsx +258 -258
  92. package/src/components/NSLabelSecret.tsx +37 -37
  93. package/src/components/quickfilter/NSAFilterBoxBase.tsx +55 -55
  94. package/src/components/quickfilter/NSAFilterBoxBoolean.tsx +54 -54
  95. package/src/components/quickfilter/NSAFilterBoxDate.tsx +104 -104
  96. package/src/components/quickfilter/NSAFilterBoxDateTime.tsx +105 -105
  97. package/src/components/quickfilter/NSAFilterBoxEnum.module.css +44 -44
  98. package/src/components/quickfilter/NSAFilterBoxEnum.tsx +79 -79
  99. package/src/components/quickfilter/NSAFilterBoxNumber.tsx +136 -136
  100. package/src/components/quickfilter/NSAFilterBoxString.tsx +81 -81
  101. package/src/components/quickfilter/NSAFilterBoxTime.tsx +101 -101
  102. package/src/components/quickfilter/NSAQuickFilterBar.module.css +19 -19
  103. package/src/components/quickfilter/NSAQuickFilterBar.tsx +114 -114
  104. package/src/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  105. package/src/components/quickfilter/NSAQuickFilterDialog.tsx +260 -260
  106. package/src/css.d.ts +13 -13
  107. package/src/formatters/SecretFormatter.tsx +24 -24
  108. package/src/index.tsx +26 -26
  109. package/src/layouts/Actions.ts +146 -146
  110. package/src/layouts/CFTUtil.ts +18 -18
  111. package/src/layouts/NSALayout.tsx +790 -790
  112. package/src/layouts/NSASectionEdit.tsx +279 -279
  113. package/src/layouts/NSASectionEditTabPage.module.css +4 -4
  114. package/src/layouts/NSASectionEditTabPage.tsx +250 -250
  115. package/src/layouts/NSASectionList.module.css +31 -31
  116. package/src/layouts/NSASectionList.tsx +149 -149
  117. package/src/layouts/NSASectionView.tsx +100 -100
  118. package/src/layouts/NSASectionViewTabMore.tsx +77 -77
  119. package/src/layouts/NSASectionViewTabPage.module.css +47 -47
  120. package/src/layouts/NSASectionViewTabPage.tsx +419 -419
  121. package/src/main.ts +46 -46
  122. package/src/pages/NSAConsentPage.module.css +26 -26
  123. package/src/pages/NSAConsentPage.tsx +120 -120
  124. package/src/pages/NSAEmailVerificationPage.tsx +30 -30
  125. package/src/pages/NSAHomePage.module.css +41 -41
  126. package/src/pages/NSAHomePage.tsx +102 -102
  127. package/src/pages/NSALoginPage.module.css +26 -26
  128. package/src/pages/NSALoginPage.tsx +87 -87
  129. package/src/pages/NSAPhoneVerificationPage.tsx +94 -94
  130. package/src/pages/NSAVerificationPage.module.css +31 -31
  131. package/src/pages/NSAVerificationPage.tsx +186 -186
  132. package/src/pages/PaymentRequired.tsx +76 -76
  133. package/tsconfig.json +43 -43
@@ -1,420 +1,420 @@
1
- import { EnvService, FilterItem, FilterItemOperator, IStorageLocal, NamingConvention } from "namirasoft-core";
2
- import { CategoryRow, FieldRow } from "namirasoft-field";
3
- import { HistoryRow, NamirasoftHistoryServer } from "namirasoft-history";
4
- import { NamirasoftMap } from "namirasoft-site-map";
5
- import { BaseColumnFormatter, DateTimeFormatter, IBaseComponentProps, IDFormatter, NSInfoProps, NSLabel, NSLoading, NSNoData, NSTable, NSTabPage, NSTabPageTab, StringFormatter, StringFormatterSizeType, TableColumnInfo } from "namirasoft-site-react";
6
- import { Component, createRef, Fragment, ReactNode } from "react";
7
- import { IEntityInfo } from "../IEntityInfo";
8
- import { NSARouterMakerProps } from "../NSARouterMakerProps";
9
- import { CFTUtil } from "./CFTUtil";
10
- import { NSASectionViewTabMore } from "./NSASectionViewTabMore";
11
- import Styles from "./NSASectionViewTabPage.module.css";
12
-
13
- export type TabRenderItem =
14
- | { type: "column"; column: TableColumnInfo }
15
- | { type: "custom"; node: ReactNode };
16
-
17
- export interface NSASectionViewTabPageTabPageTab<RowType> extends IBaseComponentProps
18
- {
19
- isVisible(model: {
20
- id: string | null;
21
- row: RowType | null;
22
- }): boolean;
23
-
24
- title: string;
25
- info?: NSInfoProps;
26
- clicked: boolean;
27
- getContent: (model: {
28
- id: string | null;
29
- row: RowType | null;
30
- }) => React.ReactNode;
31
- }
32
-
33
- export interface NSASectionViewTabPageUIProps<RowType>
34
- {
35
- enabled?: boolean;
36
- tabs?: {
37
- general?: {
38
- enabled?: boolean;
39
- getColumns?: (row: RowType) => TableColumnInfo[];
40
- getValue?: (row: RowType, column: string) => string | undefined;
41
- buildItems?: (row: RowType, tab: string, columns: TableColumnInfo[]) => TabRenderItem[];
42
- }
43
- field?: boolean;
44
- category?: boolean;
45
- tag?: boolean;
46
- history?: boolean;
47
- more?: boolean;
48
- extra?: {
49
- before_general?: NSASectionViewTabPageTabPageTab<RowType>[];
50
- after_general?: NSASectionViewTabPageTabPageTab<RowType>[];
51
- after_field?: NSASectionViewTabPageTabPageTab<RowType>[];
52
- after_category?: NSASectionViewTabPageTabPageTab<RowType>[];
53
- after_tag?: NSASectionViewTabPageTabPageTab<RowType>[];
54
- after_history?: NSASectionViewTabPageTabPageTab<RowType>[];
55
- after_more?: NSASectionViewTabPageTabPageTab<RowType>[];
56
- };
57
- };
58
- }
59
-
60
- export interface NSASectionViewTabPageCutomProps<RowType>
61
- {
62
- ui?: NSASectionViewTabPageUIProps<RowType>;
63
- onRowLoaded?: (row: RowType) => void;
64
- }
65
-
66
- export interface NSASectionViewTabPageProps<RowType extends { id: string }, RowTypeInput = RowType> extends NSARouterMakerProps, NSASectionViewTabPageCutomProps<RowType>
67
- {
68
- entity: IEntityInfo<RowType, RowTypeInput>;
69
- ctf: {
70
- enabled: boolean;
71
- fields: FieldRow[] | null;
72
- categories: CategoryRow[] | null;
73
- };
74
- model: {
75
- id: string | null;
76
- row: RowType | null;
77
- };
78
- deleteFieldCache: () => void;
79
- }
80
-
81
- interface NSASectionViewTabPageState<RowType>
82
- {
83
- row: RowType | null;
84
- }
85
-
86
- export class NSASectionViewTabPage<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSASectionViewTabPageProps<RowType, RowTypeInput>, NSASectionViewTabPageState<RowType>>
87
- {
88
- NSTabPage_Ref = createRef<NSTabPage>();
89
-
90
- constructor(props: NSASectionViewTabPageProps<RowType, RowTypeInput>)
91
- {
92
- super(props);
93
-
94
- this.state = { row: this.props.model.row };
95
-
96
- this.reload = this.reload.bind(this);
97
- this.getRow = this.getRow.bind(this);
98
- }
99
- reload()
100
- {
101
- this.setState(prev => ({ ...prev, row: null }));
102
- if (this.props.model.id)
103
- if (this.props.entity.server.get)
104
- this.props.entity.server.get(this.props.model.id).then(row =>
105
- {
106
- this.setState(prev => ({ ...prev, row }), () =>
107
- {
108
- this.props.onRowLoaded?.(row);
109
- });
110
- }).catch(() => { });
111
- }
112
- getRow()
113
- {
114
- return this.state.row;
115
- }
116
- override componentDidMount()
117
- {
118
- if (this.props.model.id)
119
- if (!this.props.model.row || this.props.model.row.id !== this.props.model.id)
120
- this.reload();
121
- }
122
- override render()
123
- {
124
- const tabs: NSTabPageTab[] = [];
125
- let namirasoft = new NamirasoftMap(this.props.account.token_manager, this.props.notifier.onError);
126
-
127
- let pushTabs = (ts?: NSASectionViewTabPageTabPageTab<RowType>[]) =>
128
- {
129
- if (ts)
130
- for (let i = 0; i < ts.length; i++)
131
- {
132
- const tab = ts[i];
133
- if (tab.isVisible(this.props.model))
134
- tabs.push({
135
- ...tab,
136
- getContent: () =>
137
- {
138
- return tab.getContent(this.props.model);
139
- }
140
- });
141
- }
142
- };
143
-
144
- pushTabs(this.props.ui?.tabs?.extra?.before_general);
145
- if (this.props.ui?.tabs?.general?.enabled ?? true)
146
- if (this.props.model.id)
147
- if (this.props.entity.server.get)
148
- {
149
- let getColumns = (): TableColumnInfo[] =>
150
- {
151
- let columns: TableColumnInfo[] = [];
152
- if (this.state.row)
153
- if (this.props.ui?.tabs?.general?.getColumns)
154
- columns = this.props.ui?.tabs?.general?.getColumns(this.state.row);
155
- if (columns.length === 0)
156
- columns = this.props.entity.client.getColumns();
157
- return columns;
158
- };
159
- let getValue = (column: string): string =>
160
- {
161
- if (this.state.row)
162
- if (this.props.ui?.tabs?.general?.getValue)
163
- {
164
- let ans = this.props.ui?.tabs?.general?.getValue(this.state.row, column);
165
- if (ans !== undefined)
166
- return ans;
167
- }
168
- return (this.state.row as any)[column];
169
- };
170
- let renderColumn = (column: TableColumnInfo, tab: string, index: number): ReactNode =>
171
- {
172
- let title = column.text;
173
- if (title.startsWith(tab))
174
- title = title.substring(tab.length + 1);
175
-
176
- let value = getValue(column.name);
177
- let formatted = column.formatter.format(value, column, { index: 0, value: this.state.row }, false);
178
-
179
- return (
180
- <NSLabel
181
- key={`NSASectionViewTabPage_NSLabel_${tab}_${index}`}
182
- title={title + ":"}
183
- classList={[Styles.nsa_section_tab_page_item]}
184
- >
185
- <div>{formatted}</div>
186
- </NSLabel>
187
- );
188
- }
189
-
190
- let TAB_GENERAL = "General";
191
- let columns = getColumns();
192
- columns.filter(c => !c.group).forEach(c => { c.group = TAB_GENERAL });
193
- let tab_names: string[] = columns.map(tab => tab.group) as string[];
194
- tab_names = [...new Set(tab_names)];
195
- tab_names = tab_names.filter(t => t !== TAB_GENERAL);
196
- tab_names = [TAB_GENERAL, ...tab_names];
197
-
198
- tab_names.forEach(tab =>
199
- {
200
- tabs.push({
201
- title: tab,
202
- clicked: false,
203
- getContent: () =>
204
- {
205
- if (!this.state.row)
206
- return <NSLoading />;
207
-
208
- let tab_columns = columns.filter(c => c.group === tab);
209
- let render_items = this.props.ui?.tabs?.general?.buildItems?.(this.state.row, tab, tab_columns);
210
-
211
- if (!render_items)
212
- return (
213
- <div className={Styles.nsa_section_tab_page_parent}>
214
- {tab_columns.map((col, index) => renderColumn(col, tab, index))}
215
- </div>
216
- )
217
-
218
- return (
219
- <div className={Styles.nsa_section_tab_page_parent}>
220
- {
221
- render_items.map((render_item, index) =>
222
- {
223
- if (render_item.type === "column")
224
- return renderColumn(render_item.column, tab, index);
225
-
226
- return (
227
- <Fragment key={`NSASectionViewTabPage_Custom_${tab}_${index}`}>
228
- {render_item.node}
229
- </Fragment>
230
- );
231
- })
232
- }
233
- </div>
234
- );
235
- }
236
- });
237
- });
238
- }
239
- pushTabs(this.props.ui?.tabs?.extra?.after_general);
240
-
241
- if (this.props.ui?.tabs?.history ?? true)
242
- if (this.props.model.id)
243
- tabs.push({
244
- title: 'History',
245
- clicked: false,
246
- getContent: () =>
247
- {
248
- return <NSTable<HistoryRow>
249
- name="History"
250
- checkbox={false}
251
- columns={[
252
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.id, new IDFormatter(namirasoft, null)),
253
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.user_id, new IDFormatter(namirasoft, new IStorageLocal())),
254
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.session_id, new IDFormatter(namirasoft, null)),
255
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.entity_name, new StringFormatter(StringFormatterSizeType.TwoWords, NamingConvention.Pascal_Case_Space)),
256
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.entity_id, new IDFormatter(namirasoft, new IStorageLocal())),
257
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.action, new StringFormatter(StringFormatterSizeType.Word)),
258
- BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.created_at, new DateTimeFormatter()),
259
- ]}
260
- getRows={async () =>
261
- {
262
- if (this.props.model.id)
263
- {
264
- let REACT_APP_BASE_URL_HISTORY = new EnvService("REACT_APP_BASE_URL_HISTORY", true).getString();
265
- let server = new NamirasoftHistoryServer(REACT_APP_BASE_URL_HISTORY, this.props.account.token_manager, this.props.notifier.onError);
266
- let filters = [new FilterItem(namirasoft.history.tables.history, namirasoft.history.tables.history.columns.entity_id, false, FilterItemOperator.all.equals, this.props.model.id)]
267
- return await server.history.List(filters, null, null, []);
268
- }
269
- return { rows: [], count: 0 };
270
- }}
271
- getRowKey={row => row.value.id}
272
- style={{ width: "100%" }}
273
- ></NSTable>;
274
- }
275
- });
276
- pushTabs(this.props.ui?.tabs?.extra?.after_history);
277
-
278
- if (this.props.ui?.tabs?.field ?? true)
279
- if (this.props.model.id)
280
- if (this.props.ctf.enabled)
281
- {
282
- let groups = Array.from(new Set(this.props.ctf.fields?.map(x => x.group) ?? []));
283
- groups.forEach(group =>
284
- {
285
- tabs.push({
286
- title: group,
287
- clicked: false,
288
- getContent: () =>
289
- {
290
- if (this.state.row == null)
291
- return <NSLoading></NSLoading>;
292
- let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
293
- if (ctf.fields.length === 0)
294
- return <NSNoData
295
- lable="No field found" />
296
- return <div className={Styles.nsa_section_tab_page_parent}>
297
- {
298
- this.props.ctf.fields?.filter(x => x.group === group).map((field, index) =>
299
- {
300
- return <NSLabel
301
- key={`NSASectionViewTabPage_NSLabel_Field_${index}`}
302
- title={field.name + ":"}
303
- classList={[Styles.nsa_section_tab_page_item]}
304
- >
305
- <div>{ctf.fields.filter(f => f.field_id === field.id).map(f => f.value).join(", ")}</div>
306
- </NSLabel>
307
- })
308
- }
309
- </div>;
310
- }
311
- });
312
- });
313
- }
314
- pushTabs(this.props.ui?.tabs?.extra?.after_field);
315
-
316
- if (this.props.ui?.tabs?.category ?? true)
317
- if (this.props.model.id)
318
- if (this.props.ctf.enabled)
319
- {
320
- let groups = Array.from(new Set(this.props.ctf.categories?.map(x => x.group) ?? []));
321
- groups.forEach(group =>
322
- {
323
- tabs.push({
324
- title: group,
325
- clicked: false,
326
- getContent: () =>
327
- {
328
- if (this.state.row == null)
329
- return <NSLoading></NSLoading>;
330
- let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
331
- if (ctf.tags.length === 0)
332
- return <NSNoData
333
- lable="No category found" />
334
- let ids = ctf.categories.map(c => c.category_id);
335
- return <div className={Styles.nsa_section_tab_page_parent}>
336
- {
337
- this.props.ctf.categories?.filter(x => x.group === group && ids.includes(x.id)).map((category, index) =>
338
- {
339
- return <NSLabel
340
- key={`NSASectionViewTabPage_NSLabel_Category_${index}`}
341
- title={category.name}
342
- classList={[Styles.nsa_section_tab_page_item]}
343
- >
344
- </NSLabel>
345
- })
346
- }
347
- </div>;
348
- }
349
- });
350
- });
351
- }
352
- pushTabs(this.props.ui?.tabs?.extra?.after_category);
353
-
354
- if (this.props.ui?.tabs?.tag ?? true)
355
- if (this.props.model.id)
356
- if (this.props.ctf.enabled)
357
- tabs.push({
358
- title: 'Tag',
359
- clicked: false,
360
- getContent: () =>
361
- {
362
- if (this.state.row == null)
363
- return <NSLoading></NSLoading>;
364
- let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
365
- if (ctf.tags.length === 0)
366
- return <NSNoData lable="No tag found" />
367
- return <div className={Styles.nsa_section_tab_page_parent}>
368
- {
369
- ctf.tags?.map((tag, index) =>
370
- {
371
- return <NSLabel
372
- key={`NSASectionViewTabPage_NSLabel_Tag_${index}`}
373
- title={tag.name + ":"}
374
- classList={[Styles.nsa_section_tab_page_item]}
375
- >
376
- <div>{tag.value}</div>
377
- </NSLabel>
378
- })
379
- }
380
- </div>;
381
- }
382
- });
383
- pushTabs(this.props.ui?.tabs?.extra?.after_tag);
384
- //todo
385
- // tabs.push({title: 'Log', getContent: todo });
386
- // tabs.push({title: 'Monitor', getContent: todo });
387
-
388
- if (this.props.ui?.tabs?.more ?? true)
389
- if (this.props.model.id)
390
- if (this.props.entity.server.get)
391
- if (this.props.ctf.enabled)
392
- tabs.push({
393
- title: "More",
394
- clicked: true,
395
- getContent: () => <NSASectionViewTabMore
396
- deleteFieldCache={this.props.deleteFieldCache}
397
- />
398
- });
399
- pushTabs(this.props.ui?.tabs?.extra?.after_more);
400
-
401
- //todo
402
- // tabs.push({title: 'How It Works', getContent: todo });
403
- // tabs.push({title: 'API', getContent: todo });
404
- // tabs.push({title: 'Sample Code', getContent: todo });
405
- //todo
406
- // tabs.push({title: 'Category', getContent: todo });
407
- // tabs.push({title: 'Field', getContent: todo });
408
-
409
- if (!(this.props.ui?.enabled ?? true))
410
- return <></>;
411
- return (
412
- <>
413
- {
414
- tabs.length > 0 &&
415
- <NSTabPage ref={this.NSTabPage_Ref} tabs={tabs} />
416
- }
417
- </>
418
- );
419
- }
1
+ import { EnvService, FilterItem, FilterItemOperator, IStorageLocal, NamingConvention } from "namirasoft-core";
2
+ import { CategoryRow, FieldRow } from "namirasoft-field";
3
+ import { HistoryRow, NamirasoftHistoryServer } from "namirasoft-history";
4
+ import { NamirasoftMap } from "namirasoft-site-map";
5
+ import { BaseColumnFormatter, DateTimeFormatter, IBaseComponentProps, IDFormatter, NSInfoProps, NSLabel, NSLoading, NSNoData, NSTable, NSTabPage, NSTabPageTab, StringFormatter, StringFormatterSizeType, TableColumnInfo } from "namirasoft-site-react";
6
+ import { Component, createRef, Fragment, ReactNode } from "react";
7
+ import { IEntityInfo } from "../IEntityInfo";
8
+ import { NSARouterMakerProps } from "../NSARouterMakerProps";
9
+ import { CFTUtil } from "./CFTUtil";
10
+ import { NSASectionViewTabMore } from "./NSASectionViewTabMore";
11
+ import Styles from "./NSASectionViewTabPage.module.css";
12
+
13
+ export type TabRenderItem =
14
+ | { type: "column"; column: TableColumnInfo }
15
+ | { type: "custom"; node: ReactNode };
16
+
17
+ export interface NSASectionViewTabPageTabPageTab<RowType> extends IBaseComponentProps
18
+ {
19
+ isVisible(model: {
20
+ id: string | null;
21
+ row: RowType | null;
22
+ }): boolean;
23
+
24
+ title: string;
25
+ info?: NSInfoProps;
26
+ clicked: boolean;
27
+ getContent: (model: {
28
+ id: string | null;
29
+ row: RowType | null;
30
+ }) => React.ReactNode;
31
+ }
32
+
33
+ export interface NSASectionViewTabPageUIProps<RowType>
34
+ {
35
+ enabled?: boolean;
36
+ tabs?: {
37
+ general?: {
38
+ enabled?: boolean;
39
+ getColumns?: (row: RowType) => TableColumnInfo[];
40
+ getValue?: (row: RowType, column: string) => string | undefined;
41
+ buildItems?: (row: RowType, tab: string, columns: TableColumnInfo[]) => TabRenderItem[];
42
+ }
43
+ field?: boolean;
44
+ category?: boolean;
45
+ tag?: boolean;
46
+ history?: boolean;
47
+ more?: boolean;
48
+ extra?: {
49
+ before_general?: NSASectionViewTabPageTabPageTab<RowType>[];
50
+ after_general?: NSASectionViewTabPageTabPageTab<RowType>[];
51
+ after_field?: NSASectionViewTabPageTabPageTab<RowType>[];
52
+ after_category?: NSASectionViewTabPageTabPageTab<RowType>[];
53
+ after_tag?: NSASectionViewTabPageTabPageTab<RowType>[];
54
+ after_history?: NSASectionViewTabPageTabPageTab<RowType>[];
55
+ after_more?: NSASectionViewTabPageTabPageTab<RowType>[];
56
+ };
57
+ };
58
+ }
59
+
60
+ export interface NSASectionViewTabPageCutomProps<RowType>
61
+ {
62
+ ui?: NSASectionViewTabPageUIProps<RowType>;
63
+ onRowLoaded?: (row: RowType) => void;
64
+ }
65
+
66
+ export interface NSASectionViewTabPageProps<RowType extends { id: string }, RowTypeInput = RowType> extends NSARouterMakerProps, NSASectionViewTabPageCutomProps<RowType>
67
+ {
68
+ entity: IEntityInfo<RowType, RowTypeInput>;
69
+ ctf: {
70
+ enabled: boolean;
71
+ fields: FieldRow[] | null;
72
+ categories: CategoryRow[] | null;
73
+ };
74
+ model: {
75
+ id: string | null;
76
+ row: RowType | null;
77
+ };
78
+ deleteFieldCache: () => void;
79
+ }
80
+
81
+ interface NSASectionViewTabPageState<RowType>
82
+ {
83
+ row: RowType | null;
84
+ }
85
+
86
+ export class NSASectionViewTabPage<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSASectionViewTabPageProps<RowType, RowTypeInput>, NSASectionViewTabPageState<RowType>>
87
+ {
88
+ NSTabPage_Ref = createRef<NSTabPage>();
89
+
90
+ constructor(props: NSASectionViewTabPageProps<RowType, RowTypeInput>)
91
+ {
92
+ super(props);
93
+
94
+ this.state = { row: this.props.model.row };
95
+
96
+ this.reload = this.reload.bind(this);
97
+ this.getRow = this.getRow.bind(this);
98
+ }
99
+ reload()
100
+ {
101
+ this.setState(prev => ({ ...prev, row: null }));
102
+ if (this.props.model.id)
103
+ if (this.props.entity.server.get)
104
+ this.props.entity.server.get(this.props.model.id).then(row =>
105
+ {
106
+ this.setState(prev => ({ ...prev, row }), () =>
107
+ {
108
+ this.props.onRowLoaded?.(row);
109
+ });
110
+ }).catch(() => { });
111
+ }
112
+ getRow()
113
+ {
114
+ return this.state.row;
115
+ }
116
+ override componentDidMount()
117
+ {
118
+ if (this.props.model.id)
119
+ if (!this.props.model.row || this.props.model.row.id !== this.props.model.id)
120
+ this.reload();
121
+ }
122
+ override render()
123
+ {
124
+ const tabs: NSTabPageTab[] = [];
125
+ let namirasoft = new NamirasoftMap(this.props.account.token_manager, this.props.notifier.onError);
126
+
127
+ let pushTabs = (ts?: NSASectionViewTabPageTabPageTab<RowType>[]) =>
128
+ {
129
+ if (ts)
130
+ for (let i = 0; i < ts.length; i++)
131
+ {
132
+ const tab = ts[i];
133
+ if (tab.isVisible(this.props.model))
134
+ tabs.push({
135
+ ...tab,
136
+ getContent: () =>
137
+ {
138
+ return tab.getContent(this.props.model);
139
+ }
140
+ });
141
+ }
142
+ };
143
+
144
+ pushTabs(this.props.ui?.tabs?.extra?.before_general);
145
+ if (this.props.ui?.tabs?.general?.enabled ?? true)
146
+ if (this.props.model.id)
147
+ if (this.props.entity.server.get)
148
+ {
149
+ let getColumns = (): TableColumnInfo[] =>
150
+ {
151
+ let columns: TableColumnInfo[] = [];
152
+ if (this.state.row)
153
+ if (this.props.ui?.tabs?.general?.getColumns)
154
+ columns = this.props.ui?.tabs?.general?.getColumns(this.state.row);
155
+ if (columns.length === 0)
156
+ columns = this.props.entity.client.getColumns();
157
+ return columns;
158
+ };
159
+ let getValue = (column: string): string =>
160
+ {
161
+ if (this.state.row)
162
+ if (this.props.ui?.tabs?.general?.getValue)
163
+ {
164
+ let ans = this.props.ui?.tabs?.general?.getValue(this.state.row, column);
165
+ if (ans !== undefined)
166
+ return ans;
167
+ }
168
+ return (this.state.row as any)[column];
169
+ };
170
+ let renderColumn = (column: TableColumnInfo, tab: string, index: number): ReactNode =>
171
+ {
172
+ let title = column.text;
173
+ if (title.startsWith(tab))
174
+ title = title.substring(tab.length + 1);
175
+
176
+ let value = getValue(column.name);
177
+ let formatted = column.formatter.format(value, column, { index: 0, value: this.state.row }, false);
178
+
179
+ return (
180
+ <NSLabel
181
+ key={`NSASectionViewTabPage_NSLabel_${tab}_${index}`}
182
+ title={title + ":"}
183
+ classList={[Styles.nsa_section_tab_page_item]}
184
+ >
185
+ <div>{formatted}</div>
186
+ </NSLabel>
187
+ );
188
+ }
189
+
190
+ let TAB_GENERAL = "General";
191
+ let columns = getColumns();
192
+ columns.filter(c => !c.group).forEach(c => { c.group = TAB_GENERAL });
193
+ let tab_names: string[] = columns.map(tab => tab.group) as string[];
194
+ tab_names = [...new Set(tab_names)];
195
+ tab_names = tab_names.filter(t => t !== TAB_GENERAL);
196
+ tab_names = [TAB_GENERAL, ...tab_names];
197
+
198
+ tab_names.forEach(tab =>
199
+ {
200
+ tabs.push({
201
+ title: tab,
202
+ clicked: false,
203
+ getContent: () =>
204
+ {
205
+ if (!this.state.row)
206
+ return <NSLoading />;
207
+
208
+ let tab_columns = columns.filter(c => c.group === tab);
209
+ let render_items = this.props.ui?.tabs?.general?.buildItems?.(this.state.row, tab, tab_columns);
210
+
211
+ if (!render_items)
212
+ return (
213
+ <div className={Styles.nsa_section_tab_page_parent}>
214
+ {tab_columns.map((col, index) => renderColumn(col, tab, index))}
215
+ </div>
216
+ )
217
+
218
+ return (
219
+ <div className={Styles.nsa_section_tab_page_parent}>
220
+ {
221
+ render_items.map((render_item, index) =>
222
+ {
223
+ if (render_item.type === "column")
224
+ return renderColumn(render_item.column, tab, index);
225
+
226
+ return (
227
+ <Fragment key={`NSASectionViewTabPage_Custom_${tab}_${index}`}>
228
+ {render_item.node}
229
+ </Fragment>
230
+ );
231
+ })
232
+ }
233
+ </div>
234
+ );
235
+ }
236
+ });
237
+ });
238
+ }
239
+ pushTabs(this.props.ui?.tabs?.extra?.after_general);
240
+
241
+ if (this.props.ui?.tabs?.history ?? true)
242
+ if (this.props.model.id)
243
+ tabs.push({
244
+ title: 'History',
245
+ clicked: false,
246
+ getContent: () =>
247
+ {
248
+ return <NSTable<HistoryRow>
249
+ name="History"
250
+ checkbox={false}
251
+ columns={[
252
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.id, new IDFormatter(namirasoft, null)),
253
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.user_id, new IDFormatter(namirasoft, new IStorageLocal())),
254
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.session_id, new IDFormatter(namirasoft, null)),
255
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.entity_name, new StringFormatter(StringFormatterSizeType.TwoWords, NamingConvention.Pascal_Case_Space)),
256
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.entity_id, new IDFormatter(namirasoft, new IStorageLocal())),
257
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.action, new StringFormatter(StringFormatterSizeType.Word)),
258
+ BaseColumnFormatter.getColumn(namirasoft.history.tables.history.columns.created_at, new DateTimeFormatter()),
259
+ ]}
260
+ getRows={async () =>
261
+ {
262
+ if (this.props.model.id)
263
+ {
264
+ let REACT_APP_BASE_URL_HISTORY = new EnvService("REACT_APP_BASE_URL_HISTORY", true).getString();
265
+ let server = new NamirasoftHistoryServer(REACT_APP_BASE_URL_HISTORY, this.props.account.token_manager, this.props.notifier.onError);
266
+ let filters = [new FilterItem(namirasoft.history.tables.history, namirasoft.history.tables.history.columns.entity_id, false, FilterItemOperator.all.equals, this.props.model.id)]
267
+ return await server.history.List(filters, null, null, []);
268
+ }
269
+ return { rows: [], count: 0 };
270
+ }}
271
+ getRowKey={row => row.value.id}
272
+ style={{ width: "100%" }}
273
+ ></NSTable>;
274
+ }
275
+ });
276
+ pushTabs(this.props.ui?.tabs?.extra?.after_history);
277
+
278
+ if (this.props.ui?.tabs?.field ?? true)
279
+ if (this.props.model.id)
280
+ if (this.props.ctf.enabled)
281
+ {
282
+ let groups = Array.from(new Set(this.props.ctf.fields?.map(x => x.group) ?? []));
283
+ groups.forEach(group =>
284
+ {
285
+ tabs.push({
286
+ title: group,
287
+ clicked: false,
288
+ getContent: () =>
289
+ {
290
+ if (this.state.row == null)
291
+ return <NSLoading></NSLoading>;
292
+ let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
293
+ if (ctf.fields.length === 0)
294
+ return <NSNoData
295
+ lable="No field found" />
296
+ return <div className={Styles.nsa_section_tab_page_parent}>
297
+ {
298
+ this.props.ctf.fields?.filter(x => x.group === group).map((field, index) =>
299
+ {
300
+ return <NSLabel
301
+ key={`NSASectionViewTabPage_NSLabel_Field_${index}`}
302
+ title={field.name + ":"}
303
+ classList={[Styles.nsa_section_tab_page_item]}
304
+ >
305
+ <div>{ctf.fields.filter(f => f.field_id === field.id).map(f => f.value).join(", ")}</div>
306
+ </NSLabel>
307
+ })
308
+ }
309
+ </div>;
310
+ }
311
+ });
312
+ });
313
+ }
314
+ pushTabs(this.props.ui?.tabs?.extra?.after_field);
315
+
316
+ if (this.props.ui?.tabs?.category ?? true)
317
+ if (this.props.model.id)
318
+ if (this.props.ctf.enabled)
319
+ {
320
+ let groups = Array.from(new Set(this.props.ctf.categories?.map(x => x.group) ?? []));
321
+ groups.forEach(group =>
322
+ {
323
+ tabs.push({
324
+ title: group,
325
+ clicked: false,
326
+ getContent: () =>
327
+ {
328
+ if (this.state.row == null)
329
+ return <NSLoading></NSLoading>;
330
+ let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
331
+ if (ctf.tags.length === 0)
332
+ return <NSNoData
333
+ lable="No category found" />
334
+ let ids = ctf.categories.map(c => c.category_id);
335
+ return <div className={Styles.nsa_section_tab_page_parent}>
336
+ {
337
+ this.props.ctf.categories?.filter(x => x.group === group && ids.includes(x.id)).map((category, index) =>
338
+ {
339
+ return <NSLabel
340
+ key={`NSASectionViewTabPage_NSLabel_Category_${index}`}
341
+ title={category.name}
342
+ classList={[Styles.nsa_section_tab_page_item]}
343
+ >
344
+ </NSLabel>
345
+ })
346
+ }
347
+ </div>;
348
+ }
349
+ });
350
+ });
351
+ }
352
+ pushTabs(this.props.ui?.tabs?.extra?.after_category);
353
+
354
+ if (this.props.ui?.tabs?.tag ?? true)
355
+ if (this.props.model.id)
356
+ if (this.props.ctf.enabled)
357
+ tabs.push({
358
+ title: 'Tag',
359
+ clicked: false,
360
+ getContent: () =>
361
+ {
362
+ if (this.state.row == null)
363
+ return <NSLoading></NSLoading>;
364
+ let ctf = CFTUtil.get(this.props.entity.name, this.state.row);
365
+ if (ctf.tags.length === 0)
366
+ return <NSNoData lable="No tag found" />
367
+ return <div className={Styles.nsa_section_tab_page_parent}>
368
+ {
369
+ ctf.tags?.map((tag, index) =>
370
+ {
371
+ return <NSLabel
372
+ key={`NSASectionViewTabPage_NSLabel_Tag_${index}`}
373
+ title={tag.name + ":"}
374
+ classList={[Styles.nsa_section_tab_page_item]}
375
+ >
376
+ <div>{tag.value}</div>
377
+ </NSLabel>
378
+ })
379
+ }
380
+ </div>;
381
+ }
382
+ });
383
+ pushTabs(this.props.ui?.tabs?.extra?.after_tag);
384
+ //todo
385
+ // tabs.push({title: 'Log', getContent: todo });
386
+ // tabs.push({title: 'Monitor', getContent: todo });
387
+
388
+ if (this.props.ui?.tabs?.more ?? true)
389
+ if (this.props.model.id)
390
+ if (this.props.entity.server.get)
391
+ if (this.props.ctf.enabled)
392
+ tabs.push({
393
+ title: "More",
394
+ clicked: true,
395
+ getContent: () => <NSASectionViewTabMore
396
+ deleteFieldCache={this.props.deleteFieldCache}
397
+ />
398
+ });
399
+ pushTabs(this.props.ui?.tabs?.extra?.after_more);
400
+
401
+ //todo
402
+ // tabs.push({title: 'How It Works', getContent: todo });
403
+ // tabs.push({title: 'API', getContent: todo });
404
+ // tabs.push({title: 'Sample Code', getContent: todo });
405
+ //todo
406
+ // tabs.push({title: 'Category', getContent: todo });
407
+ // tabs.push({title: 'Field', getContent: todo });
408
+
409
+ if (!(this.props.ui?.enabled ?? true))
410
+ return <></>;
411
+ return (
412
+ <>
413
+ {
414
+ tabs.length > 0 &&
415
+ <NSTabPage ref={this.NSTabPage_Ref} tabs={tabs} />
416
+ }
417
+ </>
418
+ );
419
+ }
420
420
  }