namirasoft-account-react 1.5.4 → 1.5.6

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