@vc-shell/vc-app-skill 2.0.0-alpha.32 → 2.0.0-alpha.33-pr220.455e322
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/CHANGELOG.md +59 -47
- package/README.md +18 -12
- package/package.json +4 -4
- package/runtime/VERSION +1 -1
- package/runtime/agents/api-analyzer.md +31 -16
- package/runtime/agents/blade-enhancer.md +15 -9
- package/runtime/agents/details-blade-generator.md +47 -31
- package/runtime/agents/list-blade-generator.md +21 -37
- package/runtime/agents/locales-generator.md +3 -0
- package/runtime/agents/migration-agent.md +94 -0
- package/runtime/agents/module-analyzer.md +2 -0
- package/runtime/agents/module-assembler.md +15 -0
- package/runtime/agents/promote-agent.md +15 -4
- package/runtime/agents/type-checker.md +11 -0
- package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
- package/runtime/knowledge/docs/core/api/platform.docs.md +30 -30
- package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +41 -41
- package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +12 -10
- package/runtime/knowledge/docs/core/composables/useApiClient/useApiClient.docs.md +11 -14
- package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +35 -35
- package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +35 -35
- package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +15 -15
- package/runtime/knowledge/docs/core/composables/useAssets/useAssets.docs.md +21 -18
- package/runtime/knowledge/docs/core/composables/useAssetsManager/useAssetsManager.docs.md +31 -27
- package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +90 -61
- package/runtime/knowledge/docs/core/composables/useBeforeUnload/useBeforeUnload.docs.md +19 -18
- package/runtime/knowledge/docs/core/composables/useBlade/useBlade.docs.md +89 -68
- package/runtime/knowledge/docs/core/composables/useBladeForm/useBladeForm.docs.md +75 -19
- package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +15 -15
- package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +74 -78
- package/runtime/knowledge/docs/core/composables/useBreadcrumbs/useBreadcrumbs.docs.md +11 -11
- package/runtime/knowledge/docs/core/composables/useConnectionStatus/useConnectionStatus.docs.md +27 -15
- package/runtime/knowledge/docs/core/composables/useDashboard/useDashboard.docs.md +30 -30
- package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +34 -36
- package/runtime/knowledge/docs/core/composables/useErrorHandler/useErrorHandler.docs.md +44 -23
- package/runtime/knowledge/docs/core/composables/useFunctions/useFunctions.docs.md +14 -11
- package/runtime/knowledge/docs/core/composables/useKeyboardNavigation/useKeyboardNavigation.docs.md +47 -38
- package/runtime/knowledge/docs/core/composables/useLanguages/useLanguages.docs.md +37 -28
- package/runtime/knowledge/docs/core/composables/useLoading/useLoading.docs.md +23 -17
- package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +10 -10
- package/runtime/knowledge/docs/core/composables/useMenuService/useMenuService.docs.md +42 -42
- package/runtime/knowledge/docs/core/composables/useModificationTracker/useModificationTracker.docs.md +22 -12
- package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +33 -41
- package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +16 -16
- package/runtime/knowledge/docs/core/composables/usePopup/usePopup.docs.md +32 -24
- package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +32 -11
- package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +24 -15
- package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +7 -7
- package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +32 -24
- package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +21 -17
- package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +24 -24
- package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +28 -31
- package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +43 -24
- package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +68 -48
- package/runtime/knowledge/docs/core/composables/useWebVitals/useWebVitals.docs.md +19 -19
- package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +42 -47
- package/runtime/knowledge/docs/core/directives/autofocus/autofocus.docs.md +10 -4
- package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +35 -20
- package/runtime/knowledge/docs/core/notifications/notifications.docs.md +36 -35
- package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +38 -38
- package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +107 -91
- package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +10 -10
- package/runtime/knowledge/docs/core/plugins/i18n/i18n.docs.md +21 -23
- package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +98 -90
- package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +10 -16
- package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +9 -9
- package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +65 -22
- package/runtime/knowledge/docs/core/services/services.docs.md +19 -22
- package/runtime/knowledge/docs/core/types/types.docs.md +40 -40
- package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +27 -27
- package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +23 -23
- package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +22 -25
- package/runtime/knowledge/docs/core/utilities/utilities.docs.md +64 -64
- package/runtime/knowledge/docs/injection-keys.docs.md +52 -51
- package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +9 -9
- package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +23 -43
- package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +102 -0
- package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +5 -5
- package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +8 -7
- package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +7 -7
- package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +8 -7
- package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +29 -13
- package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +13 -16
- package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -7
- package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +5 -5
- package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -9
- package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +12 -18
- package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +34 -65
- package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +16 -26
- package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +2 -2
- package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +7 -9
- package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +30 -40
- package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +26 -19
- package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +15 -12
- package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +15 -26
- package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +21 -19
- package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +83 -67
- package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +104 -59
- package/runtime/knowledge/docs/ui/components/atoms/vc-col/vc-col.docs.md +28 -11
- package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +20 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +26 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +30 -32
- package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +25 -48
- package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +29 -24
- package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +23 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +22 -13
- package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +33 -18
- package/runtime/knowledge/docs/ui/components/atoms/vc-row/vc-row.docs.md +56 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +28 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +40 -20
- package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +25 -14
- package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +40 -14
- package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +54 -42
- package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +17 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +21 -21
- package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +23 -10
- package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +59 -44
- package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +23 -20
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +96 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +26 -35
- package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +69 -22
- package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +58 -72
- package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +91 -85
- package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +38 -42
- package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +60 -72
- package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +65 -26
- package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +46 -49
- package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +35 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-image-tile/vc-image-tile.docs.md +38 -41
- package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +115 -130
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +53 -87
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +56 -63
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +29 -24
- package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +32 -28
- package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +63 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +28 -26
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +59 -19
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +25 -34
- package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +42 -32
- package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +78 -82
- package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +25 -15
- package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +59 -63
- package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +57 -69
- package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +58 -57
- package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +49 -26
- package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +82 -28
- package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +120 -75
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +30 -44
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +536 -365
- package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +35 -52
- package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +33 -62
- package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +17 -23
- package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +109 -68
- package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +82 -44
- package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +8 -8
- package/runtime/knowledge/docs/ui/composables/useDataTablePagination.docs.md +164 -0
- package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +34 -26
- package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +48 -40
- package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +30 -17
- package/runtime/knowledge/docs/ui/types/ui-types.docs.md +40 -29
- package/runtime/knowledge/examples/offers-module.md +15 -13
- package/runtime/knowledge/examples/team-module.md +82 -119
- package/runtime/knowledge/examples/videos-module.md +44 -17
- package/runtime/knowledge/index.md +22 -0
- package/runtime/knowledge/migration-prompts/blade-form-migration.md +255 -0
- package/runtime/knowledge/migration-prompts/blade-props-migration.md +194 -0
- package/runtime/knowledge/migration-prompts/datatable-migration.md +801 -0
- package/runtime/knowledge/migration-prompts/icon-migration.md +97 -0
- package/runtime/knowledge/migration-prompts/manual-migration-audit.md +117 -0
- package/runtime/knowledge/migration-prompts/notifications-migration.md +223 -0
- package/runtime/knowledge/migration-prompts/nswag-migration.md +244 -0
- package/runtime/knowledge/migration-prompts/use-assets-migration.md +164 -0
- package/runtime/knowledge/migration-prompts/use-data-table-pagination-migration.md +176 -0
- package/runtime/knowledge/migration-prompts/widgets-migration.md +178 -0
- package/runtime/knowledge/patterns/assets-management.md +20 -20
- package/runtime/knowledge/patterns/blade-navigation.md +7 -14
- package/runtime/knowledge/patterns/blade-widget.md +19 -17
- package/runtime/knowledge/patterns/child-blade-flow.md +19 -7
- package/runtime/knowledge/patterns/composable-details.md +20 -50
- package/runtime/knowledge/patterns/composable-list.md +43 -31
- package/runtime/knowledge/patterns/dashboard-widget.md +14 -16
- package/runtime/knowledge/patterns/datatable-pattern.md +521 -0
- package/runtime/knowledge/patterns/details-blade-pattern.md +78 -116
- package/runtime/knowledge/patterns/extension-points-usage.md +53 -44
- package/runtime/knowledge/patterns/form-validation.md +28 -64
- package/runtime/knowledge/patterns/list-blade-pattern.md +33 -21
- package/runtime/knowledge/patterns/module-structure.md +7 -1
- package/runtime/knowledge/patterns/multilanguage-fields.md +8 -14
- package/runtime/knowledge/patterns/notification-template.md +21 -14
- package/runtime/knowledge/patterns/signalr-notifications.md +30 -32
- package/runtime/knowledge/patterns/toolbar-pattern.md +18 -20
- package/runtime/vc-app.md +354 -49
- package/runtime/knowledge/docs/core/constants/constants.docs.md +0 -185
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: use-assets-migration
|
|
3
|
+
description: AI transformation rules for useAssets()/AssetsHandler migration to useAssetsManager().
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Assets Migration: useAssets -> useAssetsManager
|
|
7
|
+
|
|
8
|
+
Migrate legacy assets handling (`useAssets`, `AssetsHandler`, ad-hoc upload/remove/edit callbacks) to `useAssetsManager`.
|
|
9
|
+
|
|
10
|
+
## RULE 1: Replace `useAssets()` with `useAssetsManager()`
|
|
11
|
+
|
|
12
|
+
**BEFORE:**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { useAssets } from "@vc-shell/framework";
|
|
16
|
+
|
|
17
|
+
const { upload, remove, edit, loading } = useAssets(imagesRef, uploadPath);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**AFTER:**
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { useAssetsManager } from "@vc-shell/framework";
|
|
24
|
+
|
|
25
|
+
const assetsManager = useAssetsManager(imagesRef, {
|
|
26
|
+
uploadPath: () => uploadPath.value,
|
|
27
|
+
confirmRemove: () => showConfirmation(t("MY_MODULE.ALERTS.DELETE_CONFIRMATION")),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// assetsManager.items, assetsManager.upload, assetsManager.remove,
|
|
31
|
+
// assetsManager.removeMany, assetsManager.reorder, assetsManager.updateItem, assetsManager.loading
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Notes:
|
|
35
|
+
|
|
36
|
+
- `uploadPath` must be a function (`() => string`), not a static string.
|
|
37
|
+
- If no confirmation is needed, omit `confirmRemove`.
|
|
38
|
+
|
|
39
|
+
## RULE 2: Replace `ICommonAsset` with `AssetLike`
|
|
40
|
+
|
|
41
|
+
**BEFORE:**
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import type { ICommonAsset } from "@vc-shell/framework";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**AFTER:**
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import type { AssetLike } from "@vc-shell/framework";
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Also update all type annotations in the file.
|
|
54
|
+
|
|
55
|
+
## RULE 3: Single-image fields must be wrapped in writable computed array
|
|
56
|
+
|
|
57
|
+
For fields like `iconUrl`, `logo`, `photo`, convert single value <-> array bridge.
|
|
58
|
+
|
|
59
|
+
**BEFORE:**
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const { upload, remove } = useAssets(photoRef, () => `users/${item.value?.id}`);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**AFTER:**
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const photoAssets = computed({
|
|
69
|
+
get: () => (item.value?.iconUrl ? [{ url: item.value.iconUrl }] : []),
|
|
70
|
+
set: (val) => {
|
|
71
|
+
if (item.value) item.value.iconUrl = val[0]?.url;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const photoManager = useAssetsManager(photoAssets, {
|
|
76
|
+
uploadPath: () => `users/${item.value?.id ?? "new"}`,
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## RULE 4: `AssetsHandler` and raw handler props -> manager object
|
|
81
|
+
|
|
82
|
+
If the component receives or creates handler bundles (`assetsUploadHandler`, `assetsEditHandler`, `assetsRemoveHandler`, `AssetsHandler<T>`), replace with a manager instance.
|
|
83
|
+
|
|
84
|
+
**BEFORE:**
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface Props {
|
|
88
|
+
imageHandlers?: AssetsHandler<MyImage>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const defaultHandlers = { upload, remove, edit, loading };
|
|
92
|
+
const handlers = props.imageHandlers ?? defaultHandlers;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**AFTER:**
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
interface Props {
|
|
99
|
+
manager?: ReturnType<typeof useAssetsManager>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const defaultManager = useAssetsManager(imagesRef, {
|
|
103
|
+
uploadPath: () => `products/${item.value?.id}`,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const manager = computed(() => props.manager ?? defaultManager);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## RULE 5: `openBlade("AssetsManager")` must pass `manager: markRaw(...)`
|
|
110
|
+
|
|
111
|
+
**BEFORE:**
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
openBlade({
|
|
115
|
+
name: "AssetsManager",
|
|
116
|
+
options: {
|
|
117
|
+
assets: item.value?.assets,
|
|
118
|
+
assetsUploadHandler: upload,
|
|
119
|
+
assetsEditHandler: edit,
|
|
120
|
+
assetsRemoveHandler: remove,
|
|
121
|
+
loading,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**AFTER:**
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { markRaw } from "vue";
|
|
130
|
+
|
|
131
|
+
openBlade({
|
|
132
|
+
name: "AssetsManager",
|
|
133
|
+
options: {
|
|
134
|
+
manager: markRaw(assetsManager),
|
|
135
|
+
disabled: disabled.value,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If `manager` is already passed but not wrapped, add `markRaw()`.
|
|
141
|
+
|
|
142
|
+
## RULE 6: Keep `AssetsDetails` callbacks wired to manager methods
|
|
143
|
+
|
|
144
|
+
If opening `AssetsDetails`, connect handlers to manager methods (`updateItem`, `remove`) and keep asset type as `AssetLike`.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
openBlade({
|
|
148
|
+
name: "AssetsDetails",
|
|
149
|
+
options: {
|
|
150
|
+
asset,
|
|
151
|
+
assetEditHandler: (updated: AssetLike) => assetsManager.updateItem(updated),
|
|
152
|
+
assetRemoveHandler: (toRemove: AssetLike) => assetsManager.remove(toRemove),
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Verification
|
|
158
|
+
|
|
159
|
+
After migration:
|
|
160
|
+
|
|
161
|
+
1. Search for stale API: `useAssets(`, `AssetsHandler`, `ICommonAsset`, `assetsUploadHandler`, `assetsEditHandler`, `assetsRemoveHandler`.
|
|
162
|
+
2. Confirm `AssetsManager` blade calls pass `manager: markRaw(...)`.
|
|
163
|
+
3. Run `npx vue-tsc --noEmit`.
|
|
164
|
+
4. Validate runtime flow: upload, remove, reorder, edit metadata.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# useDataTablePagination Migration
|
|
2
|
+
|
|
3
|
+
Replace the manual `totalCount` / `pages` / `currentPage` computed triple plus hand-written `onPaginationClick` handler with a single `useDataTablePagination()` call.
|
|
4
|
+
|
|
5
|
+
## Rule 1: Update the data composable
|
|
6
|
+
|
|
7
|
+
For each list composable file:
|
|
8
|
+
|
|
9
|
+
### 1a. Add import
|
|
10
|
+
|
|
11
|
+
Add to the `@vc-shell/framework` import (merge, don't duplicate):
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { useDataTablePagination, type UseDataTablePaginationReturn } from "@vc-shell/framework";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 1b. Create `pagination` before the return
|
|
18
|
+
|
|
19
|
+
Declare, before the return block:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const pagination = useDataTablePagination({
|
|
23
|
+
pageSize,
|
|
24
|
+
totalCount: computed(() => searchResult.value?.totalCount ?? 0),
|
|
25
|
+
onPageChange: ({ skip }) => loadItems({ ...searchQuery.value, skip }),
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Use the same `pageSize` the composable already accepts as option (default 20).
|
|
30
|
+
- Pass `totalCount` as a computed (not a plain number).
|
|
31
|
+
- Use the composable's own loader name for `onPageChange` (`loadItems`, `loadMessages`, `searchXxx` — whatever already exists).
|
|
32
|
+
|
|
33
|
+
### 1c. Replace the three computed in the return
|
|
34
|
+
|
|
35
|
+
**Before:**
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
return {
|
|
39
|
+
totalCount: computed(() => searchResult.value?.totalCount || 0),
|
|
40
|
+
pages: computed(() => Math.ceil((searchResult.value?.totalCount || 1) / pageSize)),
|
|
41
|
+
currentPage: computed(() => Math.ceil((searchQuery.value?.skip || 0) / pageSize + 1)),
|
|
42
|
+
// ...other returns
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**After:**
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
return {
|
|
50
|
+
pagination,
|
|
51
|
+
// ...other returns (unchanged)
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 1d. Update the return type interface (if present)
|
|
56
|
+
|
|
57
|
+
**Before:**
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
export interface IUseList {
|
|
61
|
+
totalCount: ComputedRef<number>;
|
|
62
|
+
pages: ComputedRef<number>;
|
|
63
|
+
currentPage: ComputedRef<number>;
|
|
64
|
+
// ...
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**After:**
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
export interface IUseList {
|
|
72
|
+
pagination: UseDataTablePaginationReturn;
|
|
73
|
+
// ...
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Rule 2: Update the blade page template
|
|
78
|
+
|
|
79
|
+
### 2a. Replace VcDataTable pagination bindings
|
|
80
|
+
|
|
81
|
+
**Before:**
|
|
82
|
+
|
|
83
|
+
```vue
|
|
84
|
+
<VcDataTable :total-count="totalCount" :pagination="{ currentPage, pages }" @pagination-click="onPaginationClick" />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**After:**
|
|
88
|
+
|
|
89
|
+
```vue
|
|
90
|
+
<VcDataTable :total-count="pagination.totalCount" :pagination="pagination" @pagination-click="pagination.goToPage" />
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2b. Update the composable destructure
|
|
94
|
+
|
|
95
|
+
**Before:**
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const { items, totalCount, pages, currentPage, searchQuery, loadItems } = useList();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**After:**
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const { items, pagination, searchQuery, loadItems } = useList();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2c. Delete the manual `onPaginationClick` handler
|
|
108
|
+
|
|
109
|
+
Remove the entire function — it's redundant; `pagination.goToPage` fires the composable's `onPageChange`.
|
|
110
|
+
|
|
111
|
+
**Delete:**
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
async function onPaginationClick(page: number) {
|
|
115
|
+
await loadItems({
|
|
116
|
+
...searchQuery.value,
|
|
117
|
+
skip: (page - 1) * (searchQuery.value.take ?? 20),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2d. Rewrite `reload()` helper (if present)
|
|
123
|
+
|
|
124
|
+
If the blade has a `reload()` helper that recomputes skip from currentPage, use `pagination.skip`:
|
|
125
|
+
|
|
126
|
+
**Before:**
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const reload = async () => {
|
|
130
|
+
await loadItems({
|
|
131
|
+
...searchQuery.value,
|
|
132
|
+
skip: (currentPage.value - 1) * (searchQuery.value.take ?? 10),
|
|
133
|
+
sort: sortExpression.value,
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**After:**
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const reload = async () => {
|
|
142
|
+
await loadItems({
|
|
143
|
+
...searchQuery.value,
|
|
144
|
+
skip: pagination.skip,
|
|
145
|
+
sort: sortExpression.value,
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Rule 3: VcTable / VcTableAdapter — skip that file (not the whole topic)
|
|
151
|
+
|
|
152
|
+
Per-file check. If a specific blade page still uses `<VcTable>` (legacy adapter, with `:pages` + `:current-page` scalar props), SKIP that file — migrating pagination against a different table API would break the bindings. But:
|
|
153
|
+
|
|
154
|
+
- **Still migrate the composable** if other callers (pages with `<VcDataTable>`) exist — the composable change is independent of any single consumer.
|
|
155
|
+
- **Still migrate other pages** in the same `affectedFiles` list that DO use `<VcDataTable>`.
|
|
156
|
+
- In your report, mark the skipped file(s) as `needs vctable-audit first` so the user knows why.
|
|
157
|
+
|
|
158
|
+
Do not skip the entire topic just because one file is out of scope.
|
|
159
|
+
|
|
160
|
+
## Rule 4: Infinite-scroll tables — skip that file
|
|
161
|
+
|
|
162
|
+
If a specific VcDataTable uses `:infinite-scroll="true"`, pagination is not used — skip that file. Same per-file rule as Rule 3.
|
|
163
|
+
|
|
164
|
+
## Behavioral notes
|
|
165
|
+
|
|
166
|
+
- `pagination` is a `reactive()` object — access properties directly (`pagination.totalCount`), never `.value`.
|
|
167
|
+
- Do NOT destructure `pagination` — destructuring loses reactivity.
|
|
168
|
+
- `pagination.reset()` sets currentPage to 1 silently (no onPageChange fire). Use when resetting filters.
|
|
169
|
+
|
|
170
|
+
## Self-check after migration
|
|
171
|
+
|
|
172
|
+
- [ ] `totalCount`, `pages`, `currentPage` no longer appear in the composable's return.
|
|
173
|
+
- [ ] `onPaginationClick` function is deleted from the blade page.
|
|
174
|
+
- [ ] Template uses `pagination.goToPage` not a handwritten callback.
|
|
175
|
+
- [ ] No `.value` access on `pagination.*` properties.
|
|
176
|
+
- [ ] `useDataTablePagination` import is present in the composable.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: widgets-migration
|
|
3
|
+
description: AI transformation rules for useWidgets→useBladeWidgets migration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Widget Migration: useWidgets → useBladeWidgets
|
|
7
|
+
|
|
8
|
+
Migrate blade widgets from the imperative `useWidgets()` + `registerWidget()` API to the declarative `useBladeWidgets()` composable. The new API eliminates manual registration/cleanup and removes the need for per-widget `.vue` components when they only render a standard sidebar item.
|
|
9
|
+
|
|
10
|
+
## RULE 1: Create Widget Composable
|
|
11
|
+
|
|
12
|
+
For each blade that calls `registerWidget()`, create a `widgets/useXxxWidgets.ts` composable.
|
|
13
|
+
|
|
14
|
+
**BEFORE:**
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// In XxxDetails.vue <script setup>
|
|
18
|
+
import { useWidgets, useBlade } from "@vc-shell/framework";
|
|
19
|
+
import type { BladeInstance } from "@vc-shell/framework";
|
|
20
|
+
import { onMounted, onUnmounted } from "vue";
|
|
21
|
+
import ChildListWidget from "../widgets/ChildListWidget.vue";
|
|
22
|
+
|
|
23
|
+
const { registerWidget, clearBladeWidgets } = useWidgets();
|
|
24
|
+
const { openBlade } = useBlade();
|
|
25
|
+
|
|
26
|
+
onMounted(() => {
|
|
27
|
+
registerWidget(
|
|
28
|
+
{
|
|
29
|
+
id: "ChildListWidget",
|
|
30
|
+
component: ChildListWidget,
|
|
31
|
+
props: {
|
|
32
|
+
count: childCount,
|
|
33
|
+
onClick: () => openBlade({ name: "ChildEntityList", options: { entityId: entity.value.id } }),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
bladeContext.id,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
onUnmounted(() => {
|
|
41
|
+
clearBladeWidgets(bladeContext.id);
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**AFTER:**
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// widgets/useEntityWidgets.ts
|
|
49
|
+
import { useBladeWidgets, useBlade } from "@vc-shell/framework";
|
|
50
|
+
import type { UseBladeWidgetsReturn } from "@vc-shell/framework";
|
|
51
|
+
import { computed, type Ref } from "vue";
|
|
52
|
+
|
|
53
|
+
interface UseEntityWidgetsOptions {
|
|
54
|
+
item: Ref<Entity | undefined>;
|
|
55
|
+
isVisible: Ref<boolean> | boolean;
|
|
56
|
+
childCount: Ref<number>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function useEntityWidgets(options: UseEntityWidgetsOptions): UseBladeWidgetsReturn {
|
|
60
|
+
const { item, isVisible, childCount } = options;
|
|
61
|
+
const { openBlade } = useBlade();
|
|
62
|
+
|
|
63
|
+
return useBladeWidgets([
|
|
64
|
+
{
|
|
65
|
+
id: "ChildListWidget",
|
|
66
|
+
icon: "lucide-tag",
|
|
67
|
+
title: "MODULE.WIDGETS.CHILD_LIST.TITLE",
|
|
68
|
+
badge: computed(() => childCount.value),
|
|
69
|
+
isVisible,
|
|
70
|
+
onClick: () =>
|
|
71
|
+
openBlade({
|
|
72
|
+
name: "ChildEntityList",
|
|
73
|
+
options: { entityId: item.value?.id },
|
|
74
|
+
}),
|
|
75
|
+
onRefresh: async () => {
|
|
76
|
+
// load child count logic here
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## RULE 2: Replace Usage in Blade Page
|
|
84
|
+
|
|
85
|
+
Import the new composable and destructure `{ refreshAll }`.
|
|
86
|
+
|
|
87
|
+
**BEFORE:**
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// XxxDetails.vue <script setup>
|
|
91
|
+
import { useWidgets } from "@vc-shell/framework";
|
|
92
|
+
import ChildListWidget from "../widgets/ChildListWidget.vue";
|
|
93
|
+
import RelatedItemsWidget from "../widgets/RelatedItemsWidget.vue";
|
|
94
|
+
|
|
95
|
+
const { registerWidget, clearBladeWidgets } = useWidgets();
|
|
96
|
+
|
|
97
|
+
onMounted(() => {
|
|
98
|
+
registerWidget({ id: "ChildListWidget", component: ChildListWidget, props: { ... } }, bladeId);
|
|
99
|
+
registerWidget({ id: "RelatedItemsWidget", component: RelatedItemsWidget, props: { ... } }, bladeId);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
onUnmounted(() => {
|
|
103
|
+
clearBladeWidgets(bladeId);
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**AFTER:**
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// XxxDetails.vue <script setup>
|
|
111
|
+
import { useEntityWidgets } from "../widgets/useEntityWidgets";
|
|
112
|
+
|
|
113
|
+
const isExisting = computed(() => !!param.value);
|
|
114
|
+
|
|
115
|
+
const { refreshAll } = useEntityWidgets({
|
|
116
|
+
item: entity,
|
|
117
|
+
isVisible: isExisting,
|
|
118
|
+
childCount,
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If the old code used `updateActiveWidget()`, replace it with `refreshAll()` from the widget composable return:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// BEFORE
|
|
126
|
+
const { updateActiveWidget } = useWidgets();
|
|
127
|
+
updateActiveWidget();
|
|
128
|
+
|
|
129
|
+
// AFTER
|
|
130
|
+
const { refreshAll } = useEntityWidgets({ item: entity, isVisible: isExisting, childCount });
|
|
131
|
+
refreshAll();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## RULE 3: Remove Widget .vue Components
|
|
135
|
+
|
|
136
|
+
Delete widget `.vue` files that only render a standard sidebar item (icon + title + badge + click handler). These are replaced by the declarative config in `useBladeWidgets()`.
|
|
137
|
+
|
|
138
|
+
**Keep** the `.vue` component only if it has custom rendering beyond the standard widget layout.
|
|
139
|
+
|
|
140
|
+
**Delete:**
|
|
141
|
+
|
|
142
|
+
- `widgets/ChildListWidget.vue` (if it only shows icon, title, badge, click)
|
|
143
|
+
- `widgets/RelatedItemsWidget.vue` (same)
|
|
144
|
+
|
|
145
|
+
**Keep:**
|
|
146
|
+
|
|
147
|
+
- `widgets/CustomChartWidget.vue` (has custom chart rendering)
|
|
148
|
+
|
|
149
|
+
## RULE 4: Remove Old Imports
|
|
150
|
+
|
|
151
|
+
Remove these imports that are no longer needed:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// REMOVE all of these:
|
|
155
|
+
import { useWidgets } from "@vc-shell/framework";
|
|
156
|
+
import type { BladeInstance } from "@vc-shell/framework"; // if only used for widgets
|
|
157
|
+
import { registerWidget, unregisterWidget, clearBladeWidgets } from "...";
|
|
158
|
+
import { onUnmounted } from "vue"; // if only used for widget cleanup
|
|
159
|
+
import ChildListWidget from "../widgets/ChildListWidget.vue"; // deleted component
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## RULE 5: `defineBladeContext` only for external widgets
|
|
163
|
+
|
|
164
|
+
Do not add `defineBladeContext()` by default in this migration.
|
|
165
|
+
|
|
166
|
+
Add it only if the blade hosts external widget components that use `injectBladeContext()`.
|
|
167
|
+
|
|
168
|
+
## Verification
|
|
169
|
+
|
|
170
|
+
After migration:
|
|
171
|
+
|
|
172
|
+
1. Run `npx tsc --noEmit` to verify no TypeScript errors
|
|
173
|
+
2. Confirm widgets appear in the blade sidebar
|
|
174
|
+
3. Confirm badge counts update reactively
|
|
175
|
+
4. Confirm clicking a widget opens the correct child blade
|
|
176
|
+
5. Confirm widgets are hidden when `isVisible` is false (e.g., on "create new" blades)
|
|
177
|
+
6. Confirm no console errors about widget registration/cleanup on blade close
|
|
178
|
+
7. Confirm `updateActiveWidget()` calls are removed and replaced with `refreshAll()` from `useEntityWidgets` return
|
|
@@ -68,7 +68,9 @@ const { showConfirmation } = usePopup();
|
|
|
68
68
|
|
|
69
69
|
const images = computed({
|
|
70
70
|
get: () => item.value?.images ?? [],
|
|
71
|
-
set: (val) => {
|
|
71
|
+
set: (val) => {
|
|
72
|
+
if (item.value) item.value.images = val;
|
|
73
|
+
},
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
const assets = useAssetsManager(images, {
|
|
@@ -101,13 +103,7 @@ Use when assets are a secondary concern shown as a widget badge. Clicking the wi
|
|
|
101
103
|
```ts
|
|
102
104
|
// widgets/useEntityWidgets.ts
|
|
103
105
|
import { computed, markRaw, type Ref, type ComputedRef } from "vue";
|
|
104
|
-
import {
|
|
105
|
-
useBlade,
|
|
106
|
-
useBladeWidgets,
|
|
107
|
-
useAssetsManager,
|
|
108
|
-
usePopup,
|
|
109
|
-
type UseBladeWidgetsReturn,
|
|
110
|
-
} from "@vc-shell/framework";
|
|
106
|
+
import { useBlade, useBladeWidgets, useAssetsManager, usePopup, type UseBladeWidgetsReturn } from "@vc-shell/framework";
|
|
111
107
|
|
|
112
108
|
interface Options {
|
|
113
109
|
item: Ref<Entity | undefined>;
|
|
@@ -145,7 +141,7 @@ export function useEntityWidgets({ item, disabled, isVisible }: Options): UseBla
|
|
|
145
141
|
openBlade({
|
|
146
142
|
name: "AssetsManager",
|
|
147
143
|
options: {
|
|
148
|
-
manager: markRaw(assetsManager),
|
|
144
|
+
manager: markRaw(assetsManager), // markRaw prevents Vue from making it reactive
|
|
149
145
|
disabled: disabled.value,
|
|
150
146
|
},
|
|
151
147
|
}),
|
|
@@ -186,14 +182,18 @@ Each manager operates on a different writable computed pointing to a different a
|
|
|
186
182
|
// Gallery assets (images)
|
|
187
183
|
const productImages = computed({
|
|
188
184
|
get: () => item.value.productData?.images ?? [],
|
|
189
|
-
set: (val) => {
|
|
185
|
+
set: (val) => {
|
|
186
|
+
if (item.value.productData) item.value.productData.images = val;
|
|
187
|
+
},
|
|
190
188
|
});
|
|
191
189
|
const imageAssets = useAssetsManager(productImages, { uploadPath: () => `/catalog/${item.value.id}` });
|
|
192
190
|
|
|
193
191
|
// Widget assets (files)
|
|
194
192
|
const productFiles = computed({
|
|
195
193
|
get: () => (item.value?.productData?.assets ?? []) as Asset[],
|
|
196
|
-
set: (val) => {
|
|
194
|
+
set: (val) => {
|
|
195
|
+
if (item.value?.productData) item.value.productData.assets = val;
|
|
196
|
+
},
|
|
197
197
|
});
|
|
198
198
|
const fileAssets = useAssetsManager(productFiles, { uploadPath: () => `/catalog/${item.value.id}` });
|
|
199
199
|
```
|
|
@@ -202,12 +202,12 @@ const fileAssets = useAssetsManager(productFiles, { uploadPath: () => `/catalog/
|
|
|
202
202
|
|
|
203
203
|
## Key Points
|
|
204
204
|
|
|
205
|
-
| Concern
|
|
206
|
-
|
|
207
|
-
| Binding to entity
|
|
208
|
-
| Upload path
|
|
209
|
-
| Remove confirmation
|
|
210
|
-
| Passing to AssetsManager blade | Wrap with `markRaw()` — prevents Vue from making the manager deeply reactive
|
|
211
|
-
| Multiple asset types
|
|
212
|
-
| Gallery edit
|
|
213
|
-
| Widget visibility
|
|
205
|
+
| Concern | Approach |
|
|
206
|
+
| ------------------------------ | -------------------------------------------------------------------------------------- |
|
|
207
|
+
| Binding to entity | Writable `computed` — getter reads nested array, setter writes it back |
|
|
208
|
+
| Upload path | Callback `() => string` — resolved at upload time, so entity ID is available |
|
|
209
|
+
| Remove confirmation | Pass `confirmRemove` returning `Promise<boolean>` via `usePopup().showConfirmation` |
|
|
210
|
+
| Passing to AssetsManager blade | Wrap with `markRaw()` — prevents Vue from making the manager deeply reactive |
|
|
211
|
+
| Multiple asset types | Create separate `useAssetsManager` instances per array (images vs files) |
|
|
212
|
+
| Gallery edit | Open `AssetsDetails` blade, pass `assetEditHandler` and `assetRemoveHandler` callbacks |
|
|
213
|
+
| Widget visibility | Use `isVisible: computed(() => !!param.value)` to hide on "create new" mode |
|
|
@@ -9,15 +9,7 @@ Blades are stacked panels rendered by `VcBladeNavigation`. Navigation between bl
|
|
|
9
9
|
```ts
|
|
10
10
|
import { useBlade } from "@vc-shell/framework";
|
|
11
11
|
|
|
12
|
-
const {
|
|
13
|
-
openBlade,
|
|
14
|
-
closeSelf,
|
|
15
|
-
callParent,
|
|
16
|
-
exposeToChildren,
|
|
17
|
-
onBeforeClose,
|
|
18
|
-
param,
|
|
19
|
-
options,
|
|
20
|
-
} = useBlade<OptionsType>();
|
|
12
|
+
const { openBlade, closeSelf, callParent, exposeToChildren, onBeforeClose, param, options } = useBlade<OptionsType>();
|
|
21
13
|
```
|
|
22
14
|
|
|
23
15
|
`useBlade()` must be called inside `<script setup>` of a blade component. It uses provide/inject to wire the blade hierarchy.
|
|
@@ -58,6 +50,7 @@ entity.value.name = options.value?.prefilledName ?? "";
|
|
|
58
50
|
## `openBlade()` — Open a child blade
|
|
59
51
|
|
|
60
52
|
Full signature:
|
|
53
|
+
|
|
61
54
|
```ts
|
|
62
55
|
openBlade({
|
|
63
56
|
name: string, // defineBlade name of the target blade
|
|
@@ -133,7 +126,7 @@ const { callParent } = useBlade();
|
|
|
133
126
|
|
|
134
127
|
// In details blade after save:
|
|
135
128
|
await updateXxx(entity.value);
|
|
136
|
-
callParent("reload");
|
|
129
|
+
callParent("reload"); // calls parent's reload() function
|
|
137
130
|
closeSelf();
|
|
138
131
|
```
|
|
139
132
|
|
|
@@ -170,19 +163,19 @@ const { showConfirmation } = usePopup();
|
|
|
170
163
|
onBeforeClose(async () => {
|
|
171
164
|
if (modified.value) {
|
|
172
165
|
// returns true to BLOCK close, false to ALLOW close
|
|
173
|
-
return !(await showConfirmation(
|
|
174
|
-
unref(computed(() => t("MODULE.PAGES.ALERTS.CLOSE_CONFIRMATION"))),
|
|
175
|
-
));
|
|
166
|
+
return !(await showConfirmation(unref(computed(() => t("MODULE.PAGES.ALERTS.CLOSE_CONFIRMATION")))));
|
|
176
167
|
}
|
|
177
|
-
return false;
|
|
168
|
+
return false; // no unsaved changes — allow close
|
|
178
169
|
});
|
|
179
170
|
```
|
|
180
171
|
|
|
181
172
|
Return value semantics:
|
|
173
|
+
|
|
182
174
|
- `false` → close is allowed
|
|
183
175
|
- `true` → close is blocked (user stays on the blade)
|
|
184
176
|
|
|
185
177
|
The pattern `!(await showConfirmation(...))` works as:
|
|
178
|
+
|
|
186
179
|
- User clicks "Confirm" → `showConfirmation` returns `true` → `!true` = `false` → close allowed
|
|
187
180
|
- User clicks "Cancel" → `showConfirmation` returns `false` → `!false` = `true` → close blocked
|
|
188
181
|
|