namirasoft-account-react 1.5.21 → 1.5.23

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/SKILL.md +514 -514
  3. package/config-overrides.js +72 -72
  4. package/dist/App.d.ts +1 -1
  5. package/dist/Router.d.ts +1 -1
  6. package/dist/UseParams.d.ts +1 -1
  7. package/dist/components/NSAAccessListDialog.d.ts +2 -2
  8. package/dist/components/NSAAccessListDialog.module.css +71 -71
  9. package/dist/components/NSABoxSecret.d.ts +1 -1
  10. package/dist/components/NSABoxSecret.module.css +23 -23
  11. package/dist/components/NSAMasterMenu.d.ts +1 -1
  12. package/dist/components/NSAMasterMenu.module.css +250 -250
  13. package/dist/components/NSAMasterMenuItem.d.ts +1 -1
  14. package/dist/components/NSAMessageListDialog.d.ts +1 -1
  15. package/dist/components/NSAMessageListDialog.module.css +99 -99
  16. package/dist/components/NSANavigationGuard.d.ts +1 -1
  17. package/dist/components/NSAProductListDialog.d.ts +1 -1
  18. package/dist/components/NSAProductListDialog.module.css +44 -44
  19. package/dist/components/NSATaskBar.d.ts +1 -1
  20. package/dist/components/NSATaskBar.module.css +57 -57
  21. package/dist/components/NSAUserDialog.d.ts +1 -1
  22. package/dist/components/NSAUserDialog.module.css +67 -67
  23. package/dist/components/NSAWorkspaceListDialog.d.ts +1 -1
  24. package/dist/components/NSAWorkspaceListDialog.module.css +41 -41
  25. package/dist/components/NSFBoxCategoryScope.d.ts +1 -1
  26. package/dist/components/NSFBoxField.d.ts +1 -1
  27. package/dist/components/NSFBoxSlot.d.ts +1 -1
  28. package/dist/components/NSFBoxWrapper.d.ts +1 -1
  29. package/dist/components/NSLabelSecret.d.ts +1 -1
  30. package/dist/components/quickfilter/NSAFilterBoxEnum.module.css +44 -44
  31. package/dist/components/quickfilter/NSAQuickFilterBar.d.ts +1 -1
  32. package/dist/components/quickfilter/NSAQuickFilterBar.module.css +19 -19
  33. package/dist/components/quickfilter/NSAQuickFilterDialog.d.ts +1 -1
  34. package/dist/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  35. package/dist/layouts/NSALayout.d.ts +1 -1
  36. package/dist/layouts/NSASectionEdit.d.ts +1 -1
  37. package/dist/layouts/NSASectionEditTabPage.d.ts +1 -1
  38. package/dist/layouts/NSASectionEditTabPage.module.css +4 -4
  39. package/dist/layouts/NSASectionList.d.ts +3 -1
  40. package/dist/layouts/NSASectionList.js +14 -6
  41. package/dist/layouts/NSASectionList.js.map +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.js +1 -0
  47. package/dist/layouts/NSASectionViewTabPage.js.map +1 -1
  48. package/dist/layouts/NSASectionViewTabPage.module.css +47 -47
  49. package/dist/pages/NSAConsentPage.module.css +26 -26
  50. package/dist/pages/NSAEmailVerificationPage.d.ts +1 -1
  51. package/dist/pages/NSAHomePage.d.ts +1 -1
  52. package/dist/pages/NSAHomePage.module.css +41 -41
  53. package/dist/pages/NSALoginPage.d.ts +1 -1
  54. package/dist/pages/NSALoginPage.module.css +26 -26
  55. package/dist/pages/NSAPhoneVerificationPage.d.ts +1 -1
  56. package/dist/pages/NSAVerificationPage.d.ts +1 -1
  57. package/dist/pages/NSAVerificationPage.module.css +31 -31
  58. package/package.json +95 -95
  59. package/public/index.html +21 -21
  60. package/src/App.tsx +19 -19
  61. package/src/CTFRow.ts +7 -7
  62. package/src/FieldCacheService.tsx +84 -84
  63. package/src/IEntityInfo.ts +33 -33
  64. package/src/NSACacheService.ts +120 -120
  65. package/src/NSAFilterOperators.ts +92 -92
  66. package/src/NSARouterMaker.tsx +140 -140
  67. package/src/NSARouterMakerProps.ts +23 -23
  68. package/src/NSARouterMakerResult.ts +24 -24
  69. package/src/NSFRouterMaker.tsx +35 -35
  70. package/src/NSFRouterProps.ts +7 -7
  71. package/src/NSFRoutes.ts +30 -30
  72. package/src/Router.tsx +48 -48
  73. package/src/UseParams.tsx +17 -17
  74. package/src/components/NSAAccessListDialog.module.css +71 -71
  75. package/src/components/NSAAccessListDialog.tsx +178 -178
  76. package/src/components/NSABoxSecret.module.css +23 -23
  77. package/src/components/NSABoxSecret.tsx +264 -264
  78. package/src/components/NSAMasterMenu.module.css +250 -250
  79. package/src/components/NSAMasterMenu.tsx +169 -169
  80. package/src/components/NSAMasterMenuItem.tsx +250 -250
  81. package/src/components/NSAMessageListDialog.module.css +99 -99
  82. package/src/components/NSAMessageListDialog.tsx +142 -142
  83. package/src/components/NSANavigationGuard.tsx +79 -79
  84. package/src/components/NSAProductListDialog.module.css +44 -44
  85. package/src/components/NSAProductListDialog.tsx +88 -88
  86. package/src/components/NSATable.tsx +494 -494
  87. package/src/components/NSATaskBar.module.css +57 -57
  88. package/src/components/NSATaskBar.tsx +193 -193
  89. package/src/components/NSAUserDialog.module.css +67 -67
  90. package/src/components/NSAUserDialog.tsx +122 -122
  91. package/src/components/NSAWorkspaceListDialog.module.css +41 -41
  92. package/src/components/NSAWorkspaceListDialog.tsx +147 -147
  93. package/src/components/NSFBoxCategoryScope.tsx +52 -52
  94. package/src/components/NSFBoxField.tsx +37 -37
  95. package/src/components/NSFBoxSlot.tsx +71 -71
  96. package/src/components/NSFBoxWrapper.tsx +69 -69
  97. package/src/components/NSLabelSecret.tsx +37 -37
  98. package/src/components/quickfilter/NSAFilterBoxBase.tsx +89 -89
  99. package/src/components/quickfilter/NSAFilterBoxBoolean.tsx +66 -66
  100. package/src/components/quickfilter/NSAFilterBoxDate.tsx +110 -110
  101. package/src/components/quickfilter/NSAFilterBoxDateTime.tsx +110 -110
  102. package/src/components/quickfilter/NSAFilterBoxEnum.module.css +44 -44
  103. package/src/components/quickfilter/NSAFilterBoxEnum.tsx +79 -79
  104. package/src/components/quickfilter/NSAFilterBoxNumber.tsx +145 -145
  105. package/src/components/quickfilter/NSAFilterBoxString.tsx +83 -83
  106. package/src/components/quickfilter/NSAFilterBoxTime.tsx +106 -106
  107. package/src/components/quickfilter/NSAQuickFilterBar.module.css +19 -19
  108. package/src/components/quickfilter/NSAQuickFilterBar.tsx +142 -142
  109. package/src/components/quickfilter/NSAQuickFilterDialog.module.css +74 -74
  110. package/src/components/quickfilter/NSAQuickFilterDialog.tsx +260 -260
  111. package/src/css.d.ts +13 -13
  112. package/src/formatters/SecretFormatter.tsx +24 -24
  113. package/src/index.tsx +26 -26
  114. package/src/layouts/Actions.ts +146 -146
  115. package/src/layouts/CFTUtil.ts +18 -18
  116. package/src/layouts/NSALayout.tsx +744 -744
  117. package/src/layouts/NSALayout_Field.ts +125 -125
  118. package/src/layouts/NSASectionEdit.tsx +281 -281
  119. package/src/layouts/NSASectionEditTabPage.module.css +4 -4
  120. package/src/layouts/NSASectionEditTabPage.tsx +256 -256
  121. package/src/layouts/NSASectionList.module.css +31 -31
  122. package/src/layouts/NSASectionList.tsx +166 -147
  123. package/src/layouts/NSASectionView.tsx +98 -98
  124. package/src/layouts/NSASectionViewTabMore.tsx +78 -78
  125. package/src/layouts/NSASectionViewTabPage.module.css +47 -47
  126. package/src/layouts/NSASectionViewTabPage.tsx +400 -399
  127. package/src/main.ts +52 -52
  128. package/src/pages/NSAConsentPage.module.css +26 -26
  129. package/src/pages/NSAConsentPage.tsx +120 -120
  130. package/src/pages/NSAEmailVerificationPage.tsx +30 -30
  131. package/src/pages/NSAHomePage.module.css +41 -41
  132. package/src/pages/NSAHomePage.tsx +124 -124
  133. package/src/pages/NSALoginPage.module.css +26 -26
  134. package/src/pages/NSALoginPage.tsx +87 -87
  135. package/src/pages/NSAPhoneVerificationPage.tsx +94 -94
  136. package/src/pages/NSAVerificationPage.module.css +31 -31
  137. package/src/pages/NSAVerificationPage.tsx +185 -185
  138. package/src/pages/NSFCategoryEditPage.tsx +87 -87
  139. package/src/pages/NSFCategoryListPage.tsx +23 -23
  140. package/src/pages/NSFCategoryViewPage.tsx +23 -23
  141. package/src/pages/NSFEntities.ts +58 -58
  142. package/src/pages/PaymentRequired.tsx +80 -80
  143. package/tsconfig.json +43 -43
@@ -1,745 +1,745 @@
1
- import { NamirasoftAccountClient } from 'namirasoft-account-client';
2
- import { ProductFullRow } from 'namirasoft-api-product';
3
- import { CacheService, EnvService, IStorageLocal, NamingConvention } from 'namirasoft-core';
4
- import { NamirasoftMessageServer } from 'namirasoft-message';
5
- import { NamirasoftMap } from 'namirasoft-site-map';
6
- import { IBackgroundProps, IBaseComponentProps, IHeaderIconProps, IHeaderRightProps, NSBarActionProps, NSBarAlertProps, NSBarTitleProps, NSDialogDelete, NSLayout, NSLoading, ProductCacheService } from 'namirasoft-site-react';
7
- import { IHeaderLeftProps } from 'namirasoft-site-react/dist/props/IHeaderLeftProps';
8
- import { Component, createRef, ReactElement } from 'react';
9
- import { Helmet } from 'react-helmet';
10
- import { NSAAccessListDialog } from '../components/NSAAccessListDialog';
11
- import NSAMasterMenu from '../components/NSAMasterMenu';
12
- import { NSAMessageListDialog } from '../components/NSAMessageListDialog';
13
- import { NSAProductListDialog } from '../components/NSAProductListDialog';
14
- import { NSATaskBar } from '../components/NSATaskBar';
15
- import { NSAUserDialog } from '../components/NSAUserDialog';
16
- import { NSAWorkspaceListDialog } from '../components/NSAWorkspaceListDialog';
17
- import { FieldCacheService } from '../FieldCacheService';
18
- import { IEntityInfo } from '../IEntityInfo';
19
- import { NSACacheService } from '../NSACacheService';
20
- import { NSARouterMakerResult } from '../NSARouterMakerResult';
21
- import { UseParams } from '../UseParams';
22
- import { Actions } from './Actions';
23
- import { NSALayout_Field } from './NSALayout_Field';
24
- import { NSASectionEdit, NSASectionEditCustomProps } from './NSASectionEdit';
25
- import { NSASectionList, NSASectionListCustomProps } from './NSASectionList';
26
- import { NSASectionView, NSASectionViewCutomProps } from './NSASectionView';
27
-
28
- let REACT_APP_BASE_URL_ACCOUNT_CONSOLE = new EnvService("REACT_APP_BASE_URL_ACCOUNT_CONSOLE").getString();
29
- let client = new NamirasoftAccountClient(REACT_APP_BASE_URL_ACCOUNT_CONSOLE);
30
- client.onLoggedin = () => { window.location.reload(); };
31
- client.onLoggedout = () => { window.location.reload(); };
32
-
33
- export interface NSALayoutPagesProps<RowType extends { id: string }, RowTypeInput = RowType>
34
- {
35
- entity: IEntityInfo<RowType, RowTypeInput>;
36
- ui?: {
37
- action?: {
38
- menus: {
39
- _new?: boolean;
40
- list?: boolean;
41
- view?: boolean;
42
- view_history?: boolean;
43
- copy?: boolean;
44
- edit?: boolean;
45
- delete?: boolean;
46
- apply?: boolean;
47
- };
48
- children?: JSX.Element | JSX.Element[];
49
- };
50
- }
51
- list?: NSASectionListCustomProps<RowType, RowTypeInput>;
52
- edit?: NSASectionEditCustomProps<RowType, RowTypeInput> & {
53
- ui: {
54
- action?: {
55
- menus: {
56
- apply?: boolean,
57
- }
58
- },
59
- }
60
- };
61
- view?: NSASectionViewCutomProps<RowType>;
62
- }
63
- export interface NSALayoutCustomProps<RowType extends { id: string }, RowTypeInput = RowType> extends IBaseComponentProps, NSARouterMakerResult
64
- {
65
- action?: NSBarActionProps;
66
- title?: NSBarTitleProps;
67
- alerts?: NSBarAlertProps[];
68
- pages?: NSALayoutPagesProps<RowType, RowTypeInput>;
69
- children: ReactElement;
70
- onEnterPressed?: () => void;
71
- onDidMounted?: () => void;
72
- }
73
- export interface NSALayoutProps<RowType extends { id: string }, RowTypeInput = RowType> extends NSALayoutCustomProps<RowType, RowTypeInput>
74
- {
75
- model?: {
76
- id: string | null;
77
- }
78
- scope?: string;
79
- logo?: string;
80
- master_menu?: boolean;
81
- background?: IBackgroundProps;
82
- header?: {
83
- enabled?: boolean,
84
- right?: IHeaderRightProps;
85
- left?: IHeaderLeftProps;
86
- built_in?: {
87
- logout?: boolean;
88
- message?: boolean;
89
- access?: boolean;
90
- workspace?: boolean;
91
- product?: boolean;
92
- user?: boolean;
93
- };
94
- mega_menu?: boolean;
95
- };
96
- }
97
-
98
- interface NSALayoutState
99
- {
100
- parmas: any | null;
101
- product: ProductFullRow | null;
102
- refresher: number;
103
- message_count: number;
104
- showDeleteDialog: boolean;
105
- delete_ids: string[];
106
- delete_title: string;
107
- showMessageListDialog: boolean;
108
- showAccessListDialog: boolean;
109
- showProductListDialog: boolean;
110
- showWorkspaceListDialog: boolean;
111
- showUserDialog: boolean;
112
- showMasterMenu: boolean;
113
- }
114
-
115
- export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSALayoutProps<RowType, RowTypeInput>, NSALayoutState>
116
- {
117
- private onDidMounted_Called: boolean = false;
118
- private onDidMounted_Ready: boolean = false;
119
- private hasCFT: boolean;
120
- private isLoggedIn: boolean;
121
- private cache_product: CacheService<ProductFullRow>;
122
- private cache_message: CacheService<number>;
123
- private cache_master_menu: CacheService<{ open: boolean }>;
124
- NSASectionList_Ref = createRef<NSASectionList<RowType, RowTypeInput>>();
125
- NSASectionEdit_Ref = createRef<NSASectionEdit<RowType, RowTypeInput>>();
126
- NSASectionView_Ref = createRef<NSASectionView<RowType, RowTypeInput>>();
127
- NSATaskBar_Ref = createRef<NSATaskBar<string>>();
128
-
129
- constructor(props: NSALayoutProps<RowType, RowTypeInput>)
130
- {
131
- super(props);
132
-
133
- // Account
134
- this.isLoggedIn = this.props.account?.token_manager?.exists() ?? false;
135
-
136
- // CFT
137
- this.hasCFT = false;
138
- if (this.props.pages?.entity)
139
- try
140
- {
141
- let namirasoft = new NamirasoftMap(this.props.account.token_manager, props.notifier.onError);
142
- let table = namirasoft.getByProductID(this.props.product_id).tables[this.props.pages.entity.name];
143
- this.hasCFT = table.hasFieldTables();
144
- } catch (error)
145
- { }
146
-
147
- // Cache Product
148
- this.cache_product = ProductCacheService.get(this.props.product_id, console.error);
149
-
150
- // Cache Message
151
- this.cache_message = new CacheService<number>("ns-messsage-count", new IStorageLocal(), 15, async () => "1.0.0", async () =>
152
- {
153
- let REACT_APP_BASE_URL_MESSAGE = new EnvService("REACT_APP_BASE_URL_MESSAGE", true).getString();
154
- let server = new NamirasoftMessageServer(REACT_APP_BASE_URL_MESSAGE, this.props.account.token_manager, console.error);
155
- let res = await server.message.GetNewCount();
156
- return res.count;
157
- });
158
-
159
- this.cache_master_menu = NSACacheService.getMasterMenuStatus();
160
- this.cache_message.onExpired = () => { this.reloadMessageCount(true); };
161
-
162
- // State
163
- this.state = {
164
- parmas: null,
165
- product: null,
166
- refresher: 0,
167
- message_count: 0,
168
- showDeleteDialog: false,
169
- delete_ids: [],
170
- delete_title: "",
171
- showMessageListDialog: false,
172
- showAccessListDialog: false,
173
- showProductListDialog: false,
174
- showWorkspaceListDialog: false,
175
- showUserDialog: false,
176
- showMasterMenu: false,
177
- };
178
- }
179
- public reloadMessageCount(force: boolean)
180
- {
181
- if (force)
182
- this.cache_message.del();
183
- this.cache_message.get().then(count =>
184
- {
185
- this.setState(prev => ({ ...prev, message_count: count }));
186
- }).catch(() => { });
187
- }
188
-
189
- private async runDelete(ids: string[], name: string): Promise<void>
190
- {
191
- if (!this.props.pages?.entity.server.delete)
192
- return;
193
-
194
- await new Promise<void>(resolve => this.setState(prev => ({ ...prev, delete_ids: ids, delete_title: `Deleting ${name}` }), resolve));
195
-
196
- const result = await this.NSATaskBar_Ref.current?.run();
197
- if (!result)
198
- return;
199
-
200
- const deletedIds = result.succeeded;
201
-
202
- if (deletedIds.length === 0)
203
- return;
204
-
205
- if (this.props.pages?.list)
206
- {
207
- let table = this.NSASectionList_Ref.current?.NSATable_Main.current;
208
- if (table)
209
- {
210
- let selected_ids = table.getSelectedIDs().filter(id => !deletedIds.includes(id));
211
- let selected_rows = table.getSelectedRows().filter(row => !deletedIds.includes(row.id));
212
- table.setSelectedIDs(selected_ids, selected_rows);
213
- table.reload(null, null);
214
- }
215
- }
216
- else if (this.props.pages?.edit)
217
- {
218
- if (this.props.pages.entity.client.getListURL)
219
- this.props.url.redirect(this.props.pages.entity.client.getListURL(), {});
220
- else if (this.props.pages.entity.client.getViewURL)
221
- this.props.url.redirect(this.props.pages.entity.client.getViewURL(deletedIds[0]), {});
222
- }
223
- else if (this.props.pages?.view)
224
- {
225
- if (this.props.pages.entity.client.getListURL)
226
- this.props.url.redirect(this.props.pages.entity.client.getListURL(), {});
227
- }
228
- }
229
-
230
- override componentDidMount(): void
231
- {
232
- this.onDidMounted_Called = false;
233
- this.cache_product.get().then(product =>
234
- {
235
- this.setState(prev => ({ ...prev, product }));
236
- })
237
-
238
- this.cache_master_menu.get().then(status =>
239
- {
240
- this.setState(() => ({ showMasterMenu: status.open }));
241
- })
242
-
243
- if (this.isLoggedIn)
244
- this.reloadMessageCount(false);
245
-
246
- client.start();
247
- }
248
- override componentDidUpdate(): void
249
- {
250
- if (!this.onDidMounted_Called)
251
- if (this.onDidMounted_Ready)
252
- {
253
- this.props.onDidMounted?.();
254
- this.onDidMounted_Called = true;
255
- }
256
- }
257
- override componentWillUnmount(): void
258
- {
259
- client.stop();
260
- }
261
- override render()
262
- {
263
- this.onDidMounted_Ready = false;
264
- let id = this.props.model?.id ?? null;
265
- if (!id)
266
- {
267
- if (this.state.parmas === null)
268
- return <UseParams onLoaded={parmas =>
269
- {
270
- this.setState({ parmas });
271
- }} />;
272
- id = this.state.parmas.id;
273
- }
274
-
275
- const hideDeleteDialog = async () => { this.setState(prev => ({ ...prev, showDeleteDialog: false })); };
276
- const showDeleteDialog = async () => { this.setState(prev => ({ ...prev, showDeleteDialog: true })); };
277
-
278
- let icons: IHeaderIconProps[] = [];
279
-
280
- if (this.isLoggedIn)
281
- {
282
- if (this.props.header?.built_in?.message ?? true)
283
- icons.push({
284
- src: "https://static.namirasoft.com/image/namirasoft/message/logo/base.png", alt: "Message", onClicked: () =>
285
- {
286
- this.setState(prev => ({ ...prev, showMessageListDialog: true }));
287
- this.reloadMessageCount(true);
288
- },
289
- children: <>
290
- {
291
- (
292
- this.state.showMessageListDialog &&
293
- <NSAMessageListDialog {...this.props}
294
- onClose={() => { this.setState(prev => ({ ...prev, showMessageListDialog: false })); }}
295
- onSeenAll={() =>
296
- {
297
- this.reloadMessageCount(true);
298
- }}
299
- onMessageClick={() =>
300
- {
301
- this.reloadMessageCount(true);
302
- }}
303
- />
304
- )
305
- }
306
- </>,
307
- count: this.state.message_count,
308
- tooltip: "Message"
309
- });
310
- }
311
- if (this.isLoggedIn)
312
- if (this.props.header?.built_in?.access ?? true)
313
- icons.push({
314
- src: "https://static.namirasoft.com/image/namirasoft/access/logo/base.png", alt: "Access", onClicked: () =>
315
- {
316
- this.setState(prev => ({ ...prev, showAccessListDialog: true }));
317
- },
318
- children: <>
319
- {
320
- (this.state.showAccessListDialog) && <NSAAccessListDialog {...this.props} onClose={() =>
321
- {
322
- this.setState(prev => ({ ...prev, showAccessListDialog: false }));
323
- }} />
324
- }
325
- </>,
326
- tooltip: "Access"
327
- });
328
- if (this.isLoggedIn)
329
- if (this.props.header?.built_in?.workspace ?? true)
330
- icons.push({
331
- src: "https://static.namirasoft.com/image/namirasoft/workspace/logo/base.png", alt: "Workspace", onClicked: () =>
332
- {
333
- this.setState(prev => ({ ...prev, showWorkspaceListDialog: true }));
334
- },
335
- children: <>
336
- {
337
- (this.state.showWorkspaceListDialog) && <NSAWorkspaceListDialog {...this.props} onClose={() =>
338
- {
339
- this.setState(prev => ({ ...prev, showWorkspaceListDialog: false }));
340
- }} />
341
- }
342
- </>,
343
- tooltip: "Workspace List"
344
- });
345
- if (this.props.header?.built_in?.product ?? true)
346
- icons.push({
347
- src: "https://static.namirasoft.com/image/concept/product-list/white.svg", alt: "Product", onClicked: () =>
348
- {
349
- this.setState(prev => ({ ...prev, showProductListDialog: true }));
350
- },
351
- children: <>
352
- {
353
- (this.state.showProductListDialog) && <NSAProductListDialog {...this.props} onClose={() =>
354
- {
355
- this.setState(prev => ({ ...prev, showProductListDialog: false }));
356
- }} >
357
- <></>
358
- </NSAProductListDialog>
359
- }
360
- </>,
361
- tooltip: "Product List"
362
- });
363
-
364
- if (this.isLoggedIn)
365
- if (this.props.header?.built_in?.user ?? true)
366
- icons.push({
367
- src: "https://static.namirasoft.com/image/concept/user/white.svg",
368
- alt: "User",
369
- onClicked: () =>
370
- {
371
- this.setState(prev => ({ ...prev, showUserDialog: true }));
372
- },
373
- children: <>
374
- {
375
- (this.state.showUserDialog) &&
376
- <NSAUserDialog
377
- {...this.props}
378
- client={client}
379
- onClose={() => this.setState(prev => ({ ...prev, showUserDialog: false }))}
380
- >
381
- <></>
382
- </NSAUserDialog>
383
- }
384
- </>,
385
- tooltip: "User"
386
- });
387
-
388
- let name = "";
389
- if (this.props.pages)
390
- name = NamingConvention.lower_case_underscore.convert(this.props.pages.entity.name, NamingConvention.Pascal_Case_Space);
391
-
392
- let getIDs: (() => string[]) | null = null;
393
- let getRows: (() => RowType[]) | null = null;
394
- if (this.props.pages?.list)
395
- {
396
- getIDs = () => { return this.NSASectionList_Ref.current?.getSelectedIDs() ?? []; };
397
- getRows = () => { return this.NSASectionList_Ref.current?.getSelectedRows() ?? []; };
398
- }
399
- if (this.props.pages?.edit)
400
- {
401
- getIDs = () => [id].filter(id => id) as string[];
402
- getRows = () => [this.NSASectionEdit_Ref.current?.getRow()].filter(row => row) as RowType[];
403
- }
404
- if (this.props.pages?.view)
405
- {
406
- getIDs = () => [id].filter(id => id) as string[];
407
- getRows = () => [this.NSASectionView_Ref.current?.getRow()].filter(row => row) as RowType[];
408
- }
409
-
410
- let action: NSBarActionProps | undefined = { title: "", description: "", menus: {} };
411
- if (this.props.action?.title)
412
- action.title = this.props.action.title;
413
- if (this.props.action?.description)
414
- action.description = this.props.action.description;
415
- if (this.props.action?.menus != null)
416
- action.menus = { ...this.props.action?.menus };
417
-
418
- if (getIDs && getRows)
419
- if (this.props.pages?.entity.client.getMenus)
420
- {
421
- let menus = this.props.pages?.entity.client.getMenus(getIDs, getRows);
422
- for (let key of Object.keys(menus))
423
- {
424
- if (!action.menus)
425
- action.menus = {};
426
- if (!action.menus[key])
427
- action.menus[key] = [];
428
- action.menus[key].push(...menus[key]);
429
- }
430
- }
431
-
432
- let name_apply = "Apply";
433
- let name_actions = "Actions";
434
- if (!action.menus)
435
- action.menus = {};
436
- action.menus[name_apply] = [];
437
- action.menus[name_actions] = [];
438
-
439
- if (this.props.pages?.edit)
440
- {
441
- if (!action.title)
442
- action.title = (this.props.pages.edit.isEdit ? "Edit" : "New") + " " + name;
443
-
444
- // Menu
445
- if (this.props.pages.edit.ui.action?.menus.apply ?? true)
446
- action.menus[name_apply].push(Actions.apply({
447
- action: (onFinished) =>
448
- {
449
- if (this.props.pages?.edit)
450
- this.NSASectionEdit_Ref.current?.onApply(onFinished);
451
- }
452
- }));
453
- }
454
- else if (this.props.pages)
455
- {
456
- if (this.props.pages.entity.client.getNewURL)
457
- if (this.props.pages.entity.server.create)
458
- if (this.props.pages.ui?.action?.menus._new ?? true)
459
- action.menus[name_apply].push(Actions._new(this.props, this.props.pages.entity));
460
- }
461
-
462
- if (getIDs)
463
- if (this.props.pages)
464
- {
465
- if (this.props.pages.entity.client.getListURL)
466
- if (this.props.pages.entity.server.list)
467
- if (this.props.pages.ui?.action?.menus.list ?? true)
468
- action.menus[name_actions].push(Actions.list(this.props, this.props.pages.entity));
469
-
470
- if (this.props.pages.entity.client.getViewURL)
471
- if (this.props.pages.entity.server.get)
472
- if (this.props.pages.ui?.action?.menus.view ?? true)
473
- action.menus[name_actions].push(Actions.view(this.props, this.props.pages.entity, getIDs));
474
-
475
- if (this.props.pages.ui?.action?.menus.view_history ?? true)
476
- action.menus[name_actions].push(Actions.viewHistory(getIDs));
477
-
478
- if (this.props.pages.entity.client.getCopyURL)
479
- if (this.props.pages.entity.server.create)
480
- if (this.props.pages.ui?.action?.menus.copy ?? true)
481
- action.menus[name_actions].push(Actions.copy(this.props, this.props.pages.entity, getIDs));
482
-
483
- if (this.props.pages.entity.client.getEditURL)
484
- if (this.props.pages.entity.server.update)
485
- if (this.props.pages.ui?.action?.menus.edit ?? true)
486
- action.menus[name_actions].push(Actions.edit(this.props, this.props.pages.entity, getIDs));
487
-
488
- if (this.props.pages.entity.server.delete)
489
- if (this.props.pages.ui?.action?.menus.delete ?? true)
490
- action.menus[name_actions].push(Actions.delete(getIDs, {
491
- action: showDeleteDialog,
492
- showLoading: false
493
- }));
494
- }
495
-
496
- let action_name = "";
497
- let content;
498
- if (this.props.pages?.list)
499
- {
500
- action_name = "List";
501
- content = <FieldCacheService
502
- {...this.props}
503
- render={rows =>
504
- {
505
- if (this.props.pages?.list)
506
- return <NSASectionList<RowType, RowTypeInput>
507
- ref={this.NSASectionList_Ref}
508
- {...this.props}
509
- {...this.props.pages.list}
510
- entity={this.props.pages.entity}
511
- onIDsChanged={() =>
512
- {
513
- this.setState(prev => ({ ...prev }));
514
- this.props.pages?.list?.onIDsChanged?.();
515
- }}
516
- ctf={{
517
- enabled: this.hasCFT,
518
- rows
519
- }}
520
- >
521
- {this.props.children}
522
- </NSASectionList>;
523
- return <></>;
524
- }}
525
- />;
526
- }
527
- else if (this.props.pages?.edit)
528
- {
529
- if (this.props.pages.edit.isEdit)
530
- action_name = "Edit";
531
- else
532
- action_name = "New";
533
- content = <FieldCacheService
534
- {...this.props}
535
- render={rows =>
536
- {
537
- if (this.props.pages?.edit)
538
- return <NSASectionEdit
539
- ref={this.NSASectionEdit_Ref}
540
- {...this.props}
541
- {...this.props.pages.edit}
542
- entity={this.props.pages.entity}
543
- ctf={{
544
- enabled: this.hasCFT,
545
- rows
546
- }}
547
- onRowLoaded={(row) =>
548
- {
549
- this.setState(prev => ({ ...prev }), () =>
550
- {
551
- this.props.pages?.edit?.onRowLoaded?.(row);
552
- });
553
- }}
554
- model={{
555
- id,
556
- row: null
557
- }}
558
- >
559
- {this.props.children}
560
- </NSASectionEdit>;
561
- return <></>;
562
- }}
563
- />;
564
- }
565
- else if (this.props.pages?.view)
566
- {
567
- action_name = "View";
568
-
569
- content = <FieldCacheService
570
- {...this.props}
571
- render={rows =>
572
- {
573
- if (this.props.pages?.view)
574
- return <NSASectionView
575
- ref={this.NSASectionView_Ref}
576
- {...this.props}
577
- {...this.props.pages.view}
578
- entity={this.props.pages.entity}
579
- ctf={{
580
- enabled: this.hasCFT,
581
- rows
582
- }}
583
- onRowLoaded={(row) =>
584
- {
585
- this.setState(prev => ({ ...prev }), () =>
586
- {
587
- this.props.pages?.view?.onRowLoaded?.(row);
588
- });
589
- }}
590
- model={{
591
- id,
592
- row: null
593
- }}
594
- >
595
- {this.props.children}
596
- </NSASectionView>;
597
- return <></>;
598
- }}
599
- />;
600
- }
601
- else
602
- content = this.props.children;
603
-
604
- let fullname = "";
605
- if (this.props.pages?.entity.name)
606
- {
607
- let Name_Pascal_Space = NamingConvention.lower_case_underscore.convert(this.props.pages.entity.name, NamingConvention.Pascal_Case_Space);
608
- if (action_name === "List")
609
- fullname = Name_Pascal_Space + " " + action_name;
610
- else
611
- fullname = action_name + " " + Name_Pascal_Space;
612
- }
613
-
614
- if (!this.state.product)
615
- return <NSLoading />;
616
-
617
- let action_title = action?.title ?? "";
618
- if (!action_title)
619
- action_title = fullname;
620
- if (!action_title)
621
- action_title = this.state.product?.name
622
-
623
- let action_description = action?.description ?? "";
624
- if (!action_description)
625
- action_description = this.state.product?.description ?? "";
626
-
627
- let scope = this.props.scope ?? `${this.state.product.name} Console`;
628
- let logo = this.props.logo ?? this.state.product.logo ?? "";
629
- let background = this.props.background?.image ?? this.state.product.background ?? "";
630
-
631
- this.onDidMounted_Ready = true;
632
-
633
- let user_id = this.props.account.token_manager.getUserData(x => x.id, "");
634
- let user_first_name = this.props.account.token_manager.getUserData(x => x.first_name, "");
635
- let user_last_name = this.props.account.token_manager.getUserData(x => x.last_name, "");
636
- let user_email = this.props.account.token_manager.getUserData(x => x.email, "");
637
- let user_phone = this.props.account.token_manager.getUserData(x => x.phone ?? "", "");
638
- return (
639
- <div className="d-flex">
640
- {
641
- (this.props.master_menu ?? true) &&
642
- <NSAMasterMenu
643
- {...this.props}
644
- open={this.state.showMasterMenu}
645
- setOpen={(open) =>
646
- {
647
- this.cache_master_menu.set({ open });
648
- this.setState(() => ({ showMasterMenu: open }));
649
- }}
650
- />
651
- }
652
- <FieldCacheService
653
- {...this.props}
654
- render={(ctf_rows) => (
655
- <NSLayout
656
- {...this.props}
657
- scope={scope}
658
- logo={logo}
659
- background={{ image: background, attachment: this.props.background?.attachment, size: this.props.background?.size }}
660
- header={{
661
- enabled: this.props.header?.enabled,
662
- right: {
663
- icons: [...icons, ...(this.props.header?.right?.icons ?? [])],
664
- },
665
- left: {
666
- title: this.props.header?.left?.title
667
- },
668
- mega_menu: this.props.header?.mega_menu,
669
- onCollapse: () =>
670
- {
671
- this.setState((prev) => ({ showMasterMenu: !prev.showMasterMenu }))
672
- },
673
- filters_postprocessor: (filters) => NSALayout_Field.postprocess(filters, ctf_rows),
674
- }}
675
- action={{
676
- title: action_title,
677
- description: action_description,
678
- menus: action.menus,
679
- children: this.props.action?.children
680
- }}
681
- isLoggedIn={this.props.account?.token_manager?.exists}
682
- notifications={this.props.notifier.getNotifications()}
683
- >
684
- <Helmet>
685
- <meta name="ns-account-user-id" content={user_id} />
686
- <meta name="ns-account-user-first-name" content={user_first_name} />
687
- <meta name="ns-account-user-last-name" content={user_last_name} />
688
- <meta name="ns-account-user-email" content={user_email} />
689
- <meta name="ns-account-user-phone" content={user_phone} />
690
- </Helmet>
691
- {
692
- this.state.showDeleteDialog &&
693
- <NSDialogDelete
694
- title={"Delete Confirmation"}
695
- description={
696
- (getIDs && getIDs().length > 1)
697
- ? `Are you sure you want to delete ${getIDs().length} ${name}s?`
698
- : `Are you sure you want to delete ${name}?`
699
- }
700
- onClose={hideDeleteDialog}
701
- onNo={{ action: hideDeleteDialog, showLoading: false }}
702
- show_as_code={false}
703
- onYes={{
704
- showLoading: false,
705
- action: (onFinished) =>
706
- {
707
- try
708
- {
709
- let ids = getIDs ? getIDs() : [];
710
- if (ids.length === 0)
711
- throw new Error("Nothing was found to delete.");
712
- this.runDelete(ids, name);
713
- }
714
- catch (error: any)
715
- {
716
- this.props.notifier.onError(error);
717
- }
718
- this.setState(prev => ({ ...prev, showDeleteDialog: false }));
719
- onFinished();
720
- }
721
- }}
722
- >
723
- <></>
724
- </NSDialogDelete>}
725
- {
726
- content
727
- }
728
- </NSLayout>
729
- )}
730
- />
731
- <NSATaskBar<string>
732
- ref={this.NSATaskBar_Ref}
733
- title={this.state.delete_title}
734
- items={this.state.delete_ids}
735
- handler={async (id) =>
736
- {
737
- const del = this.props.pages?.entity.server.delete;
738
- if (del)
739
- await del(id);
740
- }}
741
- />
742
- </div >
743
- );
744
- }
1
+ import { NamirasoftAccountClient } from 'namirasoft-account-client';
2
+ import { ProductFullRow } from 'namirasoft-api-product';
3
+ import { CacheService, EnvService, IStorageLocal, NamingConvention } from 'namirasoft-core';
4
+ import { NamirasoftMessageServer } from 'namirasoft-message';
5
+ import { NamirasoftMap } from 'namirasoft-site-map';
6
+ import { IBackgroundProps, IBaseComponentProps, IHeaderIconProps, IHeaderRightProps, NSBarActionProps, NSBarAlertProps, NSBarTitleProps, NSDialogDelete, NSLayout, NSLoading, ProductCacheService } from 'namirasoft-site-react';
7
+ import { IHeaderLeftProps } from 'namirasoft-site-react/dist/props/IHeaderLeftProps';
8
+ import { Component, createRef, ReactElement } from 'react';
9
+ import { Helmet } from 'react-helmet';
10
+ import { NSAAccessListDialog } from '../components/NSAAccessListDialog';
11
+ import NSAMasterMenu from '../components/NSAMasterMenu';
12
+ import { NSAMessageListDialog } from '../components/NSAMessageListDialog';
13
+ import { NSAProductListDialog } from '../components/NSAProductListDialog';
14
+ import { NSATaskBar } from '../components/NSATaskBar';
15
+ import { NSAUserDialog } from '../components/NSAUserDialog';
16
+ import { NSAWorkspaceListDialog } from '../components/NSAWorkspaceListDialog';
17
+ import { FieldCacheService } from '../FieldCacheService';
18
+ import { IEntityInfo } from '../IEntityInfo';
19
+ import { NSACacheService } from '../NSACacheService';
20
+ import { NSARouterMakerResult } from '../NSARouterMakerResult';
21
+ import { UseParams } from '../UseParams';
22
+ import { Actions } from './Actions';
23
+ import { NSALayout_Field } from './NSALayout_Field';
24
+ import { NSASectionEdit, NSASectionEditCustomProps } from './NSASectionEdit';
25
+ import { NSASectionList, NSASectionListCustomProps } from './NSASectionList';
26
+ import { NSASectionView, NSASectionViewCutomProps } from './NSASectionView';
27
+
28
+ let REACT_APP_BASE_URL_ACCOUNT_CONSOLE = new EnvService("REACT_APP_BASE_URL_ACCOUNT_CONSOLE").getString();
29
+ let client = new NamirasoftAccountClient(REACT_APP_BASE_URL_ACCOUNT_CONSOLE);
30
+ client.onLoggedin = () => { window.location.reload(); };
31
+ client.onLoggedout = () => { window.location.reload(); };
32
+
33
+ export interface NSALayoutPagesProps<RowType extends { id: string }, RowTypeInput = RowType>
34
+ {
35
+ entity: IEntityInfo<RowType, RowTypeInput>;
36
+ ui?: {
37
+ action?: {
38
+ menus: {
39
+ _new?: boolean;
40
+ list?: boolean;
41
+ view?: boolean;
42
+ view_history?: boolean;
43
+ copy?: boolean;
44
+ edit?: boolean;
45
+ delete?: boolean;
46
+ apply?: boolean;
47
+ };
48
+ children?: JSX.Element | JSX.Element[];
49
+ };
50
+ }
51
+ list?: NSASectionListCustomProps<RowType, RowTypeInput>;
52
+ edit?: NSASectionEditCustomProps<RowType, RowTypeInput> & {
53
+ ui: {
54
+ action?: {
55
+ menus: {
56
+ apply?: boolean,
57
+ }
58
+ },
59
+ }
60
+ };
61
+ view?: NSASectionViewCutomProps<RowType>;
62
+ }
63
+ export interface NSALayoutCustomProps<RowType extends { id: string }, RowTypeInput = RowType> extends IBaseComponentProps, NSARouterMakerResult
64
+ {
65
+ action?: NSBarActionProps;
66
+ title?: NSBarTitleProps;
67
+ alerts?: NSBarAlertProps[];
68
+ pages?: NSALayoutPagesProps<RowType, RowTypeInput>;
69
+ children: ReactElement;
70
+ onEnterPressed?: () => void;
71
+ onDidMounted?: () => void;
72
+ }
73
+ export interface NSALayoutProps<RowType extends { id: string }, RowTypeInput = RowType> extends NSALayoutCustomProps<RowType, RowTypeInput>
74
+ {
75
+ model?: {
76
+ id: string | null;
77
+ }
78
+ scope?: string;
79
+ logo?: string;
80
+ master_menu?: boolean;
81
+ background?: IBackgroundProps;
82
+ header?: {
83
+ enabled?: boolean,
84
+ right?: IHeaderRightProps;
85
+ left?: IHeaderLeftProps;
86
+ built_in?: {
87
+ logout?: boolean;
88
+ message?: boolean;
89
+ access?: boolean;
90
+ workspace?: boolean;
91
+ product?: boolean;
92
+ user?: boolean;
93
+ };
94
+ mega_menu?: boolean;
95
+ };
96
+ }
97
+
98
+ interface NSALayoutState
99
+ {
100
+ parmas: any | null;
101
+ product: ProductFullRow | null;
102
+ refresher: number;
103
+ message_count: number;
104
+ showDeleteDialog: boolean;
105
+ delete_ids: string[];
106
+ delete_title: string;
107
+ showMessageListDialog: boolean;
108
+ showAccessListDialog: boolean;
109
+ showProductListDialog: boolean;
110
+ showWorkspaceListDialog: boolean;
111
+ showUserDialog: boolean;
112
+ showMasterMenu: boolean;
113
+ }
114
+
115
+ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSALayoutProps<RowType, RowTypeInput>, NSALayoutState>
116
+ {
117
+ private onDidMounted_Called: boolean = false;
118
+ private onDidMounted_Ready: boolean = false;
119
+ private hasCFT: boolean;
120
+ private isLoggedIn: boolean;
121
+ private cache_product: CacheService<ProductFullRow>;
122
+ private cache_message: CacheService<number>;
123
+ private cache_master_menu: CacheService<{ open: boolean }>;
124
+ NSASectionList_Ref = createRef<NSASectionList<RowType, RowTypeInput>>();
125
+ NSASectionEdit_Ref = createRef<NSASectionEdit<RowType, RowTypeInput>>();
126
+ NSASectionView_Ref = createRef<NSASectionView<RowType, RowTypeInput>>();
127
+ NSATaskBar_Ref = createRef<NSATaskBar<string>>();
128
+
129
+ constructor(props: NSALayoutProps<RowType, RowTypeInput>)
130
+ {
131
+ super(props);
132
+
133
+ // Account
134
+ this.isLoggedIn = this.props.account?.token_manager?.exists() ?? false;
135
+
136
+ // CFT
137
+ this.hasCFT = false;
138
+ if (this.props.pages?.entity)
139
+ try
140
+ {
141
+ let namirasoft = new NamirasoftMap(this.props.account.token_manager, props.notifier.onError);
142
+ let table = namirasoft.getByProductID(this.props.product_id).tables[this.props.pages.entity.name];
143
+ this.hasCFT = table.hasFieldTables();
144
+ } catch (error)
145
+ { }
146
+
147
+ // Cache Product
148
+ this.cache_product = ProductCacheService.get(this.props.product_id, console.error);
149
+
150
+ // Cache Message
151
+ this.cache_message = new CacheService<number>("ns-messsage-count", new IStorageLocal(), 15, async () => "1.0.0", async () =>
152
+ {
153
+ let REACT_APP_BASE_URL_MESSAGE = new EnvService("REACT_APP_BASE_URL_MESSAGE", true).getString();
154
+ let server = new NamirasoftMessageServer(REACT_APP_BASE_URL_MESSAGE, this.props.account.token_manager, console.error);
155
+ let res = await server.message.GetNewCount();
156
+ return res.count;
157
+ });
158
+
159
+ this.cache_master_menu = NSACacheService.getMasterMenuStatus();
160
+ this.cache_message.onExpired = () => { this.reloadMessageCount(true); };
161
+
162
+ // State
163
+ this.state = {
164
+ parmas: null,
165
+ product: null,
166
+ refresher: 0,
167
+ message_count: 0,
168
+ showDeleteDialog: false,
169
+ delete_ids: [],
170
+ delete_title: "",
171
+ showMessageListDialog: false,
172
+ showAccessListDialog: false,
173
+ showProductListDialog: false,
174
+ showWorkspaceListDialog: false,
175
+ showUserDialog: false,
176
+ showMasterMenu: false,
177
+ };
178
+ }
179
+ public reloadMessageCount(force: boolean)
180
+ {
181
+ if (force)
182
+ this.cache_message.del();
183
+ this.cache_message.get().then(count =>
184
+ {
185
+ this.setState(prev => ({ ...prev, message_count: count }));
186
+ }).catch(() => { });
187
+ }
188
+
189
+ private async runDelete(ids: string[], name: string): Promise<void>
190
+ {
191
+ if (!this.props.pages?.entity.server.delete)
192
+ return;
193
+
194
+ await new Promise<void>(resolve => this.setState(prev => ({ ...prev, delete_ids: ids, delete_title: `Deleting ${name}` }), resolve));
195
+
196
+ const result = await this.NSATaskBar_Ref.current?.run();
197
+ if (!result)
198
+ return;
199
+
200
+ const deletedIds = result.succeeded;
201
+
202
+ if (deletedIds.length === 0)
203
+ return;
204
+
205
+ if (this.props.pages?.list)
206
+ {
207
+ let table = this.NSASectionList_Ref.current?.NSATable_Main.current;
208
+ if (table)
209
+ {
210
+ let selected_ids = table.getSelectedIDs().filter(id => !deletedIds.includes(id));
211
+ let selected_rows = table.getSelectedRows().filter(row => !deletedIds.includes(row.id));
212
+ table.setSelectedIDs(selected_ids, selected_rows);
213
+ table.reload(null, null);
214
+ }
215
+ }
216
+ else if (this.props.pages?.edit)
217
+ {
218
+ if (this.props.pages.entity.client.getListURL)
219
+ this.props.url.redirect(this.props.pages.entity.client.getListURL(), {});
220
+ else if (this.props.pages.entity.client.getViewURL)
221
+ this.props.url.redirect(this.props.pages.entity.client.getViewURL(deletedIds[0]), {});
222
+ }
223
+ else if (this.props.pages?.view)
224
+ {
225
+ if (this.props.pages.entity.client.getListURL)
226
+ this.props.url.redirect(this.props.pages.entity.client.getListURL(), {});
227
+ }
228
+ }
229
+
230
+ override componentDidMount(): void
231
+ {
232
+ this.onDidMounted_Called = false;
233
+ this.cache_product.get().then(product =>
234
+ {
235
+ this.setState(prev => ({ ...prev, product }));
236
+ })
237
+
238
+ this.cache_master_menu.get().then(status =>
239
+ {
240
+ this.setState(() => ({ showMasterMenu: status.open }));
241
+ })
242
+
243
+ if (this.isLoggedIn)
244
+ this.reloadMessageCount(false);
245
+
246
+ client.start();
247
+ }
248
+ override componentDidUpdate(): void
249
+ {
250
+ if (!this.onDidMounted_Called)
251
+ if (this.onDidMounted_Ready)
252
+ {
253
+ this.props.onDidMounted?.();
254
+ this.onDidMounted_Called = true;
255
+ }
256
+ }
257
+ override componentWillUnmount(): void
258
+ {
259
+ client.stop();
260
+ }
261
+ override render()
262
+ {
263
+ this.onDidMounted_Ready = false;
264
+ let id = this.props.model?.id ?? null;
265
+ if (!id)
266
+ {
267
+ if (this.state.parmas === null)
268
+ return <UseParams onLoaded={parmas =>
269
+ {
270
+ this.setState({ parmas });
271
+ }} />;
272
+ id = this.state.parmas.id;
273
+ }
274
+
275
+ const hideDeleteDialog = async () => { this.setState(prev => ({ ...prev, showDeleteDialog: false })); };
276
+ const showDeleteDialog = async () => { this.setState(prev => ({ ...prev, showDeleteDialog: true })); };
277
+
278
+ let icons: IHeaderIconProps[] = [];
279
+
280
+ if (this.isLoggedIn)
281
+ {
282
+ if (this.props.header?.built_in?.message ?? true)
283
+ icons.push({
284
+ src: "https://static.namirasoft.com/image/namirasoft/message/logo/base.png", alt: "Message", onClicked: () =>
285
+ {
286
+ this.setState(prev => ({ ...prev, showMessageListDialog: true }));
287
+ this.reloadMessageCount(true);
288
+ },
289
+ children: <>
290
+ {
291
+ (
292
+ this.state.showMessageListDialog &&
293
+ <NSAMessageListDialog {...this.props}
294
+ onClose={() => { this.setState(prev => ({ ...prev, showMessageListDialog: false })); }}
295
+ onSeenAll={() =>
296
+ {
297
+ this.reloadMessageCount(true);
298
+ }}
299
+ onMessageClick={() =>
300
+ {
301
+ this.reloadMessageCount(true);
302
+ }}
303
+ />
304
+ )
305
+ }
306
+ </>,
307
+ count: this.state.message_count,
308
+ tooltip: "Message"
309
+ });
310
+ }
311
+ if (this.isLoggedIn)
312
+ if (this.props.header?.built_in?.access ?? true)
313
+ icons.push({
314
+ src: "https://static.namirasoft.com/image/namirasoft/access/logo/base.png", alt: "Access", onClicked: () =>
315
+ {
316
+ this.setState(prev => ({ ...prev, showAccessListDialog: true }));
317
+ },
318
+ children: <>
319
+ {
320
+ (this.state.showAccessListDialog) && <NSAAccessListDialog {...this.props} onClose={() =>
321
+ {
322
+ this.setState(prev => ({ ...prev, showAccessListDialog: false }));
323
+ }} />
324
+ }
325
+ </>,
326
+ tooltip: "Access"
327
+ });
328
+ if (this.isLoggedIn)
329
+ if (this.props.header?.built_in?.workspace ?? true)
330
+ icons.push({
331
+ src: "https://static.namirasoft.com/image/namirasoft/workspace/logo/base.png", alt: "Workspace", onClicked: () =>
332
+ {
333
+ this.setState(prev => ({ ...prev, showWorkspaceListDialog: true }));
334
+ },
335
+ children: <>
336
+ {
337
+ (this.state.showWorkspaceListDialog) && <NSAWorkspaceListDialog {...this.props} onClose={() =>
338
+ {
339
+ this.setState(prev => ({ ...prev, showWorkspaceListDialog: false }));
340
+ }} />
341
+ }
342
+ </>,
343
+ tooltip: "Workspace List"
344
+ });
345
+ if (this.props.header?.built_in?.product ?? true)
346
+ icons.push({
347
+ src: "https://static.namirasoft.com/image/concept/product-list/white.svg", alt: "Product", onClicked: () =>
348
+ {
349
+ this.setState(prev => ({ ...prev, showProductListDialog: true }));
350
+ },
351
+ children: <>
352
+ {
353
+ (this.state.showProductListDialog) && <NSAProductListDialog {...this.props} onClose={() =>
354
+ {
355
+ this.setState(prev => ({ ...prev, showProductListDialog: false }));
356
+ }} >
357
+ <></>
358
+ </NSAProductListDialog>
359
+ }
360
+ </>,
361
+ tooltip: "Product List"
362
+ });
363
+
364
+ if (this.isLoggedIn)
365
+ if (this.props.header?.built_in?.user ?? true)
366
+ icons.push({
367
+ src: "https://static.namirasoft.com/image/concept/user/white.svg",
368
+ alt: "User",
369
+ onClicked: () =>
370
+ {
371
+ this.setState(prev => ({ ...prev, showUserDialog: true }));
372
+ },
373
+ children: <>
374
+ {
375
+ (this.state.showUserDialog) &&
376
+ <NSAUserDialog
377
+ {...this.props}
378
+ client={client}
379
+ onClose={() => this.setState(prev => ({ ...prev, showUserDialog: false }))}
380
+ >
381
+ <></>
382
+ </NSAUserDialog>
383
+ }
384
+ </>,
385
+ tooltip: "User"
386
+ });
387
+
388
+ let name = "";
389
+ if (this.props.pages)
390
+ name = NamingConvention.lower_case_underscore.convert(this.props.pages.entity.name, NamingConvention.Pascal_Case_Space);
391
+
392
+ let getIDs: (() => string[]) | null = null;
393
+ let getRows: (() => RowType[]) | null = null;
394
+ if (this.props.pages?.list)
395
+ {
396
+ getIDs = () => { return this.NSASectionList_Ref.current?.getSelectedIDs() ?? []; };
397
+ getRows = () => { return this.NSASectionList_Ref.current?.getSelectedRows() ?? []; };
398
+ }
399
+ if (this.props.pages?.edit)
400
+ {
401
+ getIDs = () => [id].filter(id => id) as string[];
402
+ getRows = () => [this.NSASectionEdit_Ref.current?.getRow()].filter(row => row) as RowType[];
403
+ }
404
+ if (this.props.pages?.view)
405
+ {
406
+ getIDs = () => [id].filter(id => id) as string[];
407
+ getRows = () => [this.NSASectionView_Ref.current?.getRow()].filter(row => row) as RowType[];
408
+ }
409
+
410
+ let action: NSBarActionProps | undefined = { title: "", description: "", menus: {} };
411
+ if (this.props.action?.title)
412
+ action.title = this.props.action.title;
413
+ if (this.props.action?.description)
414
+ action.description = this.props.action.description;
415
+ if (this.props.action?.menus != null)
416
+ action.menus = { ...this.props.action?.menus };
417
+
418
+ if (getIDs && getRows)
419
+ if (this.props.pages?.entity.client.getMenus)
420
+ {
421
+ let menus = this.props.pages?.entity.client.getMenus(getIDs, getRows);
422
+ for (let key of Object.keys(menus))
423
+ {
424
+ if (!action.menus)
425
+ action.menus = {};
426
+ if (!action.menus[key])
427
+ action.menus[key] = [];
428
+ action.menus[key].push(...menus[key]);
429
+ }
430
+ }
431
+
432
+ let name_apply = "Apply";
433
+ let name_actions = "Actions";
434
+ if (!action.menus)
435
+ action.menus = {};
436
+ action.menus[name_apply] = [];
437
+ action.menus[name_actions] = [];
438
+
439
+ if (this.props.pages?.edit)
440
+ {
441
+ if (!action.title)
442
+ action.title = (this.props.pages.edit.isEdit ? "Edit" : "New") + " " + name;
443
+
444
+ // Menu
445
+ if (this.props.pages.edit.ui.action?.menus.apply ?? true)
446
+ action.menus[name_apply].push(Actions.apply({
447
+ action: (onFinished) =>
448
+ {
449
+ if (this.props.pages?.edit)
450
+ this.NSASectionEdit_Ref.current?.onApply(onFinished);
451
+ }
452
+ }));
453
+ }
454
+ else if (this.props.pages)
455
+ {
456
+ if (this.props.pages.entity.client.getNewURL)
457
+ if (this.props.pages.entity.server.create)
458
+ if (this.props.pages.ui?.action?.menus._new ?? true)
459
+ action.menus[name_apply].push(Actions._new(this.props, this.props.pages.entity));
460
+ }
461
+
462
+ if (getIDs)
463
+ if (this.props.pages)
464
+ {
465
+ if (this.props.pages.entity.client.getListURL)
466
+ if (this.props.pages.entity.server.list)
467
+ if (this.props.pages.ui?.action?.menus.list ?? true)
468
+ action.menus[name_actions].push(Actions.list(this.props, this.props.pages.entity));
469
+
470
+ if (this.props.pages.entity.client.getViewURL)
471
+ if (this.props.pages.entity.server.get)
472
+ if (this.props.pages.ui?.action?.menus.view ?? true)
473
+ action.menus[name_actions].push(Actions.view(this.props, this.props.pages.entity, getIDs));
474
+
475
+ if (this.props.pages.ui?.action?.menus.view_history ?? true)
476
+ action.menus[name_actions].push(Actions.viewHistory(getIDs));
477
+
478
+ if (this.props.pages.entity.client.getCopyURL)
479
+ if (this.props.pages.entity.server.create)
480
+ if (this.props.pages.ui?.action?.menus.copy ?? true)
481
+ action.menus[name_actions].push(Actions.copy(this.props, this.props.pages.entity, getIDs));
482
+
483
+ if (this.props.pages.entity.client.getEditURL)
484
+ if (this.props.pages.entity.server.update)
485
+ if (this.props.pages.ui?.action?.menus.edit ?? true)
486
+ action.menus[name_actions].push(Actions.edit(this.props, this.props.pages.entity, getIDs));
487
+
488
+ if (this.props.pages.entity.server.delete)
489
+ if (this.props.pages.ui?.action?.menus.delete ?? true)
490
+ action.menus[name_actions].push(Actions.delete(getIDs, {
491
+ action: showDeleteDialog,
492
+ showLoading: false
493
+ }));
494
+ }
495
+
496
+ let action_name = "";
497
+ let content;
498
+ if (this.props.pages?.list)
499
+ {
500
+ action_name = "List";
501
+ content = <FieldCacheService
502
+ {...this.props}
503
+ render={rows =>
504
+ {
505
+ if (this.props.pages?.list)
506
+ return <NSASectionList<RowType, RowTypeInput>
507
+ ref={this.NSASectionList_Ref}
508
+ {...this.props}
509
+ {...this.props.pages.list}
510
+ entity={this.props.pages.entity}
511
+ onIDsChanged={() =>
512
+ {
513
+ this.setState(prev => ({ ...prev }));
514
+ this.props.pages?.list?.onIDsChanged?.();
515
+ }}
516
+ ctf={{
517
+ enabled: this.hasCFT,
518
+ rows
519
+ }}
520
+ >
521
+ {this.props.children}
522
+ </NSASectionList>;
523
+ return <></>;
524
+ }}
525
+ />;
526
+ }
527
+ else if (this.props.pages?.edit)
528
+ {
529
+ if (this.props.pages.edit.isEdit)
530
+ action_name = "Edit";
531
+ else
532
+ action_name = "New";
533
+ content = <FieldCacheService
534
+ {...this.props}
535
+ render={rows =>
536
+ {
537
+ if (this.props.pages?.edit)
538
+ return <NSASectionEdit
539
+ ref={this.NSASectionEdit_Ref}
540
+ {...this.props}
541
+ {...this.props.pages.edit}
542
+ entity={this.props.pages.entity}
543
+ ctf={{
544
+ enabled: this.hasCFT,
545
+ rows
546
+ }}
547
+ onRowLoaded={(row) =>
548
+ {
549
+ this.setState(prev => ({ ...prev }), () =>
550
+ {
551
+ this.props.pages?.edit?.onRowLoaded?.(row);
552
+ });
553
+ }}
554
+ model={{
555
+ id,
556
+ row: null
557
+ }}
558
+ >
559
+ {this.props.children}
560
+ </NSASectionEdit>;
561
+ return <></>;
562
+ }}
563
+ />;
564
+ }
565
+ else if (this.props.pages?.view)
566
+ {
567
+ action_name = "View";
568
+
569
+ content = <FieldCacheService
570
+ {...this.props}
571
+ render={rows =>
572
+ {
573
+ if (this.props.pages?.view)
574
+ return <NSASectionView
575
+ ref={this.NSASectionView_Ref}
576
+ {...this.props}
577
+ {...this.props.pages.view}
578
+ entity={this.props.pages.entity}
579
+ ctf={{
580
+ enabled: this.hasCFT,
581
+ rows
582
+ }}
583
+ onRowLoaded={(row) =>
584
+ {
585
+ this.setState(prev => ({ ...prev }), () =>
586
+ {
587
+ this.props.pages?.view?.onRowLoaded?.(row);
588
+ });
589
+ }}
590
+ model={{
591
+ id,
592
+ row: null
593
+ }}
594
+ >
595
+ {this.props.children}
596
+ </NSASectionView>;
597
+ return <></>;
598
+ }}
599
+ />;
600
+ }
601
+ else
602
+ content = this.props.children;
603
+
604
+ let fullname = "";
605
+ if (this.props.pages?.entity.name)
606
+ {
607
+ let Name_Pascal_Space = NamingConvention.lower_case_underscore.convert(this.props.pages.entity.name, NamingConvention.Pascal_Case_Space);
608
+ if (action_name === "List")
609
+ fullname = Name_Pascal_Space + " " + action_name;
610
+ else
611
+ fullname = action_name + " " + Name_Pascal_Space;
612
+ }
613
+
614
+ if (!this.state.product)
615
+ return <NSLoading />;
616
+
617
+ let action_title = action?.title ?? "";
618
+ if (!action_title)
619
+ action_title = fullname;
620
+ if (!action_title)
621
+ action_title = this.state.product?.name
622
+
623
+ let action_description = action?.description ?? "";
624
+ if (!action_description)
625
+ action_description = this.state.product?.description ?? "";
626
+
627
+ let scope = this.props.scope ?? `${this.state.product.name} Console`;
628
+ let logo = this.props.logo ?? this.state.product.logo ?? "";
629
+ let background = this.props.background?.image ?? this.state.product.background ?? "";
630
+
631
+ this.onDidMounted_Ready = true;
632
+
633
+ let user_id = this.props.account.token_manager.getUserData(x => x.id, "");
634
+ let user_first_name = this.props.account.token_manager.getUserData(x => x.first_name, "");
635
+ let user_last_name = this.props.account.token_manager.getUserData(x => x.last_name, "");
636
+ let user_email = this.props.account.token_manager.getUserData(x => x.email, "");
637
+ let user_phone = this.props.account.token_manager.getUserData(x => x.phone ?? "", "");
638
+ return (
639
+ <div className="d-flex">
640
+ {
641
+ (this.props.master_menu ?? true) &&
642
+ <NSAMasterMenu
643
+ {...this.props}
644
+ open={this.state.showMasterMenu}
645
+ setOpen={(open) =>
646
+ {
647
+ this.cache_master_menu.set({ open });
648
+ this.setState(() => ({ showMasterMenu: open }));
649
+ }}
650
+ />
651
+ }
652
+ <FieldCacheService
653
+ {...this.props}
654
+ render={(ctf_rows) => (
655
+ <NSLayout
656
+ {...this.props}
657
+ scope={scope}
658
+ logo={logo}
659
+ background={{ image: background, attachment: this.props.background?.attachment, size: this.props.background?.size }}
660
+ header={{
661
+ enabled: this.props.header?.enabled,
662
+ right: {
663
+ icons: [...icons, ...(this.props.header?.right?.icons ?? [])],
664
+ },
665
+ left: {
666
+ title: this.props.header?.left?.title
667
+ },
668
+ mega_menu: this.props.header?.mega_menu,
669
+ onCollapse: () =>
670
+ {
671
+ this.setState((prev) => ({ showMasterMenu: !prev.showMasterMenu }))
672
+ },
673
+ filters_postprocessor: (filters) => NSALayout_Field.postprocess(filters, ctf_rows),
674
+ }}
675
+ action={{
676
+ title: action_title,
677
+ description: action_description,
678
+ menus: action.menus,
679
+ children: this.props.action?.children
680
+ }}
681
+ isLoggedIn={this.props.account?.token_manager?.exists}
682
+ notifications={this.props.notifier.getNotifications()}
683
+ >
684
+ <Helmet>
685
+ <meta name="ns-account-user-id" content={user_id} />
686
+ <meta name="ns-account-user-first-name" content={user_first_name} />
687
+ <meta name="ns-account-user-last-name" content={user_last_name} />
688
+ <meta name="ns-account-user-email" content={user_email} />
689
+ <meta name="ns-account-user-phone" content={user_phone} />
690
+ </Helmet>
691
+ {
692
+ this.state.showDeleteDialog &&
693
+ <NSDialogDelete
694
+ title={"Delete Confirmation"}
695
+ description={
696
+ (getIDs && getIDs().length > 1)
697
+ ? `Are you sure you want to delete ${getIDs().length} ${name}s?`
698
+ : `Are you sure you want to delete ${name}?`
699
+ }
700
+ onClose={hideDeleteDialog}
701
+ onNo={{ action: hideDeleteDialog, showLoading: false }}
702
+ show_as_code={false}
703
+ onYes={{
704
+ showLoading: false,
705
+ action: (onFinished) =>
706
+ {
707
+ try
708
+ {
709
+ let ids = getIDs ? getIDs() : [];
710
+ if (ids.length === 0)
711
+ throw new Error("Nothing was found to delete.");
712
+ this.runDelete(ids, name);
713
+ }
714
+ catch (error: any)
715
+ {
716
+ this.props.notifier.onError(error);
717
+ }
718
+ this.setState(prev => ({ ...prev, showDeleteDialog: false }));
719
+ onFinished();
720
+ }
721
+ }}
722
+ >
723
+ <></>
724
+ </NSDialogDelete>}
725
+ {
726
+ content
727
+ }
728
+ </NSLayout>
729
+ )}
730
+ />
731
+ <NSATaskBar<string>
732
+ ref={this.NSATaskBar_Ref}
733
+ title={this.state.delete_title}
734
+ items={this.state.delete_ids}
735
+ handler={async (id) =>
736
+ {
737
+ const del = this.props.pages?.entity.server.delete;
738
+ if (del)
739
+ await del(id);
740
+ }}
741
+ />
742
+ </div >
743
+ );
744
+ }
745
745
  }