@simplysm/angular 14.0.85 → 14.0.86

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.
@@ -4,12 +4,10 @@ import type { SdFlatMenu } from "./sd-app-structure.types";
4
4
  import * as i0 from "@angular/core";
5
5
  export declare function injectPermsSignal<K extends string>(viewCodes: string[], keys: K[]): Signal<K[]>;
6
6
  export declare class SdAppStructureProvider<TModule = unknown> {
7
- private readonly _sdServiceClientFactory;
8
- private readonly _sdAngularConfig;
9
7
  readonly usableModules: import("@angular/core").WritableSignal<TModule[] | undefined>;
10
8
  readonly permRecord: import("@angular/core").WritableSignal<Record<string, boolean> | undefined>;
11
9
  readonly items: import("@angular/core").WritableSignal<AppStructureItem<TModule>[]>;
12
- initialize(serviceKey: string): Promise<void>;
10
+ initialize(items: AppStructureItem<TModule>[]): void;
13
11
  usableMenus: Signal<import("./sd-app-structure.types").SdMenu[]>;
14
12
  usableFlatMenus: Signal<SdFlatMenu<TModule>[]>;
15
13
  getPermissionsByStructure(items: AppStructureItem<TModule>[], codeChain?: string[]): import("./sd-app-structure.types").SdPermission<TModule>[];
@@ -1 +1 @@
1
- {"version":3,"file":"sd-app-structure.provider.d.ts","sourceRoot":"","sources":["../../../src/core/app-structure/sd-app-structure.provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,0BAA0B,CAAC;AACtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;;AAK3D,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAG/F;AAID,qBACa,sBAAsB,CAAC,OAAO,GAAG,OAAO;IACnD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAA0C;IAClF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmC;IAEpE,QAAQ,CAAC,aAAa,gEAA4C;IAClE,QAAQ,CAAC,UAAU,8EAA0D;IAC7E,QAAQ,CAAC,KAAK,sEAA2C;IAEnD,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnD,WAAW,sDAET;IACF,eAAe,gCAEb;IAEF,yBAAyB,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,GAAE,MAAM,EAAO;IAItF,kBAAkB,CAAC,QAAQ,EAAE,MAAM;IAInC,sBAAsB,CAAC,QAAQ,EAAE,MAAM;IAIvC,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;yCApClE,sBAAsB;6CAAtB,sBAAsB;CA4ClC"}
1
+ {"version":3,"file":"sd-app-structure.provider.d.ts","sourceRoot":"","sources":["../../../src/core/app-structure/sd-app-structure.provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;;AAG3D,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAG/F;AAID,qBACa,sBAAsB,CAAC,OAAO,GAAG,OAAO;IACnD,QAAQ,CAAC,aAAa,gEAA4C;IAClE,QAAQ,CAAC,UAAU,8EAA0D;IAC7E,QAAQ,CAAC,KAAK,sEAA2C;IAEzD,UAAU,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI;IAIpD,WAAW,sDAET;IACF,eAAe,gCAEb;IAEF,yBAAyB,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,GAAE,MAAM,EAAO;IAItF,kBAAkB,CAAC,QAAQ,EAAE,MAAM;IAInC,sBAAsB,CAAC,QAAQ,EAAE,MAAM;IAIvC,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;yCA5BlE,sBAAsB;6CAAtB,sBAAsB;CAoClC"}
@@ -1,7 +1,5 @@
1
1
  import { computed, inject, Injectable, signal } from "@angular/core";
2
2
  import { SdAppStructureUtils } from "./sd-app-structure.utils";
3
- import { SdServiceClientFactoryProvider } from "../service-client/sd-service-client-factory.provider";
4
- import { SdAngularConfigProvider } from "../config/sd-angular-config.provider";
5
3
  import * as i0 from "@angular/core";
6
4
  export function injectPermsSignal(viewCodes, keys) {
7
5
  const sdAppStructure = inject(SdAppStructureProvider);
@@ -10,16 +8,11 @@ export function injectPermsSignal(viewCodes, keys) {
10
8
  // 권한은 모듈만 체크하고
11
9
  // 메뉴는 모듈/권한 모두 체크함
12
10
  export class SdAppStructureProvider {
13
- _sdServiceClientFactory = inject(SdServiceClientFactoryProvider);
14
- _sdAngularConfig = inject(SdAngularConfigProvider);
15
11
  usableModules = signal(undefined, ...(ngDevMode ? [{ debugName: "usableModules" }] : /* istanbul ignore next */ []));
16
12
  permRecord = signal(undefined, ...(ngDevMode ? [{ debugName: "permRecord" }] : /* istanbul ignore next */ []));
17
13
  items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
18
- async initialize(serviceKey) {
19
- const client = this._sdServiceClientFactory.get(serviceKey);
20
- const svc = client.getService("AppStructure");
21
- const itemsMap = await svc.getItems();
22
- this.items.set((itemsMap[this._sdAngularConfig.clientName] ?? []));
14
+ initialize(items) {
15
+ this.items.set(items);
23
16
  }
24
17
  usableMenus = computed(() => SdAppStructureUtils.getMenus(this.items(), [], this.usableModules(), this.permRecord()), ...(ngDevMode ? [{ debugName: "usableMenus" }] : /* istanbul ignore next */ []));
25
18
  usableFlatMenus = computed(() => SdAppStructureUtils.getFlatMenus(this.items(), this.usableModules(), this.permRecord()), ...(ngDevMode ? [{ debugName: "usableFlatMenus" }] : /* istanbul ignore next */ []));
@@ -61,7 +61,7 @@ export class SdSharedDataProvider {
61
61
  throw new Error(`등록되지 않은 공유 데이터: ${name}`);
62
62
  }
63
63
  const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
64
- const event = client.getEvent("SdSharedDataChange");
64
+ const event = client.getEvent(SdSharedDataChangeEvent);
65
65
  await event.emit((item) => item.name === name && obj.equal(item.filter, entry.info.filter), changeKeys);
66
66
  }
67
67
  async wait() {
@@ -82,7 +82,7 @@ export class SdSharedDataProvider {
82
82
  // 이벤트 리스너 등록
83
83
  if (entry.listenerKey == null) {
84
84
  const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
85
- const event = client.getEvent("SdSharedDataChange");
85
+ const event = client.getEvent(SdSharedDataChangeEvent);
86
86
  entry.listenerKey = await event.addListener({ name, filter: entry.info.filter }, async (changeKeys) => {
87
87
  await this._onEvent(name, entry, changeKeys, capturedGeneration);
88
88
  });
@@ -1 +1 @@
1
- {"version":3,"file":"sd-base-container.d.ts","sourceRoot":"","sources":["../../../src/data/crud/sd-base-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAGjB,MAAM,eAAe,CAAC;AAOvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;;AAK1E,qBAwDa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAEpD,SAAS,yCAA2B;IAEpC,KAAK,+CAAgB;IACrB,WAAW,+CAAgB;IAC3B,SAAS,8CAAY;IAErB,UAAU,+CAAgB;IAE1B,QAAQ,kDAAgC;IAExC,YAAY,gEAAgD;IAC5D,aAAa,gEAAiD;IAC9D,aAAa,gEAAiD;IAC9D,mBAAmB,gEAAuD;;IAoB1E,SAAS,CAAC,QAAQ,CAAC,mBAAmB,ifAAuB;yCArClD,eAAe;2CAAf,eAAe;CAsC3B"}
1
+ {"version":3,"file":"sd-base-container.d.ts","sourceRoot":"","sources":["../../../src/data/crud/sd-base-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAGjB,MAAM,eAAe,CAAC;AAOvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;;AAK1E,qBAwDa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAClF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAEpD,SAAS,yCAA2B;IAEpC,KAAK,+CAAgB;IACrB,WAAW,+CAAgB;IAC3B,SAAS,8CAAY;IAErB,UAAU,+CAAgB;IAE1B,QAAQ,kDAAgC;IAExC,YAAY,gEAAgD;IAC5D,aAAa,gEAAiD;IAC9D,aAAa,gEAAiD;IAC9D,mBAAmB,gEAAuD;;IAsB1E,SAAS,CAAC,QAAQ,CAAC,mBAAmB,ifAAuB;yCAvClD,eAAe;2CAAf,eAAe;CAwC3B"}
@@ -104,7 +104,7 @@ function SdBaseContainer_ng_template_2_Template(rf, ctx) { if (rf & 1) {
104
104
  i0.ɵɵconditional(ctx_r0.bottomCommandTplRef() ? 4 : -1);
105
105
  } }
106
106
  export class SdBaseContainer {
107
- _sdSharedData = inject(SdSharedDataProvider);
107
+ _sdSharedData = inject(SdSharedDataProvider, { optional: true });
108
108
  _sdToast = inject(SdToastProvider);
109
109
  viewTitle = injectViewTitleSignal();
110
110
  ready = model(false, ...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
@@ -123,11 +123,13 @@ export class SdBaseContainer {
123
123
  return;
124
124
  }
125
125
  void untracked(async () => {
126
- this.busyCount.update((v) => v + 1);
127
- await this._sdToast.try(async () => {
128
- await this._sdSharedData.wait();
129
- });
130
- this.busyCount.update((v) => v - 1);
126
+ if (this._sdSharedData) {
127
+ this.busyCount.update((v) => v + 1);
128
+ await this._sdToast.try(async () => {
129
+ await this._sdSharedData.wait();
130
+ });
131
+ this.busyCount.update((v) => v - 1);
132
+ }
131
133
  this.ready.set(true);
132
134
  });
133
135
  });
@@ -157,54 +159,54 @@ export class SdBaseContainer {
157
159
  encapsulation: ViewEncapsulation.None,
158
160
  standalone: true,
159
161
  imports: [SdBusyContainer, NgIcon, SdTopbarContainer, NgTemplateOutlet, SdTopbar],
160
- template: `
161
- <sd-busy-container [busy]="initialized() && busyCount() > 0">
162
- @if (initialized()) {
163
- @if (restricted()) {
164
- <div class="fill tx-theme-gray-light p-xxl tx-center">
165
- <br />
166
- <ng-icon [svg]="tablerAlertTriangle" [size]="'5rem'" />
167
- <br />
168
- <br />
169
- '{{ viewTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
170
- </div>
171
- } @else if (viewType() === "page") {
172
- <sd-topbar-container>
173
- <sd-topbar>
174
- <h4>{{ viewTitle() }}</h4>
175
-
176
- <ng-template [ngTemplateOutlet]="topbarTplRef()" />
177
- </sd-topbar>
178
-
179
- <ng-template [ngTemplateOutlet]="content" />
180
- </sd-topbar-container>
181
- } @else {
182
- <ng-template [ngTemplateOutlet]="content" />
183
- }
184
- }
185
- </sd-busy-container>
186
-
187
- <ng-template #content>
188
- <div class="flex-column fill">
189
- @if (commandTplRef()) {
190
- <div class="p-default flex-row gap-default bdb bdb-theme-gray-lightest">
191
- <ng-template [ngTemplateOutlet]="commandTplRef()" />
192
- </div>
193
- }
194
-
195
- <div class="flex-fill">
196
- @if (contentTplRef()) {
197
- <ng-template [ngTemplateOutlet]="contentTplRef()" />
198
- }
199
- </div>
200
-
201
- @if (bottomCommandTplRef()) {
202
- <div class="p-sm-default flex-row main-align-end gap-sm bdt bdt-theme-gray-lightest">
203
- <ng-template [ngTemplateOutlet]="bottomCommandTplRef()" />
204
- </div>
205
- }
206
- </div>
207
- </ng-template>
162
+ template: `
163
+ <sd-busy-container [busy]="initialized() && busyCount() > 0">
164
+ @if (initialized()) {
165
+ @if (restricted()) {
166
+ <div class="fill tx-theme-gray-light p-xxl tx-center">
167
+ <br />
168
+ <ng-icon [svg]="tablerAlertTriangle" [size]="'5rem'" />
169
+ <br />
170
+ <br />
171
+ '{{ viewTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
172
+ </div>
173
+ } @else if (viewType() === "page") {
174
+ <sd-topbar-container>
175
+ <sd-topbar>
176
+ <h4>{{ viewTitle() }}</h4>
177
+
178
+ <ng-template [ngTemplateOutlet]="topbarTplRef()" />
179
+ </sd-topbar>
180
+
181
+ <ng-template [ngTemplateOutlet]="content" />
182
+ </sd-topbar-container>
183
+ } @else {
184
+ <ng-template [ngTemplateOutlet]="content" />
185
+ }
186
+ }
187
+ </sd-busy-container>
188
+
189
+ <ng-template #content>
190
+ <div class="flex-column fill">
191
+ @if (commandTplRef()) {
192
+ <div class="p-default flex-row gap-default bdb bdb-theme-gray-lightest">
193
+ <ng-template [ngTemplateOutlet]="commandTplRef()" />
194
+ </div>
195
+ }
196
+
197
+ <div class="flex-fill">
198
+ @if (contentTplRef()) {
199
+ <ng-template [ngTemplateOutlet]="contentTplRef()" />
200
+ }
201
+ </div>
202
+
203
+ @if (bottomCommandTplRef()) {
204
+ <div class="p-sm-default flex-row main-align-end gap-sm bdt bdt-theme-gray-lightest">
205
+ <ng-template [ngTemplateOutlet]="bottomCommandTplRef()" />
206
+ </div>
207
+ }
208
+ </div>
209
+ </ng-template>
208
210
  `,
209
211
  }]
210
212
  }], () => [], { ready: [{ type: i0.Input, args: [{ isSignal: true, alias: "ready", required: false }] }, { type: i0.Output, args: ["readyChange"] }], initialized: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialized", required: false }] }], busyCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "busyCount", required: false }] }, { type: i0.Output, args: ["busyCountChange"] }], restricted: [{ type: i0.Input, args: [{ isSignal: true, alias: "restricted", required: false }] }], viewType: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewType", required: true }] }], topbarTplRef: [{ type: i0.ContentChild, args: ["topbarTpl", { isSignal: true }] }], commandTplRef: [{ type: i0.ContentChild, args: ["commandTpl", { isSignal: true }] }], contentTplRef: [{ type: i0.ContentChild, args: ["contentTpl", { isSignal: true }] }], bottomCommandTplRef: [{ type: i0.ContentChild, args: ["bottomCommandTpl", { isSignal: true }] }] }); })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/angular",
3
- "version": "14.0.85",
3
+ "version": "14.0.86",
4
4
  "description": "심플리즘 패키지 - Angular",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -24,40 +24,40 @@
24
24
  "./dist/**/*.css"
25
25
  ],
26
26
  "dependencies": {
27
- "@angular/animations": "^21.2.14",
28
- "@angular/common": "^21.2.14",
29
- "@angular/core": "^21.2.14",
30
- "@angular/platform-browser": "^21.2.14",
31
- "@angular/router": "^21.2.14",
32
- "@angular/service-worker": "^21.2.14",
33
- "@ng-icons/core": "^33.2.2",
34
- "@ng-icons/tabler-icons": "^33.2.2",
35
- "@tiptap/core": "^3.23.6",
36
- "@tiptap/extension-color": "^3.23.6",
37
- "@tiptap/extension-document": "^3.23.6",
38
- "@tiptap/extension-highlight": "^3.23.6",
39
- "@tiptap/extension-image": "^3.23.6",
40
- "@tiptap/extension-paragraph": "^3.23.6",
41
- "@tiptap/extension-placeholder": "^3.23.6",
42
- "@tiptap/extension-text": "^3.23.6",
43
- "@tiptap/extension-text-align": "^3.23.6",
44
- "@tiptap/extension-text-style": "^3.23.6",
45
- "@tiptap/extension-underline": "^3.23.6",
46
- "@tiptap/starter-kit": "^3.23.6",
47
- "bwip-js": "^4.10.1",
27
+ "@angular/animations": "^21.2.15",
28
+ "@angular/common": "^21.2.15",
29
+ "@angular/core": "^21.2.15",
30
+ "@angular/platform-browser": "^21.2.15",
31
+ "@angular/router": "^21.2.15",
32
+ "@angular/service-worker": "^21.2.15",
33
+ "@ng-icons/core": "^33.2.3",
34
+ "@ng-icons/tabler-icons": "^33.2.3",
35
+ "@tiptap/core": "^3.24.0",
36
+ "@tiptap/extension-color": "^3.24.0",
37
+ "@tiptap/extension-document": "^3.24.0",
38
+ "@tiptap/extension-highlight": "^3.24.0",
39
+ "@tiptap/extension-image": "^3.24.0",
40
+ "@tiptap/extension-paragraph": "^3.24.0",
41
+ "@tiptap/extension-placeholder": "^3.24.0",
42
+ "@tiptap/extension-text": "^3.24.0",
43
+ "@tiptap/extension-text-align": "^3.24.0",
44
+ "@tiptap/extension-text-style": "^3.24.0",
45
+ "@tiptap/extension-underline": "^3.24.0",
46
+ "@tiptap/starter-kit": "^3.24.0",
47
+ "bwip-js": "^4.11.1",
48
48
  "echarts": "^6.1.0",
49
49
  "html-to-image": "^1.11.13",
50
50
  "jspdf": "^4.2.1",
51
51
  "rxjs": "^7.8.2",
52
52
  "tabbable": "^6.4.0",
53
- "@simplysm/core-common": "14.0.85",
54
- "@simplysm/service-common": "14.0.85",
55
- "@simplysm/service-client": "14.0.85",
56
- "@simplysm/core-browser": "14.0.85"
53
+ "@simplysm/core-browser": "14.0.86",
54
+ "@simplysm/core-common": "14.0.86",
55
+ "@simplysm/service-client": "14.0.86",
56
+ "@simplysm/service-common": "14.0.86"
57
57
  },
58
58
  "devDependencies": {
59
- "@angular/compiler": "^21.2.14",
60
- "@angular/platform-browser-dynamic": "^21.2.14"
59
+ "@angular/compiler": "^21.2.15",
60
+ "@angular/platform-browser-dynamic": "^21.2.15"
61
61
  },
62
62
  "scripts": {}
63
63
  }
@@ -1,10 +1,8 @@
1
1
  import { computed, inject, Injectable, signal } from "@angular/core";
2
2
  import type { Signal } from "@angular/core";
3
- import type { AppStructureItem, AppStructureService } from "@simplysm/service-common";
3
+ import type { AppStructureItem } from "@simplysm/service-common";
4
4
  import type { SdFlatMenu } from "./sd-app-structure.types";
5
5
  import { SdAppStructureUtils } from "./sd-app-structure.utils";
6
- import { SdServiceClientFactoryProvider } from "../service-client/sd-service-client-factory.provider";
7
- import { SdAngularConfigProvider } from "../config/sd-angular-config.provider";
8
6
 
9
7
  export function injectPermsSignal<K extends string>(viewCodes: string[], keys: K[]): Signal<K[]> {
10
8
  const sdAppStructure = inject(SdAppStructureProvider);
@@ -15,20 +13,12 @@ export function injectPermsSignal<K extends string>(viewCodes: string[], keys: K
15
13
  // 메뉴는 모듈/권한 모두 체크함
16
14
  @Injectable({ providedIn: "root" })
17
15
  export class SdAppStructureProvider<TModule = unknown> {
18
- private readonly _sdServiceClientFactory = inject(SdServiceClientFactoryProvider);
19
- private readonly _sdAngularConfig = inject(SdAngularConfigProvider);
20
-
21
16
  readonly usableModules = signal<TModule[] | undefined>(undefined);
22
17
  readonly permRecord = signal<Record<string, boolean> | undefined>(undefined);
23
18
  readonly items = signal<AppStructureItem<TModule>[]>([]);
24
19
 
25
- async initialize(serviceKey: string): Promise<void> {
26
- const client = this._sdServiceClientFactory.get(serviceKey);
27
- const svc = client.getService<AppStructureService>("AppStructure");
28
- const itemsMap = await svc.getItems();
29
- this.items.set(
30
- (itemsMap[this._sdAngularConfig.clientName] ?? []) as AppStructureItem<TModule>[],
31
- );
20
+ initialize(items: AppStructureItem<TModule>[]): void {
21
+ this.items.set(items);
32
22
  }
33
23
 
34
24
  usableMenus = computed(() =>
@@ -110,7 +110,7 @@ export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBa
110
110
  }
111
111
 
112
112
  const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
113
- const event = client.getEvent<typeof SdSharedDataChangeEvent>("SdSharedDataChange");
113
+ const event = client.getEvent(SdSharedDataChangeEvent);
114
114
  await event.emit(
115
115
  (item) => item.name === (name as string) && obj.equal(item.filter, entry.info.filter),
116
116
  changeKeys,
@@ -138,7 +138,7 @@ export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBa
138
138
  // 이벤트 리스너 등록
139
139
  if (entry.listenerKey == null) {
140
140
  const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
141
- const event = client.getEvent<typeof SdSharedDataChangeEvent>("SdSharedDataChange");
141
+ const event = client.getEvent(SdSharedDataChangeEvent);
142
142
  entry.listenerKey = await event.addListener(
143
143
  { name, filter: entry.info.filter },
144
144
  async (changeKeys) => {
@@ -1,118 +1,120 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- contentChild,
5
- effect,
6
- inject,
7
- input,
8
- model,
9
- type TemplateRef,
10
- untracked,
11
- ViewEncapsulation,
12
- } from "@angular/core";
13
- import { injectViewTitleSignal } from "../../core/routing/injectViewTitleSignal";
14
- import { SdBusyContainer } from "../../core/busy/sd-busy-container";
15
- import { SdSharedDataProvider } from "../../core/shared-data/sd-shared-data.provider";
16
- import { SdToastProvider } from "../../core/toast/sd-toast.provider";
17
- import { SdTopbar } from "../../layout/topbar/sd-topbar";
18
- import { SdTopbarContainer } from "../../layout/topbar/sd-topbar-container";
19
- import type { SdViewType } from "../../core/routing/injectViewTypeSignal";
20
- import { NgIcon } from "@ng-icons/core";
21
- import { tablerAlertTriangle } from "@ng-icons/tabler-icons";
22
- import { NgTemplateOutlet } from "@angular/common";
23
-
24
- @Component({
25
- selector: "sd-base-container",
26
- changeDetection: ChangeDetectionStrategy.OnPush,
27
- encapsulation: ViewEncapsulation.None,
28
- standalone: true,
29
- imports: [SdBusyContainer, NgIcon, SdTopbarContainer, NgTemplateOutlet, SdTopbar],
30
- template: `
31
- <sd-busy-container [busy]="initialized() && busyCount() > 0">
32
- @if (initialized()) {
33
- @if (restricted()) {
34
- <div class="fill tx-theme-gray-light p-xxl tx-center">
35
- <br />
36
- <ng-icon [svg]="tablerAlertTriangle" [size]="'5rem'" />
37
- <br />
38
- <br />
39
- '{{ viewTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
40
- </div>
41
- } @else if (viewType() === "page") {
42
- <sd-topbar-container>
43
- <sd-topbar>
44
- <h4>{{ viewTitle() }}</h4>
45
-
46
- <ng-template [ngTemplateOutlet]="topbarTplRef()" />
47
- </sd-topbar>
48
-
49
- <ng-template [ngTemplateOutlet]="content" />
50
- </sd-topbar-container>
51
- } @else {
52
- <ng-template [ngTemplateOutlet]="content" />
53
- }
54
- }
55
- </sd-busy-container>
56
-
57
- <ng-template #content>
58
- <div class="flex-column fill">
59
- @if (commandTplRef()) {
60
- <div class="p-default flex-row gap-default bdb bdb-theme-gray-lightest">
61
- <ng-template [ngTemplateOutlet]="commandTplRef()" />
62
- </div>
63
- }
64
-
65
- <div class="flex-fill">
66
- @if (contentTplRef()) {
67
- <ng-template [ngTemplateOutlet]="contentTplRef()" />
68
- }
69
- </div>
70
-
71
- @if (bottomCommandTplRef()) {
72
- <div class="p-sm-default flex-row main-align-end gap-sm bdt bdt-theme-gray-lightest">
73
- <ng-template [ngTemplateOutlet]="bottomCommandTplRef()" />
74
- </div>
75
- }
76
- </div>
77
- </ng-template>
78
- `,
79
- })
80
- export class SdBaseContainer {
81
- private readonly _sdSharedData = inject(SdSharedDataProvider);
82
- private readonly _sdToast = inject(SdToastProvider);
83
-
84
- viewTitle = injectViewTitleSignal();
85
-
86
- ready = model(false);
87
- initialized = input(false);
88
- busyCount = model(0);
89
-
90
- restricted = input(false);
91
-
92
- viewType = input.required<SdViewType>();
93
-
94
- topbarTplRef = contentChild<TemplateRef<void>>("topbarTpl");
95
- commandTplRef = contentChild<TemplateRef<void>>("commandTpl");
96
- contentTplRef = contentChild<TemplateRef<void>>("contentTpl");
97
- bottomCommandTplRef = contentChild<TemplateRef<void>>("bottomCommandTpl");
98
-
99
- constructor() {
100
- effect(() => {
101
- if (this.restricted()) {
102
- this.ready.set(true);
103
- return;
104
- }
105
-
106
- void untracked(async () => {
107
- this.busyCount.update((v) => v + 1);
108
- await this._sdToast.try(async () => {
109
- await this._sdSharedData.wait();
110
- });
111
- this.busyCount.update((v) => v - 1);
112
- this.ready.set(true);
113
- });
114
- });
115
- }
116
-
117
- protected readonly tablerAlertTriangle = tablerAlertTriangle;
118
- }
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ contentChild,
5
+ effect,
6
+ inject,
7
+ input,
8
+ model,
9
+ type TemplateRef,
10
+ untracked,
11
+ ViewEncapsulation,
12
+ } from "@angular/core";
13
+ import { injectViewTitleSignal } from "../../core/routing/injectViewTitleSignal";
14
+ import { SdBusyContainer } from "../../core/busy/sd-busy-container";
15
+ import { SdSharedDataProvider } from "../../core/shared-data/sd-shared-data.provider";
16
+ import { SdToastProvider } from "../../core/toast/sd-toast.provider";
17
+ import { SdTopbar } from "../../layout/topbar/sd-topbar";
18
+ import { SdTopbarContainer } from "../../layout/topbar/sd-topbar-container";
19
+ import type { SdViewType } from "../../core/routing/injectViewTypeSignal";
20
+ import { NgIcon } from "@ng-icons/core";
21
+ import { tablerAlertTriangle } from "@ng-icons/tabler-icons";
22
+ import { NgTemplateOutlet } from "@angular/common";
23
+
24
+ @Component({
25
+ selector: "sd-base-container",
26
+ changeDetection: ChangeDetectionStrategy.OnPush,
27
+ encapsulation: ViewEncapsulation.None,
28
+ standalone: true,
29
+ imports: [SdBusyContainer, NgIcon, SdTopbarContainer, NgTemplateOutlet, SdTopbar],
30
+ template: `
31
+ <sd-busy-container [busy]="initialized() && busyCount() > 0">
32
+ @if (initialized()) {
33
+ @if (restricted()) {
34
+ <div class="fill tx-theme-gray-light p-xxl tx-center">
35
+ <br />
36
+ <ng-icon [svg]="tablerAlertTriangle" [size]="'5rem'" />
37
+ <br />
38
+ <br />
39
+ '{{ viewTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
40
+ </div>
41
+ } @else if (viewType() === "page") {
42
+ <sd-topbar-container>
43
+ <sd-topbar>
44
+ <h4>{{ viewTitle() }}</h4>
45
+
46
+ <ng-template [ngTemplateOutlet]="topbarTplRef()" />
47
+ </sd-topbar>
48
+
49
+ <ng-template [ngTemplateOutlet]="content" />
50
+ </sd-topbar-container>
51
+ } @else {
52
+ <ng-template [ngTemplateOutlet]="content" />
53
+ }
54
+ }
55
+ </sd-busy-container>
56
+
57
+ <ng-template #content>
58
+ <div class="flex-column fill">
59
+ @if (commandTplRef()) {
60
+ <div class="p-default flex-row gap-default bdb bdb-theme-gray-lightest">
61
+ <ng-template [ngTemplateOutlet]="commandTplRef()" />
62
+ </div>
63
+ }
64
+
65
+ <div class="flex-fill">
66
+ @if (contentTplRef()) {
67
+ <ng-template [ngTemplateOutlet]="contentTplRef()" />
68
+ }
69
+ </div>
70
+
71
+ @if (bottomCommandTplRef()) {
72
+ <div class="p-sm-default flex-row main-align-end gap-sm bdt bdt-theme-gray-lightest">
73
+ <ng-template [ngTemplateOutlet]="bottomCommandTplRef()" />
74
+ </div>
75
+ }
76
+ </div>
77
+ </ng-template>
78
+ `,
79
+ })
80
+ export class SdBaseContainer {
81
+ private readonly _sdSharedData = inject(SdSharedDataProvider, { optional: true });
82
+ private readonly _sdToast = inject(SdToastProvider);
83
+
84
+ viewTitle = injectViewTitleSignal();
85
+
86
+ ready = model(false);
87
+ initialized = input(false);
88
+ busyCount = model(0);
89
+
90
+ restricted = input(false);
91
+
92
+ viewType = input.required<SdViewType>();
93
+
94
+ topbarTplRef = contentChild<TemplateRef<void>>("topbarTpl");
95
+ commandTplRef = contentChild<TemplateRef<void>>("commandTpl");
96
+ contentTplRef = contentChild<TemplateRef<void>>("contentTpl");
97
+ bottomCommandTplRef = contentChild<TemplateRef<void>>("bottomCommandTpl");
98
+
99
+ constructor() {
100
+ effect(() => {
101
+ if (this.restricted()) {
102
+ this.ready.set(true);
103
+ return;
104
+ }
105
+
106
+ void untracked(async () => {
107
+ if (this._sdSharedData) {
108
+ this.busyCount.update((v) => v + 1);
109
+ await this._sdToast.try(async () => {
110
+ await this._sdSharedData!.wait();
111
+ });
112
+ this.busyCount.update((v) => v - 1);
113
+ }
114
+ this.ready.set(true);
115
+ });
116
+ });
117
+ }
118
+
119
+ protected readonly tablerAlertTriangle = tablerAlertTriangle;
120
+ }