@simplysm/angular 14.0.19 → 14.0.22
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/dist/core/provideSdAngular.js +1 -1
- package/dist/core/providers/sd-activated-modal.provider.d.ts +13 -0
- package/dist/core/providers/sd-activated-modal.provider.d.ts.map +1 -0
- package/dist/core/providers/sd-activated-modal.provider.js +15 -0
- package/dist/core/providers/sd-app-structure.provider.d.ts +3 -64
- package/dist/core/providers/sd-app-structure.provider.d.ts.map +1 -1
- package/dist/core/providers/sd-app-structure.provider.js +1 -252
- package/dist/core/providers/sd-app-structure.types.d.ts +52 -0
- package/dist/core/providers/sd-app-structure.types.d.ts.map +1 -0
- package/dist/core/providers/sd-app-structure.types.js +1 -0
- package/dist/core/providers/sd-app-structure.utils.d.ts +13 -0
- package/dist/core/providers/sd-app-structure.utils.d.ts.map +1 -0
- package/dist/core/providers/sd-app-structure.utils.js +250 -0
- package/dist/{ui/overlay/busy → core/providers}/sd-busy.provider.d.ts +1 -1
- package/dist/core/providers/sd-busy.provider.d.ts.map +1 -0
- package/dist/{ui/overlay/busy → core/providers}/sd-busy.provider.js +1 -1
- package/dist/core/providers/sd-print.provider.js +1 -1
- package/dist/core/providers/sd-service-client-factory.provider.js +1 -1
- package/dist/{ui/overlay/toast → core/providers}/sd-toast.provider.d.ts +1 -1
- package/dist/core/providers/sd-toast.provider.d.ts.map +1 -0
- package/dist/{ui/overlay/toast → core/providers}/sd-toast.provider.js +3 -3
- package/dist/core/types/select-modal-output-result.d.ts +8 -0
- package/dist/core/types/select-modal-output-result.d.ts.map +1 -0
- package/dist/core/types/select-modal-output-result.js +1 -0
- package/dist/core/utils/setups/setupCanDeactivate.js +1 -1
- package/dist/core/utils/useViewTitleSignal.js +1 -1
- package/dist/core/utils/useViewTypeSignal.js +1 -1
- package/dist/features/base/sd-base-container.control.js +1 -1
- package/dist/features/data-view/sd-data-detail.control.js +1 -1
- package/dist/features/data-view/sd-data-sheet.control.d.ts +24 -37
- package/dist/features/data-view/sd-data-sheet.control.d.ts.map +1 -1
- package/dist/features/data-view/sd-data-sheet.control.js +98 -152
- package/dist/features/data-view/sd-data-sheet.types.d.ts +17 -0
- package/dist/features/data-view/sd-data-sheet.types.d.ts.map +1 -0
- package/dist/features/data-view/sd-data-sheet.types.js +1 -0
- package/dist/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.d.ts +1 -1
- package/dist/features/data-view/setupCloserWhenSingleSelectionChange.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetExcelManager.d.ts +14 -0
- package/dist/features/data-view/useDataSheetExcelManager.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetExcelManager.js +31 -0
- package/dist/features/data-view/useDataSheetFilterManager.d.ts +13 -0
- package/dist/features/data-view/useDataSheetFilterManager.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetFilterManager.js +19 -0
- package/dist/features/data-view/useDataSheetInlineEditManager.d.ts +26 -0
- package/dist/features/data-view/useDataSheetInlineEditManager.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetInlineEditManager.js +54 -0
- package/dist/features/data-view/useDataSheetModalEditManager.d.ts +19 -0
- package/dist/features/data-view/useDataSheetModalEditManager.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetModalEditManager.js +44 -0
- package/dist/features/data-view/useDataSheetRefreshManager.d.ts +25 -0
- package/dist/features/data-view/useDataSheetRefreshManager.d.ts.map +1 -0
- package/dist/features/data-view/useDataSheetRefreshManager.js +50 -0
- package/dist/features/permission-table/sd-permission-table.control.d.ts +1 -1
- package/dist/features/permission-table/sd-permission-table.control.d.ts.map +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/ui/data/sheet/sd-sheet-config.modal.d.ts +1 -2
- package/dist/ui/data/sheet/sd-sheet-config.modal.d.ts.map +1 -1
- package/dist/ui/data/sheet/sd-sheet-config.modal.js +8 -11
- package/dist/ui/data/sheet/sd-sheet.control.d.ts +22 -30
- package/dist/ui/data/sheet/sd-sheet.control.d.ts.map +1 -1
- package/dist/ui/data/sheet/sd-sheet.control.js +52 -210
- package/dist/ui/data/sheet/useSheetCellStyling.d.ts +22 -0
- package/dist/ui/data/sheet/useSheetCellStyling.d.ts.map +1 -0
- package/dist/ui/data/sheet/useSheetCellStyling.js +95 -0
- package/dist/ui/data/sheet/useSheetColumnResizing.d.ts +17 -0
- package/dist/ui/data/sheet/useSheetColumnResizing.d.ts.map +1 -0
- package/dist/ui/data/sheet/useSheetColumnResizing.js +65 -0
- package/dist/ui/data/sheet/useSheetDisplayPipeline.d.ts +24 -0
- package/dist/ui/data/sheet/useSheetDisplayPipeline.d.ts.map +1 -0
- package/dist/ui/data/sheet/useSheetDisplayPipeline.js +52 -0
- package/dist/ui/form/button/sd-modal-select-button.control.d.ts +1 -7
- package/dist/ui/form/button/sd-modal-select-button.control.d.ts.map +1 -1
- package/dist/ui/form/button/sd-modal-select-button.control.js +1 -1
- package/dist/ui/form/choice/sd-state-preset.control.js +1 -1
- package/dist/ui/form/select/sd-select.control.d.ts +1 -1
- package/dist/ui/form/select/sd-select.control.d.ts.map +1 -1
- package/dist/ui/form/select/sd-select.control.js +23 -27
- package/dist/ui/layout/sd-gap.control.d.ts +1 -2
- package/dist/ui/layout/sd-gap.control.d.ts.map +1 -1
- package/dist/ui/layout/sd-gap.control.js +22 -24
- package/dist/ui/navigation/menu-utils.d.ts +2 -7
- package/dist/ui/navigation/menu-utils.d.ts.map +1 -1
- package/dist/ui/overlay/busy/sd-busy-container.control.d.ts +1 -1
- package/dist/ui/overlay/busy/sd-busy-container.control.d.ts.map +1 -1
- package/dist/ui/overlay/busy/sd-busy-container.control.js +1 -1
- package/dist/ui/overlay/modal/sd-confirm-modal.control.d.ts.map +1 -1
- package/dist/ui/overlay/modal/sd-confirm-modal.control.js +29 -23
- package/dist/ui/overlay/modal/sd-modal.control.js +1 -1
- package/dist/ui/overlay/modal/sd-modal.provider.d.ts +0 -10
- package/dist/ui/overlay/modal/sd-modal.provider.d.ts.map +1 -1
- package/dist/ui/overlay/modal/sd-modal.provider.js +1 -13
- package/dist/ui/overlay/modal/sd-prompt-modal.control.d.ts.map +1 -1
- package/dist/ui/overlay/modal/sd-prompt-modal.control.js +40 -33
- package/dist/ui/overlay/toast/sd-toast.control.d.ts +1 -1
- package/dist/ui/overlay/toast/sd-toast.control.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/core/provideSdAngular.ts +1 -1
- package/src/core/providers/sd-activated-modal.provider.ts +12 -0
- package/src/core/providers/sd-app-structure.provider.ts +2 -405
- package/src/core/providers/sd-app-structure.types.ts +60 -0
- package/src/core/providers/sd-app-structure.utils.ts +350 -0
- package/src/{ui/overlay/busy → core/providers}/sd-busy.provider.ts +1 -1
- package/src/core/providers/sd-print.provider.ts +1 -1
- package/src/core/providers/sd-service-client-factory.provider.ts +1 -1
- package/src/{ui/overlay/toast → core/providers}/sd-toast.provider.ts +4 -4
- package/src/core/types/select-modal-output-result.ts +7 -0
- package/src/core/utils/setups/setupCanDeactivate.ts +1 -1
- package/src/core/utils/useViewTitleSignal.ts +1 -1
- package/src/core/utils/useViewTypeSignal.ts +1 -1
- package/src/features/base/sd-base-container.control.ts +1 -1
- package/src/features/data-view/sd-data-detail.control.ts +1 -1
- package/src/features/data-view/sd-data-sheet.control.ts +117 -216
- package/src/features/data-view/sd-data-sheet.types.ts +18 -0
- package/src/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.ts +1 -1
- package/src/features/data-view/useDataSheetExcelManager.ts +57 -0
- package/src/features/data-view/useDataSheetFilterManager.ts +30 -0
- package/src/features/data-view/useDataSheetInlineEditManager.ts +89 -0
- package/src/features/data-view/useDataSheetModalEditManager.ts +76 -0
- package/src/features/data-view/useDataSheetRefreshManager.ts +90 -0
- package/src/features/permission-table/sd-permission-table.control.ts +1 -1
- package/src/index.ts +17 -11
- package/src/ui/data/sheet/sd-sheet-config.modal.ts +7 -11
- package/src/ui/data/sheet/sd-sheet.control.ts +50 -238
- package/src/ui/data/sheet/useSheetCellStyling.ts +113 -0
- package/src/ui/data/sheet/useSheetColumnResizing.ts +92 -0
- package/src/ui/data/sheet/useSheetDisplayPipeline.ts +64 -0
- package/src/ui/form/button/sd-modal-select-button.control.ts +1 -8
- package/src/ui/form/choice/sd-state-preset.control.ts +1 -1
- package/src/ui/form/select/sd-select.control.ts +21 -26
- package/src/ui/layout/sd-gap.control.ts +17 -21
- package/src/ui/navigation/menu-utils.ts +3 -7
- package/src/ui/overlay/busy/sd-busy-container.control.ts +1 -1
- package/src/ui/overlay/modal/sd-confirm-modal.control.ts +8 -26
- package/src/ui/overlay/modal/sd-modal.control.ts +1 -1
- package/src/ui/overlay/modal/sd-modal.provider.ts +1 -10
- package/src/ui/overlay/modal/sd-prompt-modal.control.ts +17 -43
- package/src/ui/overlay/toast/sd-toast.control.ts +1 -1
- package/dist/core/utils/setups/setupCloserWhenSingleSelectionChange.d.ts.map +0 -1
- package/dist/ui/overlay/busy/sd-busy.provider.d.ts.map +0 -1
- package/dist/ui/overlay/toast/sd-toast.provider.d.ts.map +0 -1
- /package/dist/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.js +0 -0
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
contentChildren,
|
|
8
8
|
Directive,
|
|
9
9
|
effect,
|
|
10
|
-
inject,
|
|
11
10
|
input,
|
|
12
11
|
type InputSignal,
|
|
13
12
|
model,
|
|
@@ -16,34 +15,34 @@ import {
|
|
|
16
15
|
signal,
|
|
17
16
|
type Signal,
|
|
18
17
|
TemplateRef,
|
|
18
|
+
type WritableSignal,
|
|
19
19
|
viewChild,
|
|
20
20
|
ViewEncapsulation,
|
|
21
21
|
} from "@angular/core";
|
|
22
|
-
import {
|
|
22
|
+
import type { ArrayOneWayDiffResult } from "@simplysm/core-common";
|
|
23
23
|
import { mark } from "../../core/utils/mark";
|
|
24
24
|
import { SdButtonControl } from "../../ui/form/button/sd-button.control";
|
|
25
25
|
import { SdFormControl } from "../../ui/form/sd-form.control";
|
|
26
26
|
import { SdSheetColumnDirective } from "../../ui/data/sheet/sd-sheet-column.directive";
|
|
27
27
|
import { SdSheetControl, type ISortingDef } from "../../ui/data/sheet/sd-sheet.control";
|
|
28
|
-
import { SdFileDialogProvider } from "../../core/providers/sd-file-dialog.provider";
|
|
29
|
-
import { SdToastProvider } from "../../ui/overlay/toast/sd-toast.provider";
|
|
30
|
-
import { SdSharedDataProvider } from "../../core/providers/sd-shared-data.provider";
|
|
31
28
|
import { useViewTypeSignal } from "../../core/utils/useViewTypeSignal";
|
|
32
29
|
import { setupCumulateSelectedKeys } from "../../core/utils/setups/setupCumulateSelectedKeys";
|
|
33
|
-
import { setupCloserWhenSingleSelectionChange } from "
|
|
30
|
+
import { setupCloserWhenSingleSelectionChange } from "./setupCloserWhenSingleSelectionChange";
|
|
34
31
|
import { setupCanDeactivate } from "../../core/utils/setups/setupCanDeactivate";
|
|
35
32
|
import { injectParent } from "../../core/utils/injectParent";
|
|
36
|
-
import { withBusy } from "../../core/utils/withBusy";
|
|
37
33
|
import { FormatPipe } from "../../core/pipes/format.pipe";
|
|
38
34
|
import { TXT_CHANGE_IGNORE_CONFIRM } from "../../core/commons";
|
|
39
35
|
import { SdBaseContainerControl } from "../base/sd-base-container.control";
|
|
40
36
|
import { SdDataSheetColumnDirective } from "./sd-data-sheet-column.directive";
|
|
41
|
-
import type {
|
|
42
|
-
|
|
43
|
-
ISelectModalOutputResult,
|
|
44
|
-
} from "../../ui/form/button/sd-modal-select-button.control";
|
|
37
|
+
import type { ISdSelectModal } from "../../ui/form/button/sd-modal-select-button.control";
|
|
38
|
+
import type { ISelectModalOutputResult } from "../../core/types/select-modal-output-result";
|
|
45
39
|
import { SdAnchorControl } from "../../ui/form/button/sd-anchor.control";
|
|
46
40
|
import { NgIcon } from "@ng-icons/core";
|
|
41
|
+
import { useDataSheetFilterManager } from "./useDataSheetFilterManager";
|
|
42
|
+
import { useDataSheetRefreshManager } from "./useDataSheetRefreshManager";
|
|
43
|
+
import { useDataSheetInlineEditManager } from "./useDataSheetInlineEditManager";
|
|
44
|
+
import { useDataSheetModalEditManager } from "./useDataSheetModalEditManager";
|
|
45
|
+
import { useDataSheetExcelManager } from "./useDataSheetExcelManager";
|
|
47
46
|
import {
|
|
48
47
|
tablerDeviceFloppy,
|
|
49
48
|
tablerEdit,
|
|
@@ -56,28 +55,16 @@ import {
|
|
|
56
55
|
tablerUpload,
|
|
57
56
|
} from "@ng-icons/tabler-icons";
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
canSelect: boolean;
|
|
70
|
-
canEdit: boolean;
|
|
71
|
-
canDelete: boolean;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface ISdDataSheetSearchResult<I> {
|
|
75
|
-
items: I[];
|
|
76
|
-
pageLength?: number;
|
|
77
|
-
summary?: Partial<I>;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
//#endregion
|
|
58
|
+
export type {
|
|
59
|
+
ISdDataSheetItemPropInfo,
|
|
60
|
+
ISdDataSheetItemInfo,
|
|
61
|
+
ISdDataSheetSearchResult,
|
|
62
|
+
} from "./sd-data-sheet.types";
|
|
63
|
+
import type {
|
|
64
|
+
ISdDataSheetItemPropInfo,
|
|
65
|
+
ISdDataSheetItemInfo,
|
|
66
|
+
ISdDataSheetSearchResult,
|
|
67
|
+
} from "./sd-data-sheet.types";
|
|
81
68
|
|
|
82
69
|
//#region AbsSdDataSheet
|
|
83
70
|
|
|
@@ -116,12 +103,18 @@ export abstract class AbsSdDataSheet<
|
|
|
116
103
|
downloadExcel?(items: TItem[]): Promise<void> | void;
|
|
117
104
|
uploadExcel?(file: File): Promise<void> | void;
|
|
118
105
|
|
|
119
|
-
//--
|
|
120
|
-
private readonly
|
|
121
|
-
private readonly
|
|
122
|
-
private readonly
|
|
123
|
-
|
|
124
|
-
|
|
106
|
+
//-- composable instances
|
|
107
|
+
private readonly _filterMgr: ReturnType<typeof useDataSheetFilterManager<TFilter>>;
|
|
108
|
+
private readonly _refreshMgr: ReturnType<typeof useDataSheetRefreshManager<TItem, TKey>>;
|
|
109
|
+
private readonly _inlineEditMgr: ReturnType<
|
|
110
|
+
typeof useDataSheetInlineEditManager<TItem, TKey>
|
|
111
|
+
>;
|
|
112
|
+
private readonly _modalEditMgr: ReturnType<
|
|
113
|
+
typeof useDataSheetModalEditManager<TItem, TKey>
|
|
114
|
+
>;
|
|
115
|
+
private readonly _excelMgr: ReturnType<typeof useDataSheetExcelManager<TItem>>;
|
|
116
|
+
|
|
117
|
+
//-- shared state (D1: class 소유)
|
|
125
118
|
key = reflectComponentType(this.constructor as any)?.selector;
|
|
126
119
|
|
|
127
120
|
viewType = useViewTypeSignal(() => this);
|
|
@@ -150,11 +143,9 @@ export abstract class AbsSdDataSheet<
|
|
|
150
143
|
pageLength = signal(0);
|
|
151
144
|
sortingDefs = signal<ISortingDef[]>([]);
|
|
152
145
|
|
|
153
|
-
filter
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//-- change tracking
|
|
157
|
-
private _itemsSnapshot: TItem[] = [];
|
|
146
|
+
//-- filter state (composable에서 생성, 재할당)
|
|
147
|
+
filter!: WritableSignal<TFilter>;
|
|
148
|
+
lastFilter!: WritableSignal<TFilter>;
|
|
158
149
|
|
|
159
150
|
//-- computed
|
|
160
151
|
isSelectedItemsHasDeleted = computed(() =>
|
|
@@ -196,56 +187,84 @@ export abstract class AbsSdDataSheet<
|
|
|
196
187
|
close: this.close,
|
|
197
188
|
});
|
|
198
189
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
202
|
-
this.
|
|
190
|
+
//-- filter composable
|
|
191
|
+
this._filterMgr = useDataSheetFilterManager({
|
|
192
|
+
bindFilter: () => this.bindFilter(),
|
|
193
|
+
busyCount: this.busyCount,
|
|
194
|
+
canUse: () => this.canUse(),
|
|
195
|
+
page: this.page,
|
|
196
|
+
checkIgnoreChanges: () => this.checkIgnoreChanges(),
|
|
197
|
+
});
|
|
198
|
+
this.filter = this._filterMgr.filter;
|
|
199
|
+
this.lastFilter = this._filterMgr.lastFilter;
|
|
200
|
+
|
|
201
|
+
//-- refresh composable
|
|
202
|
+
this._refreshMgr = useDataSheetRefreshManager({
|
|
203
|
+
busyCount: this.busyCount,
|
|
204
|
+
initialized: this.initialized,
|
|
205
|
+
canUse: () => this.canUse(),
|
|
206
|
+
items: this.items,
|
|
207
|
+
selectedItems: this.selectedItems,
|
|
208
|
+
pageLength: this.pageLength,
|
|
209
|
+
summaryData: this.summaryData,
|
|
210
|
+
page: this.page,
|
|
211
|
+
lastFilter: this.lastFilter,
|
|
212
|
+
sortingDefs: this.sortingDefs,
|
|
213
|
+
getItemInfoFn: (item) => this.getItemInfoFn(item),
|
|
214
|
+
search: (p) => this.search(p),
|
|
215
|
+
prepareRefreshEffect: () => this.prepareRefreshEffect?.(),
|
|
216
|
+
getDiffsExcludes: () => this.diffsExcludes,
|
|
203
217
|
});
|
|
204
218
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
this.
|
|
208
|
-
this.
|
|
209
|
-
this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
this.initialized.set(true);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
219
|
+
//-- inline edit composable
|
|
220
|
+
this._inlineEditMgr = useDataSheetInlineEditManager({
|
|
221
|
+
busyCount: this.busyCount,
|
|
222
|
+
canEdit: () => this.canEdit(),
|
|
223
|
+
items: this.items,
|
|
224
|
+
submitted: this.submitted,
|
|
225
|
+
itemPropInfo: () => this.itemPropInfo,
|
|
226
|
+
getItemInfoFn: (item) => this.getItemInfoFn(item),
|
|
227
|
+
getDiffs: () => this._refreshMgr.getDiffs(),
|
|
228
|
+
refresh: () => this._refreshMgr.refresh(),
|
|
229
|
+
getNewItemFn: () => this.newItem?.bind(this),
|
|
230
|
+
getSubmitFn: () => this.submit?.bind(this),
|
|
231
|
+
errorMessageFn: (err) => this._getOrmDataEditToastErrorMessage(err),
|
|
232
|
+
});
|
|
222
233
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
234
|
+
//-- modal edit composable
|
|
235
|
+
this._modalEditMgr = useDataSheetModalEditManager({
|
|
236
|
+
busyCount: this.busyCount,
|
|
237
|
+
canEdit: () => this.canEdit(),
|
|
238
|
+
selectedItemKeys: this.selectedItemKeys,
|
|
239
|
+
selectedItems: this.selectedItems,
|
|
240
|
+
close: this.close,
|
|
241
|
+
refresh: () => this._refreshMgr.refresh(),
|
|
242
|
+
getEditItemFn: () => this.editItem?.bind(this),
|
|
243
|
+
getToggleDeleteItemsFn: () => this.toggleDeleteItems?.bind(this),
|
|
244
|
+
errorMessageFn: (err) => this._getOrmDataEditToastErrorMessage(err),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
//-- excel composable
|
|
248
|
+
this._excelMgr = useDataSheetExcelManager({
|
|
249
|
+
busyCount: this.busyCount,
|
|
250
|
+
search: (p) => this.search(p),
|
|
251
|
+
refresh: () => this._refreshMgr.refresh(),
|
|
252
|
+
getDownloadExcelFn: () => this.downloadExcel?.bind(this),
|
|
253
|
+
getUploadExcelFn: () => this.uploadExcel?.bind(this),
|
|
254
|
+
errorMessageFn: (err) => this._getOrmDataEditToastErrorMessage(err),
|
|
231
255
|
});
|
|
232
256
|
|
|
233
257
|
setupCanDeactivate(() => this.viewType() === "modal" || this.checkIgnoreChanges());
|
|
234
258
|
}
|
|
235
259
|
|
|
236
|
-
//--
|
|
260
|
+
//-- D2: class 메서드 (커스터마이징 가능)
|
|
237
261
|
|
|
238
262
|
checkIgnoreChanges() {
|
|
239
|
-
return this.
|
|
263
|
+
return this._refreshMgr.getDiffs().length === 0 || confirm(TXT_CHANGE_IGNORE_CONFIRM);
|
|
240
264
|
}
|
|
241
265
|
|
|
242
266
|
doFilterSubmit() {
|
|
243
|
-
|
|
244
|
-
if (!this.canUse()) return;
|
|
245
|
-
if (!this.checkIgnoreChanges()) return;
|
|
246
|
-
|
|
247
|
-
this.page.set(0);
|
|
248
|
-
this.lastFilter.set(obj.clone(this.filter()));
|
|
267
|
+
this._filterMgr.doFilterSubmit();
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
doRefresh() {
|
|
@@ -257,171 +276,53 @@ export abstract class AbsSdDataSheet<
|
|
|
257
276
|
}
|
|
258
277
|
|
|
259
278
|
async refresh() {
|
|
260
|
-
|
|
261
|
-
this.items.set(result.items);
|
|
262
|
-
this._itemsSnapshot = obj.clone(result.items);
|
|
263
|
-
|
|
264
|
-
this.pageLength.set(result.pageLength ?? 0);
|
|
265
|
-
this.summaryData.set(result.summary ?? {});
|
|
266
|
-
|
|
267
|
-
const selectedKeySet = new Set(
|
|
268
|
-
this.selectedItems().map((sel) => this.getItemInfoFn(sel).key),
|
|
269
|
-
);
|
|
270
|
-
this.selectedItems.set(
|
|
271
|
-
this.items().filter((item) => selectedKeySet.has(this.getItemInfoFn(item).key)),
|
|
272
|
-
);
|
|
279
|
+
await this._refreshMgr.refresh();
|
|
273
280
|
}
|
|
274
281
|
|
|
275
|
-
//-- inline edit
|
|
282
|
+
//-- inline edit (delegated to composable)
|
|
276
283
|
|
|
277
284
|
async doAddItem() {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
await withBusy(this.busyCount, () =>
|
|
281
|
-
this._sdToast.try(async () => {
|
|
282
|
-
const newItem = await this.newItem!();
|
|
283
|
-
this.items.update((items) => [newItem, ...items]);
|
|
284
|
-
}),
|
|
285
|
-
);
|
|
285
|
+
await this._inlineEditMgr.doAddItem();
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
async doSubmit(opt?: { permCheck?: boolean; hideNoChangeMessage?: boolean }) {
|
|
289
|
-
|
|
290
|
-
if (opt?.permCheck && !this.canEdit()) return;
|
|
291
|
-
if (!this.submit) return;
|
|
292
|
-
|
|
293
|
-
const diffs = this._getDiffs();
|
|
294
|
-
|
|
295
|
-
if (diffs.length === 0) {
|
|
296
|
-
if (!opt?.hideNoChangeMessage) {
|
|
297
|
-
this._sdToast.info("변경사항이 없습니다.");
|
|
298
|
-
}
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
await withBusy(this.busyCount, () =>
|
|
303
|
-
this._sdToast.try(
|
|
304
|
-
async () => {
|
|
305
|
-
const result = await this.submit!(diffs);
|
|
306
|
-
if (!result) return;
|
|
307
|
-
|
|
308
|
-
this._sdToast.success("저장되었습니다.");
|
|
309
|
-
await this.refresh();
|
|
310
|
-
this.submitted.emit(true);
|
|
311
|
-
},
|
|
312
|
-
(err) => this._getOrmDataEditToastErrorMessage(err),
|
|
313
|
-
),
|
|
314
|
-
);
|
|
289
|
+
await this._inlineEditMgr.doSubmit(opt);
|
|
315
290
|
}
|
|
316
291
|
|
|
317
292
|
doToggleDeleteItem(item: TItem) {
|
|
318
|
-
|
|
319
|
-
if (this.itemPropInfo.isDeleted == null) return;
|
|
320
|
-
|
|
321
|
-
if (this.getItemInfoFn(item).key == null) {
|
|
322
|
-
this.items.update((items) => items.filter((item1) => item1 !== item));
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
(item[this.itemPropInfo.isDeleted] as boolean) = !(item[
|
|
327
|
-
this.itemPropInfo.isDeleted
|
|
328
|
-
] as boolean);
|
|
329
|
-
mark(this.items);
|
|
293
|
+
this._inlineEditMgr.doToggleDeleteItem(item);
|
|
330
294
|
}
|
|
331
295
|
|
|
332
|
-
//-- modal edit
|
|
296
|
+
//-- modal edit (delegated to composable)
|
|
333
297
|
|
|
334
298
|
async doEditItem(item?: TItem) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const result = await this.editItem(item);
|
|
338
|
-
if (!result) return;
|
|
339
|
-
|
|
340
|
-
await withBusy(this.busyCount, () =>
|
|
341
|
-
this._sdToast.try(async () => {
|
|
342
|
-
await this.refresh();
|
|
343
|
-
}),
|
|
344
|
-
);
|
|
299
|
+
await this._modalEditMgr.doEditItem(item);
|
|
345
300
|
}
|
|
346
301
|
|
|
347
302
|
async doToggleDeleteItems(del: boolean) {
|
|
348
|
-
|
|
349
|
-
if (!this.toggleDeleteItems) return;
|
|
350
|
-
|
|
351
|
-
await withBusy(this.busyCount, () =>
|
|
352
|
-
this._sdToast.try(
|
|
353
|
-
async () => {
|
|
354
|
-
const result = await this.toggleDeleteItems!(del);
|
|
355
|
-
if (!result) return;
|
|
356
|
-
|
|
357
|
-
await this.refresh();
|
|
358
|
-
this._sdToast.success(`${del ? "삭제" : "복구"} 되었습니다.`);
|
|
359
|
-
},
|
|
360
|
-
(err) => this._getOrmDataEditToastErrorMessage(err),
|
|
361
|
-
),
|
|
362
|
-
);
|
|
303
|
+
await this._modalEditMgr.doToggleDeleteItems(del);
|
|
363
304
|
}
|
|
364
305
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
async doDownloadExcel() {
|
|
368
|
-
if (!this.downloadExcel) return;
|
|
369
|
-
|
|
370
|
-
await withBusy(this.busyCount, () =>
|
|
371
|
-
this._sdToast.try(async () => {
|
|
372
|
-
const items = (await this.search(false)).items;
|
|
373
|
-
await this.downloadExcel!(items);
|
|
374
|
-
}),
|
|
375
|
-
);
|
|
306
|
+
doModalConfirm() {
|
|
307
|
+
this._modalEditMgr.doModalConfirm();
|
|
376
308
|
}
|
|
377
309
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const file = await this._sdFileDialog.showAsync(
|
|
382
|
-
false,
|
|
383
|
-
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
384
|
-
);
|
|
385
|
-
if (!file) return;
|
|
386
|
-
|
|
387
|
-
await withBusy(this.busyCount, () =>
|
|
388
|
-
this._sdToast.try(
|
|
389
|
-
async () => {
|
|
390
|
-
await this.uploadExcel!(file);
|
|
391
|
-
await this.refresh();
|
|
392
|
-
this._sdToast.success("엑셀 업로드가 완료 되었습니다.");
|
|
393
|
-
},
|
|
394
|
-
(err) => this._getOrmDataEditToastErrorMessage(err),
|
|
395
|
-
),
|
|
396
|
-
);
|
|
310
|
+
doModalCancel() {
|
|
311
|
+
this._modalEditMgr.doModalCancel();
|
|
397
312
|
}
|
|
398
313
|
|
|
399
|
-
//--
|
|
314
|
+
//-- excel (delegated to composable)
|
|
400
315
|
|
|
401
|
-
|
|
402
|
-
this.
|
|
403
|
-
selectedItemKeys: this.selectedItemKeys(),
|
|
404
|
-
selectedItems: this.selectedItems(),
|
|
405
|
-
});
|
|
316
|
+
async doDownloadExcel() {
|
|
317
|
+
await this._excelMgr.doDownloadExcel();
|
|
406
318
|
}
|
|
407
319
|
|
|
408
|
-
|
|
409
|
-
this.
|
|
410
|
-
selectedItemKeys: [],
|
|
411
|
-
selectedItems: [],
|
|
412
|
-
});
|
|
320
|
+
async doUploadExcel() {
|
|
321
|
+
await this._excelMgr.doUploadExcel();
|
|
413
322
|
}
|
|
414
323
|
|
|
415
324
|
//-- private
|
|
416
325
|
|
|
417
|
-
private _getDiffs(): ArrayOneWayDiffResult<TItem>[] {
|
|
418
|
-
return this.items().oneWayDiffs(
|
|
419
|
-
this._itemsSnapshot,
|
|
420
|
-
(item) => this.getItemInfoFn(item).key,
|
|
421
|
-
this.diffsExcludes ? { excludes: this.diffsExcludes } : undefined,
|
|
422
|
-
).filter((d) => d.type !== "same");
|
|
423
|
-
}
|
|
424
|
-
|
|
425
326
|
private _getOrmDataEditToastErrorMessage(err: unknown) {
|
|
426
327
|
const message = err instanceof Error ? err.message : String(err);
|
|
427
328
|
if (
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ISdDataSheetItemPropInfo<I> {
|
|
2
|
+
isDeleted: (keyof I & string) | undefined;
|
|
3
|
+
lastModifiedAt: (keyof I & string) | undefined;
|
|
4
|
+
lastModifiedBy: (keyof I & string) | undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ISdDataSheetItemInfo<K> {
|
|
8
|
+
key: K;
|
|
9
|
+
canSelect: boolean;
|
|
10
|
+
canEdit: boolean;
|
|
11
|
+
canDelete: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ISdDataSheetSearchResult<I> {
|
|
15
|
+
items: I[];
|
|
16
|
+
pageLength?: number;
|
|
17
|
+
summary?: Partial<I>;
|
|
18
|
+
}
|
package/src/{core/utils/setups → features/data-view}/setupCloserWhenSingleSelectionChange.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type OutputEmitterRef, type Signal, effect } from "@angular/core";
|
|
2
|
-
import type { ISelectModalOutputResult } from "
|
|
2
|
+
import type { ISelectModalOutputResult } from "../../core/types/select-modal-output-result";
|
|
3
3
|
|
|
4
4
|
export function setupCloserWhenSingleSelectionChange<TItem, TKey>(options: {
|
|
5
5
|
selectedItemKeys: Signal<TKey[]>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type WritableSignal, inject } from "@angular/core";
|
|
2
|
+
import { SdToastProvider } from "../../core/providers/sd-toast.provider";
|
|
3
|
+
import { SdFileDialogProvider } from "../../core/providers/sd-file-dialog.provider";
|
|
4
|
+
import { withBusy } from "../../core/utils/withBusy";
|
|
5
|
+
import type { ISdDataSheetSearchResult } from "./sd-data-sheet.types";
|
|
6
|
+
|
|
7
|
+
export function useDataSheetExcelManager<TItem>(options: {
|
|
8
|
+
busyCount: WritableSignal<number>;
|
|
9
|
+
search: (
|
|
10
|
+
usePagination: boolean,
|
|
11
|
+
) => Promise<ISdDataSheetSearchResult<TItem>> | ISdDataSheetSearchResult<TItem>;
|
|
12
|
+
refresh: () => Promise<void>;
|
|
13
|
+
getDownloadExcelFn: () =>
|
|
14
|
+
| ((items: TItem[]) => Promise<void> | void)
|
|
15
|
+
| undefined;
|
|
16
|
+
getUploadExcelFn: () => ((file: File) => Promise<void> | void) | undefined;
|
|
17
|
+
errorMessageFn: (err: unknown) => string;
|
|
18
|
+
}) {
|
|
19
|
+
const sdToast = inject(SdToastProvider);
|
|
20
|
+
const sdFileDialog = inject(SdFileDialogProvider);
|
|
21
|
+
|
|
22
|
+
async function doDownloadExcel(): Promise<void> {
|
|
23
|
+
const downloadExcelFn = options.getDownloadExcelFn();
|
|
24
|
+
if (!downloadExcelFn) return;
|
|
25
|
+
|
|
26
|
+
await withBusy(options.busyCount, () =>
|
|
27
|
+
sdToast.try(async () => {
|
|
28
|
+
const items = (await options.search(false)).items;
|
|
29
|
+
await downloadExcelFn(items);
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function doUploadExcel(): Promise<void> {
|
|
35
|
+
const uploadExcelFn = options.getUploadExcelFn();
|
|
36
|
+
if (!uploadExcelFn) return;
|
|
37
|
+
|
|
38
|
+
const file = await sdFileDialog.showAsync(
|
|
39
|
+
false,
|
|
40
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
41
|
+
);
|
|
42
|
+
if (!file) return;
|
|
43
|
+
|
|
44
|
+
await withBusy(options.busyCount, () =>
|
|
45
|
+
sdToast.try(
|
|
46
|
+
async () => {
|
|
47
|
+
await uploadExcelFn(file);
|
|
48
|
+
await options.refresh();
|
|
49
|
+
sdToast.success("엑셀 업로드가 완료 되었습니다.");
|
|
50
|
+
},
|
|
51
|
+
(err) => options.errorMessageFn(err),
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { doDownloadExcel, doUploadExcel };
|
|
57
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Signal, type WritableSignal, linkedSignal } from "@angular/core";
|
|
2
|
+
import { obj } from "@simplysm/core-common";
|
|
3
|
+
|
|
4
|
+
export function useDataSheetFilterManager<TFilter extends Record<string, any>>(options: {
|
|
5
|
+
bindFilter: () => TFilter;
|
|
6
|
+
busyCount: Signal<number>;
|
|
7
|
+
canUse: () => boolean;
|
|
8
|
+
page: WritableSignal<number>;
|
|
9
|
+
checkIgnoreChanges: () => boolean;
|
|
10
|
+
}) {
|
|
11
|
+
const filter = linkedSignal<TFilter, TFilter>({
|
|
12
|
+
source: options.bindFilter,
|
|
13
|
+
computation: (f) => f,
|
|
14
|
+
});
|
|
15
|
+
const lastFilter = linkedSignal<TFilter, TFilter>({
|
|
16
|
+
source: options.bindFilter,
|
|
17
|
+
computation: (f) => obj.clone(f),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function doFilterSubmit(): void {
|
|
21
|
+
if (options.busyCount() > 0) return;
|
|
22
|
+
if (!options.canUse()) return;
|
|
23
|
+
if (!options.checkIgnoreChanges()) return;
|
|
24
|
+
|
|
25
|
+
options.page.set(0);
|
|
26
|
+
lastFilter.set(obj.clone(filter()));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return { filter, lastFilter, doFilterSubmit };
|
|
30
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type OutputEmitterRef,
|
|
3
|
+
type WritableSignal,
|
|
4
|
+
inject,
|
|
5
|
+
} from "@angular/core";
|
|
6
|
+
import type { ArrayOneWayDiffResult } from "@simplysm/core-common";
|
|
7
|
+
import { mark } from "../../core/utils/mark";
|
|
8
|
+
import { SdToastProvider } from "../../core/providers/sd-toast.provider";
|
|
9
|
+
import { withBusy } from "../../core/utils/withBusy";
|
|
10
|
+
import type { ISdDataSheetItemPropInfo } from "./sd-data-sheet.types";
|
|
11
|
+
|
|
12
|
+
export function useDataSheetInlineEditManager<TItem, TKey>(options: {
|
|
13
|
+
busyCount: WritableSignal<number>;
|
|
14
|
+
canEdit: () => boolean;
|
|
15
|
+
items: WritableSignal<TItem[]>;
|
|
16
|
+
submitted: OutputEmitterRef<boolean>;
|
|
17
|
+
itemPropInfo: () => ISdDataSheetItemPropInfo<TItem>;
|
|
18
|
+
getItemInfoFn: (item: TItem) => { key: TKey };
|
|
19
|
+
getDiffs: () => ArrayOneWayDiffResult<TItem>[];
|
|
20
|
+
refresh: () => Promise<void>;
|
|
21
|
+
getNewItemFn: () => (() => Promise<TItem> | TItem) | undefined;
|
|
22
|
+
getSubmitFn: () =>
|
|
23
|
+
| ((diffs: ArrayOneWayDiffResult<TItem>[]) => Promise<boolean> | boolean)
|
|
24
|
+
| undefined;
|
|
25
|
+
errorMessageFn: (err: unknown) => string;
|
|
26
|
+
}) {
|
|
27
|
+
const sdToast = inject(SdToastProvider);
|
|
28
|
+
|
|
29
|
+
async function doAddItem(): Promise<void> {
|
|
30
|
+
const newItemFn = options.getNewItemFn();
|
|
31
|
+
if (!newItemFn) return;
|
|
32
|
+
|
|
33
|
+
await withBusy(options.busyCount, () =>
|
|
34
|
+
sdToast.try(async () => {
|
|
35
|
+
const newItem = await newItemFn();
|
|
36
|
+
options.items.update((items) => [newItem, ...items]);
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function doSubmit(opt?: {
|
|
42
|
+
permCheck?: boolean;
|
|
43
|
+
hideNoChangeMessage?: boolean;
|
|
44
|
+
}): Promise<void> {
|
|
45
|
+
if (options.busyCount() > 0) return;
|
|
46
|
+
if (opt?.permCheck && !options.canEdit()) return;
|
|
47
|
+
const submitFn = options.getSubmitFn();
|
|
48
|
+
if (!submitFn) return;
|
|
49
|
+
|
|
50
|
+
const diffs = options.getDiffs();
|
|
51
|
+
|
|
52
|
+
if (diffs.length === 0) {
|
|
53
|
+
if (!opt?.hideNoChangeMessage) {
|
|
54
|
+
sdToast.info("변경사항이 없습니다.");
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await withBusy(options.busyCount, () =>
|
|
60
|
+
sdToast.try(
|
|
61
|
+
async () => {
|
|
62
|
+
const result = await submitFn(diffs);
|
|
63
|
+
if (!result) return;
|
|
64
|
+
|
|
65
|
+
sdToast.success("저장되었습니다.");
|
|
66
|
+
await options.refresh();
|
|
67
|
+
options.submitted.emit(true);
|
|
68
|
+
},
|
|
69
|
+
(err) => options.errorMessageFn(err),
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function doToggleDeleteItem(item: TItem): void {
|
|
75
|
+
if (!options.canEdit()) return;
|
|
76
|
+
const propInfo = options.itemPropInfo();
|
|
77
|
+
if (propInfo.isDeleted == null) return;
|
|
78
|
+
|
|
79
|
+
if (options.getItemInfoFn(item).key == null) {
|
|
80
|
+
options.items.update((items) => items.filter((item1) => item1 !== item));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
(item[propInfo.isDeleted] as boolean) = !(item[propInfo.isDeleted] as boolean);
|
|
85
|
+
mark(options.items);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return { doAddItem, doSubmit, doToggleDeleteItem };
|
|
89
|
+
}
|