@simplysm/angular 14.0.47 → 14.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +467 -0
  2. package/dist/controls/dropdown/sd-dropdown-popup.d.ts +1 -0
  3. package/dist/controls/dropdown/sd-dropdown-popup.d.ts.map +1 -1
  4. package/dist/controls/dropdown/sd-dropdown-popup.js +6 -1
  5. package/dist/controls/dropdown/sd-dropdown.d.ts.map +1 -1
  6. package/dist/controls/dropdown/sd-dropdown.js +6 -2
  7. package/dist/controls/select/sd-select.d.ts.map +1 -1
  8. package/dist/controls/select/sd-select.js +12 -34
  9. package/dist/core/routing/injectViewTypeSignal.d.ts +1 -1
  10. package/dist/core/routing/injectViewTypeSignal.d.ts.map +1 -1
  11. package/dist/core/routing/injectViewTypeSignal.js +15 -7
  12. package/dist/core/selection/useSelectionManager.d.ts +1 -0
  13. package/dist/core/selection/useSelectionManager.d.ts.map +1 -1
  14. package/dist/core/selection/useSelectionManager.js +54 -14
  15. package/dist/data/shared-data/sd-shared-data-select-button.d.ts +11 -5
  16. package/dist/data/shared-data/sd-shared-data-select-button.d.ts.map +1 -1
  17. package/dist/data/shared-data/sd-shared-data-select-button.js +68 -29
  18. package/dist/data/sheet/sd-sheet.d.ts +4 -1
  19. package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
  20. package/dist/data/sheet/sd-sheet.js +23 -4
  21. package/dist/index.d.ts +0 -14
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +0 -19
  24. package/dist/styles.css +9 -0
  25. package/docs/bootstrap.md +38 -0
  26. package/docs/directives.md +236 -0
  27. package/docs/features.md +154 -0
  28. package/docs/pipes.md +32 -0
  29. package/docs/plugins.md +37 -0
  30. package/docs/provider-types.md +283 -0
  31. package/docs/providers.md +379 -0
  32. package/docs/recipes/crud-detail.md +875 -0
  33. package/docs/recipes/crud-list.md +1037 -0
  34. package/docs/recipes/data-select-button.md +318 -0
  35. package/docs/recipes/page-modal-container.md +178 -0
  36. package/docs/styling.md +222 -0
  37. package/docs/type-utilities.md +250 -0
  38. package/docs/ui-data.md +333 -0
  39. package/docs/ui-form.md +502 -0
  40. package/docs/ui-layout.md +140 -0
  41. package/docs/ui-navigation.md +303 -0
  42. package/docs/ui-overlay.md +157 -0
  43. package/docs/ui-visual.md +127 -0
  44. package/docs/utils.md +244 -0
  45. package/package.json +21 -20
  46. package/scss/commons/_styles.scss +12 -0
  47. package/src/controls/dropdown/sd-dropdown-popup.ts +6 -2
  48. package/src/controls/dropdown/sd-dropdown.ts +3 -4
  49. package/src/controls/select/sd-select.ts +6 -30
  50. package/src/core/routing/injectViewTypeSignal.ts +17 -10
  51. package/src/core/selection/useSelectionManager.ts +62 -12
  52. package/src/data/shared-data/sd-shared-data-select-button.ts +49 -14
  53. package/src/data/sheet/sd-sheet.ts +21 -0
  54. package/src/index.ts +0 -32
  55. package/dist/core/commons.d.ts +0 -2
  56. package/dist/core/commons.d.ts.map +0 -1
  57. package/dist/core/commons.js +0 -4
  58. package/dist/core/injectParent.d.ts +0 -7
  59. package/dist/core/injectParent.d.ts.map +0 -1
  60. package/dist/core/injectParent.js +0 -30
  61. package/dist/core/selection/setupCumulateSelectedKeys.d.ts +0 -9
  62. package/dist/core/selection/setupCumulateSelectedKeys.d.ts.map +0 -1
  63. package/dist/core/selection/setupCumulateSelectedKeys.js +0 -27
  64. package/dist/core/withBusy.d.ts +0 -3
  65. package/dist/core/withBusy.d.ts.map +0 -1
  66. package/dist/core/withBusy.js +0 -9
  67. package/dist/data/data-detail/sd-data-detail.base.d.ts +0 -51
  68. package/dist/data/data-detail/sd-data-detail.base.d.ts.map +0 -1
  69. package/dist/data/data-detail/sd-data-detail.base.js +0 -127
  70. package/dist/data/data-detail/sd-data-detail.d.ts +0 -30
  71. package/dist/data/data-detail/sd-data-detail.d.ts.map +0 -1
  72. package/dist/data/data-detail/sd-data-detail.js +0 -495
  73. package/dist/data/data-select-button/sd-data-select-button.base.d.ts +0 -24
  74. package/dist/data/data-select-button/sd-data-select-button.base.d.ts.map +0 -1
  75. package/dist/data/data-select-button/sd-data-select-button.base.js +0 -68
  76. package/dist/data/data-select-button/sd-data-select-button.d.ts +0 -15
  77. package/dist/data/data-select-button/sd-data-select-button.d.ts.map +0 -1
  78. package/dist/data/data-select-button/sd-data-select-button.js +0 -152
  79. package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts +0 -14
  80. package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts.map +0 -1
  81. package/dist/data/data-sheet/injectDataSheetExcelManager.js +0 -31
  82. package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts +0 -26
  83. package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts.map +0 -1
  84. package/dist/data/data-sheet/injectDataSheetInlineEditManager.js +0 -54
  85. package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts +0 -19
  86. package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts.map +0 -1
  87. package/dist/data/data-sheet/injectDataSheetModalEditManager.js +0 -44
  88. package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts +0 -25
  89. package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts.map +0 -1
  90. package/dist/data/data-sheet/injectDataSheetRefreshManager.js +0 -50
  91. package/dist/data/data-sheet/sd-data-sheet-column.d.ts +0 -8
  92. package/dist/data/data-sheet/sd-data-sheet-column.d.ts.map +0 -1
  93. package/dist/data/data-sheet/sd-data-sheet-column.js +0 -15
  94. package/dist/data/data-sheet/sd-data-sheet.base.d.ts +0 -75
  95. package/dist/data/data-sheet/sd-data-sheet.base.d.ts.map +0 -1
  96. package/dist/data/data-sheet/sd-data-sheet.base.js +0 -188
  97. package/dist/data/data-sheet/sd-data-sheet.d.ts +0 -49
  98. package/dist/data/data-sheet/sd-data-sheet.d.ts.map +0 -1
  99. package/dist/data/data-sheet/sd-data-sheet.js +0 -968
  100. package/dist/data/data-sheet/sd-data-sheet.types.d.ts +0 -17
  101. package/dist/data/data-sheet/sd-data-sheet.types.d.ts.map +0 -1
  102. package/dist/data/data-sheet/sd-data-sheet.types.js +0 -1
  103. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts +0 -9
  104. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts.map +0 -1
  105. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.js +0 -20
  106. package/dist/data/data-sheet/useDataSheetFilterManager.d.ts +0 -13
  107. package/dist/data/data-sheet/useDataSheetFilterManager.d.ts.map +0 -1
  108. package/dist/data/data-sheet/useDataSheetFilterManager.js +0 -19
  109. package/dist/data/getOrmDataEditToastErrorMessage.d.ts +0 -2
  110. package/dist/data/getOrmDataEditToastErrorMessage.d.ts.map +0 -1
  111. package/dist/data/getOrmDataEditToastErrorMessage.js +0 -8
  112. package/dist/layout/base-container/sd-base-container.d.ts +0 -27
  113. package/dist/layout/base-container/sd-base-container.d.ts.map +0 -1
  114. package/dist/layout/base-container/sd-base-container.js +0 -193
  115. package/src/core/commons.ts +0 -4
  116. package/src/core/injectParent.ts +0 -45
  117. package/src/core/selection/setupCumulateSelectedKeys.ts +0 -38
  118. package/src/core/withBusy.ts +0 -13
  119. package/src/data/data-detail/sd-data-detail.base.ts +0 -187
  120. package/src/data/data-detail/sd-data-detail.ts +0 -237
  121. package/src/data/data-select-button/sd-data-select-button.base.ts +0 -104
  122. package/src/data/data-select-button/sd-data-select-button.ts +0 -105
  123. package/src/data/data-sheet/injectDataSheetExcelManager.ts +0 -57
  124. package/src/data/data-sheet/injectDataSheetInlineEditManager.ts +0 -89
  125. package/src/data/data-sheet/injectDataSheetModalEditManager.ts +0 -76
  126. package/src/data/data-sheet/injectDataSheetRefreshManager.ts +0 -90
  127. package/src/data/data-sheet/sd-data-sheet-column.ts +0 -10
  128. package/src/data/data-sheet/sd-data-sheet.base.ts +0 -294
  129. package/src/data/data-sheet/sd-data-sheet.ts +0 -479
  130. package/src/data/data-sheet/sd-data-sheet.types.ts +0 -18
  131. package/src/data/data-sheet/setupCloserWhenSingleSelectionChange.ts +0 -29
  132. package/src/data/data-sheet/useDataSheetFilterManager.ts +0 -30
  133. package/src/data/getOrmDataEditToastErrorMessage.ts +0 -10
  134. package/src/layout/base-container/sd-base-container.ts +0 -121
@@ -1,479 +0,0 @@
1
- import { NgTemplateOutlet } from "@angular/common";
2
- import {
3
- ChangeDetectionStrategy,
4
- Component,
5
- contentChild,
6
- contentChildren,
7
- effect,
8
- input,
9
- TemplateRef,
10
- viewChild,
11
- ViewEncapsulation,
12
- } from "@angular/core";
13
- import { SdButton } from "../../controls/button/sd-button";
14
- import { SdForm } from "../../controls/form/sd-form";
15
- import { SdSheetColumn } from "../sheet/sd-sheet-column";
16
- import { SdSheetColumnCellTemplate } from "../sheet/sd-sheet-column-cell-template";
17
- import { SdSheet } from "../sheet/sd-sheet";
18
- import { injectParent } from "../../core/injectParent";
19
- import { FormatPipe } from "../../core/format.pipe";
20
- import { SdBaseContainer } from "../../layout/base-container/sd-base-container";
21
- import { SdDataSheetColumn } from "./sd-data-sheet-column";
22
- import { SdAnchor } from "../../controls/button/sd-anchor";
23
- import { NgIcon } from "@ng-icons/core";
24
- import {
25
- tablerDeviceFloppy,
26
- tablerEdit,
27
- tablerEraser,
28
- tablerCirclePlus,
29
- tablerFileExcel,
30
- tablerRefresh,
31
- tablerRestore,
32
- tablerSearch,
33
- tablerUpload,
34
- } from "@ng-icons/tabler-icons";
35
- import { SdDataSheetBase } from "./sd-data-sheet.base";
36
- import { SdCommandDirective } from "../../core/commands/sd-command";
37
-
38
- //#region SdDataSheet
39
-
40
- @Component({
41
- selector: "sd-data-sheet",
42
- changeDetection: ChangeDetectionStrategy.OnPush,
43
- encapsulation: ViewEncapsulation.None,
44
- standalone: true,
45
- imports: [
46
- SdForm,
47
- SdButton,
48
- SdSheet,
49
- SdSheetColumn,
50
- SdSheetColumnCellTemplate,
51
- NgTemplateOutlet,
52
- SdBaseContainer,
53
- FormatPipe,
54
- SdAnchor,
55
- NgIcon,
56
- ],
57
- hostDirectives: [
58
- { directive: SdCommandDirective, outputs: ["sdRefreshCommand", "sdSaveCommand"] },
59
- ],
60
- host: {
61
- "(sdRefreshCommand)": "onRefreshButtonClick()",
62
- "(sdSaveCommand)": "onSubmitButtonClick()",
63
- },
64
- template: `
65
- <sd-base-container
66
- [busy]="parent.busyCount() > 0"
67
- [busyMessage]="parent.busyMessage()"
68
- [viewType]="parent.viewType()"
69
- [initialized]="parent.initialized()"
70
- [restricted]="!parent.canUse()"
71
- >
72
- <ng-template #pageTopbarTpl>
73
- @if (parent.canEdit() && parent.submit) {
74
- <sd-button [theme]="'link-primary'" (click)="onSubmitButtonClick()">
75
- <ng-icon [svg]="icons.tablerDeviceFloppy" />
76
- 저장
77
- <small>(CTRL+S)</small>
78
- </sd-button>
79
- }
80
- <sd-button [theme]="'link-info'" (click)="onRefreshButtonClick()">
81
- <ng-icon [svg]="icons.tablerRefresh" />
82
- 새로고침
83
- <small>(CTRL+ALT+L)</small>
84
- </sd-button>
85
-
86
- <ng-template [ngTemplateOutlet]="pageTopbarTplRef() ?? null" />
87
- </ng-template>
88
-
89
- <ng-template #contentTpl>
90
- <div class="flex-column fill">
91
- @if (parent.canEdit() && parent.submit && parent.viewType() === "control") {
92
- <div class="flex-row gap-sm p-default bdb bdb-theme-gray-lightest">
93
- <sd-button [size]="'sm'" [theme]="'primary'" (click)="onSubmitButtonClick()">
94
- <ng-icon [svg]="icons.tablerDeviceFloppy" />
95
- 저장
96
- <small>(CTRL+S)</small>
97
- </sd-button>
98
- <sd-button [size]="'sm'" [theme]="'info'" (click)="onRefreshButtonClick()">
99
- <ng-icon [svg]="icons.tablerRefresh" />
100
- 새로고침
101
- <small>(CTRL+ALT+L)</small>
102
- </sd-button>
103
- <ng-template [ngTemplateOutlet]="prevTplRef() ?? null" />
104
- </div>
105
- } @else {
106
- <ng-template [ngTemplateOutlet]="prevTplRef() ?? null" />
107
- }
108
-
109
- @if (filterTplRef()) {
110
- <div class="p-default">
111
- <sd-form (formSubmit)="onFilterSubmit()">
112
- <div class="form-box-inline">
113
- <div>
114
- <sd-button [type]="'submit'" [theme]="'info'">
115
- <ng-icon [svg]="icons.tablerSearch" />
116
- 조회
117
- </sd-button>
118
- </div>
119
- <ng-template [ngTemplateOutlet]="filterTplRef()!" />
120
- </div>
121
- </sd-form>
122
- </div>
123
- }
124
-
125
- @if (!parent.hideTool || !parent.hideTool()) {
126
- @if (parent.canEdit() || beforeToolTplRef() || parent.downloadExcel) {
127
- <div class="flex-row gap-sm p-xs-default">
128
- @if (parent.canEdit()) {
129
- @if (parent.editMode === "modal" && parent.editItem) {
130
- <sd-button
131
- [size]="'sm'"
132
- [theme]="'link-primary'"
133
- (click)="onCreateItemButtonClick()"
134
- >
135
- <ng-icon [svg]="icons.tablerCirclePlus" />
136
- {{ insertText() ?? "등록" }}
137
- </sd-button>
138
- } @else if (parent.editMode === "inline" && parent.newItem) {
139
- <sd-button
140
- [size]="'sm'"
141
- [theme]="'link-primary'"
142
- (click)="onAddItemButtonClick()"
143
- >
144
- <ng-icon [svg]="icons.tablerCirclePlus" />
145
- 행 추가
146
- </sd-button>
147
- }
148
- }
149
-
150
- <ng-template [ngTemplateOutlet]="beforeToolTplRef() ?? null" />
151
-
152
- @if (parent.canEdit()) {
153
- @if (parent.editMode === "modal" && parent.toggleDeleteItems) {
154
- <sd-button
155
- [size]="'sm'"
156
- [theme]="'link-danger'"
157
- (click)="onToggleDeleteItemsButtonClick(true)"
158
- [disabled]="!parent.isSelectedItemsHasNotDeleted()"
159
- >
160
- <ng-icon [svg]="deleteIcon()" />
161
- 선택 {{ deleteText() ?? "삭제" }}
162
- </sd-button>
163
- @if (parent.isSelectedItemsHasDeleted()) {
164
- <sd-button
165
- [size]="'sm'"
166
- [theme]="'link-warning'"
167
- (click)="onToggleDeleteItemsButtonClick(false)"
168
- >
169
- <ng-icon [svg]="restoreIcon()" />
170
- 선택 {{ restoreText() ?? "복구" }}
171
- </sd-button>
172
- }
173
- }
174
-
175
- @if (parent.uploadExcel) {
176
- <sd-button
177
- [size]="'sm'"
178
- [theme]="'link-success'"
179
- (click)="onUploadExcelButtonClick()"
180
- >
181
- <ng-icon [svg]="icons.tablerUpload" />
182
- 엑셀 업로드
183
- </sd-button>
184
- }
185
- }
186
-
187
- @if (parent.downloadExcel) {
188
- <sd-button
189
- [size]="'sm'"
190
- [theme]="'link-success'"
191
- (click)="onDownloadExcelButtonClick()"
192
- >
193
- <ng-icon [svg]="icons.tablerFileExcel" />
194
- 엑셀 다운로드
195
- </sd-button>
196
- }
197
-
198
- <ng-template [ngTemplateOutlet]="toolTplRef() ?? null" />
199
- </div>
200
- }
201
- }
202
-
203
- <sd-form #formCtrl (formSubmit)="onSubmit()" class="flex-fill p-default pt-0">
204
- <sd-sheet
205
- [key]="parent.key + '-sheet'"
206
- [items]="parent.items()"
207
- [(currentPage)]="parent.page"
208
- [totalPageCount]="parent.pageLength()"
209
- [(sorts)]="parent.sortingDefs"
210
- [selectMode]="parent.selectMode()"
211
- [autoSelect]="parent.autoSelect()"
212
- [(selectedItems)]="parent.selectedItems"
213
- [trackByFn]="parent.trackByFn"
214
- [getItemCellStyleFn]="parent.getItemCellStyleFn"
215
- [getItemSelectableFn]="parent.getItemSelectableFn"
216
- >
217
- @if (
218
- parent.editMode === "inline" && parent.canEdit() && parent.itemPropInfo.isDeleted
219
- ) {
220
- <sd-sheet-column [fixed]="true" [key]="parent.itemPropInfo.isDeleted!">
221
- <ng-template #headerTpl>
222
- <div class="p-xs-sm tx-center">
223
- <ng-icon [svg]="deleteIcon()" />
224
- </div>
225
- </ng-template>
226
- <ng-template [cell]="parent.items()" let-item="item">
227
- <div class="p-xs-sm tx-center">
228
- <sd-anchor
229
- [theme]="'danger'"
230
- (click)="onToggleDeleteItemButtonClick(item)"
231
- [disabled]="!parent.getItemInfoFn(item).canDelete"
232
- >
233
- <ng-icon
234
- [svg]="
235
- item[parent.itemPropInfo.isDeleted!] ? restoreIcon() : deleteIcon()
236
- "
237
- />
238
- {{ item[parent.itemPropInfo.isDeleted!] ? restoreText() : deleteText() }}
239
- </sd-anchor>
240
- </div>
241
- </ng-template>
242
- </sd-sheet-column>
243
- }
244
-
245
- @for (columnControl of columnControls(); track columnControl.key()) {
246
- <sd-sheet-column
247
- [key]="columnControl.key()"
248
- [fixed]="columnControl.fixed()"
249
- [header]="columnControl.header()"
250
- [headerStyle]="columnControl.headerStyle()"
251
- [tooltip]="columnControl.tooltip()"
252
- [width]="columnControl.width()"
253
- [disableSorting]="columnControl.disableSorting()"
254
- [disableResizing]="columnControl.disableResizing()"
255
- [hidden]="columnControl.hidden()"
256
- [collapse]="columnControl.collapse()"
257
- >
258
- @if (columnControl.headerTplRef()) {
259
- <ng-template #headerTpl>
260
- <ng-template [ngTemplateOutlet]="columnControl.headerTplRef()!" />
261
- </ng-template>
262
- }
263
- @if (columnControl.summaryTplRef()) {
264
- <ng-template #summaryTpl>
265
- <ng-template [ngTemplateOutlet]="columnControl.summaryTplRef()!" />
266
- </ng-template>
267
- }
268
-
269
- <ng-template
270
- [cell]="parent.items()"
271
- let-item="item"
272
- let-index="index"
273
- let-depth="depth"
274
- let-edit="edit"
275
- >
276
- @if (
277
- parent.editMode === "modal" &&
278
- parent.canEdit() &&
279
- columnControl.edit() &&
280
- parent.getItemInfoFn(item).canEdit
281
- ) {
282
- <sd-anchor
283
- (click)="onEditItemButtonClick(item, index, $event)"
284
- class="flex-row"
285
- >
286
- <div class="p-xs-sm">
287
- <ng-icon [svg]="icons.tablerEdit" />
288
- </div>
289
- <div class="flex-fill">
290
- <ng-template
291
- [ngTemplateOutlet]="columnControl.cellTplRef()"
292
- [ngTemplateOutletContext]="{
293
- $implicit: item,
294
- item: item,
295
- index: index,
296
- depth: depth,
297
- edit: edit,
298
- }"
299
- />
300
- </div>
301
- </sd-anchor>
302
- } @else {
303
- <ng-template
304
- [ngTemplateOutlet]="columnControl.cellTplRef()"
305
- [ngTemplateOutletContext]="{
306
- $implicit: item,
307
- item: item,
308
- index: index,
309
- depth: depth,
310
- edit: edit,
311
- }"
312
- />
313
- }
314
- </ng-template>
315
- </sd-sheet-column>
316
- }
317
-
318
- @if (parent.itemPropInfo.lastModifiedAt) {
319
- <sd-sheet-column
320
- [header]="'수정일시'"
321
- [key]="parent.itemPropInfo.lastModifiedAt!"
322
- [hidden]="true"
323
- >
324
- <ng-template [cell]="parent.items()" let-item="item">
325
- <div class="p-xs-sm tx-center">
326
- {{ item[parent.itemPropInfo.lastModifiedAt!] | format: "yyyy-MM-dd HH:mm" }}
327
- </div>
328
- </ng-template>
329
- </sd-sheet-column>
330
- }
331
- @if (parent.itemPropInfo.lastModifiedBy) {
332
- <sd-sheet-column
333
- [header]="'수정자'"
334
- [key]="parent.itemPropInfo.lastModifiedBy!"
335
- [hidden]="true"
336
- >
337
- <ng-template [cell]="parent.items()" let-item="item">
338
- <div class="p-xs-sm tx-center">
339
- {{ item[parent.itemPropInfo.lastModifiedBy!] }}
340
- </div>
341
- </ng-template>
342
- </sd-sheet-column>
343
- }
344
- </sd-sheet>
345
- </sd-form>
346
- </div>
347
- </ng-template>
348
-
349
- @if (parent.selectMode()) {
350
- <ng-template #modalBottomTpl>
351
- <div class="p-sm-default flex-row gap-sm">
352
- <div class="flex-fill flex-row gap-sm">
353
- @if (modalBottomTplRef()) {
354
- <ng-template [ngTemplateOutlet]="modalBottomTplRef()!" />
355
- }
356
- </div>
357
-
358
- @if (parent.selectedItemKeys().length > 0) {
359
- <sd-button [size]="'sm'" [theme]="'danger'" (click)="onCancelButtonClick()">
360
- {{ parent.selectMode() === "multi" ? "모두" : "선택" }}
361
- 해제
362
- </sd-button>
363
- }
364
- @if (parent.selectMode() === "multi") {
365
- <sd-button [size]="'sm'" [theme]="'primary'" (click)="onConfirmButtonClick()">
366
- 확인({{ parent.selectedItemKeys().length }})
367
- </sd-button>
368
- }
369
- </div>
370
- </ng-template>
371
-
372
- <ng-template #modalActionTpl>
373
- <sd-anchor
374
- [theme]="'gray'"
375
- class="p-sm-default"
376
- (click)="onRefreshButtonClick()"
377
- title="새로고침(CTRL+ALT+L)"
378
- >
379
- <ng-icon [svg]="icons.tablerRefresh" />
380
- </sd-anchor>
381
- </ng-template>
382
- }
383
- </sd-base-container>
384
- `,
385
- })
386
- export class SdDataSheet {
387
- parent = injectParent<SdDataSheetBase<any, any, any>>();
388
-
389
- formCtrl = viewChild<SdForm>("formCtrl");
390
-
391
- insertText = input<string>();
392
- deleteText = input<string>();
393
- restoreText = input<string>();
394
- deleteIcon = input(tablerEraser);
395
- restoreIcon = input(tablerRestore);
396
-
397
- pageTopbarTplRef = contentChild("pageTopbarTpl", { read: TemplateRef });
398
- prevTplRef = contentChild("prevTpl", { read: TemplateRef });
399
- filterTplRef = contentChild("filterTpl", { read: TemplateRef });
400
- beforeToolTplRef = contentChild("beforeToolTpl", { read: TemplateRef });
401
- toolTplRef = contentChild("toolTpl", { read: TemplateRef });
402
- modalBottomTplRef = contentChild("modalBottomTpl", { read: TemplateRef });
403
-
404
- columnControls = contentChildren(SdDataSheetColumn);
405
-
406
- modalActionTplRef = viewChild("modalActionTpl", { read: TemplateRef });
407
-
408
- constructor() {
409
- effect(() => {
410
- this.parent.actionTplRef = this.modalActionTplRef();
411
- });
412
- }
413
-
414
- protected readonly icons = {
415
- tablerRefresh,
416
- tablerDeviceFloppy,
417
- tablerSearch,
418
- tablerCirclePlus,
419
- tablerUpload,
420
- tablerFileExcel,
421
- tablerEdit,
422
- };
423
-
424
- onFilterSubmit() {
425
- this.parent.doFilterSubmit();
426
- }
427
-
428
- onRefreshButtonClick() {
429
- this.parent.doRefresh();
430
- }
431
-
432
- async onCreateItemButtonClick() {
433
- await this.parent.doEditItem();
434
- }
435
-
436
- async onEditItemButtonClick(item: any, index: number, event: MouseEvent) {
437
- event.preventDefault();
438
- event.stopPropagation();
439
- await this.parent.doEditItem(item);
440
- }
441
-
442
- async onToggleDeleteItemsButtonClick(del: boolean) {
443
- await this.parent.doToggleDeleteItems(del);
444
- }
445
-
446
- onToggleDeleteItemButtonClick(item: any) {
447
- this.parent.doToggleDeleteItem(item);
448
- }
449
-
450
- onSubmitButtonClick() {
451
- this.formCtrl()?.requestSubmit();
452
- }
453
-
454
- async onSubmit() {
455
- await this.parent.doSubmit({ permCheck: true });
456
- }
457
-
458
- async onAddItemButtonClick() {
459
- await this.parent.doAddItem();
460
- }
461
-
462
- async onDownloadExcelButtonClick() {
463
- await this.parent.doDownloadExcel();
464
- }
465
-
466
- async onUploadExcelButtonClick() {
467
- await this.parent.doUploadExcel();
468
- }
469
-
470
- onConfirmButtonClick() {
471
- this.parent.doModalConfirm();
472
- }
473
-
474
- onCancelButtonClick() {
475
- this.parent.doModalCancel();
476
- }
477
- }
478
-
479
- //#endregion
@@ -1,18 +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
-
7
- export interface SdDataSheetItemInfo<K> {
8
- key: K;
9
- canSelect: boolean;
10
- canEdit: boolean;
11
- canDelete: boolean;
12
- }
13
-
14
- export interface SdDataSheetSearchResult<I> {
15
- items: I[];
16
- pageLength?: number;
17
- summary?: Partial<I>;
18
- }
@@ -1,29 +0,0 @@
1
- import { type OutputEmitterRef, type Signal, effect } from "@angular/core";
2
- import type { SelectModalOutputResult } from "../../core/select-modal-output-result";
3
-
4
- export function setupCloserWhenSingleSelectionChange<TItem, TKey>(options: {
5
- selectedItemKeys: Signal<TKey[]>;
6
- selectedItems: Signal<TItem[]>;
7
- selectMode: () => "single" | "multi" | undefined;
8
- close: OutputEmitterRef<SelectModalOutputResult<TItem>>;
9
- }): void {
10
- let initialized = false;
11
-
12
- effect(() => {
13
- const keys = options.selectedItemKeys();
14
- const items = options.selectedItems();
15
-
16
- if (!initialized) {
17
- initialized = true;
18
- return;
19
- }
20
-
21
- if (options.selectMode() !== "single") return;
22
- if (keys.length === 0) return;
23
-
24
- options.close.emit({
25
- selectedItemKeys: keys,
26
- selectedItems: items,
27
- });
28
- });
29
- }
@@ -1,30 +0,0 @@
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
- }
@@ -1,10 +0,0 @@
1
- export function getOrmDataEditToastErrorMessage(err: unknown): string {
2
- const message = err instanceof Error ? err.message : String(err);
3
- if (
4
- message.includes("a parent row: a foreign key constraint") ||
5
- message.includes("conflicted with the REFERENCE")
6
- ) {
7
- return "경고! 연결된 작업에 의한 처리 거부. 후속작업 확인 요망";
8
- }
9
- return message;
10
- }
@@ -1,121 +0,0 @@
1
- import { NgTemplateOutlet } from "@angular/common";
2
- import {
3
- booleanAttribute,
4
- ChangeDetectionStrategy,
5
- Component,
6
- computed,
7
- contentChild,
8
- inject,
9
- input,
10
- TemplateRef,
11
- ViewEncapsulation,
12
- } from "@angular/core";
13
- import { SdBusyContainer } from "../../core/busy/sd-busy-container";
14
- import { SdTopbarContainer } from "../topbar/sd-topbar-container";
15
- import { SdTopbar } from "../topbar/sd-topbar";
16
- import { SdAppStructureProvider } from "../../core/app-structure/sd-app-structure.provider";
17
- import { SdActivatedModalProvider } from "../../core/modal/sd-activated-modal.provider";
18
- import { injectCurrentPageCodeSignal } from "../../core/routing/injectCurrentPageCodeSignal";
19
- import { injectFullPageCodeSignal } from "../../core/routing/injectFullPageCodeSignal";
20
- import {
21
- injectViewTypeSignal,
22
- type SdViewType,
23
- } from "../../core/routing/injectViewTypeSignal";
24
- import { injectParent } from "../../core/injectParent";
25
- import { SdSystemLogProvider } from "../../core/config/sd-system-log.provider";
26
- import { NgIcon } from "@ng-icons/core";
27
- import { tablerAlertTriangle } from "@ng-icons/tabler-icons";
28
-
29
- @Component({
30
- selector: "sd-base-container",
31
- changeDetection: ChangeDetectionStrategy.OnPush,
32
- encapsulation: ViewEncapsulation.None,
33
- standalone: true,
34
- imports: [
35
- SdBusyContainer,
36
- SdTopbarContainer,
37
- SdTopbar,
38
- NgTemplateOutlet,
39
- NgIcon,
40
- ],
41
- template: `
42
- <sd-busy-container [busy]="busy()" [message]="busyMessage()">
43
- @if (initialized() == null || initialized()) {
44
- @if (restricted()) {
45
- <div class="fill tx-theme-gray-light p-xxl tx-center">
46
- <br />
47
- <ng-icon [svg]="tablerAlertTriangle" [size]="'5em'" />
48
- <br />
49
- <br />
50
- '{{ modalOrPageTitle() }}'에 대한 사용권한이 없습니다. 시스템 관리자에게 문의하세요.
51
- </div>
52
- } @else if (currViewType() === "page") {
53
- <sd-topbar-container>
54
- <sd-topbar>
55
- <h4>{{ modalOrPageTitle() }}</h4>
56
-
57
- <ng-template [ngTemplateOutlet]="pageTopbarTplRef() ?? null" />
58
- </sd-topbar>
59
-
60
- <div class="fill">
61
- <ng-template [ngTemplateOutlet]="contentTplRef()" />
62
- </div>
63
- </sd-topbar-container>
64
- } @else if (currViewType() === "modal") {
65
- <div class="flex-column fill">
66
- <div class="flex-fill">
67
- <ng-template [ngTemplateOutlet]="contentTplRef()" />
68
- </div>
69
- @if (modalBottomTplRef()) {
70
- <div class="bdt bdt-theme-gray-lightest">
71
- <ng-template [ngTemplateOutlet]="modalBottomTplRef() ?? null" />
72
- </div>
73
- }
74
- </div>
75
- } @else {
76
- <ng-template [ngTemplateOutlet]="contentTplRef()" />
77
- }
78
- }
79
- </sd-busy-container>
80
- `,
81
- })
82
- export class SdBaseContainer {
83
- private readonly _sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
84
- private readonly _sdAppStructure = inject(SdAppStructureProvider);
85
- private readonly _sdSystemLog = inject(SdSystemLogProvider);
86
-
87
- private readonly _parent = injectParent();
88
-
89
- private readonly _fullPageCode = injectFullPageCodeSignal();
90
- private readonly _currPageCode = injectCurrentPageCodeSignal();
91
-
92
- contentTplRef = contentChild.required("contentTpl", { read: TemplateRef });
93
-
94
- pageTopbarTplRef = contentChild("pageTopbarTpl", { read: TemplateRef });
95
- modalBottomTplRef = contentChild("modalBottomTpl", { read: TemplateRef });
96
-
97
- private readonly _parentViewType = injectViewTypeSignal(() => this._parent);
98
- viewType = input<SdViewType>();
99
- currViewType = computed(() => this.viewType() ?? this._parentViewType());
100
-
101
- header = input<string>();
102
- modalOrPageTitle = computed(() => {
103
- try {
104
- return (
105
- this.header() ??
106
- this._sdActivatedModal?.modalComponent()?.title() ??
107
- this._sdAppStructure.getTitleByFullCode(this._currPageCode?.() ?? this._fullPageCode())
108
- );
109
- } catch (err) {
110
- void this._sdSystemLog.writeAsync("warn", `modalOrPageTitle 계산 중 에러: ${String(err)}`);
111
- return "";
112
- }
113
- });
114
-
115
- initialized = input<boolean | undefined>(undefined);
116
- restricted = input(false, { transform: booleanAttribute });
117
- busy = input(false, { transform: booleanAttribute });
118
- busyMessage = input<string>();
119
-
120
- protected readonly tablerAlertTriangle = tablerAlertTriangle;
121
- }