@simplysm/angular 14.0.19 → 14.0.21

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 (125) hide show
  1. package/dist/core/provideSdAngular.js +1 -1
  2. package/dist/core/providers/sd-activated-modal.provider.d.ts +13 -0
  3. package/dist/core/providers/sd-activated-modal.provider.d.ts.map +1 -0
  4. package/dist/core/providers/sd-activated-modal.provider.js +15 -0
  5. package/dist/core/providers/sd-app-structure.provider.d.ts +3 -64
  6. package/dist/core/providers/sd-app-structure.provider.d.ts.map +1 -1
  7. package/dist/core/providers/sd-app-structure.provider.js +1 -252
  8. package/dist/core/providers/sd-app-structure.types.d.ts +52 -0
  9. package/dist/core/providers/sd-app-structure.types.d.ts.map +1 -0
  10. package/dist/core/providers/sd-app-structure.types.js +1 -0
  11. package/dist/core/providers/sd-app-structure.utils.d.ts +13 -0
  12. package/dist/core/providers/sd-app-structure.utils.d.ts.map +1 -0
  13. package/dist/core/providers/sd-app-structure.utils.js +250 -0
  14. package/dist/{ui/overlay/busy → core/providers}/sd-busy.provider.d.ts +1 -1
  15. package/dist/core/providers/sd-busy.provider.d.ts.map +1 -0
  16. package/dist/{ui/overlay/busy → core/providers}/sd-busy.provider.js +1 -1
  17. package/dist/core/providers/sd-print.provider.js +1 -1
  18. package/dist/core/providers/sd-service-client-factory.provider.js +1 -1
  19. package/dist/{ui/overlay/toast → core/providers}/sd-toast.provider.d.ts +1 -1
  20. package/dist/core/providers/sd-toast.provider.d.ts.map +1 -0
  21. package/dist/{ui/overlay/toast → core/providers}/sd-toast.provider.js +3 -3
  22. package/dist/core/types/select-modal-output-result.d.ts +8 -0
  23. package/dist/core/types/select-modal-output-result.d.ts.map +1 -0
  24. package/dist/core/types/select-modal-output-result.js +1 -0
  25. package/dist/core/utils/setups/setupCanDeactivate.js +1 -1
  26. package/dist/core/utils/useViewTitleSignal.js +1 -1
  27. package/dist/core/utils/useViewTypeSignal.js +1 -1
  28. package/dist/features/base/sd-base-container.control.js +1 -1
  29. package/dist/features/data-view/sd-data-detail.control.js +1 -1
  30. package/dist/features/data-view/sd-data-sheet.control.d.ts +24 -37
  31. package/dist/features/data-view/sd-data-sheet.control.d.ts.map +1 -1
  32. package/dist/features/data-view/sd-data-sheet.control.js +98 -152
  33. package/dist/features/data-view/sd-data-sheet.types.d.ts +17 -0
  34. package/dist/features/data-view/sd-data-sheet.types.d.ts.map +1 -0
  35. package/dist/features/data-view/sd-data-sheet.types.js +1 -0
  36. package/dist/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.d.ts +1 -1
  37. package/dist/features/data-view/setupCloserWhenSingleSelectionChange.d.ts.map +1 -0
  38. package/dist/features/data-view/useDataSheetExcelManager.d.ts +14 -0
  39. package/dist/features/data-view/useDataSheetExcelManager.d.ts.map +1 -0
  40. package/dist/features/data-view/useDataSheetExcelManager.js +31 -0
  41. package/dist/features/data-view/useDataSheetFilterManager.d.ts +13 -0
  42. package/dist/features/data-view/useDataSheetFilterManager.d.ts.map +1 -0
  43. package/dist/features/data-view/useDataSheetFilterManager.js +22 -0
  44. package/dist/features/data-view/useDataSheetInlineEditManager.d.ts +26 -0
  45. package/dist/features/data-view/useDataSheetInlineEditManager.d.ts.map +1 -0
  46. package/dist/features/data-view/useDataSheetInlineEditManager.js +54 -0
  47. package/dist/features/data-view/useDataSheetModalEditManager.d.ts +19 -0
  48. package/dist/features/data-view/useDataSheetModalEditManager.d.ts.map +1 -0
  49. package/dist/features/data-view/useDataSheetModalEditManager.js +44 -0
  50. package/dist/features/data-view/useDataSheetRefreshManager.d.ts +25 -0
  51. package/dist/features/data-view/useDataSheetRefreshManager.d.ts.map +1 -0
  52. package/dist/features/data-view/useDataSheetRefreshManager.js +50 -0
  53. package/dist/features/permission-table/sd-permission-table.control.d.ts +1 -1
  54. package/dist/features/permission-table/sd-permission-table.control.d.ts.map +1 -1
  55. package/dist/index.d.ts +12 -6
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +10 -5
  58. package/dist/ui/data/sheet/sd-sheet.control.d.ts +22 -30
  59. package/dist/ui/data/sheet/sd-sheet.control.d.ts.map +1 -1
  60. package/dist/ui/data/sheet/sd-sheet.control.js +52 -210
  61. package/dist/ui/data/sheet/useSheetCellStyling.d.ts +22 -0
  62. package/dist/ui/data/sheet/useSheetCellStyling.d.ts.map +1 -0
  63. package/dist/ui/data/sheet/useSheetCellStyling.js +95 -0
  64. package/dist/ui/data/sheet/useSheetColumnResizing.d.ts +17 -0
  65. package/dist/ui/data/sheet/useSheetColumnResizing.d.ts.map +1 -0
  66. package/dist/ui/data/sheet/useSheetColumnResizing.js +65 -0
  67. package/dist/ui/data/sheet/useSheetDisplayPipeline.d.ts +24 -0
  68. package/dist/ui/data/sheet/useSheetDisplayPipeline.d.ts.map +1 -0
  69. package/dist/ui/data/sheet/useSheetDisplayPipeline.js +52 -0
  70. package/dist/ui/form/button/sd-modal-select-button.control.d.ts +1 -7
  71. package/dist/ui/form/button/sd-modal-select-button.control.d.ts.map +1 -1
  72. package/dist/ui/form/button/sd-modal-select-button.control.js +1 -1
  73. package/dist/ui/form/choice/sd-state-preset.control.js +1 -1
  74. package/dist/ui/navigation/menu-utils.d.ts +2 -7
  75. package/dist/ui/navigation/menu-utils.d.ts.map +1 -1
  76. package/dist/ui/overlay/busy/sd-busy-container.control.d.ts +1 -1
  77. package/dist/ui/overlay/busy/sd-busy-container.control.d.ts.map +1 -1
  78. package/dist/ui/overlay/busy/sd-busy-container.control.js +1 -1
  79. package/dist/ui/overlay/modal/sd-modal.control.js +1 -1
  80. package/dist/ui/overlay/modal/sd-modal.provider.d.ts +0 -10
  81. package/dist/ui/overlay/modal/sd-modal.provider.d.ts.map +1 -1
  82. package/dist/ui/overlay/modal/sd-modal.provider.js +1 -13
  83. package/dist/ui/overlay/toast/sd-toast.control.d.ts +1 -1
  84. package/dist/ui/overlay/toast/sd-toast.control.d.ts.map +1 -1
  85. package/package.json +5 -5
  86. package/src/core/provideSdAngular.ts +1 -1
  87. package/src/core/providers/sd-activated-modal.provider.ts +12 -0
  88. package/src/core/providers/sd-app-structure.provider.ts +2 -405
  89. package/src/core/providers/sd-app-structure.types.ts +60 -0
  90. package/src/core/providers/sd-app-structure.utils.ts +350 -0
  91. package/src/{ui/overlay/busy → core/providers}/sd-busy.provider.ts +1 -1
  92. package/src/core/providers/sd-print.provider.ts +1 -1
  93. package/src/core/providers/sd-service-client-factory.provider.ts +1 -1
  94. package/src/{ui/overlay/toast → core/providers}/sd-toast.provider.ts +4 -4
  95. package/src/core/types/select-modal-output-result.ts +7 -0
  96. package/src/core/utils/setups/setupCanDeactivate.ts +1 -1
  97. package/src/core/utils/useViewTitleSignal.ts +1 -1
  98. package/src/core/utils/useViewTypeSignal.ts +1 -1
  99. package/src/features/base/sd-base-container.control.ts +1 -1
  100. package/src/features/data-view/sd-data-detail.control.ts +1 -1
  101. package/src/features/data-view/sd-data-sheet.control.ts +117 -216
  102. package/src/features/data-view/sd-data-sheet.types.ts +18 -0
  103. package/src/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.ts +1 -1
  104. package/src/features/data-view/useDataSheetExcelManager.ts +57 -0
  105. package/src/features/data-view/useDataSheetFilterManager.ts +30 -0
  106. package/src/features/data-view/useDataSheetInlineEditManager.ts +89 -0
  107. package/src/features/data-view/useDataSheetModalEditManager.ts +76 -0
  108. package/src/features/data-view/useDataSheetRefreshManager.ts +90 -0
  109. package/src/features/permission-table/sd-permission-table.control.ts +1 -1
  110. package/src/index.ts +17 -11
  111. package/src/ui/data/sheet/sd-sheet.control.ts +50 -238
  112. package/src/ui/data/sheet/useSheetCellStyling.ts +113 -0
  113. package/src/ui/data/sheet/useSheetColumnResizing.ts +92 -0
  114. package/src/ui/data/sheet/useSheetDisplayPipeline.ts +64 -0
  115. package/src/ui/form/button/sd-modal-select-button.control.ts +1 -8
  116. package/src/ui/form/choice/sd-state-preset.control.ts +1 -1
  117. package/src/ui/navigation/menu-utils.ts +3 -7
  118. package/src/ui/overlay/busy/sd-busy-container.control.ts +1 -1
  119. package/src/ui/overlay/modal/sd-modal.control.ts +1 -1
  120. package/src/ui/overlay/modal/sd-modal.provider.ts +1 -10
  121. package/src/ui/overlay/toast/sd-toast.control.ts +1 -1
  122. package/dist/core/utils/setups/setupCloserWhenSingleSelectionChange.d.ts.map +0 -1
  123. package/dist/ui/overlay/busy/sd-busy.provider.d.ts.map +0 -1
  124. package/dist/ui/overlay/toast/sd-toast.provider.d.ts.map +0 -1
  125. /package/dist/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.js +0 -0
@@ -1,6 +1,7 @@
1
1
  import { type InputSignal } from "@angular/core";
2
2
  import { type ISdModal, type ISdModalInfo, type ISdModalOptions } from "../../overlay/modal/sd-modal.provider";
3
3
  import type { TSelectModeValue } from "../select/sd-select.control";
4
+ import type { ISelectModalOutputResult } from "../../../core/types/select-modal-output-result";
4
5
  import * as i0 from "@angular/core";
5
6
  /**
6
7
  * 모달 선택 컴포넌트가 구현해야 하는 인터페이스
@@ -10,13 +11,6 @@ export interface ISdSelectModal<T> extends ISdModal<ISelectModalOutputResult<T>>
10
11
  selectMode: InputSignal<"single" | "multi" | undefined>;
11
12
  selectedItemKeys: InputSignal<any[]>;
12
13
  }
13
- /**
14
- * 모달 선택 결과
15
- */
16
- export interface ISelectModalOutputResult<T> {
17
- selectedItemKeys: any[];
18
- selectedItems: T[];
19
- }
20
14
  /**
21
15
  * 모달 선택 정보 (selectMode/selectedItemKeys를 제외한 inputs)
22
16
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sd-modal-select-button.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/form/button/sd-modal-select-button.control.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAEjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;;AAOpE;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAC9E,UAAU,EAAE,WAAW,CAAC,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACxD,gBAAgB,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACxB,aAAa,EAAE,CAAC,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,IAAI,YAAY,CAC1E,CAAC,EACD,YAAY,GAAG,kBAAkB,CAClC,CAAC;AAEF,qBAuGa,0BAA0B,CACrC,CAAC,SAAS,MAAM,EAChB,CAAC,EACD,CAAC,SAAS,MAAM,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,gBAAgB,CAAC,CAAC,CAAC;IAE/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAEpD,KAAK,qDAA2D;IAEhE,KAAK,0EAAmC;IACxC,aAAa,2CAAkB;IAE/B,QAAQ,qEAAiD;IACzD,QAAQ,qEAAiD;IACzD,KAAK,qEAAiD;IACtD,IAAI,uCAAwB;IAC5B,UAAU,iBAA2B;IACrC,YAAY,2CAA4B;IAExC,UAAU,sBAAuB;IAEjC,SAAS,CAAC,QAAQ,CAAC,YAAY,obAAgB;IAE/C,SAAS,0CAKN;;IAYH,YAAY,IAAI,IAAI;IAKd,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;yCA7CzB,0BAA0B;2CAA1B,0BAA0B;CAkEtC"}
1
+ {"version":3,"file":"sd-modal-select-button.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/form/button/sd-modal-select-button.control.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAEjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAIpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAC;;AAI/F;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAC9E,UAAU,EAAE,WAAW,CAAC,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACxD,gBAAgB,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,IAAI,YAAY,CAC1E,CAAC,EACD,YAAY,GAAG,kBAAkB,CAClC,CAAC;AAEF,qBAuGa,0BAA0B,CACrC,CAAC,SAAS,MAAM,EAChB,CAAC,EACD,CAAC,SAAS,MAAM,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,gBAAgB,CAAC,CAAC,CAAC;IAE/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAEpD,KAAK,qDAA2D;IAEhE,KAAK,0EAAmC;IACxC,aAAa,2CAAkB;IAE/B,QAAQ,qEAAiD;IACzD,QAAQ,qEAAiD;IACzD,KAAK,qEAAiD;IACtD,IAAI,uCAAwB;IAC5B,UAAU,iBAA2B;IACrC,YAAY,2CAA4B;IAExC,UAAU,sBAAuB;IAEjC,SAAS,CAAC,QAAQ,CAAC,YAAY,obAAgB;IAE/C,SAAS,0CAKN;;IAYH,YAAY,IAAI,IAAI;IAKd,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;yCA7CzB,0BAA0B;2CAA1B,0BAA0B;CAkEtC"}
@@ -129,4 +129,4 @@ export class SdModalSelectButtonControl {
129
129
  "[attr.data-sd-disabled]": "disabled()",
130
130
  }, styles: ["sd-modal-select-button {\n display: flex;\n flex-direction: row;\n gap: var(--gap-sm);\n position: relative;\n border: 1px solid var(--trans-light);\n border-radius: var(--border-radius-default);\n overflow: hidden;\n}\nsd-modal-select-button > ._content {\n flex: 1;\n padding: var(--gap-sm) var(--gap-default);\n}\nsd-modal-select-button > ._button {\n display: flex;\n flex-wrap: nowrap;\n flex-direction: row;\n}\n@supports not (appearance: auto) {\n sd-modal-select-button > ._button.gap-xxs {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-xxs > * + * {\n margin-left: var(--gap-xxs);\n }\n sd-modal-select-button > ._button.gap-xs {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-xs > * + * {\n margin-left: var(--gap-xs);\n }\n sd-modal-select-button > ._button.gap-sm {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-sm > * + * {\n margin-left: var(--gap-sm);\n }\n sd-modal-select-button > ._button.gap-default {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-default > * + * {\n margin-left: var(--gap-default);\n }\n sd-modal-select-button > ._button.gap-lg {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-lg > * + * {\n margin-left: var(--gap-lg);\n }\n sd-modal-select-button > ._button.gap-xl {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-xl > * + * {\n margin-left: var(--gap-xl);\n }\n sd-modal-select-button > ._button.gap-xxl {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-xxl > * + * {\n margin-left: var(--gap-xxl);\n }\n sd-modal-select-button > ._button.gap-0 {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-0 > * + * {\n margin-left: var(--gap-0);\n }\n sd-modal-select-button > ._button.gap-auto {\n gap: 0;\n }\n sd-modal-select-button > ._button.gap-auto > * + * {\n margin-left: var(--gap-auto);\n }\n}\nsd-modal-select-button > ._button > sd-anchor {\n padding: var(--gap-sm) !important;\n}\nsd-modal-select-button > ._button > sd-button > button {\n border-left: 1px solid var(--trans-lighter) !important;\n padding: var(--gap-sm) !important;\n height: 100%;\n}\nsd-modal-select-button[data-sd-inset=true] {\n border-radius: 0;\n border: none;\n}\nsd-modal-select-button[data-sd-size=sm] > ._content {\n padding: var(--gap-xs) var(--gap-default);\n}\nsd-modal-select-button[data-sd-size=sm] > ._button > sd-anchor {\n padding: var(--gap-xs) var(--gap-sm) !important;\n}\nsd-modal-select-button[data-sd-size=sm] > ._button > sd-button > button {\n padding: var(--gap-xs) var(--gap-sm) !important;\n}\nsd-modal-select-button[data-sd-size=lg] > ._content {\n padding: var(--gap-default) var(--gap-xl);\n}\nsd-modal-select-button[data-sd-size=lg] > ._button > sd-anchor {\n padding: var(--gap-default) !important;\n}\nsd-modal-select-button[data-sd-size=lg] > ._button > sd-button > button {\n padding: var(--gap-default) !important;\n}"] }]
131
131
  }], () => [], { modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], selectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItems", required: false }] }, { type: i0.Output, args: ["selectedItemsChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], inset: [{ type: i0.Input, args: [{ isSignal: true, alias: "inset", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], selectMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectMode", required: false }] }], modalOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOptions", required: false }] }], searchIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchIcon", required: false }] }] }); })();
132
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdModalSelectButtonControl, { className: "SdModalSelectButtonControl", filePath: "packages/angular/src/ui/form/button/sd-modal-select-button.control.ts", lineNumber: 153, forbidOrphanRendering: true }); })();
132
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdModalSelectButtonControl, { className: "SdModalSelectButtonControl", filePath: "packages/angular/src/ui/form/button/sd-modal-select-button.control.ts", lineNumber: 146, forbidOrphanRendering: true }); })();
@@ -1,6 +1,6 @@
1
1
  import { ChangeDetectionStrategy, Component, computed, inject, input, model, ViewEncapsulation, } from "@angular/core";
2
2
  import { SdModalProvider } from "../../overlay/modal/sd-modal.provider";
3
- import { SdToastProvider } from "../../overlay/toast/sd-toast.provider";
3
+ import { SdToastProvider } from "../../../core/providers/sd-toast.provider";
4
4
  import { SdPromptModalControl } from "../../overlay/modal/sd-prompt-modal.control";
5
5
  import { SdConfirmModalControl } from "../../overlay/modal/sd-confirm-modal.control";
6
6
  import { useSdSystemConfigResource } from "../../../core/utils/useSdSystemConfigResource";
@@ -1,10 +1,5 @@
1
- export interface ISdMenu {
2
- title: string;
3
- codeChain: string[];
4
- url?: string;
5
- icon?: string;
6
- children?: ISdMenu[];
7
- }
1
+ import type { ISdMenu } from "../../core/providers/sd-app-structure.types";
2
+ export type { ISdMenu } from "../../core/providers/sd-app-structure.types";
8
3
  export declare function getMenuRouterLinkOption(menu: ISdMenu): {
9
4
  link: string;
10
5
  queryParams: Record<string, string> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"menu-utils.d.ts","sourceRoot":"","sources":["../../../src/ui/navigation/menu-utils.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAiB/E;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GACpC,OAAO,CAET"}
1
+ {"version":3,"file":"menu-utils.d.ts","sourceRoot":"","sources":["../../../src/ui/navigation/menu-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6CAA6C,CAAC;AAE3E,YAAY,EAAE,OAAO,EAAE,MAAM,6CAA6C,CAAC;AAE3E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAiB/E;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GACpC,OAAO,CAET"}
@@ -1,4 +1,4 @@
1
- import { type TSdBusyType } from "./sd-busy.provider";
1
+ import { type TSdBusyType } from "../../../core/providers/sd-busy.provider";
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SdBusyContainerControl {
4
4
  private readonly _sdBusy;
@@ -1 +1 @@
1
- {"version":3,"file":"sd-busy-container.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/busy/sd-busy-container.control.ts"],"names":[],"mappings":"AAUA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;;AAEtE,qBA+Ma,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,IAAI,qEAAiD;IACrD,OAAO,0DAAwC;IAC/C,IAAI,+DAA6C;IACjD,eAAe,0DAAwC;IAEvD,QAAQ,8CAAsD;;yCARnD,sBAAsB;2CAAtB,sBAAsB;CAuBlC"}
1
+ {"version":3,"file":"sd-busy-container.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/busy/sd-busy-container.control.ts"],"names":[],"mappings":"AAUA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,0CAA0C,CAAC;;AAE5F,qBA+Ma,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,IAAI,qEAAiD;IACrD,OAAO,0DAAwC;IAC/C,IAAI,+DAA6C;IACjD,eAAe,0DAAwC;IAEvD,QAAQ,8CAAsD;;yCARnD,sBAAsB;2CAAtB,sBAAsB;CAuBlC"}
@@ -1,5 +1,5 @@
1
1
  import { booleanAttribute, ChangeDetectionStrategy, Component, computed, ElementRef, inject, input, ViewEncapsulation, } from "@angular/core";
2
- import { SdBusyProvider } from "./sd-busy.provider";
2
+ import { SdBusyProvider } from "../../../core/providers/sd-busy.provider";
3
3
  import * as i0 from "@angular/core";
4
4
  const _c0 = ["*"];
5
5
  function SdBusyContainerControl_Conditional_0_Case_3_Template(rf, ctx) { if (rf & 1) {
@@ -1,7 +1,7 @@
1
1
  import { ChangeDetectionStrategy, Component, DestroyRef, effect, ElementRef, inject, input, model, output, ViewEncapsulation, } from "@angular/core";
2
2
  import { isTabbable } from "tabbable";
3
3
  import { NgTemplateOutlet } from "@angular/common";
4
- import { SdActivatedModalProvider } from "./sd-modal.provider";
4
+ import { SdActivatedModalProvider } from "../../../core/providers/sd-activated-modal.provider";
5
5
  import { SdSystemConfigProvider } from "../../../core/providers/sd-system-config.provider";
6
6
  import "@simplysm/core-browser";
7
7
  import * as i0 from "@angular/core";
@@ -44,16 +44,6 @@ export interface ISdModalOptions {
44
44
  headerStyle?: string;
45
45
  noFirstControlFocusing?: boolean;
46
46
  }
47
- /**
48
- * 모달 내부에서 inject하여 사용하는 프로바이더
49
- */
50
- export declare class SdActivatedModalProvider<T extends ISdModal<any> = ISdModal<any>> {
51
- modalComponent: import("@angular/core").WritableSignal<any>;
52
- contentComponent: import("@angular/core").WritableSignal<T | undefined>;
53
- canDeactiveFn: () => boolean;
54
- static ɵfac: i0.ɵɵFactoryDeclaration<SdActivatedModalProvider<any>, never>;
55
- static ɵprov: i0.ɵɵInjectableDeclaration<SdActivatedModalProvider<any>>;
56
- }
57
47
  /**
58
48
  * 모달을 프로그래밍 방식으로 생성하는 프로바이더
59
49
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sd-modal.provider.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/modal/sd-modal.provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sd-modal.provider.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/modal/sd-modal.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,IAAI,EACV,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EACV,sBAAsB,EACtB,aAAa,EACd,MAAM,4CAA4C,CAAC;AAGpD,OAAO,wBAAwB,CAAC;;AAEhC;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,KAAK,EAAE,gBAAgB,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;IAChC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED,KAAK,mBAAmB,GAAG,aAAa,GAAG,OAAO,GAAG,cAAc,GAAG,sBAAsB,CAAC;AAC7F,KAAK,oBAAoB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,SAAS,MAAM,CAAA;CAAE,GACtF,CAAC,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,GAAG,EAAE;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,MAAM,EAAE,aAAa,CACnB,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,mBAAmB,GAAG,CAAC,CAAC,EACxD,oBAAoB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,mBAAmB,GAAG,CAAC,CAAC,CACzF,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;GAEG;AACH,qBACa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAC5D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAE9C,UAAU,iDAAa;IAEjB,SAAS,CAAC,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EACrC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAmJzD,OAAO,CAAC,aAAa;yCA7JV,eAAe;6CAAf,eAAe;CAwK3B"}
@@ -2,21 +2,9 @@ import { ApplicationRef, createComponent, EnvironmentInjector, inject, Injectabl
2
2
  import { outputToObservable } from "@angular/core/rxjs-interop";
3
3
  import { Subscription } from "rxjs";
4
4
  import { SdModalControl } from "./sd-modal.control";
5
+ import { SdActivatedModalProvider } from "../../../core/providers/sd-activated-modal.provider";
5
6
  import "@simplysm/core-browser";
6
7
  import * as i0 from "@angular/core";
7
- /**
8
- * 모달 내부에서 inject하여 사용하는 프로바이더
9
- */
10
- export class SdActivatedModalProvider {
11
- modalComponent = signal(undefined, ...(ngDevMode ? [{ debugName: "modalComponent" }] : /* istanbul ignore next */ []));
12
- contentComponent = signal(undefined, ...(ngDevMode ? [{ debugName: "contentComponent" }] : /* istanbul ignore next */ []));
13
- canDeactiveFn = () => true;
14
- static ɵfac = function SdActivatedModalProvider_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdActivatedModalProvider)(); };
15
- static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: SdActivatedModalProvider, factory: SdActivatedModalProvider.ɵfac });
16
- }
17
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SdActivatedModalProvider, [{
18
- type: Injectable
19
- }], null, null); })();
20
8
  /**
21
9
  * 모달을 프로그래밍 방식으로 생성하는 프로바이더
22
10
  */
@@ -1,4 +1,4 @@
1
- import type { TSdToastTheme } from "./sd-toast.provider";
1
+ import type { TSdToastTheme } from "../../../core/providers/sd-toast.provider";
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SdToastControl {
4
4
  open: import("@angular/core").ModelSignal<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"sd-toast.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/toast/sd-toast.control.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;;AAKzD,qBAwFa,cAAc;IACzB,IAAI,+CAAgB;IACpB,WAAW,qEAAiD;IAC5D,KAAK,qDAAgC;IACrC,QAAQ,8CAAY;IACpB,OAAO,0DAAwC;IAE/C,QAAQ,iEAKL;IAEH,QAAQ,qEAKL;yCAnBQ,cAAc;2CAAd,cAAc;CAoB1B"}
1
+ {"version":3,"file":"sd-toast.control.d.ts","sourceRoot":"","sources":["../../../../src/ui/overlay/toast/sd-toast.control.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;;AAK/E,qBAwFa,cAAc;IACzB,IAAI,+CAAgB;IACpB,WAAW,qEAAiD;IAC5D,KAAK,qDAAgC;IACrC,QAAQ,8CAAY;IACpB,OAAO,0DAAwC;IAE/C,QAAQ,iEAKL;IAEH,QAAQ,qEAKL;yCAnBQ,cAAc;2CAAd,cAAc;CAoB1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/angular",
3
- "version": "14.0.19",
3
+ "version": "14.0.21",
4
4
  "description": "심플리즘 패키지 - Angular",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -50,10 +50,10 @@
50
50
  "jspdf": "^4.2.1",
51
51
  "rxjs": "^7.8.2",
52
52
  "tabbable": "^6.4.0",
53
- "@simplysm/core-common": "14.0.19",
54
- "@simplysm/core-browser": "14.0.19",
55
- "@simplysm/service-client": "14.0.19",
56
- "@simplysm/service-common": "14.0.19"
53
+ "@simplysm/core-browser": "14.0.21",
54
+ "@simplysm/core-common": "14.0.21",
55
+ "@simplysm/service-client": "14.0.21",
56
+ "@simplysm/service-common": "14.0.21"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@angular/compiler": "^21.2.7",
@@ -22,7 +22,7 @@ import {
22
22
  } from "@angular/router";
23
23
  import { SwUpdate } from "@angular/service-worker";
24
24
  import { provideNgIconsConfig } from "@ng-icons/core";
25
- import { SdBusyProvider } from "../ui/overlay/busy/sd-busy.provider";
25
+ import { SdBusyProvider } from "./providers/sd-busy.provider";
26
26
  import { SdAngularConfigProvider } from "./providers/sd-angular-config.provider";
27
27
  import { SdThemeProvider } from "./providers/sd-theme-provider";
28
28
  import { SdLocalStorageProvider } from "./providers/sd-local-storage.provider";
@@ -0,0 +1,12 @@
1
+ import { Injectable, signal } from "@angular/core";
2
+ import type { ISdModal } from "../../ui/overlay/modal/sd-modal.provider";
3
+
4
+ /**
5
+ * 모달 내부에서 inject하여 사용하는 프로바이더
6
+ */
7
+ @Injectable()
8
+ export class SdActivatedModalProvider<T extends ISdModal<any> = ISdModal<any>> {
9
+ modalComponent = signal<any>(undefined);
10
+ contentComponent = signal<T | undefined>(undefined);
11
+ canDeactiveFn: () => boolean = () => true;
12
+ }
@@ -1,5 +1,7 @@
1
1
  import { computed, inject, Injectable } from "@angular/core";
2
2
  import type { Signal } from "@angular/core";
3
+ import type { TSdAppStructureItem, ISdFlatMenu } from "./sd-app-structure.types";
4
+ import { SdAppStructureUtils } from "./sd-app-structure.utils";
3
5
 
4
6
  export function usePermsSignal<K extends string>(viewCodes: string[], keys: K[]): Signal<K[]> {
5
7
  const sdAppStructure = inject(SdAppStructureProvider);
@@ -42,408 +44,3 @@ export abstract class SdAppStructureProvider<TModule = unknown> {
42
44
  );
43
45
  }
44
46
  }
45
-
46
- export abstract class SdAppStructureUtils {
47
- //---------- Info
48
-
49
- static getTitleByFullCode<TModule>(items: TSdAppStructureItem<TModule>[], fullCode: string) {
50
- const itemChain = this.getItemChainByFullCode(items, fullCode);
51
- if (itemChain.length === 0) {
52
- throw new Error(`Item not found for fullCode: ${fullCode}`);
53
- }
54
- const parent = itemChain
55
- .slice(0, -1)
56
- .map((item) => item.title)
57
- .join(" > ");
58
- const current = itemChain.last()!.title;
59
- return (parent ? `[${parent}] ` : "") + current;
60
- }
61
-
62
- static getPermsByFullCode<TModule, K extends string>(
63
- items: TSdAppStructureItem<TModule>[],
64
- fullCodes: string[],
65
- permKeys: K[],
66
- permRecord: Record<string, boolean> | undefined,
67
- ): K[] {
68
- if (permRecord === undefined) return [] as K[];
69
-
70
- const result = [] as K[];
71
- for (const permKey of permKeys) {
72
- // 해당 권한이 설정되어있거나
73
- if (fullCodes.some((fullCode) => permRecord[fullCode + "." + permKey])) {
74
- result.push(permKey);
75
- }
76
- // 권한이라는것이 아얘 존재하지 않거나
77
- else if (
78
- fullCodes.every((fullCode) => {
79
- const item = this.getItemChainByFullCode(items, fullCode).last();
80
- return item != null && !("perms" in item);
81
- })
82
- ) {
83
- result.push(permKey);
84
- }
85
- }
86
-
87
- return result;
88
- }
89
-
90
- static getItemChainByFullCode<TModule>(
91
- items: TSdAppStructureItem<TModule>[],
92
- fullCode: string,
93
- ): TSdAppStructureItem<TModule>[] {
94
- const codeChain = fullCode.split(".");
95
-
96
- const result: TSdAppStructureItem<TModule>[] = [];
97
-
98
- let cursorChildren = items;
99
- for (const currCode of codeChain) {
100
- const cursor = cursorChildren.single((item) => item.code === currCode);
101
- if (cursor == null) return [];
102
- cursorChildren = "children" in cursor ? cursor.children : [];
103
- result.push(cursor);
104
- }
105
-
106
- return result;
107
- }
108
-
109
- //---------- Menus
110
-
111
- static getMenus<TModule>(
112
- items: TSdAppStructureItem<TModule>[],
113
- codeChain: string[],
114
- usableModules: TModule[] | undefined,
115
- permRecord: Record<string, boolean> | undefined,
116
- ): ISdMenu<TModule>[] {
117
- const resultMenus: ISdMenu<TModule>[] = [];
118
-
119
- for (const item of items) {
120
- if ("isNotMenu" in item && item.isNotMenu) continue;
121
-
122
- const currCodeChain = [...codeChain, item.code];
123
-
124
- // 모듈 활성화 여부 확인
125
- if (!this._isUsableModules(item.modules, item.requiredModules, usableModules)) continue;
126
-
127
- // 그룹 메뉴
128
- if ("children" in item) {
129
- const children = this.getMenus(item.children, currCodeChain, usableModules, permRecord);
130
-
131
- // 자식 중 표시 가능한 게 있으면 그룹 메뉴 포함
132
- if (children.length > 0) {
133
- resultMenus.push({
134
- title: item.title,
135
- icon: item.icon,
136
- codeChain: currCodeChain,
137
- modules: item.modules,
138
- children,
139
- });
140
- }
141
- }
142
- // Leaf 메뉴
143
- else {
144
- const code = currCodeChain.join(".");
145
-
146
- if (item.perms != null && !permRecord?.[code + ".use"]) continue;
147
-
148
- resultMenus.push({
149
- title: item.title,
150
- icon: item.icon,
151
- codeChain: currCodeChain,
152
- modules: item.modules,
153
- children: undefined,
154
- });
155
- }
156
- }
157
-
158
- return resultMenus;
159
- }
160
-
161
- static getFlatMenus<TModule>(
162
- items: TSdAppStructureItem<TModule>[],
163
- usableModules: TModule[] | undefined,
164
- permRecord: Record<string, boolean> | undefined,
165
- ): ISdFlatMenu<TModule>[] {
166
- const resultFlatMenus: ISdFlatMenu<TModule>[] = [];
167
-
168
- type QueueItem = {
169
- item: TSdAppStructureItem<TModule>;
170
- titleChain: string[];
171
- codeChain: string[];
172
- modulesChain: TModule[][];
173
- requiredModulesChain: TModule[][];
174
- };
175
-
176
- const queue: QueueItem[] = items.map((item) => ({
177
- item,
178
- titleChain: [],
179
- codeChain: [],
180
- modulesChain: [],
181
- requiredModulesChain: [],
182
- }));
183
-
184
- while (queue.length > 0) {
185
- const { item, titleChain, codeChain, modulesChain, requiredModulesChain } = queue.shift()!;
186
-
187
- if ("isNotMenu" in item && item.isNotMenu) continue;
188
-
189
- const currTitleChain = [...titleChain, item.title];
190
- const currCodeChain = [...codeChain, item.code];
191
- const currModulesChain = item.modules ? [...modulesChain, item.modules] : modulesChain;
192
- const currRequiredModulesChain = item.requiredModules
193
- ? [...requiredModulesChain, item.requiredModules]
194
- : requiredModulesChain;
195
-
196
- if (!this._isUsableModulesChain(currModulesChain, currRequiredModulesChain, usableModules))
197
- continue;
198
-
199
- if ("children" in item) {
200
- for (const child of item.children) {
201
- queue.push({
202
- item: child,
203
- titleChain: currTitleChain,
204
- codeChain: currCodeChain,
205
- modulesChain: currModulesChain,
206
- requiredModulesChain: currRequiredModulesChain,
207
- });
208
- }
209
- } else if (item.perms == null || Boolean(permRecord?.[currCodeChain.join(".") + ".use"])) {
210
- resultFlatMenus.push({
211
- titleChain: currTitleChain,
212
- codeChain: currCodeChain,
213
- modulesChain: currModulesChain,
214
- });
215
- }
216
- }
217
-
218
- return resultFlatMenus;
219
- }
220
-
221
- //---------- Perms
222
-
223
- static getPermissions<TModule>(
224
- items: TSdAppStructureItem<TModule>[],
225
- codeChain: string[],
226
- usableModules: TModule[] | undefined,
227
- ): ISdPermission<TModule>[] {
228
- const results: ISdPermission<TModule>[] = [];
229
- for (const item of items) {
230
- const currCodeChain = [...codeChain, item.code];
231
-
232
- // 모듈 활성화 여부 확인
233
- if (!this._isUsableModules(item.modules, item.requiredModules, usableModules)) continue;
234
-
235
- // 그룹
236
- if ("children" in item) {
237
- const children = this.getPermissions(item.children, currCodeChain, usableModules);
238
-
239
- results.push({
240
- title: item.title,
241
- codeChain: currCodeChain,
242
- modules: item.modules,
243
- perms: undefined,
244
- children: children,
245
- });
246
- }
247
- // Leaf
248
- else {
249
- results.push({
250
- title: item.title,
251
- codeChain: currCodeChain,
252
- perms: item.perms,
253
- modules: item.modules,
254
- children: item.subPerms?.map((subPerm) => ({
255
- title: subPerm.title,
256
- codeChain: [...currCodeChain, subPerm.code],
257
- perms: subPerm.perms,
258
- modules: subPerm.modules,
259
- children: undefined,
260
- })),
261
- });
262
- }
263
- }
264
-
265
- return results;
266
- }
267
-
268
- static getFlatPermissions<TModule>(
269
- items: TSdAppStructureItem<TModule>[],
270
- usableModules: TModule[] | undefined,
271
- ) {
272
- const results: ISdFlatPermission<TModule>[] = [];
273
-
274
- type QueueItem = {
275
- item: TSdAppStructureItem<TModule>;
276
- titleChain: string[];
277
- codeChain: string[];
278
- modulesChain: TModule[][];
279
- requiredModulesChain: TModule[][];
280
- };
281
-
282
- const queue: QueueItem[] = items.map((item) => ({
283
- item,
284
- titleChain: [],
285
- codeChain: [],
286
- modulesChain: [],
287
- requiredModulesChain: [],
288
- }));
289
-
290
- while (queue.length > 0) {
291
- const { item, titleChain, codeChain, modulesChain, requiredModulesChain } = queue.shift()!;
292
-
293
- const currTitleChain = [...titleChain, item.title];
294
- const currCodeChain = [...codeChain, item.code];
295
- const currModulesChain = item.modules ? [...modulesChain, item.modules] : modulesChain;
296
- const currRequiredModulesChain = item.requiredModules
297
- ? [...requiredModulesChain, item.requiredModules]
298
- : requiredModulesChain;
299
-
300
- if (!this._isUsableModulesChain(currModulesChain, currRequiredModulesChain, usableModules))
301
- continue;
302
-
303
- // 1. 자식 enqueue
304
- if ("children" in item) {
305
- for (const child of item.children) {
306
- queue.push({
307
- item: child,
308
- titleChain: currTitleChain,
309
- codeChain: currCodeChain,
310
- modulesChain: currModulesChain,
311
- requiredModulesChain: currRequiredModulesChain,
312
- });
313
- }
314
- }
315
-
316
- // 1. 직접 perms 처리
317
- if ("perms" in item) {
318
- for (const perm of item.perms ?? []) {
319
- results.push({
320
- titleChain: currTitleChain,
321
- codeChain: [...currCodeChain, perm],
322
- modulesChain: currModulesChain,
323
- });
324
- }
325
- }
326
-
327
- // 2. subPerms 처리
328
- if ("subPerms" in item) {
329
- for (const subPerm of item.subPerms ?? []) {
330
- // subPerm도 모듈 체크
331
- if (!this._isUsableModules(subPerm.modules, subPerm.requiredModules, usableModules))
332
- continue;
333
-
334
- for (const perm of subPerm.perms) {
335
- results.push({
336
- titleChain: currTitleChain,
337
- codeChain: [...currCodeChain, subPerm.code, perm],
338
- modulesChain: [...currModulesChain, subPerm.modules ?? []],
339
- });
340
- }
341
- }
342
- }
343
- }
344
-
345
- return results;
346
- }
347
-
348
- //-- Modules (private)
349
-
350
- private static _isUsableModulesChain<TModule>(
351
- modulesChain: TModule[][],
352
- requiredModulesChain: TModule[][],
353
- usableModules: TModule[] | undefined,
354
- ) {
355
- // 각 레벨의 modules (OR) 체크
356
- for (const modules of modulesChain) {
357
- if (!this._isUsableModules(modules, undefined, usableModules)) {
358
- return false;
359
- }
360
- }
361
-
362
- // 각 레벨의 requiredModules (AND) 체크
363
- for (const requiredModules of requiredModulesChain) {
364
- if (!this._isUsableModules(undefined, requiredModules, usableModules)) {
365
- return false;
366
- }
367
- }
368
-
369
- return true;
370
- }
371
-
372
- private static _isUsableModules<TModule>(
373
- modules: TModule[] | undefined,
374
- requiredModules: TModule[] | undefined,
375
- usableModules: TModule[] | undefined,
376
- ): boolean {
377
- // 1. requiredModules: 모두 있어야 함 (AND)
378
- if (requiredModules && requiredModules.length > 0) {
379
- if (!requiredModules.every((m) => usableModules?.includes(m))) {
380
- return false;
381
- }
382
- }
383
-
384
- // 2. modules: 하나라도 있으면 됨 (OR)
385
- return (
386
- modules == null || modules.length === 0 || modules.some((m) => usableModules?.includes(m))
387
- );
388
- }
389
- }
390
-
391
- export type TSdAppStructureItem<TModule = unknown> =
392
- | ISdAppStructureGroupItem<TModule>
393
- | ISdAppStructureLeafItem<TModule>;
394
-
395
- interface ISdAppStructureGroupItem<TModule> {
396
- code: string;
397
- title: string;
398
- modules?: TModule[];
399
- requiredModules?: TModule[];
400
- icon?: string;
401
- children: TSdAppStructureItem<TModule>[];
402
- }
403
-
404
- interface ISdAppStructureLeafItem<TModule> {
405
- code: string;
406
- title: string;
407
- modules?: TModule[];
408
- requiredModules?: TModule[];
409
- perms?: ("use" | "edit")[];
410
- subPerms?: ISdAppStructureSubPermission<TModule>[];
411
- icon?: string;
412
- isNotMenu?: boolean;
413
- }
414
-
415
- interface ISdAppStructureSubPermission<TModule> {
416
- code: string;
417
- title: string;
418
- modules?: TModule[];
419
- requiredModules?: TModule[];
420
- perms: ("use" | "edit")[];
421
- }
422
-
423
- export interface ISdMenu<TModule = unknown> {
424
- title: string;
425
- codeChain: string[];
426
- icon: string | undefined;
427
- modules: TModule[] | undefined;
428
- children: ISdMenu<TModule>[] | undefined;
429
- }
430
-
431
- export interface ISdFlatMenu<TModule = unknown> {
432
- titleChain: string[];
433
- codeChain: string[];
434
- modulesChain: TModule[][];
435
- }
436
-
437
- export interface ISdPermission<TModule = unknown> {
438
- title: string;
439
- codeChain: string[];
440
- modules: TModule[] | undefined;
441
- perms: ("use" | "edit")[] | undefined;
442
- children: ISdPermission<TModule>[] | undefined;
443
- }
444
-
445
- export interface ISdFlatPermission<TModule = unknown> {
446
- titleChain: string[];
447
- codeChain: string[];
448
- modulesChain: TModule[][];
449
- }