@simplysm/angular 14.0.47 → 14.0.48
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.
- package/README.md +468 -0
- package/dist/controls/dropdown/sd-dropdown-popup.d.ts +1 -0
- package/dist/controls/dropdown/sd-dropdown-popup.d.ts.map +1 -1
- package/dist/controls/dropdown/sd-dropdown-popup.js +6 -1
- package/dist/controls/dropdown/sd-dropdown.d.ts.map +1 -1
- package/dist/controls/dropdown/sd-dropdown.js +6 -2
- package/dist/controls/select/sd-select.d.ts.map +1 -1
- package/dist/controls/select/sd-select.js +12 -34
- package/dist/core/routing/injectViewTypeSignal.d.ts +1 -1
- package/dist/core/routing/injectViewTypeSignal.d.ts.map +1 -1
- package/dist/core/routing/injectViewTypeSignal.js +15 -7
- package/dist/core/selection/useSelectionManager.d.ts +1 -0
- package/dist/core/selection/useSelectionManager.d.ts.map +1 -1
- package/dist/core/selection/useSelectionManager.js +54 -14
- package/dist/data/shared-data/sd-shared-data-select-button.d.ts +11 -5
- package/dist/data/shared-data/sd-shared-data-select-button.d.ts.map +1 -1
- package/dist/data/shared-data/sd-shared-data-select-button.js +68 -29
- package/dist/data/sheet/sd-sheet.d.ts +4 -1
- package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet.js +23 -4
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -17
- package/docs/bootstrap.md +38 -0
- package/docs/directives.md +236 -0
- package/docs/features.md +169 -0
- package/docs/pipes.md +32 -0
- package/docs/plugins.md +37 -0
- package/docs/provider-types.md +283 -0
- package/docs/providers.md +379 -0
- package/docs/recipes/crud-detail.md +860 -0
- package/docs/recipes/crud-list.md +779 -0
- package/docs/recipes/data-select-button.md +319 -0
- package/docs/recipes/page-modal-container.md +178 -0
- package/docs/styling.md +222 -0
- package/docs/type-utilities.md +250 -0
- package/docs/ui-data.md +333 -0
- package/docs/ui-form.md +502 -0
- package/docs/ui-layout.md +140 -0
- package/docs/ui-navigation.md +273 -0
- package/docs/ui-overlay.md +157 -0
- package/docs/ui-visual.md +127 -0
- package/docs/utils.md +244 -0
- package/package.json +19 -18
- package/src/controls/dropdown/sd-dropdown-popup.ts +6 -2
- package/src/controls/dropdown/sd-dropdown.ts +3 -4
- package/src/controls/select/sd-select.ts +6 -30
- package/src/core/routing/injectViewTypeSignal.ts +17 -10
- package/src/core/selection/useSelectionManager.ts +62 -12
- package/src/data/shared-data/sd-shared-data-select-button.ts +49 -14
- package/src/data/sheet/sd-sheet.ts +21 -0
- package/src/index.ts +0 -29
- package/dist/core/commons.d.ts +0 -2
- package/dist/core/commons.d.ts.map +0 -1
- package/dist/core/commons.js +0 -4
- package/dist/core/injectParent.d.ts +0 -7
- package/dist/core/injectParent.d.ts.map +0 -1
- package/dist/core/injectParent.js +0 -30
- package/dist/core/selection/setupCumulateSelectedKeys.d.ts +0 -9
- package/dist/core/selection/setupCumulateSelectedKeys.d.ts.map +0 -1
- package/dist/core/selection/setupCumulateSelectedKeys.js +0 -27
- package/dist/core/withBusy.d.ts +0 -3
- package/dist/core/withBusy.d.ts.map +0 -1
- package/dist/core/withBusy.js +0 -9
- package/dist/data/data-detail/sd-data-detail.base.d.ts +0 -51
- package/dist/data/data-detail/sd-data-detail.base.d.ts.map +0 -1
- package/dist/data/data-detail/sd-data-detail.base.js +0 -127
- package/dist/data/data-detail/sd-data-detail.d.ts +0 -30
- package/dist/data/data-detail/sd-data-detail.d.ts.map +0 -1
- package/dist/data/data-detail/sd-data-detail.js +0 -495
- package/dist/data/data-select-button/sd-data-select-button.base.d.ts +0 -24
- package/dist/data/data-select-button/sd-data-select-button.base.d.ts.map +0 -1
- package/dist/data/data-select-button/sd-data-select-button.base.js +0 -68
- package/dist/data/data-select-button/sd-data-select-button.d.ts +0 -15
- package/dist/data/data-select-button/sd-data-select-button.d.ts.map +0 -1
- package/dist/data/data-select-button/sd-data-select-button.js +0 -152
- package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts +0 -14
- package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts.map +0 -1
- package/dist/data/data-sheet/injectDataSheetExcelManager.js +0 -31
- package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts +0 -26
- package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts.map +0 -1
- package/dist/data/data-sheet/injectDataSheetInlineEditManager.js +0 -54
- package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts +0 -19
- package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts.map +0 -1
- package/dist/data/data-sheet/injectDataSheetModalEditManager.js +0 -44
- package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts +0 -25
- package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts.map +0 -1
- package/dist/data/data-sheet/injectDataSheetRefreshManager.js +0 -50
- package/dist/data/data-sheet/sd-data-sheet-column.d.ts +0 -8
- package/dist/data/data-sheet/sd-data-sheet-column.d.ts.map +0 -1
- package/dist/data/data-sheet/sd-data-sheet-column.js +0 -15
- package/dist/data/data-sheet/sd-data-sheet.base.d.ts +0 -75
- package/dist/data/data-sheet/sd-data-sheet.base.d.ts.map +0 -1
- package/dist/data/data-sheet/sd-data-sheet.base.js +0 -188
- package/dist/data/data-sheet/sd-data-sheet.d.ts +0 -49
- package/dist/data/data-sheet/sd-data-sheet.d.ts.map +0 -1
- package/dist/data/data-sheet/sd-data-sheet.js +0 -968
- package/dist/data/data-sheet/sd-data-sheet.types.d.ts +0 -17
- package/dist/data/data-sheet/sd-data-sheet.types.d.ts.map +0 -1
- package/dist/data/data-sheet/sd-data-sheet.types.js +0 -1
- package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts +0 -9
- package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts.map +0 -1
- package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.js +0 -20
- package/dist/data/data-sheet/useDataSheetFilterManager.d.ts +0 -13
- package/dist/data/data-sheet/useDataSheetFilterManager.d.ts.map +0 -1
- package/dist/data/data-sheet/useDataSheetFilterManager.js +0 -19
- package/dist/layout/base-container/sd-base-container.d.ts +0 -27
- package/dist/layout/base-container/sd-base-container.d.ts.map +0 -1
- package/dist/layout/base-container/sd-base-container.js +0 -193
- package/src/core/commons.ts +0 -4
- package/src/core/injectParent.ts +0 -45
- package/src/core/selection/setupCumulateSelectedKeys.ts +0 -38
- package/src/core/withBusy.ts +0 -13
- package/src/data/data-detail/sd-data-detail.base.ts +0 -187
- package/src/data/data-detail/sd-data-detail.ts +0 -237
- package/src/data/data-select-button/sd-data-select-button.base.ts +0 -104
- package/src/data/data-select-button/sd-data-select-button.ts +0 -105
- package/src/data/data-sheet/injectDataSheetExcelManager.ts +0 -57
- package/src/data/data-sheet/injectDataSheetInlineEditManager.ts +0 -89
- package/src/data/data-sheet/injectDataSheetModalEditManager.ts +0 -76
- package/src/data/data-sheet/injectDataSheetRefreshManager.ts +0 -90
- package/src/data/data-sheet/sd-data-sheet-column.ts +0 -10
- package/src/data/data-sheet/sd-data-sheet.base.ts +0 -294
- package/src/data/data-sheet/sd-data-sheet.ts +0 -479
- package/src/data/data-sheet/sd-data-sheet.types.ts +0 -18
- package/src/data/data-sheet/setupCloserWhenSingleSelectionChange.ts +0 -29
- package/src/data/data-sheet/useDataSheetFilterManager.ts +0 -30
- package/src/layout/base-container/sd-base-container.ts +0 -121
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export interface SdDataSheetItemPropInfo<I> {
|
|
2
|
-
isDeleted: (keyof I & string) | undefined;
|
|
3
|
-
lastModifiedAt: (keyof I & string) | undefined;
|
|
4
|
-
lastModifiedBy: (keyof I & string) | undefined;
|
|
5
|
-
}
|
|
6
|
-
export interface SdDataSheetItemInfo<K> {
|
|
7
|
-
key: K;
|
|
8
|
-
canSelect: boolean;
|
|
9
|
-
canEdit: boolean;
|
|
10
|
-
canDelete: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface SdDataSheetSearchResult<I> {
|
|
13
|
-
items: I[];
|
|
14
|
-
pageLength?: number;
|
|
15
|
-
summary?: Partial<I>;
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=sd-data-sheet.types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sd-data-sheet.types.d.ts","sourceRoot":"","sources":["../../../src/data/data-sheet/sd-data-sheet.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,SAAS,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,CAAC;IAC1C,cAAc,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,CAAC;IAC/C,cAAc,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,GAAG,EAAE,CAAC,CAAC;IACP,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CACtB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type OutputEmitterRef, type Signal } from "@angular/core";
|
|
2
|
-
import type { SelectModalOutputResult } from "../../core/select-modal-output-result";
|
|
3
|
-
export declare function setupCloserWhenSingleSelectionChange<TItem, TKey>(options: {
|
|
4
|
-
selectedItemKeys: Signal<TKey[]>;
|
|
5
|
-
selectedItems: Signal<TItem[]>;
|
|
6
|
-
selectMode: () => "single" | "multi" | undefined;
|
|
7
|
-
close: OutputEmitterRef<SelectModalOutputResult<TItem>>;
|
|
8
|
-
}): void;
|
|
9
|
-
//# sourceMappingURL=setupCloserWhenSingleSelectionChange.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setupCloserWhenSingleSelectionChange.d.ts","sourceRoot":"","sources":["../../../src/data/data-sheet/setupCloserWhenSingleSelectionChange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,MAAM,EAAU,MAAM,eAAe,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAErF,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;IACzE,gBAAgB,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IACjD,KAAK,EAAE,gBAAgB,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;CACzD,GAAG,IAAI,CAoBP"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { effect } from "@angular/core";
|
|
2
|
-
export function setupCloserWhenSingleSelectionChange(options) {
|
|
3
|
-
let initialized = false;
|
|
4
|
-
effect(() => {
|
|
5
|
-
const keys = options.selectedItemKeys();
|
|
6
|
-
const items = options.selectedItems();
|
|
7
|
-
if (!initialized) {
|
|
8
|
-
initialized = true;
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
if (options.selectMode() !== "single")
|
|
12
|
-
return;
|
|
13
|
-
if (keys.length === 0)
|
|
14
|
-
return;
|
|
15
|
-
options.close.emit({
|
|
16
|
-
selectedItemKeys: keys,
|
|
17
|
-
selectedItems: items,
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type Signal, type WritableSignal } from "@angular/core";
|
|
2
|
-
export declare function useDataSheetFilterManager<TFilter extends Record<string, any>>(options: {
|
|
3
|
-
bindFilter: () => TFilter;
|
|
4
|
-
busyCount: Signal<number>;
|
|
5
|
-
canUse: () => boolean;
|
|
6
|
-
page: WritableSignal<number>;
|
|
7
|
-
checkIgnoreChanges: () => boolean;
|
|
8
|
-
}): {
|
|
9
|
-
filter: WritableSignal<TFilter>;
|
|
10
|
-
lastFilter: WritableSignal<TFilter>;
|
|
11
|
-
doFilterSubmit: () => void;
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=useDataSheetFilterManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useDataSheetFilterManager.d.ts","sourceRoot":"","sources":["../../../src/data/data-sheet/useDataSheetFilterManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,eAAe,CAAC;AAG/E,wBAAgB,yBAAyB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE;IACtF,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7B,kBAAkB,EAAE,MAAM,OAAO,CAAC;CACnC;;;0BAU4B,IAAI;EAUhC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { linkedSignal } from "@angular/core";
|
|
2
|
-
import { obj } from "@simplysm/core-common";
|
|
3
|
-
export function useDataSheetFilterManager(options) {
|
|
4
|
-
const filter = linkedSignal({ ...(ngDevMode ? { debugName: "filter" } : /* istanbul ignore next */ {}), source: options.bindFilter,
|
|
5
|
-
computation: (f) => f });
|
|
6
|
-
const lastFilter = linkedSignal({ ...(ngDevMode ? { debugName: "lastFilter" } : /* istanbul ignore next */ {}), source: options.bindFilter,
|
|
7
|
-
computation: (f) => obj.clone(f) });
|
|
8
|
-
function doFilterSubmit() {
|
|
9
|
-
if (options.busyCount() > 0)
|
|
10
|
-
return;
|
|
11
|
-
if (!options.canUse())
|
|
12
|
-
return;
|
|
13
|
-
if (!options.checkIgnoreChanges())
|
|
14
|
-
return;
|
|
15
|
-
options.page.set(0);
|
|
16
|
-
lastFilter.set(obj.clone(filter()));
|
|
17
|
-
}
|
|
18
|
-
return { filter, lastFilter, doFilterSubmit };
|
|
19
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { TemplateRef } from "@angular/core";
|
|
2
|
-
import { type SdViewType } from "../../core/routing/injectViewTypeSignal";
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class SdBaseContainer {
|
|
5
|
-
private readonly _sdActivatedModal;
|
|
6
|
-
private readonly _sdAppStructure;
|
|
7
|
-
private readonly _sdSystemLog;
|
|
8
|
-
private readonly _parent;
|
|
9
|
-
private readonly _fullPageCode;
|
|
10
|
-
private readonly _currPageCode;
|
|
11
|
-
contentTplRef: import("@angular/core").Signal<TemplateRef<any>>;
|
|
12
|
-
pageTopbarTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
|
|
13
|
-
modalBottomTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
|
|
14
|
-
private readonly _parentViewType;
|
|
15
|
-
viewType: import("@angular/core").InputSignal<SdViewType | undefined>;
|
|
16
|
-
currViewType: import("@angular/core").Signal<SdViewType>;
|
|
17
|
-
header: import("@angular/core").InputSignal<string | undefined>;
|
|
18
|
-
modalOrPageTitle: import("@angular/core").Signal<any>;
|
|
19
|
-
initialized: import("@angular/core").InputSignal<boolean | undefined>;
|
|
20
|
-
restricted: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
21
|
-
busy: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
22
|
-
busyMessage: import("@angular/core").InputSignal<string | undefined>;
|
|
23
|
-
protected readonly tablerAlertTriangle = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"stroke-width:var(--ng-icon__stroke-width, 2)\"><path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"></path><path d=\"M12 9v4\"></path><path d=\"M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z\"></path><path d=\"M12 16h.01\"></path></svg>";
|
|
24
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<SdBaseContainer, never>;
|
|
25
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SdBaseContainer, "sd-base-container", never, { "viewType": { "alias": "viewType"; "required": false; "isSignal": true; }; "header": { "alias": "header"; "required": false; "isSignal": true; }; "initialized": { "alias": "initialized"; "required": false; "isSignal": true; }; "restricted": { "alias": "restricted"; "required": false; "isSignal": true; }; "busy": { "alias": "busy"; "required": false; "isSignal": true; }; "busyMessage": { "alias": "busyMessage"; "required": false; "isSignal": true; }; }, {}, ["contentTplRef", "pageTopbarTplRef", "modalBottomTplRef"], never, true, never>;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=sd-base-container.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sd-base-container.d.ts","sourceRoot":"","sources":["../../../src/layout/base-container/sd-base-container.ts"],"names":[],"mappings":"AACA,OAAO,EAQL,WAAW,EAEZ,MAAM,eAAe,CAAC;AAQvB,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,yCAAyC,CAAC;;AAMjD,qBAqDa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwD;IAC1F,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAE5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAE1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8B;IAC5D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAE/D,aAAa,mDAA8D;IAE3E,gBAAgB,+DAAwD;IACxE,iBAAiB,+DAAyD;IAE1E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4C;IAC5E,QAAQ,8DAAuB;IAC/B,YAAY,6CAA6D;IAEzE,MAAM,0DAAmB;IACzB,gBAAgB,sCAWb;IAEH,WAAW,2DAAyC;IACpD,UAAU,qEAAiD;IAC3D,IAAI,qEAAiD;IACrD,WAAW,0DAAmB;IAE9B,SAAS,CAAC,QAAQ,CAAC,mBAAmB,ifAAuB;yCAtClD,eAAe;2CAAf,eAAe;CAuC3B"}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { NgTemplateOutlet } from "@angular/common";
|
|
2
|
-
import { booleanAttribute, ChangeDetectionStrategy, Component, computed, contentChild, inject, input, TemplateRef, ViewEncapsulation, } from "@angular/core";
|
|
3
|
-
import { SdBusyContainer } from "../../core/busy/sd-busy-container";
|
|
4
|
-
import { SdTopbarContainer } from "../topbar/sd-topbar-container";
|
|
5
|
-
import { SdTopbar } from "../topbar/sd-topbar";
|
|
6
|
-
import { SdAppStructureProvider } from "../../core/app-structure/sd-app-structure.provider";
|
|
7
|
-
import { SdActivatedModalProvider } from "../../core/modal/sd-activated-modal.provider";
|
|
8
|
-
import { injectCurrentPageCodeSignal } from "../../core/routing/injectCurrentPageCodeSignal";
|
|
9
|
-
import { injectFullPageCodeSignal } from "../../core/routing/injectFullPageCodeSignal";
|
|
10
|
-
import { injectViewTypeSignal, } from "../../core/routing/injectViewTypeSignal";
|
|
11
|
-
import { injectParent } from "../../core/injectParent";
|
|
12
|
-
import { SdSystemLogProvider } from "../../core/config/sd-system-log.provider";
|
|
13
|
-
import { NgIcon } from "@ng-icons/core";
|
|
14
|
-
import { tablerAlertTriangle } from "@ng-icons/tabler-icons";
|
|
15
|
-
import * as i0 from "@angular/core";
|
|
16
|
-
const _c0 = ["contentTpl"];
|
|
17
|
-
const _c1 = ["pageTopbarTpl"];
|
|
18
|
-
const _c2 = ["modalBottomTpl"];
|
|
19
|
-
function SdBaseContainer_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
20
|
-
i0.ɵɵelementStart(0, "div", 1);
|
|
21
|
-
i0.ɵɵelement(1, "br")(2, "ng-icon", 4)(3, "br")(4, "br");
|
|
22
|
-
i0.ɵɵtext(5);
|
|
23
|
-
i0.ɵɵelementEnd();
|
|
24
|
-
} if (rf & 2) {
|
|
25
|
-
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
26
|
-
i0.ɵɵadvance(2);
|
|
27
|
-
i0.ɵɵproperty("svg", ctx_r0.tablerAlertTriangle)("size", "5em");
|
|
28
|
-
i0.ɵɵadvance(3);
|
|
29
|
-
i0.ɵɵtextInterpolate1(" '", ctx_r0.modalOrPageTitle(), "'\uC5D0 \uB300\uD55C \uC0AC\uC6A9\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC2DC\uC2A4\uD15C \uAD00\uB9AC\uC790\uC5D0\uAC8C \uBB38\uC758\uD558\uC138\uC694. ");
|
|
30
|
-
} }
|
|
31
|
-
function SdBaseContainer_Conditional_1_Conditional_1_ng_template_4_Template(rf, ctx) { }
|
|
32
|
-
function SdBaseContainer_Conditional_1_Conditional_1_ng_template_6_Template(rf, ctx) { }
|
|
33
|
-
function SdBaseContainer_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
34
|
-
i0.ɵɵelementStart(0, "sd-topbar-container")(1, "sd-topbar")(2, "h4");
|
|
35
|
-
i0.ɵɵtext(3);
|
|
36
|
-
i0.ɵɵelementEnd();
|
|
37
|
-
i0.ɵɵtemplate(4, SdBaseContainer_Conditional_1_Conditional_1_ng_template_4_Template, 0, 0, "ng-template", 3);
|
|
38
|
-
i0.ɵɵelementEnd();
|
|
39
|
-
i0.ɵɵelementStart(5, "div", 5);
|
|
40
|
-
i0.ɵɵtemplate(6, SdBaseContainer_Conditional_1_Conditional_1_ng_template_6_Template, 0, 0, "ng-template", 3);
|
|
41
|
-
i0.ɵɵelementEnd()();
|
|
42
|
-
} if (rf & 2) {
|
|
43
|
-
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
44
|
-
i0.ɵɵadvance(3);
|
|
45
|
-
i0.ɵɵtextInterpolate(ctx_r0.modalOrPageTitle());
|
|
46
|
-
i0.ɵɵadvance();
|
|
47
|
-
i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.pageTopbarTplRef() ?? null);
|
|
48
|
-
i0.ɵɵadvance(2);
|
|
49
|
-
i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.contentTplRef());
|
|
50
|
-
} }
|
|
51
|
-
function SdBaseContainer_Conditional_1_Conditional_2_ng_template_2_Template(rf, ctx) { }
|
|
52
|
-
function SdBaseContainer_Conditional_1_Conditional_2_Conditional_3_ng_template_1_Template(rf, ctx) { }
|
|
53
|
-
function SdBaseContainer_Conditional_1_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
-
i0.ɵɵelementStart(0, "div", 7);
|
|
55
|
-
i0.ɵɵtemplate(1, SdBaseContainer_Conditional_1_Conditional_2_Conditional_3_ng_template_1_Template, 0, 0, "ng-template", 3);
|
|
56
|
-
i0.ɵɵelementEnd();
|
|
57
|
-
} if (rf & 2) {
|
|
58
|
-
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
59
|
-
i0.ɵɵadvance();
|
|
60
|
-
i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.modalBottomTplRef() ?? null);
|
|
61
|
-
} }
|
|
62
|
-
function SdBaseContainer_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
-
i0.ɵɵelementStart(0, "div", 2)(1, "div", 6);
|
|
64
|
-
i0.ɵɵtemplate(2, SdBaseContainer_Conditional_1_Conditional_2_ng_template_2_Template, 0, 0, "ng-template", 3);
|
|
65
|
-
i0.ɵɵelementEnd();
|
|
66
|
-
i0.ɵɵconditionalCreate(3, SdBaseContainer_Conditional_1_Conditional_2_Conditional_3_Template, 2, 1, "div", 7);
|
|
67
|
-
i0.ɵɵelementEnd();
|
|
68
|
-
} if (rf & 2) {
|
|
69
|
-
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
70
|
-
i0.ɵɵadvance(2);
|
|
71
|
-
i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.contentTplRef());
|
|
72
|
-
i0.ɵɵadvance();
|
|
73
|
-
i0.ɵɵconditional(ctx_r0.modalBottomTplRef() ? 3 : -1);
|
|
74
|
-
} }
|
|
75
|
-
function SdBaseContainer_Conditional_1_Conditional_3_ng_template_0_Template(rf, ctx) { }
|
|
76
|
-
function SdBaseContainer_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
77
|
-
i0.ɵɵtemplate(0, SdBaseContainer_Conditional_1_Conditional_3_ng_template_0_Template, 0, 0, "ng-template", 3);
|
|
78
|
-
} if (rf & 2) {
|
|
79
|
-
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
80
|
-
i0.ɵɵproperty("ngTemplateOutlet", ctx_r0.contentTplRef());
|
|
81
|
-
} }
|
|
82
|
-
function SdBaseContainer_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
83
|
-
i0.ɵɵconditionalCreate(0, SdBaseContainer_Conditional_1_Conditional_0_Template, 6, 3, "div", 1)(1, SdBaseContainer_Conditional_1_Conditional_1_Template, 7, 3, "sd-topbar-container")(2, SdBaseContainer_Conditional_1_Conditional_2_Template, 4, 2, "div", 2)(3, SdBaseContainer_Conditional_1_Conditional_3_Template, 1, 1, null, 3);
|
|
84
|
-
} if (rf & 2) {
|
|
85
|
-
const ctx_r0 = i0.ɵɵnextContext();
|
|
86
|
-
i0.ɵɵconditional(ctx_r0.restricted() ? 0 : ctx_r0.currViewType() === "page" ? 1 : ctx_r0.currViewType() === "modal" ? 2 : 3);
|
|
87
|
-
} }
|
|
88
|
-
export class SdBaseContainer {
|
|
89
|
-
_sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
90
|
-
_sdAppStructure = inject(SdAppStructureProvider);
|
|
91
|
-
_sdSystemLog = inject(SdSystemLogProvider);
|
|
92
|
-
_parent = injectParent();
|
|
93
|
-
_fullPageCode = injectFullPageCodeSignal();
|
|
94
|
-
_currPageCode = injectCurrentPageCodeSignal();
|
|
95
|
-
contentTplRef = contentChild.required("contentTpl", { read: TemplateRef });
|
|
96
|
-
pageTopbarTplRef = contentChild("pageTopbarTpl", { ...(ngDevMode ? { debugName: "pageTopbarTplRef" } : /* istanbul ignore next */ {}), read: TemplateRef });
|
|
97
|
-
modalBottomTplRef = contentChild("modalBottomTpl", { ...(ngDevMode ? { debugName: "modalBottomTplRef" } : /* istanbul ignore next */ {}), read: TemplateRef });
|
|
98
|
-
_parentViewType = injectViewTypeSignal(() => this._parent);
|
|
99
|
-
viewType = input(...(ngDevMode ? [undefined, { debugName: "viewType" }] : /* istanbul ignore next */ []));
|
|
100
|
-
currViewType = computed(() => this.viewType() ?? this._parentViewType(), ...(ngDevMode ? [{ debugName: "currViewType" }] : /* istanbul ignore next */ []));
|
|
101
|
-
header = input(...(ngDevMode ? [undefined, { debugName: "header" }] : /* istanbul ignore next */ []));
|
|
102
|
-
modalOrPageTitle = computed(() => {
|
|
103
|
-
try {
|
|
104
|
-
return (this.header() ??
|
|
105
|
-
this._sdActivatedModal?.modalComponent()?.title() ??
|
|
106
|
-
this._sdAppStructure.getTitleByFullCode(this._currPageCode?.() ?? this._fullPageCode()));
|
|
107
|
-
}
|
|
108
|
-
catch (err) {
|
|
109
|
-
void this._sdSystemLog.writeAsync("warn", `modalOrPageTitle 계산 중 에러: ${String(err)}`);
|
|
110
|
-
return "";
|
|
111
|
-
}
|
|
112
|
-
}, ...(ngDevMode ? [{ debugName: "modalOrPageTitle" }] : /* istanbul ignore next */ []));
|
|
113
|
-
initialized = input(undefined, ...(ngDevMode ? [{ debugName: "initialized" }] : /* istanbul ignore next */ []));
|
|
114
|
-
restricted = input(false, { ...(ngDevMode ? { debugName: "restricted" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
115
|
-
busy = input(false, { ...(ngDevMode ? { debugName: "busy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
116
|
-
busyMessage = input(...(ngDevMode ? [undefined, { debugName: "busyMessage" }] : /* istanbul ignore next */ []));
|
|
117
|
-
tablerAlertTriangle = tablerAlertTriangle;
|
|
118
|
-
static ɵfac = function SdBaseContainer_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdBaseContainer)(); };
|
|
119
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SdBaseContainer, selectors: [["sd-base-container"]], contentQueries: function SdBaseContainer_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
|
|
120
|
-
i0.ɵɵcontentQuerySignal(dirIndex, ctx.contentTplRef, _c0, 5, TemplateRef)(dirIndex, ctx.pageTopbarTplRef, _c1, 5, TemplateRef)(dirIndex, ctx.modalBottomTplRef, _c2, 5, TemplateRef);
|
|
121
|
-
} if (rf & 2) {
|
|
122
|
-
i0.ɵɵqueryAdvance(3);
|
|
123
|
-
} }, inputs: { viewType: [1, "viewType"], header: [1, "header"], initialized: [1, "initialized"], restricted: [1, "restricted"], busy: [1, "busy"], busyMessage: [1, "busyMessage"] }, decls: 2, vars: 3, consts: [[3, "busy", "message"], [1, "fill", "tx-theme-gray-light", "p-xxl", "tx-center"], [1, "flex-column", "fill"], [3, "ngTemplateOutlet"], [3, "svg", "size"], [1, "fill"], [1, "flex-fill"], [1, "bdt", "bdt-theme-gray-lightest"]], template: function SdBaseContainer_Template(rf, ctx) { if (rf & 1) {
|
|
124
|
-
i0.ɵɵelementStart(0, "sd-busy-container", 0);
|
|
125
|
-
i0.ɵɵconditionalCreate(1, SdBaseContainer_Conditional_1_Template, 4, 1);
|
|
126
|
-
i0.ɵɵelementEnd();
|
|
127
|
-
} if (rf & 2) {
|
|
128
|
-
i0.ɵɵproperty("busy", ctx.busy())("message", ctx.busyMessage());
|
|
129
|
-
i0.ɵɵadvance();
|
|
130
|
-
i0.ɵɵconditional(ctx.initialized() == null || ctx.initialized() ? 1 : -1);
|
|
131
|
-
} }, dependencies: [SdBusyContainer,
|
|
132
|
-
SdTopbarContainer,
|
|
133
|
-
SdTopbar,
|
|
134
|
-
NgTemplateOutlet,
|
|
135
|
-
NgIcon], encapsulation: 2, changeDetection: 0 });
|
|
136
|
-
}
|
|
137
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SdBaseContainer, [{
|
|
138
|
-
type: Component,
|
|
139
|
-
args: [{
|
|
140
|
-
selector: "sd-base-container",
|
|
141
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
142
|
-
encapsulation: ViewEncapsulation.None,
|
|
143
|
-
standalone: true,
|
|
144
|
-
imports: [
|
|
145
|
-
SdBusyContainer,
|
|
146
|
-
SdTopbarContainer,
|
|
147
|
-
SdTopbar,
|
|
148
|
-
NgTemplateOutlet,
|
|
149
|
-
NgIcon,
|
|
150
|
-
],
|
|
151
|
-
template: `
|
|
152
|
-
<sd-busy-container [busy]="busy()" [message]="busyMessage()">
|
|
153
|
-
@if (initialized() == null || initialized()) {
|
|
154
|
-
@if (restricted()) {
|
|
155
|
-
<div class="fill tx-theme-gray-light p-xxl tx-center">
|
|
156
|
-
<br />
|
|
157
|
-
<ng-icon [svg]="tablerAlertTriangle" [size]="'5em'" />
|
|
158
|
-
<br />
|
|
159
|
-
<br />
|
|
160
|
-
'{{ modalOrPageTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
|
|
161
|
-
</div>
|
|
162
|
-
} @else if (currViewType() === "page") {
|
|
163
|
-
<sd-topbar-container>
|
|
164
|
-
<sd-topbar>
|
|
165
|
-
<h4>{{ modalOrPageTitle() }}</h4>
|
|
166
|
-
|
|
167
|
-
<ng-template [ngTemplateOutlet]="pageTopbarTplRef() ?? null" />
|
|
168
|
-
</sd-topbar>
|
|
169
|
-
|
|
170
|
-
<div class="fill">
|
|
171
|
-
<ng-template [ngTemplateOutlet]="contentTplRef()" />
|
|
172
|
-
</div>
|
|
173
|
-
</sd-topbar-container>
|
|
174
|
-
} @else if (currViewType() === "modal") {
|
|
175
|
-
<div class="flex-column fill">
|
|
176
|
-
<div class="flex-fill">
|
|
177
|
-
<ng-template [ngTemplateOutlet]="contentTplRef()" />
|
|
178
|
-
</div>
|
|
179
|
-
@if (modalBottomTplRef()) {
|
|
180
|
-
<div class="bdt bdt-theme-gray-lightest">
|
|
181
|
-
<ng-template [ngTemplateOutlet]="modalBottomTplRef() ?? null" />
|
|
182
|
-
</div>
|
|
183
|
-
}
|
|
184
|
-
</div>
|
|
185
|
-
} @else {
|
|
186
|
-
<ng-template [ngTemplateOutlet]="contentTplRef()" />
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
</sd-busy-container>
|
|
190
|
-
`,
|
|
191
|
-
}]
|
|
192
|
-
}], null, { contentTplRef: [{ type: i0.ContentChild, args: ["contentTpl", { ...{ read: TemplateRef }, isSignal: true }] }], pageTopbarTplRef: [{ type: i0.ContentChild, args: ["pageTopbarTpl", { ...{ read: TemplateRef }, isSignal: true }] }], modalBottomTplRef: [{ type: i0.ContentChild, args: ["modalBottomTpl", { ...{ read: TemplateRef }, isSignal: true }] }], viewType: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewType", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], initialized: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialized", required: false }] }], restricted: [{ type: i0.Input, args: [{ isSignal: true, alias: "restricted", required: false }] }], busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }], busyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "busyMessage", required: false }] }] }); })();
|
|
193
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdBaseContainer, { className: "SdBaseContainer", filePath: "packages/angular/src/layout/base-container/sd-base-container.ts", lineNumber: 82 }); })();
|
package/src/core/commons.ts
DELETED
package/src/core/injectParent.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type AbstractType, inject, Injector, ViewContainerRef } from "@angular/core";
|
|
2
|
-
|
|
3
|
-
export function injectParent<T = object>(): T;
|
|
4
|
-
export function injectParent<T = object>(type: AbstractType<T>): T;
|
|
5
|
-
export function injectParent<T = object>(
|
|
6
|
-
type: AbstractType<T>,
|
|
7
|
-
options: { optional: true },
|
|
8
|
-
): T | undefined;
|
|
9
|
-
export function injectParent<T = object>(
|
|
10
|
-
type?: AbstractType<T>,
|
|
11
|
-
options?: { optional: true },
|
|
12
|
-
): T | undefined {
|
|
13
|
-
let currentInjector: Injector | undefined = inject(ViewContainerRef).injector;
|
|
14
|
-
while (currentInjector != null) {
|
|
15
|
-
// Angular internal: NodeInjector._lView[CONTEXT=8]에 컴포넌트 인스턴스 저장
|
|
16
|
-
const lView: unknown[] | undefined = (
|
|
17
|
-
currentInjector as unknown as { _lView?: unknown[] }
|
|
18
|
-
)._lView;
|
|
19
|
-
if (lView == null) {
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const comp = lView[8];
|
|
24
|
-
// 컴포넌트 인스턴스 검증: null, primitive, plain object({})는 건너뜀
|
|
25
|
-
// Angular 내부 슬롯 변경 시 잘못된 객체 반환을 방지하는 방어 코드
|
|
26
|
-
if (comp != null && typeof comp === "object" && comp.constructor !== Object) {
|
|
27
|
-
if (type == null) {
|
|
28
|
-
return comp as T;
|
|
29
|
-
}
|
|
30
|
-
if (comp instanceof type) {
|
|
31
|
-
return comp as T;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
currentInjector = currentInjector.get(Injector, undefined, {
|
|
36
|
-
skipSelf: true,
|
|
37
|
-
optional: true,
|
|
38
|
-
}) as Injector | undefined;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (options?.optional) {
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
throw new Error("부모 컴포넌트를 찾을 수 없습니다.");
|
|
45
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { type Signal, type WritableSignal, effect, untracked } from "@angular/core";
|
|
2
|
-
|
|
3
|
-
export function setupCumulateSelectedKeys<TItem, TKey>(options: {
|
|
4
|
-
items: Signal<TItem[]>;
|
|
5
|
-
selectedItems: WritableSignal<TItem[]>;
|
|
6
|
-
selectedItemKeys: WritableSignal<TKey[]>;
|
|
7
|
-
selectMode: () => "single" | "multi" | undefined;
|
|
8
|
-
keySelectorFn: (item: TItem) => TKey | undefined;
|
|
9
|
-
}): void {
|
|
10
|
-
// items 변경 시 selectedItems에서 현재 items에 존재하지 않는 항목 제거
|
|
11
|
-
// selectedItems는 untracked로 읽어 effect 재실행 방지
|
|
12
|
-
effect(() => {
|
|
13
|
-
const items = options.items();
|
|
14
|
-
const selectedItems = untracked(() => options.selectedItems());
|
|
15
|
-
if (selectedItems.length === 0) return;
|
|
16
|
-
|
|
17
|
-
const itemKeySet = new Set(
|
|
18
|
-
items.map((item) => options.keySelectorFn(item)).filter((k) => k != null),
|
|
19
|
-
);
|
|
20
|
-
const filtered = selectedItems.filter((item) => {
|
|
21
|
-
const key = options.keySelectorFn(item);
|
|
22
|
-
return key != null && itemKeySet.has(key);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (filtered.length !== selectedItems.length) {
|
|
26
|
-
options.selectedItems.set(filtered);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// selectedItems 변경 시 selectedItemKeys 갱신
|
|
31
|
-
effect(() => {
|
|
32
|
-
const selectedItems = options.selectedItems();
|
|
33
|
-
const keys = selectedItems
|
|
34
|
-
.map((item) => options.keySelectorFn(item))
|
|
35
|
-
.filter((k): k is TKey => k != null);
|
|
36
|
-
options.selectedItemKeys.set(keys);
|
|
37
|
-
});
|
|
38
|
-
}
|
package/src/core/withBusy.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { WritableSignal } from "@angular/core";
|
|
2
|
-
|
|
3
|
-
export async function withBusy(
|
|
4
|
-
busyCount: WritableSignal<number>,
|
|
5
|
-
fn: () => Promise<void>,
|
|
6
|
-
): Promise<void> {
|
|
7
|
-
busyCount.update((v) => v + 1);
|
|
8
|
-
try {
|
|
9
|
-
await fn();
|
|
10
|
-
} finally {
|
|
11
|
-
busyCount.update((v) => v - 1);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Directive,
|
|
3
|
-
effect,
|
|
4
|
-
ErrorHandler,
|
|
5
|
-
inject,
|
|
6
|
-
output,
|
|
7
|
-
signal,
|
|
8
|
-
type Signal,
|
|
9
|
-
TemplateRef,
|
|
10
|
-
} from "@angular/core";
|
|
11
|
-
import { DateTime, obj } from "@simplysm/core-common";
|
|
12
|
-
import { TXT_CHANGE_IGNORE_CONFIRM } from "../../core/commons";
|
|
13
|
-
import { SdSharedDataProvider } from "../../core/shared-data/sd-shared-data.provider";
|
|
14
|
-
import { setupCanDeactivate } from "../../core/routing/setupCanDeactivate";
|
|
15
|
-
import { injectViewTypeSignal } from "../../core/routing/injectViewTypeSignal";
|
|
16
|
-
import { withBusy } from "../../core/withBusy";
|
|
17
|
-
import { type SdModalContentDef } from "../../core/modal/sd-modal.provider";
|
|
18
|
-
import { SdToastProvider } from "../../core/toast/sd-toast.provider";
|
|
19
|
-
import { getOrmDataEditToastErrorMessage } from "../getOrmDataEditToastErrorMessage";
|
|
20
|
-
|
|
21
|
-
export interface SdDataDetailDataInfo {
|
|
22
|
-
isNew: boolean;
|
|
23
|
-
isDeleted: boolean;
|
|
24
|
-
lastModifiedAt: DateTime | undefined;
|
|
25
|
-
lastModifiedBy: string | undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@Directive()
|
|
29
|
-
export abstract class SdDataDetailBase<T extends object, R = boolean>
|
|
30
|
-
implements SdModalContentDef<R>
|
|
31
|
-
{
|
|
32
|
-
//-- abstract
|
|
33
|
-
|
|
34
|
-
abstract canUse: Signal<boolean>;
|
|
35
|
-
abstract canEdit: Signal<boolean>;
|
|
36
|
-
canDelete?: Signal<boolean>;
|
|
37
|
-
|
|
38
|
-
prepareRefreshEffect?(): void;
|
|
39
|
-
|
|
40
|
-
abstract load():
|
|
41
|
-
| Promise<{ data: T; info: SdDataDetailDataInfo }>
|
|
42
|
-
| { data: T; info: SdDataDetailDataInfo };
|
|
43
|
-
|
|
44
|
-
toggleDelete?(del: boolean): Promise<R | undefined> | R | undefined;
|
|
45
|
-
|
|
46
|
-
submit?(data: T): Promise<R | undefined> | R | undefined;
|
|
47
|
-
|
|
48
|
-
//-- implement
|
|
49
|
-
|
|
50
|
-
protected readonly _sdToast = inject(SdToastProvider);
|
|
51
|
-
protected readonly _sdSharedData = inject(SdSharedDataProvider);
|
|
52
|
-
protected readonly _errorHandler = inject(ErrorHandler);
|
|
53
|
-
|
|
54
|
-
viewType = injectViewTypeSignal(() => this);
|
|
55
|
-
|
|
56
|
-
busyCount = signal(0);
|
|
57
|
-
busyMessage = signal<string | undefined>(undefined);
|
|
58
|
-
initialized = signal(false);
|
|
59
|
-
close = output<R>();
|
|
60
|
-
actionTplRef?: TemplateRef<any>;
|
|
61
|
-
|
|
62
|
-
data = signal<T>({} as T);
|
|
63
|
-
|
|
64
|
-
dataInfo = signal<SdDataDetailDataInfo | undefined>(undefined);
|
|
65
|
-
|
|
66
|
-
private _dataSnapshot?: T;
|
|
67
|
-
|
|
68
|
-
constructor() {
|
|
69
|
-
effect((onCleanup) => {
|
|
70
|
-
this.prepareRefreshEffect?.();
|
|
71
|
-
|
|
72
|
-
let cancelled = false;
|
|
73
|
-
onCleanup(() => {
|
|
74
|
-
cancelled = true;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
queueMicrotask(async () => {
|
|
78
|
-
try {
|
|
79
|
-
if (cancelled) return;
|
|
80
|
-
|
|
81
|
-
if (!this.canUse()) {
|
|
82
|
-
this.initialized.set(true);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
await withBusy(this.busyCount, () =>
|
|
87
|
-
this._sdToast.try(async () => {
|
|
88
|
-
await this._sdSharedData.wait();
|
|
89
|
-
await this.refresh();
|
|
90
|
-
}),
|
|
91
|
-
);
|
|
92
|
-
this.initialized.set(true);
|
|
93
|
-
} catch (err) {
|
|
94
|
-
this._errorHandler.handleError(err);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
setupCanDeactivate(() => this.viewType() === "modal" || this.checkIgnoreChanges());
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
checkIgnoreChanges() {
|
|
103
|
-
return (
|
|
104
|
-
this._dataSnapshot == null ||
|
|
105
|
-
obj.equal(this.data(), this._dataSnapshot) ||
|
|
106
|
-
confirm(TXT_CHANGE_IGNORE_CONFIRM)
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async doRefresh() {
|
|
111
|
-
if (this.busyCount() > 0) return;
|
|
112
|
-
if (!this.canUse()) return;
|
|
113
|
-
if (!this.checkIgnoreChanges()) return;
|
|
114
|
-
|
|
115
|
-
await withBusy(this.busyCount, () =>
|
|
116
|
-
this._sdToast.try(async () => {
|
|
117
|
-
await this.refresh();
|
|
118
|
-
}),
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async refresh() {
|
|
123
|
-
const result = await this.load();
|
|
124
|
-
this.data.set(result.data);
|
|
125
|
-
this.dataInfo.set(result.info);
|
|
126
|
-
if (!result.info.isNew) {
|
|
127
|
-
this._dataSnapshot = obj.clone(result.data);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async doToggleDelete(del: boolean) {
|
|
132
|
-
if (this.busyCount() > 0) return;
|
|
133
|
-
if (!this.canEdit()) return;
|
|
134
|
-
if (this.canDelete && !this.canDelete()) return;
|
|
135
|
-
if (!this.toggleDelete) return;
|
|
136
|
-
|
|
137
|
-
await withBusy(this.busyCount, () =>
|
|
138
|
-
this._sdToast.try(
|
|
139
|
-
async () => {
|
|
140
|
-
const result = await this.toggleDelete!(del);
|
|
141
|
-
if (!result) return;
|
|
142
|
-
|
|
143
|
-
this._sdToast.success(`${del ? "삭제" : "복구"}되었습니다.`);
|
|
144
|
-
|
|
145
|
-
this.close.emit(result);
|
|
146
|
-
},
|
|
147
|
-
(err) => getOrmDataEditToastErrorMessage(err),
|
|
148
|
-
),
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async doSubmit(opt?: { permCheck?: boolean; hideNoChangeMessage?: boolean }) {
|
|
153
|
-
if (this.busyCount() > 0) return;
|
|
154
|
-
if (opt?.permCheck && !this.canEdit()) return;
|
|
155
|
-
if (!this.submit) return;
|
|
156
|
-
|
|
157
|
-
const dataInfo = this.dataInfo();
|
|
158
|
-
if (dataInfo == null) return;
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
!dataInfo.isNew &&
|
|
162
|
-
(this._dataSnapshot == null || obj.equal(this.data(), this._dataSnapshot))
|
|
163
|
-
) {
|
|
164
|
-
if (!opt?.hideNoChangeMessage) {
|
|
165
|
-
this._sdToast.info("변경사항이 없습니다.");
|
|
166
|
-
}
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
await withBusy(this.busyCount, () =>
|
|
171
|
-
this._sdToast.try(
|
|
172
|
-
async () => {
|
|
173
|
-
const result = await this.submit!(this.data());
|
|
174
|
-
if (!result) return;
|
|
175
|
-
|
|
176
|
-
this._sdToast.success("저장되었습니다.");
|
|
177
|
-
|
|
178
|
-
this.close.emit(result);
|
|
179
|
-
|
|
180
|
-
await this.refresh();
|
|
181
|
-
},
|
|
182
|
-
(err) => getOrmDataEditToastErrorMessage(err),
|
|
183
|
-
),
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
}
|