namirasoft-account-react 1.5.2 → 1.5.4

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 (59) hide show
  1. package/SKILLS.md +5 -5
  2. package/dist/FieldCacheService.d.ts +6 -0
  3. package/dist/FieldCacheService.js +40 -0
  4. package/dist/FieldCacheService.js.map +1 -0
  5. package/dist/components/{NSBoxSecret.d.ts → NSABoxSecret.d.ts} +4 -4
  6. package/dist/components/{NSBoxSecret.js → NSABoxSecret.js} +3 -3
  7. package/dist/components/NSABoxSecret.js.map +1 -0
  8. package/dist/components/NSATable.d.ts +2 -3
  9. package/dist/components/NSATable.js +16 -15
  10. package/dist/components/NSATable.js.map +1 -1
  11. package/dist/components/NSFBoxCategoryScope.d.ts +16 -0
  12. package/dist/components/NSFBoxCategoryScope.js +34 -0
  13. package/dist/components/NSFBoxCategoryScope.js.map +1 -0
  14. package/dist/components/NSFBoxField.d.ts +15 -0
  15. package/dist/components/NSFBoxField.js +16 -0
  16. package/dist/components/NSFBoxField.js.map +1 -0
  17. package/dist/components/NSFBoxSlot.d.ts +22 -0
  18. package/dist/components/NSFBoxSlot.js +49 -0
  19. package/dist/components/NSFBoxSlot.js.map +1 -0
  20. package/dist/components/NSFBoxWrapper.d.ts +15 -0
  21. package/dist/components/NSFBoxWrapper.js +44 -0
  22. package/dist/components/NSFBoxWrapper.js.map +1 -0
  23. package/dist/layouts/NSALayout.d.ts +3 -4
  24. package/dist/layouts/NSALayout.js +14 -52
  25. package/dist/layouts/NSALayout.js.map +1 -1
  26. package/dist/layouts/NSASectionEdit.d.ts +4 -5
  27. package/dist/layouts/NSASectionEdit.js +4 -5
  28. package/dist/layouts/NSASectionEdit.js.map +1 -1
  29. package/dist/layouts/NSASectionEditTabPage.d.ts +3 -5
  30. package/dist/layouts/NSASectionEditTabPage.js +60 -52
  31. package/dist/layouts/NSASectionEditTabPage.js.map +1 -1
  32. package/dist/layouts/NSASectionList.d.ts +2 -3
  33. package/dist/layouts/NSASectionList.js.map +1 -1
  34. package/dist/layouts/NSASectionView.d.ts +2 -3
  35. package/dist/layouts/NSASectionView.js.map +1 -1
  36. package/dist/layouts/NSASectionViewTabPage.d.ts +2 -3
  37. package/dist/layouts/NSASectionViewTabPage.js +45 -53
  38. package/dist/layouts/NSASectionViewTabPage.js.map +1 -1
  39. package/dist/main.d.ts +1 -1
  40. package/dist/main.js +1 -1
  41. package/dist/main.js.map +1 -1
  42. package/package.json +6 -5
  43. package/src/FieldCacheService.ts +39 -0
  44. package/src/components/{NSBoxSecret.tsx → NSABoxSecret.tsx} +6 -5
  45. package/src/components/NSATable.tsx +13 -14
  46. package/src/components/NSFBoxCategoryScope.tsx +53 -0
  47. package/src/components/NSFBoxField.tsx +38 -0
  48. package/src/components/NSFBoxSlot.tsx +72 -0
  49. package/src/components/NSFBoxWrapper.tsx +70 -0
  50. package/src/layouts/NSALayout.tsx +17 -68
  51. package/src/layouts/NSASectionEdit.tsx +9 -10
  52. package/src/layouts/NSASectionEditTabPage.tsx +79 -72
  53. package/src/layouts/NSASectionList.tsx +2 -3
  54. package/src/layouts/NSASectionView.tsx +2 -3
  55. package/src/layouts/NSASectionViewTabPage.tsx +52 -71
  56. package/src/main.ts +1 -1
  57. package/dist/components/NSBoxSecret.js.map +0 -1
  58. /package/dist/components/{NSBoxSecret.module.css → NSABoxSecret.module.css} +0 -0
  59. /package/src/components/{NSBoxSecret.module.css → NSABoxSecret.module.css} +0 -0
@@ -0,0 +1,38 @@
1
+ import { FieldRow, SlotRow } from "namirasoft-field";
2
+ import { NSBoxDynamic } from "namirasoft-site-react";
3
+ import { Component, createRef } from "react";
4
+ import { NSFBoxSlot } from "./NSFBoxSlot";
5
+
6
+ export interface NSFBoxFieldProps
7
+ {
8
+ slot: SlotRow;
9
+ field: FieldRow;
10
+ }
11
+
12
+ interface NSFBoxFieldState
13
+ {
14
+ }
15
+
16
+ export class NSFBoxField extends Component<NSFBoxFieldProps, NSFBoxFieldState>
17
+ {
18
+ NSBoxDynamic_Ref = createRef<NSBoxDynamic>();
19
+
20
+ constructor(props: NSFBoxFieldProps)
21
+ {
22
+ super(props);
23
+
24
+ this.state = {};
25
+ }
26
+ override render()
27
+ {
28
+ return <NSBoxDynamic
29
+ key={`NSFBoxField_NSBoxDynamic_${this.props.field.id}`}
30
+ ref={this.NSBoxDynamic_Ref}
31
+ name={this.props.slot.id}
32
+ title={this.props.slot.name}
33
+ variable={this.props.field.type}
34
+ info={{ text: this.props.slot.description ?? this.props.field.description ?? "" }}
35
+ style={{ width: NSFBoxSlot.getSize(this.props.slot.size) }}
36
+ />;
37
+ }
38
+ }
@@ -0,0 +1,72 @@
1
+ import { CategoryScopeRow, FieldRow, SlotEntityType, SlotRow, SlotSize } from "namirasoft-field";
2
+ import { NSBox } from "namirasoft-site-react";
3
+ import { Component, createRef } from "react";
4
+ import { NSARouterMakerProps } from "../NSARouterMakerProps";
5
+ import { NSFBoxCategoryScope } from "./NSFBoxCategoryScope";
6
+ import { NSFBoxField } from "./NSFBoxField";
7
+
8
+ export interface NSFBoxSlotProps extends NSARouterMakerProps
9
+ {
10
+ slot: SlotRow;
11
+ getField: () => FieldRow;
12
+ getCategoryScope: () => CategoryScopeRow;
13
+ }
14
+
15
+ interface NSFBoxSlotState
16
+ {
17
+ }
18
+
19
+ export class NSFBoxSlot extends Component<NSFBoxSlotProps, NSFBoxSlotState>
20
+ {
21
+ static getSize(size: SlotSize)
22
+ {
23
+ if (size === SlotSize.Small)
24
+ return NSBox.width.one;
25
+ if (size === SlotSize.Medium)
26
+ return NSBox.width.double;
27
+ if (size === SlotSize.Big)
28
+ return NSBox.width.triple;
29
+ return "";
30
+ }
31
+ NSFBoxCategoryScope_Ref = createRef<NSFBoxCategoryScope>();
32
+ NSFBoxField_Ref = createRef<NSFBoxField>();
33
+ constructor(props: NSFBoxSlotProps)
34
+ {
35
+ super(props);
36
+
37
+ this.state = {};
38
+
39
+ this.getValue = this.getValue.bind(this);
40
+ this.setValue = this.setValue.bind(this);
41
+ }
42
+ getValue(checkError?: boolean)
43
+ {
44
+ if (this.props.slot.entity_type === SlotEntityType.CategoryScope)
45
+ return this.NSFBoxCategoryScope_Ref.current?.NSBoxEntity_Ref.current?.getValue(checkError);
46
+ if (this.props.slot.entity_type === SlotEntityType.Field)
47
+ return this.NSFBoxField_Ref.current?.NSBoxDynamic_Ref.current?.getValue(checkError);
48
+ return null;
49
+ }
50
+ setValue(value: any | null, callback: () => void)
51
+ {
52
+ if (this.props.slot.entity_type === SlotEntityType.CategoryScope)
53
+ return this.NSFBoxCategoryScope_Ref.current?.NSBoxEntity_Ref.current?.setValue(value, callback);
54
+ if (this.props.slot.entity_type === SlotEntityType.Field)
55
+ return this.NSFBoxField_Ref.current?.NSBoxDynamic_Ref.current?.setValue(value, callback);
56
+ return null;
57
+ }
58
+ override render()
59
+ {
60
+ if (this.props.slot.entity_type === SlotEntityType.CategoryScope)
61
+ return <NSFBoxCategoryScope
62
+ {...this.props}
63
+ category_scope={this.props.getCategoryScope()}
64
+ />;
65
+ if (this.props.slot.entity_type === SlotEntityType.Field)
66
+ return <NSFBoxField
67
+ {...this.props}
68
+ field={this.props.getField()}
69
+ />;
70
+ return <></>;
71
+ }
72
+ }
@@ -0,0 +1,70 @@
1
+ import { SlotPositionSide, SlotRow } from "namirasoft-field";
2
+ import { Children, cloneElement, Component, isValidElement, ReactNode } from "react";
3
+
4
+ export interface NSFBoxWrapperProps
5
+ {
6
+ slots: SlotRow[];
7
+ renderSlot: (slot: SlotRow) => ReactNode;
8
+ children?: ReactNode;
9
+ }
10
+
11
+ interface NSFBoxWrapperState
12
+ {
13
+ }
14
+
15
+ export class NSFBoxWrapper extends Component<NSFBoxWrapperProps, NSFBoxWrapperState>
16
+ {
17
+ constructor(props: NSFBoxWrapperProps)
18
+ {
19
+ super(props);
20
+
21
+ this.state = {};
22
+
23
+ this.inject = this.inject.bind(this);
24
+ }
25
+ private inject(nodes: ReactNode, used: Set<string>): ReactNode
26
+ {
27
+ return Children.map(nodes, node =>
28
+ {
29
+ if (!isValidElement(node))
30
+ return node;
31
+
32
+ let title = (node.props as any)?.title;
33
+
34
+ let before: ReactNode[] = [];
35
+ let after: ReactNode[] = [];
36
+ if (typeof title === "string")
37
+ for (let slot of this.props.slots)
38
+ {
39
+ if (used.has(slot.id))
40
+ continue;
41
+ if (slot.position_target === title)
42
+ {
43
+ used.add(slot.id);
44
+ if (slot.position_side === SlotPositionSide.Before)
45
+ before.push(this.props.renderSlot(slot));
46
+ else
47
+ after.push(this.props.renderSlot(slot));
48
+ }
49
+ }
50
+
51
+ let children = (node.props as any)?.children;
52
+ let element = children !== undefined
53
+ ? cloneElement(node, undefined, this.inject(children, used))
54
+ : node;
55
+
56
+ return <>{before}{element}{after}</>;
57
+ });
58
+ }
59
+ override render()
60
+ {
61
+ let used = new Set<string>();
62
+ let content = this.inject(this.props.children, used);
63
+ let leftovers = this.props.slots.filter(slot => !used.has(slot.id));
64
+
65
+ return <>
66
+ {content}
67
+ {leftovers.map(slot => this.props.renderSlot(slot))}
68
+ </>;
69
+ }
70
+ }
@@ -1,7 +1,7 @@
1
1
  import { NamirasoftAccountClient } from 'namirasoft-account-client';
2
2
  import { ProductFullRow } from 'namirasoft-api-product';
3
- import { CacheService, CookieService, EnvService, FilterItem, FilterItemOperator, IStorageLocal, NamingConvention } from 'namirasoft-core';
4
- import { CategoryRow, FieldRow, NamirasoftFieldMetaDatabase, NamirasoftFieldServer } from 'namirasoft-field';
3
+ import { CacheService, EnvService, IStorageLocal, NamingConvention } from 'namirasoft-core';
4
+ import { EntityResolveResponseRow } from 'namirasoft-field';
5
5
  import { NamirasoftMessageServer } from 'namirasoft-message';
6
6
  import { NamirasoftMap } from 'namirasoft-site-map';
7
7
  import { IBackgroundProps, IBaseComponentProps, IHeaderIconProps, IHeaderRightProps, NSBarActionProps, NSBarAlertProps, NSBarTitleProps, NSDialogDelete, NSLayout, NSLoading, ProductCacheService } from 'namirasoft-site-react';
@@ -15,6 +15,7 @@ import { NSAProductListDialog } from '../components/NSAProductListDialog';
15
15
  import { NSATaskBar } from '../components/NSATaskBar';
16
16
  import { NSAUserDialog } from '../components/NSAUserDialog';
17
17
  import { NSAWorkspaceListDialog } from '../components/NSAWorkspaceListDialog';
18
+ import { FieldCacheService } from '../FieldCacheService';
18
19
  import { IEntityInfo } from '../IEntityInfo';
19
20
  import { NSACacheService } from '../NSACacheService';
20
21
  import { NSARouterMakerProps } from '../NSARouterMakerProps';
@@ -110,8 +111,7 @@ interface NSALayoutState
110
111
  showUserDialog: boolean;
111
112
  showMasterMenu: boolean;
112
113
  ctf_enabled: boolean;
113
- ctf_categories: CategoryRow[] | null;
114
- ctf_fields: FieldRow[] | null;
114
+ ctf_rows: EntityResolveResponseRow | null;
115
115
  }
116
116
 
117
117
  export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSALayoutProps<RowType, RowTypeInput>, NSALayoutState>
@@ -121,10 +121,7 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
121
121
  private hasCFT: boolean;
122
122
  private isLoggedIn: boolean;
123
123
  private cache_product: CacheService<ProductFullRow>;
124
- private cache_fields: CacheService<{
125
- ctf_categories: CategoryRow[] | null;
126
- ctf_fields: FieldRow[] | null;
127
- }>;
124
+ private cache_field: CacheService<EntityResolveResponseRow>;
128
125
  private cache_message: CacheService<number>;
129
126
  private cache_master_menu: CacheService<{ open: boolean }>;
130
127
  NSASectionList_Ref = createRef<NSASectionList<RowType, RowTypeInput>>();
@@ -154,52 +151,8 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
154
151
  this.cache_product = ProductCacheService.get(this.props.product_id, console.error);
155
152
 
156
153
  // Cache Fields
157
- // todo this must be owner_id, otherwise switching between owners does not work correctly
158
- let user_id = this.props.account.token_manager.getUserData(x => x.id, "");
159
- let key_field = `ns-fields-${user_id}-${props.pages?.entity?.product_id ?? "*"}-${props.pages?.entity?.name ?? "*"}`;
160
- this.cache_fields = new CacheService<{
161
- ctf_categories: CategoryRow[] | null;
162
- ctf_fields: FieldRow[] | null;
163
- }>(key_field, new IStorageLocal(), 24 * 60, async () =>
164
- {
165
- let service = new CookieService(document.cookie, "ns-field-version");
166
- return (this.props.account?.token_manager?.getUserData(x => x.id, "") ?? "") + "" + service.getString();
167
- }, async () =>
168
- {
169
- let REACT_APP_BASE_URL_FIELD = new EnvService("REACT_APP_BASE_URL_FIELD", true).getString();
170
- let server = new NamirasoftFieldServer(REACT_APP_BASE_URL_FIELD, props.account.token_manager, props.notifier.onError);
171
- let ans: {
172
- ctf_categories: CategoryRow[] | null;
173
- ctf_fields: FieldRow[] | null;
174
- } = { ctf_categories: null, ctf_fields: null };
175
- if (this.props.pages)
176
- {
177
- let meta = new NamirasoftFieldMetaDatabase();
178
- try
179
- {
180
- let filters: FilterItem[] = [];
181
- filters.push(new FilterItem(meta.tables.category, meta.tables.category.columns.product_id, false, FilterItemOperator.all.equals, this.props.pages.entity.product_id));
182
- filters.push(new FilterItem(meta.tables.category, meta.tables.category.columns.entity, false, FilterItemOperator.all.equals, this.props.pages.entity.name));
183
- let res = await server.category.List(filters, null, null, [], null);
184
- ans.ctf_categories = res.rows;
185
- } catch (error)
186
- {
187
- ans.ctf_categories = [];
188
- }
189
- try
190
- {
191
- let filters: FilterItem[] = [];
192
- filters.push(new FilterItem(meta.tables.field, meta.tables.field.columns.product_id, false, FilterItemOperator.all.equals, this.props.pages.entity.product_id));
193
- filters.push(new FilterItem(meta.tables.field, meta.tables.field.columns.entity, false, FilterItemOperator.all.equals, this.props.pages.entity.name));
194
- let res = await server.field.List(filters, null, null, [], null);
195
- ans.ctf_fields = res.rows;
196
- } catch (error)
197
- {
198
- ans.ctf_fields = [];
199
- }
200
- }
201
- return ans;
202
- });
154
+ this.cache_field = FieldCacheService.get(this.props.account.token_manager, this.props.pages?.entity.product_id, this.props.pages?.entity.name, props.notifier.onError)
155
+
203
156
  // Cache Message
204
157
  this.cache_message = new CacheService<number>("ns-messsage-count", new IStorageLocal(), 15, async () => "1.0.0", async () =>
205
158
  {
@@ -228,8 +181,7 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
228
181
  showUserDialog: false,
229
182
  showMasterMenu: false,
230
183
  ctf_enabled: this.hasCFT,
231
- ctf_fields: null,
232
- ctf_categories: null,
184
+ ctf_rows: null
233
185
  };
234
186
  }
235
187
  public reloadMessageCount(force: boolean)
@@ -299,9 +251,9 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
299
251
  if (this.hasCFT)
300
252
  if (this.props.pages?.entity)
301
253
  {
302
- this.cache_fields.get().then(res =>
254
+ this.cache_field.get().then(res =>
303
255
  {
304
- this.setState(prev => { return { ...prev, ctf_categories: res.ctf_categories ?? [], ctf_fields: res.ctf_fields ?? [] } });
256
+ this.setState(prev => { return { ...prev, ctf_rows: res } });
305
257
  });
306
258
  }
307
259
 
@@ -575,10 +527,9 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
575
527
  }}
576
528
  ctf={{
577
529
  enabled: this.state.ctf_enabled,
578
- categories: this.state.ctf_categories,
579
- fields: this.state.ctf_fields
530
+ rows: this.state.ctf_rows
580
531
  }}
581
- deleteFieldCache={() => { this.cache_fields.del(); }}
532
+ deleteFieldCache={() => { this.cache_field.del(); }}
582
533
  >
583
534
  {this.props.children}
584
535
  </NSASectionList>
@@ -597,10 +548,9 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
597
548
  entity={this.props.pages.entity}
598
549
  ctf={{
599
550
  enabled: this.state.ctf_enabled,
600
- categories: this.state.ctf_categories,
601
- fields: this.state.ctf_fields
551
+ rows: this.state.ctf_rows
602
552
  }}
603
- deleteFieldCache={() => { this.cache_fields.del(); }}
553
+ deleteFieldCache={() => { this.cache_field.del(); }}
604
554
  onRowLoaded={(row) =>
605
555
  {
606
556
  this.setState(prev => ({ ...prev }), () =>
@@ -627,10 +577,9 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
627
577
  entity={this.props.pages.entity}
628
578
  ctf={{
629
579
  enabled: this.state.ctf_enabled,
630
- categories: this.state.ctf_categories,
631
- fields: this.state.ctf_fields
580
+ rows: this.state.ctf_rows
632
581
  }}
633
- deleteFieldCache={() => { this.cache_fields.del(); }}
582
+ deleteFieldCache={() => { this.cache_field.del(); }}
634
583
  onRowLoaded={(row) =>
635
584
  {
636
585
  this.setState(prev => ({ ...prev }), () =>
@@ -767,7 +716,7 @@ export class NSALayout<RowType extends { id: string }, RowTypeInput = RowType> e
767
716
  <></>
768
717
  </NSDialogDelete>}
769
718
  {
770
- (!this.state.ctf_enabled || (this.state.ctf_fields && this.state.ctf_categories))
719
+ (!this.state.ctf_enabled || (this.state.ctf_rows))
771
720
  ?
772
721
  content
773
722
  :
@@ -1,13 +1,12 @@
1
- import { IBaseComponentProps, NSID, NSLoading } from "namirasoft-site-react";
2
- import { NSSection, NSPanel, NSButtonBlue, NSLine, NSSpace, NSSpaceSizeType } from 'namirasoft-site-react';
3
- import { NSARouterMakerProps } from "../NSARouterMakerProps";
1
+ import { IStorageLocal, NamingConvention } from "namirasoft-core";
2
+ import { EntityResolveResponseRow } from "namirasoft-field";
3
+ import { IBaseComponentProps, NSButtonBlue, NSID, NSLine, NSLoading, NSPanel, NSSection, NSSpace, NSSpaceSizeType } from "namirasoft-site-react";
4
4
  import { Component, createRef, FormHTMLAttributes, ReactNode } from "react";
5
+ import { NSANavigationGuard } from "../components/NSANavigationGuard";
5
6
  import { IEntityInfo } from "../IEntityInfo";
6
- import { IStorageLocal, NamingConvention } from "namirasoft-core";
7
- import { NSASectionViewTabPage, NSASectionViewTabPageUIProps } from "./NSASectionViewTabPage";
7
+ import { NSARouterMakerProps } from "../NSARouterMakerProps";
8
8
  import { NSASectionEditTabPage, NSASectionEditTabPageEditorProps, NSASectionEditTabPageUIProps } from "./NSASectionEditTabPage";
9
- import { CategoryRow, FieldRow } from "namirasoft-field";
10
- import { NSANavigationGuard } from "../components/NSANavigationGuard";
9
+ import { NSASectionViewTabPage, NSASectionViewTabPageUIProps } from "./NSASectionViewTabPage";
11
10
 
12
11
  export interface NSASectionEditCustomProps<RowType extends { id: string }, RowTypeInput = RowType> extends NSARouterMakerProps, IBaseComponentProps
13
12
  {
@@ -37,8 +36,7 @@ export interface NSASectionEditProps<RowType extends { id: string }, RowTypeInpu
37
36
  entity: IEntityInfo<RowType, RowTypeInput>,
38
37
  ctf: {
39
38
  enabled: boolean;
40
- fields: FieldRow[] | null;
41
- categories: CategoryRow[] | null;
39
+ rows: EntityResolveResponseRow | null;
42
40
  };
43
41
  deleteFieldCache: () => void;
44
42
  children: ReactNode;
@@ -221,7 +219,8 @@ export class NSASectionEdit<RowType extends { id: string }, RowTypeInput = RowTy
221
219
  {...this.props.ui.form}
222
220
  onInput={this.markDirty}
223
221
  onChange={this.markDirty}
224
- onSubmit={(e) => {
222
+ onSubmit={(e) =>
223
+ {
225
224
  e.preventDefault()
226
225
  }}
227
226
  >
@@ -1,6 +1,8 @@
1
- import { CategoryRow, EntityCategoryInputRow, EntityFieldInputRow, EntityTagInputRow, FieldRow } from "namirasoft-field";
2
- import { IBaseComponentProps, NSBoxBooleans, NSBoxDynamic, NSColumn, NSRepeaterNSTag, NSRow, NSTabPage, NSTabPageTab } from "namirasoft-site-react";
3
- import { Component, createRef, ReactNode } from "react";
1
+ import { EntityCategoryInputRow, EntityFieldInputRow, EntityResolveResponseRow, EntityTagInputRow, SlotEntityType, SlotRow } from "namirasoft-field";
2
+ import { IBaseComponentProps, NSColumn, NSRepeaterNSTag, NSRow, NSTabPage, NSTabPageTab } from "namirasoft-site-react";
3
+ import { Component, createRef, ReactNode, RefObject } from "react";
4
+ import { NSFBoxSlot } from "../components/NSFBoxSlot";
5
+ import { NSFBoxWrapper } from "../components/NSFBoxWrapper";
4
6
  import { CTFRow } from "../CTFRow";
5
7
  import { IEntityInfo } from "../IEntityInfo";
6
8
  import { NSARouterMakerProps } from "../NSARouterMakerProps";
@@ -32,8 +34,7 @@ export interface NSASectionEditTabPageProps<RowType extends { id: string }, RowT
32
34
  entity: IEntityInfo<RowType & { id: string }, RowTypeInput>;
33
35
  ctf: {
34
36
  enabled: boolean;
35
- fields: FieldRow[] | null;
36
- categories: CategoryRow[] | null;
37
+ rows: EntityResolveResponseRow | null;
37
38
  }
38
39
  model: {
39
40
  id: string | null;
@@ -49,8 +50,7 @@ interface NSASectionEditTabPageState<RowType>
49
50
 
50
51
  export class NSASectionEditTabPage<RowType extends { id: string }, RowTypeInput = RowType> extends Component<NSASectionEditTabPageProps<RowType, RowTypeInput>, NSASectionEditTabPageState<RowType>>
51
52
  {
52
- private Fields_Refs: { [id: string]: React.RefObject<NSBoxDynamic> } = {};
53
- private Categories_Refs: { [group: string]: React.RefObject<NSBoxBooleans> } = {};
53
+ private Slots_Refs: { [id: string]: RefObject<NSFBoxSlot> } = {};
54
54
  private Tags_Refs = createRef<NSRepeaterNSTag>();
55
55
 
56
56
  constructor(props: NSASectionEditTabPageProps<RowType, RowTypeInput>)
@@ -60,14 +60,11 @@ export class NSASectionEditTabPage<RowType extends { id: string }, RowTypeInput
60
60
  this.state = { row: props.model.row };
61
61
 
62
62
  if (props.ctf.enabled)
63
- {
64
- props.ctf.fields?.forEach(field => this.Fields_Refs[field.id] = createRef<NSBoxDynamic>());
65
- props.ctf.categories?.forEach(category =>
63
+ props.ctf.rows?.slots?.forEach(slot =>
66
64
  {
67
- if (!this.Categories_Refs[category.group])
68
- this.Categories_Refs[category.group] = createRef<NSBoxBooleans>()
65
+ if (!this.Slots_Refs[slot.id])
66
+ this.Slots_Refs[slot.id] = createRef<NSFBoxSlot>();
69
67
  });
70
- }
71
68
 
72
69
  this.reload = this.reload.bind(this);
73
70
  this.getRow = this.getRow.bind(this);
@@ -113,19 +110,24 @@ export class NSASectionEditTabPage<RowType extends { id: string }, RowTypeInput
113
110
  let categories: EntityCategoryInputRow[] = [];
114
111
  let tags: EntityTagInputRow[] = [];
115
112
 
116
- if (this.props.ctf.fields)
117
- for (let field of this.props.ctf.fields)
113
+ let rows = this.props.ctf.rows;
114
+ if (rows)
115
+ for (let slot of rows.slots)
118
116
  {
119
- let ref = this.Fields_Refs[field.id];
120
- if (ref.current)
121
- fields.push({ field_id: field.id, value: ref.current.getValue() });
117
+ let ref = this.Slots_Refs[slot.id];
118
+ if (!ref?.current)
119
+ continue;
120
+ let value = ref.current.getValue();
121
+ if (slot.entity_type === SlotEntityType.Field)
122
+ fields.push({ field_id: slot.entity_id, value });
123
+ else if (slot.entity_type === SlotEntityType.CategoryScope)
124
+ {
125
+ if (Array.isArray(value))
126
+ value.forEach(id => categories.push({ category_id: id }));
127
+ else if (value != null)
128
+ categories.push({ category_id: value });
129
+ }
122
130
  }
123
- for (let group in this.Categories_Refs)
124
- {
125
- let ref = this.Categories_Refs[group];
126
- if (ref.current)
127
- categories.push(...ref.current?.getValues().map(x => { return { category_id: x } }));
128
- }
129
131
  if (this.Tags_Refs.current)
130
132
  tags = this.Tags_Refs.current.getValue().map(x => { return { name: x.name, value: x.value } });
131
133
 
@@ -133,18 +135,27 @@ export class NSASectionEditTabPage<RowType extends { id: string }, RowTypeInput
133
135
  }
134
136
  private setFields(ctf: CTFRow)
135
137
  {
136
- for (let field of ctf.fields)
137
- {
138
- let ref = this.Fields_Refs[field.field_id];
139
- if (ref?.current)
140
- ref.current.setValue(field.value);
141
- }
142
- for (let key of Object.keys(this.Categories_Refs))
143
- {
144
- let ref = this.Categories_Refs[key];
145
- if (ref.current)
146
- ref.current.setValues(ctf.categories.map(x => x.category_id));
147
- }
138
+ let rows = this.props.ctf.rows;
139
+ if (rows)
140
+ for (let slot of rows.slots)
141
+ {
142
+ let ref = this.Slots_Refs[slot.id];
143
+ if (!ref?.current)
144
+ continue;
145
+ if (slot.entity_type === SlotEntityType.Field)
146
+ {
147
+ let field = ctf.fields.find(x => x.field_id === slot.entity_id);
148
+ if (field)
149
+ ref.current.setValue(field.value, () => { });
150
+ }
151
+ else if (slot.entity_type === SlotEntityType.CategoryScope)
152
+ {
153
+ let ids = ctf.categories
154
+ .map(x => x.category_id)
155
+ .filter(id => rows.categories.find(category => category.id === id)?.category_scope_id === slot.entity_id);
156
+ ref.current.setValue(slot.multiple ? ids : (ids[0] ?? null), () => { });
157
+ }
158
+ }
148
159
  if (this.Tags_Refs.current)
149
160
  this.Tags_Refs.current.setValue(ctf.tags.map(x => { return { name: x.name, value: x.value ?? "" } }));
150
161
  }
@@ -161,60 +172,56 @@ export class NSASectionEditTabPage<RowType extends { id: string }, RowTypeInput
161
172
  }
162
173
  override render()
163
174
  {
164
- let groups_fields = Array.from(new Set(this.props.ctf.fields?.map(x => x.group) ?? []));
165
- let groups_categories = Array.from(new Set(this.props.ctf.categories?.map(x => x.group) ?? []));
175
+ const TAB_GENERAL = "General";
176
+
177
+ let rows = this.props.ctf.enabled ? this.props.ctf.rows : null;
178
+ let slots = rows?.slots ?? [];
179
+
180
+ let renderSlot = (slot: SlotRow) =>
181
+ {
182
+ if (!this.Slots_Refs[slot.id])
183
+ this.Slots_Refs[slot.id] = createRef<NSFBoxSlot>();
184
+ return <NSFBoxSlot
185
+ key={`NSASectionEditTabPage_NSFBoxSlot_${slot.id}`}
186
+ {...this.props}
187
+ ref={this.Slots_Refs[slot.id]}
188
+ slot={slot}
189
+ getField={() => rows!.fields.find(x => x.id === slot.entity_id)!}
190
+ getCategoryScope={() => rows!.category_scopes.find(x => x.id === slot.entity_id)!}
191
+ />;
192
+ };
166
193
 
167
194
  let tabs: NSTabPageTab[] = [{
168
- title: "General",
195
+ title: TAB_GENERAL,
169
196
  clicked: true,
170
197
  getContent: () => <NSColumn
171
198
  {...this.props.ui?.tab_main}
172
199
  >
173
- {this.props.children}
200
+ <NSFBoxWrapper
201
+ slots={slots.filter(x => x.tab === TAB_GENERAL)}
202
+ renderSlot={renderSlot}
203
+ >
204
+ {this.props.children}
205
+ </NSFBoxWrapper>
174
206
  </NSColumn>
175
207
  }];
176
208
  this.props.ui?.extra_tabs?.forEach(tab => tabs.push(tab));
177
209
  if (this.props.ctf.enabled)
178
210
  {
179
- groups_fields.forEach(group =>
180
- {
181
- tabs.push({
182
- title: group,
183
- clicked: true,
184
- getContent: () => <NSColumn
185
- classList={[`${Styles.nsa_section_edit_tab_page}`]}
186
- >
187
- <NSRow>
188
- {
189
- this.props.ctf.fields?.filter(x => x.group === group).map((field, index) =>
190
- <NSBoxDynamic
191
- key={`NSASectionViewTabPage_NSBoxDynamic_${index}`}
192
- ref={this.Fields_Refs[field.id]}
193
- name={field.id}
194
- title={field.name}
195
- variable={field.type}
196
- />
197
- )
198
- }
199
- </NSRow>
200
- </NSColumn>
201
- });
202
- });
203
- groups_categories.forEach(group =>
211
+ let tab_names = Array.from(new Set(slots.map(x => x.tab))).filter(tab => tab !== TAB_GENERAL);
212
+ tab_names.forEach(tab =>
204
213
  {
205
- let items = this.props.ctf.categories?.filter(x => x.group === group).map(category => { return { value: category.id, text: category.name } }) ?? [];
206
214
  tabs.push({
207
- title: group,
215
+ title: tab,
208
216
  clicked: true,
209
217
  getContent: () => <NSColumn
210
218
  classList={[`${Styles.nsa_section_edit_tab_page}`]}
211
219
  >
212
220
  <NSRow>
213
- <NSBoxBooleans
214
- ref={this.Categories_Refs[group]}
215
- box_all={{ hideHeader: true }}
216
- items={items}
217
- ></NSBoxBooleans>
221
+ <NSFBoxWrapper
222
+ slots={slots.filter(x => x.tab === tab)}
223
+ renderSlot={renderSlot}
224
+ />
218
225
  </NSRow>
219
226
  </NSColumn>
220
227
  });
@@ -1,4 +1,4 @@
1
- import { CategoryRow, FieldRow } from "namirasoft-field";
1
+ import { EntityResolveResponseRow } from "namirasoft-field";
2
2
  import { IBaseComponentProps, NSBoxCombo, NSRow, NSSpace, NSSpaceSizeType, NSSplitter } from "namirasoft-site-react";
3
3
  import { Component, ReactNode, createRef } from "react";
4
4
  import { IEntityInfo } from "../IEntityInfo";
@@ -23,8 +23,7 @@ export interface NSASectionListProps<RowType extends { id: string }, RowTypeInpu
23
23
  entity: IEntityInfo<RowType, RowTypeInput>;
24
24
  ctf: {
25
25
  enabled: boolean;
26
- fields: FieldRow[] | null;
27
- categories: CategoryRow[] | null;
26
+ rows: EntityResolveResponseRow | null;
28
27
  };
29
28
  deleteFieldCache: () => void;
30
29
  children?: ReactNode;
@@ -1,4 +1,4 @@
1
- import { CategoryRow, FieldRow } from "namirasoft-field";
1
+ import { EntityResolveResponseRow } from "namirasoft-field";
2
2
  import { IBaseComponentProps, NSLoading } from "namirasoft-site-react";
3
3
  import { Component, createRef, ReactNode } from "react";
4
4
  import { IEntityInfo } from "../IEntityInfo";
@@ -21,8 +21,7 @@ export interface NSASectionViewProps<RowType extends { id: string }, RowTypeInpu
21
21
  entity: IEntityInfo<RowType, RowTypeInput>;
22
22
  ctf: {
23
23
  enabled: boolean;
24
- fields: FieldRow[] | null;
25
- categories: CategoryRow[] | null;
24
+ rows: EntityResolveResponseRow | null;
26
25
  };
27
26
  model: {
28
27
  id: string | null;