@simplysm/sd-claude 14.0.50 → 14.0.52
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/claude/references/sd-frontend-design.md +10 -9
- package/claude/references/sd-simplysm-v14/angular/README.md +497 -0
- package/claude/references/sd-simplysm-v14/angular/bootstrap/provide-sd-angular.md +37 -0
- package/claude/references/sd-simplysm-v14/angular/bootstrap/sd-angular-config-provider.md +16 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-command-directive.md +27 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-events.md +25 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-intersection-directive.md +36 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-invalid.md +24 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-resize-directive.md +42 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-ripple.md +23 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-router-link.md +38 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-show-effect.md +18 -0
- package/claude/references/sd-simplysm-v14/angular/directives/sd-typed-template.md +69 -0
- package/claude/references/sd-simplysm-v14/angular/features/sd-address-search-modal.md +50 -0
- package/claude/references/sd-simplysm-v14/angular/features/sd-permission-table.md +20 -0
- package/claude/references/sd-simplysm-v14/angular/features/sd-shared-data-components.md +158 -0
- package/claude/references/sd-simplysm-v14/angular/features/sd-tiptap-editor.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/pipes/format-pipe.md +41 -0
- package/claude/references/sd-simplysm-v14/angular/plugins/sd-global-error-handler.md +23 -0
- package/claude/references/sd-simplysm-v14/angular/plugins/sd-option-event-plugin.md +34 -0
- package/claude/references/sd-simplysm-v14/angular/provider-types/sd-menu.md +65 -0
- package/claude/references/sd-simplysm-v14/angular/provider-types/sd-modal-content-def.md +148 -0
- package/claude/references/sd-simplysm-v14/angular/provider-types/sd-toast-content-def.md +73 -0
- package/claude/references/sd-simplysm-v14/angular/provider-types/shared-data-base.md +59 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-activated-modal-provider.md +34 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-app-structure-provider.md +81 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-busy-provider.md +18 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-file-dialog-provider.md +40 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-local-storage-provider.md +20 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-modal-provider.md +67 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-navigate-window-provider.md +18 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-print-provider.md +25 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-service-client-factory-provider.md +43 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-shared-data-provider.md +64 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-system-config-provider.md +46 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-system-log-provider.md +18 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-theme-provider.md +38 -0
- package/claude/references/sd-simplysm-v14/angular/providers/sd-toast-provider.md +65 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/_common-rules.md +336 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-a-edit-save.md +191 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-b-delete-restore.md +103 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-c-modal-view.md +198 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-d-control-view.md +109 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-e-auxiliary.md +87 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-f-complex-detail.md +202 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail.md +280 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-a-inline-edit.md +386 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-b-selection.md +215 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-c-inline-delete.md +64 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-d-select-modal.md +193 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-e-readonly-modal.md +140 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-f-modal-edit.md +123 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-g-excel.md +145 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/crud-list.md +377 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/data-select-button.md +368 -0
- package/claude/references/sd-simplysm-v14/angular/recipes/page-modal-container.md +238 -0
- package/claude/references/sd-simplysm-v14/angular/styling/classes.md +149 -0
- package/claude/references/sd-simplysm-v14/angular/styling/mixins.md +100 -0
- package/claude/references/sd-simplysm-v14/angular/styling/themes.md +35 -0
- package/claude/references/sd-simplysm-v14/angular/styling/variables.md +147 -0
- package/claude/references/sd-simplysm-v14/angular/type-utilities/directive-input-signals.md +232 -0
- package/claude/references/sd-simplysm-v14/angular/ui-data/sd-list.md +37 -0
- package/claude/references/sd-simplysm-v14/angular/ui-data/sd-sheet.md +212 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-additional-button.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-anchor.md +31 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-button.md +103 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-checkbox-group.md +39 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-checkbox.md +81 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-date-range-picker.md +27 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-form.md +89 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-modal-select-button.md +54 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-numpad.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-range.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-select.md +68 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-shared-data-select.md +52 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-state-preset.md +37 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-switch.md +27 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-textarea.md +33 -0
- package/claude/references/sd-simplysm-v14/angular/ui-form/sd-textfield.md +145 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-dock-container.md +64 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-dock.md +37 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-gap.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban-board.md +96 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban-lane.md +34 -0
- package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban.md +29 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-collapse.md +35 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-pagination.md +26 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-container.md +49 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-menu.md +22 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-user.md +43 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-tab.md +51 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-container.md +97 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-menu.md +23 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-user.md +38 -0
- package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar.md +30 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-busy-container.md +69 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-confirm-modal.md +30 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-dropdown.md +40 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-modal.md +34 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-prompt-modal.md +30 -0
- package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-toast.md +35 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-barcode.md +36 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-calendar.md +34 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-echarts.md +32 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-label.md +24 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-note.md +23 -0
- package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-progress.md +23 -0
- package/claude/references/sd-simplysm-v14/angular/utils/inject-routing-signals.md +161 -0
- package/claude/references/sd-simplysm-v14/angular/utils/inject-sd-system-config-resource.md +35 -0
- package/claude/references/sd-simplysm-v14/angular/utils/mark.md +43 -0
- package/claude/references/sd-simplysm-v14/angular/utils/selection-managers.md +96 -0
- package/claude/references/sd-simplysm-v14/angular/utils/set-safe-style.md +19 -0
- package/claude/references/sd-simplysm-v14/angular/utils/setup-functions.md +93 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/README.md +38 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/apk-installer/apk-installer.md +115 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/auto-update/auto-update.md +113 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-file-system/README.md +197 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-intent/README.md +235 -0
- package/claude/references/sd-simplysm-v14/capacitor-plugin-usb-storage/README.md +251 -0
- package/claude/references/sd-simplysm-v14/core-browser/README.md +52 -0
- package/claude/references/sd-simplysm-v14/core-browser/extensions/copy-paste.md +59 -0
- package/claude/references/sd-simplysm-v14/core-browser/extensions/element-prototype-extensions.md +137 -0
- package/claude/references/sd-simplysm-v14/core-browser/extensions/get-bounds.md +84 -0
- package/claude/references/sd-simplysm-v14/core-browser/utils/download-blob.md +59 -0
- package/claude/references/sd-simplysm-v14/core-browser/utils/fetch-url-bytes.md +91 -0
- package/claude/references/sd-simplysm-v14/core-browser/utils/indexed-db-store.md +131 -0
- package/claude/references/sd-simplysm-v14/core-browser/utils/indexed-db-virtual-fs.md +121 -0
- package/claude/references/sd-simplysm-v14/core-browser/utils/open-file-dialog.md +60 -0
- package/claude/references/sd-simplysm-v14/core-common/README.md +179 -0
- package/claude/references/sd-simplysm-v14/core-common/errors/argument-error.md +26 -0
- package/claude/references/sd-simplysm-v14/core-common/errors/not-implemented-error.md +33 -0
- package/claude/references/sd-simplysm-v14/core-common/errors/sd-error.md +38 -0
- package/claude/references/sd-simplysm-v14/core-common/errors/timeout-error.md +36 -0
- package/claude/references/sd-simplysm-v14/core-common/extensions/array.md +125 -0
- package/claude/references/sd-simplysm-v14/core-common/extensions/map.md +43 -0
- package/claude/references/sd-simplysm-v14/core-common/extensions/set.md +35 -0
- package/claude/references/sd-simplysm-v14/core-common/features/debounce-queue.md +48 -0
- package/claude/references/sd-simplysm-v14/core-common/features/event-emitter.md +52 -0
- package/claude/references/sd-simplysm-v14/core-common/features/serial-queue.md +44 -0
- package/claude/references/sd-simplysm-v14/core-common/type-utils/common-types.md +100 -0
- package/claude/references/sd-simplysm-v14/core-common/type-utils/env.md +42 -0
- package/claude/references/sd-simplysm-v14/core-common/types/date-only.md +86 -0
- package/claude/references/sd-simplysm-v14/core-common/types/date-time.md +106 -0
- package/claude/references/sd-simplysm-v14/core-common/types/lazy-gc-map.md +59 -0
- package/claude/references/sd-simplysm-v14/core-common/types/time.md +62 -0
- package/claude/references/sd-simplysm-v14/core-common/types/uuid.md +41 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/bytes.md +36 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/dt.md +60 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/err.md +26 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/json.md +58 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/num.md +56 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/obj.md +107 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/path.md +30 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/primitive.md +28 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/str.md +63 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/template-strings.md +49 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/transfer.md +35 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/wait.md +35 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/xml.md +49 -0
- package/claude/references/sd-simplysm-v14/core-common/utils/zip-archive.md +77 -0
- package/claude/references/sd-simplysm-v14/core-node/README.md +59 -0
- package/claude/references/sd-simplysm-v14/core-node/features/fs-watcher.md +110 -0
- package/claude/references/sd-simplysm-v14/core-node/logging/create-file-reporter.md +78 -0
- package/claude/references/sd-simplysm-v14/core-node/logging/pretty-reporter.md +38 -0
- package/claude/references/sd-simplysm-v14/core-node/logging/setup-consola.md +77 -0
- package/claude/references/sd-simplysm-v14/core-node/utils/cpx.md +128 -0
- package/claude/references/sd-simplysm-v14/core-node/utils/fsx.md +168 -0
- package/claude/references/sd-simplysm-v14/core-node/utils/pathx.md +73 -0
- package/claude/references/sd-simplysm-v14/core-node/worker/create-worker.md +85 -0
- package/claude/references/sd-simplysm-v14/core-node/worker/worker.md +160 -0
- package/claude/references/sd-simplysm-v14/excel/README.md +66 -0
- package/claude/references/sd-simplysm-v14/excel/core-classes/excel-cell.md +79 -0
- package/claude/references/sd-simplysm-v14/excel/core-classes/excel-col.md +36 -0
- package/claude/references/sd-simplysm-v14/excel/core-classes/excel-row.md +34 -0
- package/claude/references/sd-simplysm-v14/excel/core-classes/excel-workbook.md +93 -0
- package/claude/references/sd-simplysm-v14/excel/core-classes/excel-worksheet.md +147 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-address-point.md +33 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-style-options.md +57 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-value-type.md +28 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-content-type-data.md +23 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-drawing-data.md +29 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-relationship-data.md +39 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-shared-string-data.md +42 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-style-data.md +97 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-workbook-data.md +22 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml-worksheet-data.md +68 -0
- package/claude/references/sd-simplysm-v14/excel/types/excel-xml.md +15 -0
- package/claude/references/sd-simplysm-v14/excel/utilities/excel-utils.md +101 -0
- package/claude/references/sd-simplysm-v14/excel/wrapper/excel-wrapper.md +108 -0
- package/claude/references/sd-simplysm-v14/lint/README.md +183 -0
- package/claude/references/sd-simplysm-v14/orm-common/README.md +156 -0
- package/claude/references/sd-simplysm-v14/orm-common/core/db-context.md +208 -0
- package/claude/references/sd-simplysm-v14/orm-common/core/db-transaction-error.md +64 -0
- package/claude/references/sd-simplysm-v14/orm-common/expression/expr-unit.md +62 -0
- package/claude/references/sd-simplysm-v14/orm-common/expression/expr.md +198 -0
- package/claude/references/sd-simplysm-v14/orm-common/models/migration.md +37 -0
- package/claude/references/sd-simplysm-v14/orm-common/query-builder/create-query-builder.md +80 -0
- package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/executable.md +54 -0
- package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/parse-search-query.md +75 -0
- package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/queryable.md +238 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/column-builder.md +63 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/foreign-key-builder.md +137 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/index-builder.md +54 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/procedure.md +67 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/table.md +95 -0
- package/claude/references/sd-simplysm-v14/orm-common/schema-builders/view.md +71 -0
- package/claude/references/sd-simplysm-v14/orm-common/types/data-type.md +146 -0
- package/claude/references/sd-simplysm-v14/orm-common/types/dialect.md +151 -0
- package/claude/references/sd-simplysm-v14/orm-common/types/expr.md +175 -0
- package/claude/references/sd-simplysm-v14/orm-common/types/parse-query-result.md +58 -0
- package/claude/references/sd-simplysm-v14/orm-common/types/query-def.md +224 -0
- package/claude/references/sd-simplysm-v14/orm-node/README.md +65 -0
- package/claude/references/sd-simplysm-v14/orm-node/connections/mssql-db-conn.md +85 -0
- package/claude/references/sd-simplysm-v14/orm-node/connections/mysql-db-conn.md +83 -0
- package/claude/references/sd-simplysm-v14/orm-node/connections/postgresql-db-conn.md +86 -0
- package/claude/references/sd-simplysm-v14/orm-node/core/create-db-conn.md +62 -0
- package/claude/references/sd-simplysm-v14/orm-node/core/create-orm.md +107 -0
- package/claude/references/sd-simplysm-v14/orm-node/core/node-db-context-executor.md +50 -0
- package/claude/references/sd-simplysm-v14/orm-node/types/db-conn-config.md +91 -0
- package/claude/references/sd-simplysm-v14/orm-node/types/db-conn-constants.md +33 -0
- package/claude/references/sd-simplysm-v14/orm-node/types/db-conn.md +60 -0
- package/claude/references/sd-simplysm-v14/orm-node/types/get-dialect-from-config.md +17 -0
- package/{README.md → claude/references/sd-simplysm-v14/sd-claude/README.md} +85 -84
- package/{docs → claude/references/sd-simplysm-v14/sd-claude}/assets.md +2 -2
- package/{docs → claude/references/sd-simplysm-v14/sd-claude}/hooks.md +15 -1
- package/claude/references/sd-simplysm-v14/sd-cli/README.md +138 -0
- package/claude/references/sd-simplysm-v14/sd-cli/angular-vite-plugin/sd-angular-plugin.md +60 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/build-target.md +31 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/npm-config.md +27 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-browser-support-config.md +19 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-build-package-config.md +21 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-capacitor-config.md +109 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-client-package-config.md +33 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-config.md +78 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-electron-config.md +27 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-package-config.md +18 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-post-publish-script-config.md +19 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-publish-config.md +72 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-pwa-config.md +41 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-scripts-package-config.md +19 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-server-package-config.md +32 -0
- package/claude/references/sd-simplysm-v14/sd-cli/config/sd-watch-hook-config.md +19 -0
- package/claude/references/sd-simplysm-v14/sd-cli/ts-compiler/sd-ts-compiler.md +158 -0
- package/claude/references/sd-simplysm-v14/service-client/README.md +74 -0
- package/claude/references/sd-simplysm-v14/service-client/features/event-client.md +93 -0
- package/claude/references/sd-simplysm-v14/service-client/features/file-client.md +63 -0
- package/claude/references/sd-simplysm-v14/service-client/features/orm-client-connector.md +89 -0
- package/claude/references/sd-simplysm-v14/service-client/features/orm-client-db-context-executor.md +31 -0
- package/claude/references/sd-simplysm-v14/service-client/main/service-client.md +206 -0
- package/claude/references/sd-simplysm-v14/service-client/protocol/client-protocol-wrapper.md +64 -0
- package/claude/references/sd-simplysm-v14/service-client/transport/service-transport.md +68 -0
- package/claude/references/sd-simplysm-v14/service-client/transport/socket-provider.md +100 -0
- package/claude/references/sd-simplysm-v14/service-client/types/blob-input.md +7 -0
- package/claude/references/sd-simplysm-v14/service-client/types/browser-worker.md +47 -0
- package/claude/references/sd-simplysm-v14/service-client/types/file-collection.md +21 -0
- package/claude/references/sd-simplysm-v14/service-client/types/service-connection-options.md +22 -0
- package/claude/references/sd-simplysm-v14/service-client/types/service-progress.md +39 -0
- package/claude/references/sd-simplysm-v14/service-common/README.md +161 -0
- package/claude/references/sd-simplysm-v14/service-common/app-structure/app-structure-item.md +107 -0
- package/claude/references/sd-simplysm-v14/service-common/app-structure/get-flat-permissions.md +57 -0
- package/claude/references/sd-simplysm-v14/service-common/app-structure/is-usable-modules-chain.md +23 -0
- package/claude/references/sd-simplysm-v14/service-common/app-structure/is-usable-modules.md +42 -0
- package/claude/references/sd-simplysm-v14/service-common/events/define-event.md +68 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/create-service-protocol.md +93 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/protocol-config.md +21 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-add-event-listener-message.md +23 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-auth-message.md +17 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-emit-event-message.md +21 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-error-message.md +29 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-event-message.md +21 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-get-event-listener-infos-message.md +19 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-message.md +52 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-progress-message.md +21 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-remove-event-listener-message.md +19 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-request-message.md +17 -0
- package/claude/references/sd-simplysm-v14/service-common/protocol/service-response-message.md +17 -0
- package/claude/references/sd-simplysm-v14/service-common/service-types/app-structure-service.md +15 -0
- package/claude/references/sd-simplysm-v14/service-common/service-types/auto-update-service.md +20 -0
- package/claude/references/sd-simplysm-v14/service-common/service-types/orm-service.md +61 -0
- package/claude/references/sd-simplysm-v14/service-common/types/service-upload-result.md +19 -0
- package/claude/references/sd-simplysm-v14/service-server/README.md +162 -0
- package/claude/references/sd-simplysm-v14/service-server/auth/auth-token-payload.md +18 -0
- package/claude/references/sd-simplysm-v14/service-server/auth/sign-jwt.md +30 -0
- package/claude/references/sd-simplysm-v14/service-server/auth/verify-jwt.md +35 -0
- package/claude/references/sd-simplysm-v14/service-server/core/auth.md +64 -0
- package/claude/references/sd-simplysm-v14/service-server/core/define-service.md +81 -0
- package/claude/references/sd-simplysm-v14/service-server/core/execute-service-method.md +43 -0
- package/claude/references/sd-simplysm-v14/service-server/core/service-context.md +79 -0
- package/claude/references/sd-simplysm-v14/service-server/legacy/handle-v1-connection.md +25 -0
- package/claude/references/sd-simplysm-v14/service-server/main/create-service-server.md +32 -0
- package/claude/references/sd-simplysm-v14/service-server/main/service-server.md +113 -0
- package/claude/references/sd-simplysm-v14/service-server/protocol/server-protocol-wrapper.md +35 -0
- package/claude/references/sd-simplysm-v14/service-server/services/app-structure-service.md +59 -0
- package/claude/references/sd-simplysm-v14/service-server/services/auto-update-service.md +34 -0
- package/claude/references/sd-simplysm-v14/service-server/services/orm-service.md +43 -0
- package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-http-request.md +33 -0
- package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-static-file.md +29 -0
- package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-upload.md +33 -0
- package/claude/references/sd-simplysm-v14/service-server/transport-socket/service-socket.md +64 -0
- package/claude/references/sd-simplysm-v14/service-server/transport-socket/websocket-handler.md +57 -0
- package/claude/references/sd-simplysm-v14/service-server/types/service-server-options.md +36 -0
- package/claude/references/sd-simplysm-v14/service-server/utils/get-config.md +29 -0
- package/claude/references/sd-simplysm-v14/storage/README.md +99 -0
- package/claude/references/sd-simplysm-v14/storage/clients/ftp-storage-client.md +99 -0
- package/claude/references/sd-simplysm-v14/storage/clients/sftp-storage-client.md +108 -0
- package/claude/references/sd-simplysm-v14/storage/factory/storage-factory.md +114 -0
- package/claude/references/sd-simplysm-v14/storage/types/file-info.md +32 -0
- package/claude/references/sd-simplysm-v14/storage/types/storage-client.md +55 -0
- package/claude/references/sd-simplysm-v14/storage/types/storage-conn-config.md +34 -0
- package/claude/rules/sd-claude-rules.md +8 -8
- package/claude/rules/sd-simplysm-v14.md +33 -0
- package/claude/skills/sd-claude-docs/SKILL.md +41 -24
- package/claude/skills/sd-claude-docs/references/package-docs.md +240 -116
- package/claude/skills/sd-inner-debug/SKILL.md +1 -1
- package/claude/skills/sd-inner-review/SKILL.md +4 -2
- package/package.json +2 -3
- /package/{docs → claude/references/sd-simplysm-v14/sd-claude}/cli.md +0 -0
- /package/{docs → claude/references/sd-simplysm-v14/sd-claude}/scripts.md +0 -0
package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-e-auxiliary.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
← [CRUD 상세폼 레시피 진입점](../crud-detail.md)
|
|
2
|
+
|
|
3
|
+
# 확장 E: 보조 기능 영역
|
|
4
|
+
|
|
5
|
+
> **선행:** [확장 A: 편집/저장](./extension-a-edit-save.md)
|
|
6
|
+
|
|
7
|
+
확장 A(편집/저장)를 전제로, 메인 폼의 submit과 **별개인 보조 기능**(예: 다른 사용자로부터 권한 복사, 출력, 엑셀 다운로드 등)을 추가한다. 과거 `#toolTpl` 슬롯이 담당하던 역할을 소비 화면에 직접 인라인한다. 보조 영역은 control 뷰 상단 `<sd-dock>` 내부 / modal 뷰 하단 바 옆 / main 영역 내 별도 `<sd-form>` 중 하나에 배치한다. 뷰별 UI 배치 본문은 [확장 C](./extension-c-modal-view.md) / [확장 D](./extension-d-control-view.md)에서 처리한다.
|
|
8
|
+
|
|
9
|
+
**이 확장이 도입하는 요소:**
|
|
10
|
+
|
|
11
|
+
- **imports:** `SdSharedDataSelect` (`@simplysm/angular`), 앱 공용 `useSharedSignal` (예: `@adtek/client-common` — `SdSharedDataProvider` 위에 각 앱이 정의하는 공용 훅)
|
|
12
|
+
- **상태:** 예시 — `permCopySourceId = signal<number | undefined>(undefined)`, `sharedUsers = useSharedSignal("사용자")`
|
|
13
|
+
- **메서드:** 예시 — `onImportFormSubmit` (권한·busy 가드 + 메인 폼 변경 보호 호출 + 앱별 ORM 조회·병합)
|
|
14
|
+
- **템플릿 추가:** 보조 `<sd-form (formSubmit)="onImportFormSubmit()">` 블록을 배치(아래 예시는 control 뷰 `<sd-dock>` 내부). 메인 `<sd-form #formCtrl>`과 **별도** 인스턴스
|
|
15
|
+
- **공유 데이터 대기:** 본 확장이 `useSharedSignal`을 도입하므로 `_refresh()` 선두에 `await this._sdSharedData.wait();`가 필요해진다 → [공통 규칙: `_sdSharedData.wait()`](../_common-rules.md#공유-데이터-사용-화면은-_refresh-선두에서-_sdshareddatawait를-호출한다)
|
|
16
|
+
|
|
17
|
+
> 상세: [`<sd-shared-data-select>`](../../ui-form/sd-shared-data-select.md)
|
|
18
|
+
|
|
19
|
+
> **아래 코드 블록은 diff 조각이다.** 독립 실행 가능한 완성 클래스가 아니며, 선행 확장(A) 위에 번호 순서대로 삽입할 지점을 나타낸다. 그대로 컴파일되지 않는다.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// 1) imports 추가
|
|
23
|
+
import { SdSharedDataSelect } from "@simplysm/angular";
|
|
24
|
+
// 앱 공용 훅 — @simplysm/angular 소유 아님. 각 앱이 SdSharedDataProvider 위에 정의.
|
|
25
|
+
import { useSharedSignal } from "@adtek/client-common";
|
|
26
|
+
|
|
27
|
+
// 2) 클래스에 상태 추가
|
|
28
|
+
protected readonly permCopySourceId = signal<number | undefined>(undefined);
|
|
29
|
+
protected readonly sharedUsers = useSharedSignal("사용자");
|
|
30
|
+
|
|
31
|
+
// 3) template — 보조 form 블록을 배치한다. 아래는 control 뷰 <sd-dock>(상단 바) 내부 예시.
|
|
32
|
+
// modal 뷰는 하단 바(<sd-dock [position]="'bottom'">) 옆, main 영역은 메인 form 옆이나 아래에 배치할 수 있다.
|
|
33
|
+
@if (viewType() === "control" && canEdit()) {
|
|
34
|
+
<sd-dock class="p-default flex-row gap-default bdb bdb-theme-gray-lightest">
|
|
35
|
+
<!-- 기본 저장/삭제 버튼 (확장 D) -->
|
|
36
|
+
<!-- ... -->
|
|
37
|
+
|
|
38
|
+
<!-- 보조 기능: 다른 사용자로부터 가져오기 -->
|
|
39
|
+
<sd-form (formSubmit)="onImportFormSubmit()">
|
|
40
|
+
<div class="form-box-inline">
|
|
41
|
+
<div class="form-box-item">
|
|
42
|
+
<label>가져오기</label>
|
|
43
|
+
<sd-shared-data-select
|
|
44
|
+
[items]="sharedUsers.items()"
|
|
45
|
+
[(value)]="permCopySourceId"
|
|
46
|
+
[inset]="true"
|
|
47
|
+
[size]="'sm'"
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="form-box-item">
|
|
51
|
+
<sd-button [type]="'submit'" [disabled]="permCopySourceId() == null">
|
|
52
|
+
가져오기
|
|
53
|
+
</sd-button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</sd-form>
|
|
57
|
+
</sd-dock>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 4) 메서드 추가
|
|
61
|
+
protected async onImportFormSubmit(): Promise<void> {
|
|
62
|
+
if (this.busyCount() > 0 || !this.perms().includes("edit")) return;
|
|
63
|
+
if (this.permCopySourceId() == null) return;
|
|
64
|
+
// 메인 폼의 미저장 변경사항 보호 — 확장 A가 제공하는 _checkIgnoreChanges() 재호출
|
|
65
|
+
if (!this._checkIgnoreChanges()) return;
|
|
66
|
+
|
|
67
|
+
this.busyCount.update((v) => v + 1);
|
|
68
|
+
await this._sdToast.try(async () => {
|
|
69
|
+
// 앱별 서버 호출로 다른 사용자의 데이터를 조회·병합 — 예:
|
|
70
|
+
// const src = await this._appOrm.connectAsync(async (db) =>
|
|
71
|
+
// (await db.customer.where((it) => [expr.eq(it.id, this.permCopySourceId())]).single())!
|
|
72
|
+
// );
|
|
73
|
+
// this.data.set({ ...this.data(), ...src });
|
|
74
|
+
});
|
|
75
|
+
this.busyCount.update((v) => v - 1);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**포인트:**
|
|
80
|
+
|
|
81
|
+
- **보조 `<sd-form>`은 메인 `<sd-form #formCtrl>`과 별도 인스턴스**다. `SdCommandDirective.sdSaveCommand` → `formCtrl()?.requestSubmit()` 경로는 메인 form 한 곳에만 연결된다(확장 A). 보조 form의 submit 버튼은 Ctrl+S와 연동되지 않고 버튼 클릭(또는 submit 버튼에서 Enter 제출)만 발동한다. 보조 form에는 `#formCtrl` template 변수를 부여하지 않는다.
|
|
82
|
+
- **보조 작업 전에도 `_checkIgnoreChanges()`를 호출**하여 메인 폼의 미저장 변경사항을 보호한다. 보조 form이 메인 `data()`를 덮어쓰는 경우(권한 복사 등) 필수. `_checkIgnoreChanges`는 확장 A가 제공하므로 재정의하지 않는다.
|
|
83
|
+
- **공유 데이터 도입으로 `_refresh()` 선두에 `await this._sdSharedData.wait();`가 필요해진다.** 판정 기준·코드 예시는 [공통 규칙: `_sdSharedData.wait()`](../_common-rules.md#공유-데이터-사용-화면은-_refresh-선두에서-_sdshareddatawait를-호출한다) 참조.
|
|
84
|
+
- **`<sd-shared-data-select>`에 `[inset]="true" [size]="'sm'"`을 명시**한다. `<sd-dock>` 도구 바 내부 치수와 `form-box-inline` 간격이 sm 기준으로 정합하므로 인셋·사이즈를 생략하면 컨트롤 높이가 들쭉날쭉해진다.
|
|
85
|
+
- **배치 위치 선택:** control 뷰는 상단 `<sd-dock>` 안, modal 뷰는 하단 바(`<sd-dock [position]="'bottom'">`) 옆, main 영역에서는 메인 form과 나란한 별도 블록. 뷰 분기 본문 UI는 [확장 C](./extension-c-modal-view.md) / [확장 D](./extension-d-control-view.md)에서 정의한다.
|
|
86
|
+
- **읽기 전용 보조(출력·엑셀 다운로드 등)는 `<sd-form>` 래핑 없이 버튼 `(click)`으로 직접 처리 가능**하다. 입력 값을 수집하지 않는 단일 액션은 form submit 절차가 불필요하다. 이 경우 `_checkIgnoreChanges()` 호출도 상황에 맞게 판단한다(읽기 전용이라 메인 변경 보호가 불필요할 수 있음).
|
|
87
|
+
- **`useSharedSignal`은 `@simplysm/angular` 제공이 아님** — `SdSharedDataProvider`(`packages/angular/src/core/shared-data/sd-shared-data.provider.ts`) 위에서 각 앱이 정의하는 공용 훅이다. 배포 패키지 소속이 다르므로 import 경로 혼동에 주의한다.
|
package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-f-complex-detail.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
← [CRUD 상세폼 레시피 진입점](../crud-detail.md)
|
|
2
|
+
|
|
3
|
+
# 확장 F: 복합 상세 (내부 `<sd-sheet>`)
|
|
4
|
+
|
|
5
|
+
> **선행:** [확장 A: 편집/저장](./extension-a-edit-save.md)
|
|
6
|
+
|
|
7
|
+
확장 A(편집/저장)를 전제로, 상세 폼 안에 **하위 컬렉션**(박스 목록, 품목 라인 등)을 편집하는 구조를 도입한다. `<sd-form>` 본문 내부에 `<sd-sheet>`를 중첩하고, 하위 컬렉션의 행 추가·수정·삭제는 `item.isDeleted = true` 플래그로 표현하여 `oneWayDiffs` 기반 일괄 저장에 포함시킨다.
|
|
8
|
+
|
|
9
|
+
**이 확장이 도입하는 요소:**
|
|
10
|
+
|
|
11
|
+
- **imports:** `SdSheet`, `SdSheetColumn`, `SdSheetColumnCellTemplate`, `SdAnchor`(하위 행 삭제/복구 아이콘 호스트), `Uuid`, `oneWayDiffs`(side-effect import), 아이콘 `tablerCirclePlus` / `tablerEraser` / `tablerRestore` (`mark`는 확장 A에서 이미 도입)
|
|
12
|
+
- **데이터 타입 확장:** `ICustomer.boxes: ICustomerBox[]` + `interface ICustomerBox { id: string; seq: number; note: string; isDeleted: boolean; }`
|
|
13
|
+
- **data 초기값:** `boxes: []` 필드 추가
|
|
14
|
+
- **시트 함수 (클래스 필드):** `boxTrackByFn`, `getBoxCellStyleFn`
|
|
15
|
+
- **메서드:** `onAddBoxButtonClick`, `onToggleDeleteBoxButtonClick`
|
|
16
|
+
- **템플릿:** main 영역 `<sd-form>` 내부를 [상단 단일 필드 블록 + 하위 컬렉션 도구 dock(`<sd-button>` "박스 추가") + 하위 `<sd-sheet>` 중첩] 구조로 교체
|
|
17
|
+
- **onSubmit 변경:** `_sdToast.try(...)` 블록 내부를 diff 계산(`data().boxes.oneWayDiffs(_dataSnapshot?.boxes, "id")`) + 일괄 제출로 교체
|
|
18
|
+
|
|
19
|
+
> 상세: [`<sd-sheet>`](../../ui-data/sd-sheet.md) · [`<sd-sheet-column>`](../../ui-data/sd-sheet.md#sdsheetcolumn) · [`[cell]`](../../ui-data/sd-sheet.md#sdsheetcolumncelltemplate) · [`<sd-anchor>`](../../ui-form/sd-anchor.md)
|
|
20
|
+
|
|
21
|
+
> **아래 코드 블록은 diff 조각이다.** 독립 실행 가능한 완성 클래스가 아니며, 선행 확장(A) 위에 번호 순서대로 삽입·교체할 지점을 나타낸다. 그대로 컴파일되지 않는다.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// 1) imports 추가 — @simplysm/angular에 {SdSheet, SdSheetColumn, SdSheetColumnCellTemplate, SdAnchor} 추가.
|
|
25
|
+
// @simplysm/core-common에서 {Uuid} 추가 + 프로토타입 확장 활성화용 side-effect import.
|
|
26
|
+
// 아이콘에 tablerCirclePlus / tablerEraser / tablerRestore 추가. (mark는 확장 A에서 이미 import됨)
|
|
27
|
+
import { SdSheet, SdSheetColumn, SdSheetColumnCellTemplate, SdAnchor } from "@simplysm/angular";
|
|
28
|
+
import { Uuid } from "@simplysm/core-common";
|
|
29
|
+
import { tablerCirclePlus, tablerEraser, tablerRestore } from "@ng-icons/tabler-icons";
|
|
30
|
+
import "@simplysm/core-common"; // Array.prototype.oneWayDiffs 활성화 (side-effect import)
|
|
31
|
+
|
|
32
|
+
// 2) 데이터 타입 확장 — 진입점 3.1 최소 뼈대의 ICustomer에 boxes 필드만 추가, ICustomerBox 신설
|
|
33
|
+
// (확장 B를 함께 적용하면 ICustomer.isDeleted 필드가 별도로 들어가며, 본 확장 단독 적용에는 포함되지 않는다)
|
|
34
|
+
interface ICustomer {
|
|
35
|
+
id: number | undefined;
|
|
36
|
+
name: string;
|
|
37
|
+
phone: string;
|
|
38
|
+
lastModifiedAt: DateTime | undefined;
|
|
39
|
+
lastModifiedBy: string | undefined;
|
|
40
|
+
boxes: ICustomerBox[]; // 하위 컬렉션 추가
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ICustomerBox {
|
|
44
|
+
id: string; // 클라이언트 생성 UUID (서버 저장 시 교체 가능)
|
|
45
|
+
seq: number;
|
|
46
|
+
note: string;
|
|
47
|
+
isDeleted: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 3) data 초기값에 boxes: [] 추가 — 진입점 3.1 최소 뼈대의 data = signal<ICustomer>({ ... }) 초기값에 포함
|
|
51
|
+
|
|
52
|
+
// 4) template — main 영역(<sd-dock-container> 안쪽 <sd-form> 내부)을
|
|
53
|
+
// [단일 필드 + 도구 dock + 시트]로 교체. 최종수정 표시 블록은 최소 뼈대와 동일.
|
|
54
|
+
<div class="flex-column fill">
|
|
55
|
+
<sd-form #formCtrl (formSubmit)="onSubmit()" class="flex-fill flex-column">
|
|
56
|
+
<!-- 상단 단일 필드 -->
|
|
57
|
+
<div class="p-default">
|
|
58
|
+
<table class="form-table">
|
|
59
|
+
<tbody>
|
|
60
|
+
<tr>
|
|
61
|
+
<th>명칭</th>
|
|
62
|
+
<td>
|
|
63
|
+
<sd-textfield
|
|
64
|
+
[type]="'text'"
|
|
65
|
+
[required]="true"
|
|
66
|
+
[disabled]="!canEdit()"
|
|
67
|
+
[(value)]="data().name"
|
|
68
|
+
/>
|
|
69
|
+
</td>
|
|
70
|
+
</tr>
|
|
71
|
+
</tbody>
|
|
72
|
+
</table>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<!-- 하위 컬렉션 도구 영역 -->
|
|
76
|
+
@if (canEdit()) {
|
|
77
|
+
<div class="flex-row gap-sm p-xs-default">
|
|
78
|
+
<sd-button [size]="'sm'" [theme]="'link-primary'" (click)="onAddBoxButtonClick()">
|
|
79
|
+
<ng-icon [svg]="tablerCirclePlus" />
|
|
80
|
+
박스 추가
|
|
81
|
+
</sd-button>
|
|
82
|
+
</div>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
<!-- 하위 컬렉션 시트 -->
|
|
86
|
+
<div class="flex-fill">
|
|
87
|
+
<sd-sheet
|
|
88
|
+
[items]="data().boxes"
|
|
89
|
+
[trackByFn]="boxTrackByFn"
|
|
90
|
+
[getItemCellStyleFn]="getBoxCellStyleFn"
|
|
91
|
+
>
|
|
92
|
+
@if (canEdit()) {
|
|
93
|
+
<sd-sheet-column [fixed]="true" [key]="'_isDeleted'">
|
|
94
|
+
<ng-template #headerTpl>
|
|
95
|
+
<div class="p-xs-sm tx-center">
|
|
96
|
+
<ng-icon [svg]="tablerEraser" />
|
|
97
|
+
</div>
|
|
98
|
+
</ng-template>
|
|
99
|
+
<ng-template [cell]="data().boxes" let-item="item">
|
|
100
|
+
<div class="p-xs-sm tx-center">
|
|
101
|
+
<sd-anchor
|
|
102
|
+
[theme]="'danger'"
|
|
103
|
+
(click)="onToggleDeleteBoxButtonClick(item)"
|
|
104
|
+
>
|
|
105
|
+
<ng-icon [svg]="item.isDeleted ? tablerRestore : tablerEraser" />
|
|
106
|
+
</sd-anchor>
|
|
107
|
+
</div>
|
|
108
|
+
</ng-template>
|
|
109
|
+
</sd-sheet-column>
|
|
110
|
+
}
|
|
111
|
+
<sd-sheet-column [key]="'seq'" [header]="'박스#'">
|
|
112
|
+
<ng-template [cell]="data().boxes" let-item="item">
|
|
113
|
+
<sd-textfield
|
|
114
|
+
[type]="'number'"
|
|
115
|
+
[required]="true"
|
|
116
|
+
[disabled]="!canEdit()"
|
|
117
|
+
[(value)]="item.seq"
|
|
118
|
+
[inset]="true"
|
|
119
|
+
[size]="'sm'"
|
|
120
|
+
/>
|
|
121
|
+
</ng-template>
|
|
122
|
+
</sd-sheet-column>
|
|
123
|
+
<sd-sheet-column [key]="'note'" [header]="'비고'">
|
|
124
|
+
<ng-template [cell]="data().boxes" let-item="item">
|
|
125
|
+
<sd-textfield
|
|
126
|
+
[type]="'text'"
|
|
127
|
+
[disabled]="!canEdit()"
|
|
128
|
+
[(value)]="item.note"
|
|
129
|
+
[inset]="true"
|
|
130
|
+
[size]="'sm'"
|
|
131
|
+
/>
|
|
132
|
+
</ng-template>
|
|
133
|
+
</sd-sheet-column>
|
|
134
|
+
</sd-sheet>
|
|
135
|
+
</div>
|
|
136
|
+
</sd-form>
|
|
137
|
+
<!-- 최종수정 표시는 최소 뼈대와 동일 -->
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
// 5) 시트 함수 (클래스 필드) 추가
|
|
141
|
+
protected readonly boxTrackByFn = (item: ICustomerBox): string => item.id;
|
|
142
|
+
|
|
143
|
+
protected readonly getBoxCellStyleFn = (item: ICustomerBox): string | undefined =>
|
|
144
|
+
item.isDeleted ? "text-decoration: line-through;" : undefined;
|
|
145
|
+
|
|
146
|
+
// 6) 메서드 추가
|
|
147
|
+
protected onAddBoxButtonClick(): void {
|
|
148
|
+
const newBox: ICustomerBox = {
|
|
149
|
+
id: Uuid.generate().toString(),
|
|
150
|
+
seq: (this.data().boxes.at(-1)?.seq ?? 0) + 1,
|
|
151
|
+
note: "",
|
|
152
|
+
isDeleted: false,
|
|
153
|
+
};
|
|
154
|
+
this.data().boxes.push(newBox);
|
|
155
|
+
mark(this.data);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
protected onToggleDeleteBoxButtonClick(item: ICustomerBox): void {
|
|
159
|
+
item.isDeleted = !item.isDeleted;
|
|
160
|
+
mark(this.data);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 7) onSubmit의 _sdToast.try(...) 블록 내부 교체 — diff 계산 + 일괄 제출
|
|
164
|
+
await this._sdToast.try(async () => {
|
|
165
|
+
// 삭제 플래그가 섞여 있으면 사용자 확인
|
|
166
|
+
if (this.data().boxes.some((b) => b.isDeleted)) {
|
|
167
|
+
if (!confirm("삭제 표시된 박스가 있습니다. 정말 저장하시겠습니까?")) return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 하위 컬렉션 diff 계산 — 반환 type은 "create" | "update" | "same" 3종
|
|
171
|
+
const snapshotBoxes = this._dataSnapshot?.boxes ?? [];
|
|
172
|
+
const boxDiffs = this.data().boxes.oneWayDiffs(snapshotBoxes, "id");
|
|
173
|
+
|
|
174
|
+
// 앱별 ORM 호출:
|
|
175
|
+
// await this._appOrm.connectAsync(async (db) => {
|
|
176
|
+
// await db.customer().where((c) => [expr.eq(c.id, this.data().id)])
|
|
177
|
+
// .upsert(() => ({ name: this.data().name, phone: this.data().phone }));
|
|
178
|
+
// for (const d of boxDiffs) {
|
|
179
|
+
// if (d.type === "create") {
|
|
180
|
+
// await db.customerBox().insert({ ...d.item, customerId: this.data().id! });
|
|
181
|
+
// } else if (d.type === "update") {
|
|
182
|
+
// await db.customerBox().where((c) => [expr.eq(c.id, d.item.id)])
|
|
183
|
+
// .update(() => d.item);
|
|
184
|
+
// }
|
|
185
|
+
// }
|
|
186
|
+
// });
|
|
187
|
+
|
|
188
|
+
this._sdToast.success("저장되었습니다.");
|
|
189
|
+
// 확장 C(modal 뷰)가 함께 적용된 경우에만 존재: this.close.emit(true); — modal 호출 측에 결과 전달
|
|
190
|
+
await this._refresh();
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**포인트:**
|
|
195
|
+
|
|
196
|
+
- **하위 컬렉션의 삭제는 `isDeleted: true` 플래그로 표현한다.** 이것은 상위 테이블의 삭제 방식([공통 규칙: 삭제 방식](../_common-rules.md#삭제-방식은-db-스키마에-따라-결정한다))과 **무관**하게, `oneWayDiffs`가 `"delete"` 타입을 지원하지 않기 때문에 하위 컬렉션에서는 항상 이 방식을 사용한다. 반환 `type`은 `"create" | "update" | "same"` 3종뿐이다(`packages/core-common/src/extensions/arr-ext.types.ts:206`). 서버는 `isDeleted: true` row를 soft-delete 또는 물리 삭제로 처리한다.
|
|
197
|
+
- **시트 셀 내부 컨트롤은 `[inset]="true" [size]="'sm'"` 명시 필수** — [공통 규칙: 시트 셀 `[inset]/[size]`](../_common-rules.md#시트-셀-내부-컨트롤에-insettrue-sizesm을-명시한다).
|
|
198
|
+
- **`data().boxes.push(newBox)` 같은 배열 mutation 후에는 `mark(this.data)`로 signal 참조를 갱신한다** — OnPush 템플릿 재렌더링·연계 computed 갱신 용도의 **통지**이며, 값 비교(저장 감지)와는 별개다: [공통 규칙: `mark(sig)`…](../_common-rules.md#marksig를-저장-감지-수단으로-사용하지-않는다).
|
|
199
|
+
- **`id`는 클라이언트에서 UUID로 생성** — `Uuid.generate().toString()`으로 문자열 key를 만들어 `trackByFn` + `oneWayDiffs`의 key로 사용한다. 서버가 발급한 PK가 별도로 있다면 별도 컬럼으로 관리하고 클라이언트 UUID는 row 식별자로만 쓴다.
|
|
200
|
+
- **삭제 플래그 혼재 시 `confirm`** — `this.data().boxes.some((b) => b.isDeleted)`이면 저장 직전 사용자 확인을 요청한다.
|
|
201
|
+
|
|
202
|
+
> 공통 규칙(시트 셀 `[inset]/[size]`, `mark` 오용, 상위 테이블 soft-delete 선택 기준)은 [레시피 공통 규칙](../_common-rules.md)을 참조한다.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Recipe: CRUD 상세폼 화면 직접 조립
|
|
2
|
+
|
|
3
|
+
단일 레코드 CRUD 상세폼을, `<sd-busy-container>` · `<sd-topbar-container>` · `<sd-topbar>` · `<sd-form>` 표준 컴포넌트를 소비 화면이 **직접 조립**하여 구성한다. 과거 `SdDataDetail` / `SdDataDetailBase`가 감추고 있던 load·save·delete 라이프사이클, snapshot 기반 변경 감지, 이탈 방지, busy 카운트, Ctrl+S 단축키를 화면 내부에 인라인으로 풀어쓴다.
|
|
4
|
+
|
|
5
|
+
## When to use / When NOT to use
|
|
6
|
+
|
|
7
|
+
- ✅ 단일 레코드(고객, 주문 헤더 등)의 CRUD 상세폼을 만들 때
|
|
8
|
+
- ✅ page / modal / control 뷰 중 **필요한 뷰만 선택적으로** 지원해야 할 때
|
|
9
|
+
- ✅ 편집·저장·삭제·복구·보조 기능·복합 상세(내부 시트)를 상황에 따라 누적해야 할 때
|
|
10
|
+
- ❌ CRUD 리스트(시트) 화면 → [`crud-list.md`](./crud-list.md)
|
|
11
|
+
- ❌ 페이지/모달 뷰 분기만 필요한 단순 컨테이너(라이프사이클 없음) → [`page-modal-container.md`](./page-modal-container.md)
|
|
12
|
+
- ❌ 다른 화면에서 데이터를 고르는 선택 버튼 → [`data-select-button.md`](./data-select-button.md)
|
|
13
|
+
|
|
14
|
+
## 전제조건
|
|
15
|
+
|
|
16
|
+
- `provideSdAngular({ clientName })` 부트스트랩 완료
|
|
17
|
+
- 앱별 ORM provider (예: `AppOrmProvider`) — `@simplysm/angular`가 아니라 각 앱이 소유
|
|
18
|
+
- 권한 제어가 있는 경우 `SdAppStructureProvider` 등록 (`injectPermsSignal` 전제)
|
|
19
|
+
- 횡단 규칙: [`_common-rules.md`](./_common-rules.md)에 정의된 공통 규칙을 모두 준수한다
|
|
20
|
+
- [화면 레이아웃 구간과 버튼 스타일 구분](./_common-rules.md#화면-레이아웃-구간과-버튼-스타일을-구분한다)
|
|
21
|
+
- [page 컴포넌트가 `<sd-topbar>`를 소유](./_common-rules.md#page-컴포넌트가-sd-topbar-container와-sd-topbar를-소유한다)
|
|
22
|
+
|
|
23
|
+
## 기본 레시피 (page 뷰, 읽기 전용)
|
|
24
|
+
|
|
25
|
+
라우트 진입 시 `itemId`를 받아 단일 레코드를 로드하고 읽기 전용 필드로 표시하는 최소 완성 컴포넌트다. 편집·삭제·modal·control·보조·복합이 필요하면 [변형](#변형-확장-a-f-인덱스)의 확장을 선택적으로 얹는다.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import {
|
|
29
|
+
ChangeDetectionStrategy,
|
|
30
|
+
Component,
|
|
31
|
+
effect,
|
|
32
|
+
inject,
|
|
33
|
+
input,
|
|
34
|
+
signal,
|
|
35
|
+
untracked,
|
|
36
|
+
ViewEncapsulation,
|
|
37
|
+
} from "@angular/core";
|
|
38
|
+
import type { DateTime } from "@simplysm/core-common";
|
|
39
|
+
import {
|
|
40
|
+
FormatPipe,
|
|
41
|
+
injectPermsSignal,
|
|
42
|
+
injectViewTitleSignal,
|
|
43
|
+
SdBusyContainer,
|
|
44
|
+
SdButton,
|
|
45
|
+
SdForm,
|
|
46
|
+
SdTextfield,
|
|
47
|
+
SdToastProvider,
|
|
48
|
+
SdTopbar,
|
|
49
|
+
SdTopbarContainer,
|
|
50
|
+
} from "@simplysm/angular";
|
|
51
|
+
// 앱별 대체: ORM provider + DbContext. @simplysm/angular가 아니라 각 앱이 소유한다.
|
|
52
|
+
import { AppOrmProvider } from "@adtek/client-common";
|
|
53
|
+
|
|
54
|
+
interface ICustomer {
|
|
55
|
+
id: number | undefined; // undefined면 신규 — 확장 A 편집/저장 시 활용
|
|
56
|
+
name: string;
|
|
57
|
+
phone: string;
|
|
58
|
+
lastModifiedAt: DateTime | undefined;
|
|
59
|
+
lastModifiedBy: string | undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Component({
|
|
63
|
+
selector: "app-customer-detail",
|
|
64
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
65
|
+
encapsulation: ViewEncapsulation.None,
|
|
66
|
+
standalone: true,
|
|
67
|
+
imports: [
|
|
68
|
+
SdBusyContainer, SdTopbarContainer, SdTopbar,
|
|
69
|
+
SdForm, SdButton, SdTextfield,
|
|
70
|
+
FormatPipe,
|
|
71
|
+
],
|
|
72
|
+
template: `
|
|
73
|
+
<sd-busy-container [busy]="busyCount() > 0">
|
|
74
|
+
@if (initialized()) {
|
|
75
|
+
<sd-topbar-container>
|
|
76
|
+
<sd-topbar>
|
|
77
|
+
<h4>{{ viewTitle() }}</h4>
|
|
78
|
+
</sd-topbar>
|
|
79
|
+
|
|
80
|
+
<div class="flex-column fill">
|
|
81
|
+
<sd-form class="flex-fill">
|
|
82
|
+
<div class="p-default">
|
|
83
|
+
<table class="form-table">
|
|
84
|
+
<tbody>
|
|
85
|
+
<tr>
|
|
86
|
+
<th>명칭</th>
|
|
87
|
+
<td>
|
|
88
|
+
<sd-textfield
|
|
89
|
+
[type]="'text'"
|
|
90
|
+
[readonly]="true"
|
|
91
|
+
[(value)]="data().name"
|
|
92
|
+
/>
|
|
93
|
+
</td>
|
|
94
|
+
</tr>
|
|
95
|
+
<tr>
|
|
96
|
+
<th>전화번호</th>
|
|
97
|
+
<td>
|
|
98
|
+
<sd-textfield
|
|
99
|
+
[type]="'text'"
|
|
100
|
+
[readonly]="true"
|
|
101
|
+
[(value)]="data().phone"
|
|
102
|
+
/>
|
|
103
|
+
</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</div>
|
|
108
|
+
</sd-form>
|
|
109
|
+
|
|
110
|
+
@if (data().lastModifiedAt || data().lastModifiedBy) {
|
|
111
|
+
<div class="p-sm-default">
|
|
112
|
+
최종수정:
|
|
113
|
+
@if (data().lastModifiedAt) {
|
|
114
|
+
{{ data().lastModifiedAt | format: "yyyy-MM-dd HH:mm" }}
|
|
115
|
+
}
|
|
116
|
+
@if (data().lastModifiedBy) {
|
|
117
|
+
({{ data().lastModifiedBy }})
|
|
118
|
+
}
|
|
119
|
+
</div>
|
|
120
|
+
}
|
|
121
|
+
</div>
|
|
122
|
+
</sd-topbar-container>
|
|
123
|
+
}
|
|
124
|
+
</sd-busy-container>
|
|
125
|
+
`,
|
|
126
|
+
})
|
|
127
|
+
export class CustomerDetail {
|
|
128
|
+
//== DI ==
|
|
129
|
+
private readonly _appOrm = inject(AppOrmProvider);
|
|
130
|
+
private readonly _sdToast = inject(SdToastProvider);
|
|
131
|
+
|
|
132
|
+
//== input ==
|
|
133
|
+
itemId = input<number>();
|
|
134
|
+
|
|
135
|
+
//== 타이틀 / 권한 ==
|
|
136
|
+
protected readonly viewTitle = injectViewTitleSignal();
|
|
137
|
+
perms = injectPermsSignal(["sales.customer"], ["use"]);
|
|
138
|
+
|
|
139
|
+
//== 상태 ==
|
|
140
|
+
protected readonly busyCount = signal(0);
|
|
141
|
+
protected readonly initialized = signal(false);
|
|
142
|
+
protected readonly data = signal<ICustomer>({
|
|
143
|
+
id: undefined,
|
|
144
|
+
name: "",
|
|
145
|
+
phone: "",
|
|
146
|
+
lastModifiedAt: undefined,
|
|
147
|
+
lastModifiedBy: undefined,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
//== 라이프사이클 ==
|
|
151
|
+
constructor() {
|
|
152
|
+
// 최초 진입 + itemId 변경 시 재조회.
|
|
153
|
+
effect(() => {
|
|
154
|
+
this.itemId(); // 의존성 등록
|
|
155
|
+
if (!this.perms().includes("use")) {
|
|
156
|
+
this.initialized.set(true);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
void untracked(async () => {
|
|
161
|
+
this.busyCount.update((v) => v + 1);
|
|
162
|
+
await this._sdToast.try(async () => {
|
|
163
|
+
await this._refresh();
|
|
164
|
+
});
|
|
165
|
+
this.busyCount.update((v) => v - 1);
|
|
166
|
+
this.initialized.set(true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//== 내부 메서드 ==
|
|
172
|
+
private async _refresh(): Promise<void> {
|
|
173
|
+
let data: ICustomer;
|
|
174
|
+
if (this.itemId() == null) {
|
|
175
|
+
data = {
|
|
176
|
+
id: undefined, name: "", phone: "",
|
|
177
|
+
lastModifiedAt: undefined, lastModifiedBy: undefined,
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
// 앱별 ORM 조회 — 예:
|
|
181
|
+
// data = await this._appOrm.connectAsync(async (db) =>
|
|
182
|
+
// (await db.customer.where((it) => [expr.eq(it.id, this.itemId())]).single())!
|
|
183
|
+
// );
|
|
184
|
+
throw new Error("구현 필요");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.data.set(data);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 조건부 요소 포함 기준
|
|
194
|
+
|
|
195
|
+
인프라·라이프사이클 요소는 화면 요건에 따라 포함·생략한다. 필요 없는 요소를 기계적으로 포함하지 않는다.
|
|
196
|
+
|
|
197
|
+
| 요소 | 포함 조건 | 생략 예시 |
|
|
198
|
+
|------|----------|----------|
|
|
199
|
+
| `<sd-topbar-container>` + `<sd-topbar>` | routes로 연결된 page에서 헤더가 필요할 때. 기본 레시피는 page 전용이라 조건 없이 렌더 | route 미연결(control·래퍼) |
|
|
200
|
+
| `injectViewTitleSignal()` | topbar에 타이틀을 표시할 때 | topbar 없음·타이틀 불필요 |
|
|
201
|
+
| `injectViewTypeSignal()` + 분기 | page 외에 modal/control로도 겸용될 때. 기본 레시피는 page 전용이므로 **미포함** — [확장 C](./crud-detail/extension-c-modal-view.md) / [확장 D](./crud-detail/extension-d-control-view.md)에서 도입 | page 전용 |
|
|
202
|
+
| `injectPermsSignal()` + effect 내 권한 체크 | 권한 제어가 있는 화면. effect에서 `perms().includes("use")` 검사 후 미보유 시 `return` | 권한 제어 없음 |
|
|
203
|
+
| `<sd-busy-container>` + `busyCount` | 비동기 작업(DB 조회 등)이 있어 busy 표시가 필요할 때 | 동기 래퍼·레이아웃 |
|
|
204
|
+
| `initialized` + `@if (initialized())` | 초기 로딩 완료 전 깜박임 방지가 필요할 때 | 빈 상태 렌더가 무방 |
|
|
205
|
+
|
|
206
|
+
## 변형 (확장 A~F 인덱스)
|
|
207
|
+
|
|
208
|
+
| 상황 | 시작 지점 + 필요한 확장 |
|
|
209
|
+
|---|---|
|
|
210
|
+
| 단일 레코드 **읽기 전용 상세 폼** (page 뷰, 감사 필드 표시) | 기본 레시피만 |
|
|
211
|
+
| 편집·저장 가능한 단일 레코드 상세 폼 | 기본 + [확장 A](./crud-detail/extension-a-edit-save.md) |
|
|
212
|
+
| 삭제·복구 토글 포함 | 기본 + A + [확장 B](./crud-detail/extension-b-delete-restore.md) |
|
|
213
|
+
| page + **modal 뷰** 재사용 (확인·취소·삭제·복구 하단 바) | 기본 + A + B + [확장 C](./crud-detail/extension-c-modal-view.md) |
|
|
214
|
+
| 마스터-디테일의 "디테일" 영역 (**control 뷰**) | 기본 + A + B + [확장 D](./crud-detail/extension-d-control-view.md) |
|
|
215
|
+
| page + modal + control **3뷰** 모두 지원 | 기본 + A + B + C + D |
|
|
216
|
+
| 메인 폼과 별개의 **보조 기능** (가져오기/출력 등) | 기본 + A + [확장 E](./crud-detail/extension-e-auxiliary.md) |
|
|
217
|
+
| 상세 폼 내부에 **하위 컬렉션** 편집 (박스 목록 등) | 기본 + A + [확장 F](./crud-detail/extension-f-complex-detail.md) |
|
|
218
|
+
|
|
219
|
+
### 각 확장 요약
|
|
220
|
+
|
|
221
|
+
- **A. 편집/저장** (선행: 없음) — 읽기 전용을 편집 가능으로 전환. snapshot 기반 변경 감지, `setupCanDeactivate` 이탈 방지, Ctrl+S 일괄 저장. → [상세](./crud-detail/extension-a-edit-save.md)
|
|
222
|
+
- **B. 삭제/복구 토글** (선행: A) — soft-delete 전제. `isDeleted` 필드 + 삭제·복구 버튼. → [상세](./crud-detail/extension-b-delete-restore.md)
|
|
223
|
+
- **C. modal 뷰** (선행: A + B) — `SdModalContentDef` 계약, 하단 액션 바, 모달 우측 상단 액션 슬롯. → [상세](./crud-detail/extension-c-modal-view.md)
|
|
224
|
+
- **D. control 뷰** (선행: A + B) — 마스터-디테일 디테일 영역. 상단 `<sd-dock>` 도구 바. 확장 C와 병행 가능. → [상세](./crud-detail/extension-d-control-view.md)
|
|
225
|
+
- **E. 보조 기능 영역** (선행: A) — 메인 submit과 분리된 보조 `<sd-form>`. 권한 복사·출력 등. → [상세](./crud-detail/extension-e-auxiliary.md)
|
|
226
|
+
- **F. 복합 상세** (선행: A) — 내부 `<sd-sheet>` 중첩, `oneWayDiffs` 기반 일괄 저장. → [상세](./crud-detail/extension-f-complex-detail.md)
|
|
227
|
+
|
|
228
|
+
## 🚫 흔한 실수 (Anti-patterns)
|
|
229
|
+
|
|
230
|
+
> 공통 규칙(`mark` 오용, `injectViewTypeSignal()` 호출 위치, `_sdSharedData.wait()` 조건, 시트 셀 `[inset]`/`[size]`, soft-delete 선택 기준 등)은 [레시피 공통 규칙](./_common-rules.md)을 참조한다. 이 섹션은 **CRUD 상세폼 진입점 고유 실수**만 다룬다.
|
|
231
|
+
|
|
232
|
+
### 지원할 뷰를 확인하지 않고 3뷰 분기를 미리 박는다
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// ✅ 기본 레시피는 page 전용으로 시작. 필요한 뷰가 생기면 확장을 얹는다
|
|
236
|
+
// modal 뷰가 필요해지는 시점에 확장 C를, control 뷰는 확장 D를 추가.
|
|
237
|
+
@Component({ /* ... */ })
|
|
238
|
+
export class CustomerDetail {
|
|
239
|
+
itemId = input<number>();
|
|
240
|
+
// page 전용 — viewType 분기·close output 없음
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**근거**: 실제 호출되지 않는 뷰의 계약·분기·슬롯은 죽은 코드로 남아 LLM이 모달 사용처 탐색 시 오판 원인이 된다. 지원할 뷰를 먼저 확정하고 필요한 확장만 얹는다.
|
|
245
|
+
|
|
246
|
+
### `effect` 내부 비동기 호출을 `untracked`로 감싸지 않는다
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// ✅ 비동기 작업은 untracked로 감싸 의존성 등록을 차단한다
|
|
250
|
+
constructor() {
|
|
251
|
+
effect(() => {
|
|
252
|
+
this.itemId(); // 여기서만 의존성 등록
|
|
253
|
+
void untracked(async () => {
|
|
254
|
+
await this._sdToast.try(() => this._refresh());
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**근거**: Angular `effect`는 콜백 실행 중 읽힌 모든 signal을 의존성으로 등록한다. 비동기 함수 내부에서 signal을 읽으면 effect가 재실행되어 무한 루프가 발생한다.
|
|
261
|
+
|
|
262
|
+
### `setupCanDeactivate`를 `computed`·`effect`·일반 메서드에서 호출한다
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// ✅ 생성자(또는 필드 이니셜라이저)에서만 호출
|
|
266
|
+
constructor() {
|
|
267
|
+
setupCanDeactivate(() => !this._dirty());
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**근거**: `setupCanDeactivate`는 내부에서 `inject(Router)` 등을 사용하므로 injection context가 필수다. computed/effect 콜백이나 일반 메서드 호출 시점엔 context가 없다.
|
|
272
|
+
|
|
273
|
+
## 관련 Entry
|
|
274
|
+
|
|
275
|
+
- [`crud-list.md`](./crud-list.md) — 시트 기반 CRUD 리스트. 차이: 단일 레코드 vs 컬렉션
|
|
276
|
+
- [`page-modal-container.md`](./page-modal-container.md) — page/modal 뷰 분기만 필요한 단순 컨테이너. 차이: CRUD 라이프사이클 없음
|
|
277
|
+
- [`data-select-button.md`](./data-select-button.md) — 데이터 선택 버튼. 차이: 모달 내부 선택 UI
|
|
278
|
+
- [`_common-rules.md`](./_common-rules.md) — 레시피 공통 규칙 (✅ Always / ⚠️ Ask first / 🚫 Never)
|
|
279
|
+
- [`SdModalContentDef`](../provider-types/sd-modal-content-def.md) — 확장 C(modal 뷰)에서 구현하는 계약
|
|
280
|
+
- [`SdModalProvider.showAsync`](../providers/sd-modal-provider.md) — 프로그래밍 방식 모달 호출
|