@vc-shell/vc-app-skill 2.0.5 → 2.0.6
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 +6 -0
- package/README.md +7 -7
- package/package.json +1 -1
- package/runtime/VERSION +1 -1
- package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
- package/runtime/knowledge/docs/core/api/platform.docs.md +6 -6
- package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +1 -1
- package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +2 -2
- package/runtime/knowledge/docs/core/composables/useApiClient/useApiClient.docs.md +67 -42
- package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +2 -2
- package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +15 -13
- package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +11 -11
- package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +17 -14
- package/runtime/knowledge/docs/core/composables/useBeforeUnload/useBeforeUnload.docs.md +4 -2
- package/runtime/knowledge/docs/core/composables/useBlade/useBlade.docs.md +31 -23
- package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +46 -26
- package/runtime/knowledge/docs/core/composables/useDashboard/useDashboard.docs.md +1 -0
- package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +1 -1
- package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +1 -1
- package/runtime/knowledge/docs/core/composables/useMenuService/useMenuService.docs.md +1 -0
- package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +20 -6
- package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +2 -1
- package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +2 -2
- package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +109 -133
- package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +1 -2
- package/runtime/knowledge/docs/core/notifications/composables/useBladeNotifications.docs.md +184 -0
- package/runtime/knowledge/docs/core/notifications/composables/useBroadcastFilter.docs.md +117 -0
- package/runtime/knowledge/docs/core/notifications/composables/useNotificationContext.docs.md +150 -0
- package/runtime/knowledge/docs/core/notifications/composables/useNotificationStore.docs.md +113 -0
- package/runtime/knowledge/docs/core/notifications/notifications.docs.md +12 -15
- package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +1 -1
- package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +54 -116
- package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +12 -3
- package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +20 -20
- package/runtime/knowledge/docs/injection-keys.docs.md +1 -1
- package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/notification-dropdown/notification-dropdown.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +7 -7
- package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +2 -2
- package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +4 -4
- package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +21 -1
- package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +22 -6
- package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +2 -2
- package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +32 -26
- package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +3 -3
- package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +13 -13
- package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +4 -4
- package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +39 -37
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +17 -17
- package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +16 -7
- package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +1 -1
|
@@ -37,8 +37,8 @@ If you are building anything in vc-shell -- a new page, a CRUD flow, a dashboard
|
|
|
37
37
|
- [Registering Notification Types](#registering-notification-types)
|
|
38
38
|
- [Adding Locales](#adding-locales)
|
|
39
39
|
- [Registering Dashboard Widgets](#registering-dashboard-widgets)
|
|
40
|
-
- [
|
|
41
|
-
- [
|
|
40
|
+
- [Plugin Compatibility](#plugin-compatibility)
|
|
41
|
+
- [Plugin Loading (Module Federation)](#plugin-loading-module-federation)
|
|
42
42
|
- [Recipes](#recipes)
|
|
43
43
|
- [Minimal Module (Blades Only)](#minimal-module-blades-only)
|
|
44
44
|
- [Module with CRUD Blades (List + Details)](#module-with-crud-blades-list--details)
|
|
@@ -69,24 +69,15 @@ export default defineAppModule({
|
|
|
69
69
|
```vue
|
|
70
70
|
<!-- modules/my-feature/pages/MyFeatureList.vue -->
|
|
71
71
|
<template>
|
|
72
|
-
<VcBlade
|
|
73
|
-
title="My Feature"
|
|
74
|
-
:closable="closable"
|
|
75
|
-
@close="$emit('close:blade')"
|
|
76
|
-
>
|
|
72
|
+
<VcBlade title="My Feature">
|
|
77
73
|
<p>Hello from my first module!</p>
|
|
78
74
|
</VcBlade>
|
|
79
75
|
</template>
|
|
80
76
|
|
|
81
77
|
<script setup lang="ts">
|
|
82
|
-
import { VcBlade } from "@vc-shell/framework";
|
|
78
|
+
import { VcBlade } from "@vc-shell/framework/ui";
|
|
83
79
|
|
|
84
|
-
|
|
85
|
-
defineEmits(["close:blade"]);
|
|
86
|
-
</script>
|
|
87
|
-
|
|
88
|
-
<script lang="ts">
|
|
89
|
-
defineOptions({
|
|
80
|
+
defineBlade({
|
|
90
81
|
name: "MyFeatureList",
|
|
91
82
|
url: "/my-feature",
|
|
92
83
|
isWorkspace: true,
|
|
@@ -99,6 +90,8 @@ defineOptions({
|
|
|
99
90
|
</script>
|
|
100
91
|
```
|
|
101
92
|
|
|
93
|
+
`VcBlade` reads `expanded` and `closable` directly from the blade descriptor and emits its own close action — blade pages no longer declare those as props or wire up `@close` / `@expand` / `@collapse` emits.
|
|
94
|
+
|
|
102
95
|
```json
|
|
103
96
|
// modules/my-feature/locales/en.json
|
|
104
97
|
{
|
|
@@ -153,31 +146,12 @@ my-feature-module/
|
|
|
153
146
|
|
|
154
147
|
When the host application calls `app.use(module)`, the `install()` function runs the following steps **synchronously and in order**:
|
|
155
148
|
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
- Register in BladeRegistry (name, component, route, permissions)
|
|
163
|
-
- If blade has `url` + `menuItem` --> register sidebar menu entry
|
|
164
|
-
|
|
|
165
|
-
v
|
|
166
|
-
2. NOTIFICATION REGISTRATION (new API)
|
|
167
|
-
For each entry in `notifications`:
|
|
168
|
-
- Register type + config in NotificationStore
|
|
169
|
-
|
|
|
170
|
-
v
|
|
171
|
-
3. LEGACY NOTIFICATION COMPAT (deprecated)
|
|
172
|
-
If `notifications` is NOT provided but `notificationTemplates` is:
|
|
173
|
-
- Register templates with notifyType in NotificationStore
|
|
174
|
-
If any blade has `notifyType`:
|
|
175
|
-
- Create automatic toast subscription (with deprecation warning)
|
|
176
|
-
|
|
|
177
|
-
v
|
|
178
|
-
4. LOCALE MERGE
|
|
179
|
-
For each entry in `locales`:
|
|
180
|
-
- mergeLocaleMessage(langCode, messages) into vue-i18n
|
|
149
|
+
```mermaid
|
|
150
|
+
flowchart TD
|
|
151
|
+
Entry["app.use(module)"] --> S1["1. BLADE REGISTRATION<br/>For each entry in <code>blades</code>:<br/>• Register in BladeRegistry (name, component, route, permissions)<br/>• If blade has <code>url</code> + <code>menuItem</code> → register sidebar menu entry"]
|
|
152
|
+
S1 --> S2["2. NOTIFICATION REGISTRATION<br/>For each entry in <code>notifications</code>:<br/>• Register type + config in NotificationStore"]
|
|
153
|
+
S2 --> S3["3. LEGACY NOTIFICATION COMPAT (deprecated)<br/>If <code>notifications</code> is NOT provided but <code>notificationTemplates</code> is:<br/>• Register templates with notifyType<br/>If any blade has <code>notifyType</code>:<br/>• Create automatic toast subscription (with deprecation warning)"]
|
|
154
|
+
S3 --> S4["4. LOCALE MERGE<br/>For each entry in <code>locales</code>:<br/>• mergeLocaleMessage(langCode, messages) into vue-i18n"]
|
|
181
155
|
```
|
|
182
156
|
|
|
183
157
|
> **Why this order matters:** Blades must be registered before anything references them (e.g., menu items link to blade routes). Notifications are independent. Locales come last because they are purely additive.
|
|
@@ -274,15 +248,15 @@ Each blade is registered in the `BladeRegistry` with:
|
|
|
274
248
|
| `routable` | `component.routable` | `true` = gets a Vue Router route (default: `true`) |
|
|
275
249
|
| `permissions` | `component.permissions` | Required permissions to access the blade |
|
|
276
250
|
|
|
277
|
-
> **Tip:** The export key (e.g., `ProductsList` in `{ ProductsList }`) is used as a fallback name when `
|
|
251
|
+
> **Tip:** The export key (e.g., `ProductsList` in `{ ProductsList }`) is used as a fallback name when `defineBlade` does not set a name. Always set `defineBlade({ name: "..." })` explicitly.
|
|
278
252
|
|
|
279
253
|
### Blade Static Properties
|
|
280
254
|
|
|
281
|
-
Blades declare their routing, permissions, and menu behavior through
|
|
255
|
+
Blades declare their routing, permissions, and menu behavior through `defineBlade`:
|
|
282
256
|
|
|
283
257
|
```vue
|
|
284
|
-
<script lang="ts">
|
|
285
|
-
|
|
258
|
+
<script setup lang="ts">
|
|
259
|
+
defineBlade({
|
|
286
260
|
// REQUIRED: Unique name for the blade (used in BladeRegistry)
|
|
287
261
|
name: "OrdersList",
|
|
288
262
|
|
|
@@ -310,13 +284,13 @@ defineOptions({
|
|
|
310
284
|
</script>
|
|
311
285
|
```
|
|
312
286
|
|
|
313
|
-
> **Note:** `
|
|
287
|
+
> **Note:** `defineBlade` is compiled by the VC-Shell Vite plugin. It emits Vue component options and registers blade metadata before module installation.
|
|
314
288
|
|
|
315
289
|
**Child blades** (detail pages opened from a list) typically do NOT need `url`, `isWorkspace`, or `menuItem`:
|
|
316
290
|
|
|
317
291
|
```vue
|
|
318
|
-
<script lang="ts">
|
|
319
|
-
|
|
292
|
+
<script setup lang="ts">
|
|
293
|
+
defineBlade({
|
|
320
294
|
name: "OrderDetails",
|
|
321
295
|
// No url, no menuItem -- this blade is opened programmatically via openBlade()
|
|
322
296
|
});
|
|
@@ -328,8 +302,8 @@ defineOptions({
|
|
|
328
302
|
Menu items are created **automatically** when a blade has both `url` and `menuItem` static properties. You do not call any menu API yourself.
|
|
329
303
|
|
|
330
304
|
```vue
|
|
331
|
-
<script lang="ts">
|
|
332
|
-
|
|
305
|
+
<script setup lang="ts">
|
|
306
|
+
defineBlade({
|
|
333
307
|
name: "ProductsList",
|
|
334
308
|
url: "/products",
|
|
335
309
|
isWorkspace: true,
|
|
@@ -509,64 +483,31 @@ export default defineAppModule({ blades: pages, locales });
|
|
|
509
483
|
| `permissions` | `string[]` | Required permissions (optional) |
|
|
510
484
|
| `props` | `Record<string, unknown>` | Props passed to the component (optional) |
|
|
511
485
|
|
|
512
|
-
###
|
|
513
|
-
|
|
514
|
-
Remote modules loaded via Module Federation can declare framework compatibility using semver ranges. The host checks these ranges at load time and skips incompatible modules:
|
|
515
|
-
|
|
516
|
-
```json
|
|
517
|
-
// Remote module's manifest (served by the backend)
|
|
518
|
-
{
|
|
519
|
-
"id": "my-remote-module",
|
|
520
|
-
"entry": "https://cdn.example.com/my-module/remoteEntry.js",
|
|
521
|
-
"version": "1.2.0",
|
|
522
|
-
"compatibleWith": {
|
|
523
|
-
"dependencies": {
|
|
524
|
-
"@vc-shell/framework": ">=2.0.0 <3.0.0"
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
At startup, the host:
|
|
486
|
+
### Plugin Compatibility
|
|
531
487
|
|
|
532
|
-
|
|
533
|
-
2. Checks each remote module's `compatibleWith.dependencies["@vc-shell/framework"]` range
|
|
534
|
-
3. Skips modules that fail the semver check (with a console warning)
|
|
535
|
-
4. Loads and installs compatible modules
|
|
488
|
+
Plugin compatibility is settled on the Platform side, not in the browser. The Platform validates each plugin's `<dependency>` declarations in **module.manifest** at .NET module install time and refuses incompatible installs. By the time a plugin appears in the manifest endpoint, the dependency graph has already approved it — there is no client-side semver filter.
|
|
536
489
|
|
|
537
|
-
|
|
490
|
+
Upgrading the host's framework does not silently drop older plugins; if a plugin becomes incompatible, the Platform admin sees an install-time error first.
|
|
538
491
|
|
|
539
|
-
###
|
|
492
|
+
### Plugin Loading (Module Federation)
|
|
540
493
|
|
|
541
|
-
vc-shell
|
|
494
|
+
vc-shell loads plugin extensions at runtime via Module Federation. A plugin remote is built by a .NET module's Vue subpackage and discovered by the Platform from the dependency graph. The host fetches a manifest of plugins for its `appId` at boot and installs each as a Vue plugin.
|
|
542
495
|
|
|
543
496
|
The loading sequence:
|
|
544
497
|
|
|
498
|
+
```mermaid
|
|
499
|
+
flowchart TD
|
|
500
|
+
A["App Start (host main.ts)"] --> N1["1. Fetch plugin manifest<br/>GET /api/apps/{appId}/manifest"]
|
|
501
|
+
N1 --> N2["2. Initialize MF runtime<br/>with shared deps from @vc-shell/mf-config"]
|
|
502
|
+
N2 --> N3["3. Load each plugin's remoteEntry.js<br/>(Promise.allSettled in parallel)"]
|
|
503
|
+
N3 --> N4["4. Resolve Vue plugins from each remote's default export"]
|
|
504
|
+
N4 --> N5["5. app.use(plugin, { router }) for each<br/>→ triggers defineAppModule's install()"]
|
|
505
|
+
N5 --> N6["6. provide(ModulesReadyKey, true)<br/>→ app.mount('#app')"]
|
|
545
506
|
```
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
|
551
|
-
v
|
|
552
|
-
2. Filter by framework version compatibility (semver check)
|
|
553
|
-
|
|
|
554
|
-
v
|
|
555
|
-
3. Initialize Module Federation runtime with shared deps
|
|
556
|
-
(vue, vue-router, vue-i18n, @vc-shell/framework, etc.)
|
|
557
|
-
|
|
|
558
|
-
v
|
|
559
|
-
4. Load all compatible remote modules in parallel
|
|
560
|
-
|
|
|
561
|
-
v
|
|
562
|
-
5. Resolve Vue plugins from each module's exports
|
|
563
|
-
|
|
|
564
|
-
v
|
|
565
|
-
6. app.use(plugin) for each module --> triggers defineAppModule's install()
|
|
566
|
-
|
|
|
567
|
-
v
|
|
568
|
-
7. Set modulesReady = true --> app renders
|
|
569
|
-
```
|
|
507
|
+
|
|
508
|
+
Non-OK manifest responses (401 / 403 / 404 / 5xx) are treated as "no plugins" — the host logs a `console.warn`, sets `modulesReady=true`, and mounts without extensions. Only network or parse failures set `modulesLoadError=true`.
|
|
509
|
+
|
|
510
|
+
See the [Module Federation guide](../guides/module-federation/index.md) for the full plugin-author + host-app walkthrough.
|
|
570
511
|
|
|
571
512
|
The host shares singleton instances of core dependencies (Vue, Vue Router, vue-i18n, @vc-shell/framework) so that remote modules use the same runtime. This is critical for reactivity, routing, and DI to work across module boundaries.
|
|
572
513
|
|
|
@@ -626,8 +567,12 @@ The list blade (workspace):
|
|
|
626
567
|
|
|
627
568
|
```vue
|
|
628
569
|
<!-- pages/ProductsList.vue -->
|
|
629
|
-
<script lang="ts">
|
|
630
|
-
|
|
570
|
+
<script setup lang="ts">
|
|
571
|
+
import { useBlade } from "@vc-shell/framework";
|
|
572
|
+
import { VcBlade, VcDataTable, VcColumn } from "@vc-shell/framework/ui";
|
|
573
|
+
import useProducts from "../composables/useProducts";
|
|
574
|
+
|
|
575
|
+
defineBlade({
|
|
631
576
|
name: "ProductsList",
|
|
632
577
|
url: "/products",
|
|
633
578
|
isWorkspace: true,
|
|
@@ -638,11 +583,6 @@ defineOptions({
|
|
|
638
583
|
priority: 10,
|
|
639
584
|
},
|
|
640
585
|
});
|
|
641
|
-
</script>
|
|
642
|
-
|
|
643
|
-
<script setup lang="ts">
|
|
644
|
-
import { useBlade, VcBlade, VcDataTable, VcColumn } from "@vc-shell/framework";
|
|
645
|
-
import useProducts from "../composables/useProducts";
|
|
646
586
|
|
|
647
587
|
const { openBlade } = useBlade();
|
|
648
588
|
const { items, loading, totalCount, load } = useProducts();
|
|
@@ -660,15 +600,13 @@ The details blade (child):
|
|
|
660
600
|
|
|
661
601
|
```vue
|
|
662
602
|
<!-- pages/ProductDetails.vue -->
|
|
663
|
-
<script lang="ts">
|
|
664
|
-
|
|
603
|
+
<script setup lang="ts">
|
|
604
|
+
import { VcBlade } from "@vc-shell/framework/ui";
|
|
605
|
+
|
|
606
|
+
defineBlade({
|
|
665
607
|
name: "ProductDetails",
|
|
666
608
|
// No url, no menuItem -- opened programmatically
|
|
667
609
|
});
|
|
668
|
-
</script>
|
|
669
|
-
|
|
670
|
-
<script setup lang="ts">
|
|
671
|
-
import { VcBlade } from "@vc-shell/framework";
|
|
672
610
|
|
|
673
611
|
const props = defineProps<{
|
|
674
612
|
param?: { productId: string };
|
|
@@ -758,7 +696,7 @@ import { ExtensionPoint } from "@vc-shell/framework";
|
|
|
758
696
|
|
|
759
697
|
## Common Mistakes
|
|
760
698
|
|
|
761
|
-
### Forgetting `
|
|
699
|
+
### Forgetting `defineBlade` on a blade
|
|
762
700
|
|
|
763
701
|
```typescript
|
|
764
702
|
// module/index.ts
|
|
@@ -770,11 +708,11 @@ export default defineAppModule({
|
|
|
770
708
|
```vue
|
|
771
709
|
<!-- MyBlade.vue -->
|
|
772
710
|
<script setup lang="ts">
|
|
773
|
-
// No
|
|
711
|
+
// No defineBlade!
|
|
774
712
|
</script>
|
|
775
713
|
```
|
|
776
714
|
|
|
777
|
-
The blade will be registered with the export key (`"MyBlade"`) as its name, but it will have **no route and no menu entry
|
|
715
|
+
The blade will be registered with the export key (`"MyBlade"`) as its name, but it will have **no route and no menu entry** because `defineBlade` is what writes routing, permissions, and menu config into the blade config registry. Always call `defineBlade({ name, url?, menuItem?, ... })` at the top of `<script setup>`.
|
|
778
716
|
|
|
779
717
|
### Using `createAppModule` with the new notifications API
|
|
780
718
|
|
|
@@ -821,11 +759,11 @@ export default defineAppModule({
|
|
|
821
759
|
|
|
822
760
|
// Module B
|
|
823
761
|
export default defineAppModule({
|
|
824
|
-
blades: { Dashboard: DashboardB }, //
|
|
762
|
+
blades: { Dashboard: DashboardB }, // Throws at install time!
|
|
825
763
|
});
|
|
826
764
|
```
|
|
827
765
|
|
|
828
|
-
Blade names
|
|
766
|
+
`BladeRegistry` throws when a name is registered twice: `Blade 'Dashboard' is already registered`. The error halts module installation, so duplicate names are caught at startup rather than silently shadowing each other. Use descriptive, module-prefixed names: `OrdersDashboard`, `ProductsDashboard`.
|
|
829
767
|
|
|
830
768
|
### Locale key collisions
|
|
831
769
|
|
|
@@ -122,10 +122,14 @@ export default defineAppModule({
|
|
|
122
122
|
|
|
123
123
|
### Toolbar Button Visibility
|
|
124
124
|
|
|
125
|
-
Toolbar
|
|
125
|
+
Toolbar items are declared as an `IBladeToolbar[]` array and bound to `<VcBlade :toolbar-items>`. The `permissions` property on each entry is filtered out before render when the user lacks the listed permission(s):
|
|
126
126
|
|
|
127
|
-
```
|
|
128
|
-
|
|
127
|
+
```vue
|
|
128
|
+
<script setup lang="ts">
|
|
129
|
+
import { ref } from "vue";
|
|
130
|
+
import { VcBlade, type IBladeToolbar } from "@vc-shell/framework";
|
|
131
|
+
|
|
132
|
+
const bladeToolbar = ref<IBladeToolbar[]>([
|
|
129
133
|
{
|
|
130
134
|
id: "save",
|
|
131
135
|
title: "Save",
|
|
@@ -141,6 +145,11 @@ const toolbar = useToolbar([
|
|
|
141
145
|
clickHandler: () => deleteOrder(),
|
|
142
146
|
},
|
|
143
147
|
]);
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<template>
|
|
151
|
+
<VcBlade :toolbar-items="bladeToolbar" />
|
|
152
|
+
</template>
|
|
144
153
|
```
|
|
145
154
|
|
|
146
155
|
## Tip: Permission Naming Convention
|
|
@@ -67,26 +67,26 @@ Module developers do not install this plugin. It is registered once by the frame
|
|
|
67
67
|
|
|
68
68
|
## Connection Lifecycle
|
|
69
69
|
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
connection.stop()
|
|
70
|
+
```mermaid
|
|
71
|
+
sequenceDiagram
|
|
72
|
+
participant U as User
|
|
73
|
+
participant C as SignalR client
|
|
74
|
+
participant Hub as /pushNotificationHub
|
|
75
|
+
participant Store as NotificationStore
|
|
76
|
+
|
|
77
|
+
U->>C: log in (isAuthenticated = true)
|
|
78
|
+
C->>Hub: connection.start() (WebSocket)
|
|
79
|
+
Note over C,Hub: connection open
|
|
80
|
+
|
|
81
|
+
Hub-->>C: "Send" (targeted)
|
|
82
|
+
C->>Store: ingest(message)
|
|
83
|
+
Hub-->>C: "SendSystemEvents" (broadcast, filtered by creator)
|
|
84
|
+
C->>Store: ingest(message, { broadcast: true })
|
|
85
|
+
|
|
86
|
+
Store->>Store: toast • subscriber callbacks • history update
|
|
87
|
+
|
|
88
|
+
U->>C: log out
|
|
89
|
+
C->>Hub: connection.stop()
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
### Reconnection Behavior
|
|
@@ -49,7 +49,7 @@ This centralized approach has several advantages:
|
|
|
49
49
|
| `DashboardServiceKey` | `IDashboardService` | Dashboard widget management |
|
|
50
50
|
| `MenuServiceKey` | `MenuService` | Main navigation menu |
|
|
51
51
|
| `SettingsMenuServiceKey` | `ISettingsMenuService` | Settings sidebar menu |
|
|
52
|
-
| `AppBarWidgetServiceKey` | `IAppBarWidgetService` | App
|
|
52
|
+
| `AppBarWidgetServiceKey` | `IAppBarWidgetService` | App hub widget registry |
|
|
53
53
|
| `AppBarMobileButtonsServiceKey` | `IAppBarMobileButtonsService` | Mobile app bar buttons |
|
|
54
54
|
| `LanguageServiceKey` | `ILanguageService` | Localization service |
|
|
55
55
|
| `ToolbarServiceKey` | `IToolbarService` | Blade toolbar actions |
|
|
@@ -102,4 +102,4 @@ async function onLogin(user) {
|
|
|
102
102
|
- [SettingsMenu](../settings-menu/settings-menu.docs.md) -- parent container
|
|
103
103
|
- [SettingsMenuItem](../settings-menu-item/settings-menu-item.docs.md) -- base menu item used internally
|
|
104
104
|
- [ThemeSelector](../theme-selector/theme-selector.docs.md) -- sibling preference entry
|
|
105
|
-
- [MultilanguageSelector](
|
|
105
|
+
- [MultilanguageSelector](../../../ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md) -- content language picker (different purpose)
|
package/runtime/knowledge/docs/shell/components/notification-dropdown/notification-dropdown.docs.md
CHANGED
|
@@ -123,4 +123,4 @@ When a notification's `notifyType` matches a registered template key, that compo
|
|
|
123
123
|
## Related Components
|
|
124
124
|
|
|
125
125
|
- [NotificationTemplate](../notification-template/notification-template.docs.md) -- base template for each notification row
|
|
126
|
-
- [Notifications](
|
|
126
|
+
- [Notifications](../../../core/notifications/notifications.docs.md) -- push notification system (store, registration, blade-scoped subscriptions)
|
package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md
CHANGED
|
@@ -175,4 +175,4 @@ const isRunning = computed(() => (notification.value as any).isRunning ?? false)
|
|
|
175
175
|
## Related Components
|
|
176
176
|
|
|
177
177
|
- [NotificationDropdown](../notification-dropdown/notification-dropdown.docs.md) -- parent dropdown container
|
|
178
|
-
- [Notifications](
|
|
178
|
+
- [Notifications](../../../core/notifications/notifications.docs.md) -- push notification system (store, registration, blade-scoped subscriptions)
|
|
@@ -53,7 +53,7 @@ This component has no props. All content is driven by the settings menu service
|
|
|
53
53
|
A typical module registers all its settings entries during the module install phase:
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
|
-
//
|
|
56
|
+
// settings-module/index.ts
|
|
57
57
|
import { markRaw } from "vue";
|
|
58
58
|
import { useSettingsMenu, ThemeSelector, LanguageSelector, ChangePasswordButton, LogoutButton } from "@vc-shell/framework";
|
|
59
59
|
|
|
@@ -98,12 +98,12 @@ export default {
|
|
|
98
98
|
|
|
99
99
|
### Registration options
|
|
100
100
|
|
|
101
|
-
| Option | Type | Required | Description
|
|
102
|
-
| ----------- | ----------- | -------- |
|
|
103
|
-
| `id` | `string` |
|
|
104
|
-
| `group` | `string` |
|
|
105
|
-
| `order` | `number` |
|
|
106
|
-
| `component` | `Component` | Yes | Vue component to render as the menu item
|
|
101
|
+
| Option | Type | Required | Description |
|
|
102
|
+
| ----------- | ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `id` | `string` | No | Unique identifier for the entry. Auto-generated when omitted. |
|
|
104
|
+
| `group` | `string` | No | Group name (entries are grouped and separated by dividers). Defaults to `"general"`. |
|
|
105
|
+
| `order` | `number` | No | Sort order within the group (lower = higher position). Defaults to the current registry size at registration time, preserving insertion order. |
|
|
106
|
+
| `component` | `Component` | Yes | Vue component to render as the menu item. |
|
|
107
107
|
|
|
108
108
|
### Group rendering
|
|
109
109
|
|
package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md
CHANGED
|
@@ -201,5 +201,5 @@ Do not set `triggerAction="none"` and then rely on `@trigger:click` -- the event
|
|
|
201
201
|
- [SettingsMenu](../settings-menu/settings-menu.docs.md) -- parent container
|
|
202
202
|
- [ThemeSelector](../theme-selector/theme-selector.docs.md) -- uses SettingsMenuItem with submenu slot
|
|
203
203
|
- [LanguageSelector](../language-selector/language-selector.docs.md) -- uses SettingsMenuItem with submenu slot
|
|
204
|
-
- [VcDropdownPanel](
|
|
205
|
-
- [
|
|
204
|
+
- [VcDropdownPanel](../../../ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md) -- used internally for desktop sub-menus
|
|
205
|
+
- [VcDropdown](../../../ui/components/molecules/vc-dropdown/vc-dropdown.docs.md) -- recommended for sub-menu option rows
|
package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md
CHANGED
|
@@ -11,7 +11,7 @@ Gridstack.js-powered dashboard container that renders registered widgets in a dr
|
|
|
11
11
|
|
|
12
12
|
## When to Use
|
|
13
13
|
|
|
14
|
-
- Use as the main dashboard view for
|
|
14
|
+
- Use as the main dashboard view for a shell application
|
|
15
15
|
- When you need a customizable widget grid with drag-and-drop rearrangement
|
|
16
16
|
- Do NOT use for static, non-rearrangeable layouts (use a regular grid/flex layout instead)
|
|
17
17
|
|
|
@@ -85,12 +85,12 @@ A small indicator component for displaying counts, status dots, or short text la
|
|
|
85
85
|
## Recipe: Status Tags in a Table Cell
|
|
86
86
|
|
|
87
87
|
```vue
|
|
88
|
-
<VcColumn id="status"
|
|
89
|
-
<template #
|
|
88
|
+
<VcColumn id="status" title="Status" width="120px">
|
|
89
|
+
<template #body="{ data }">
|
|
90
90
|
<VcBadge
|
|
91
91
|
inline
|
|
92
|
-
:content="
|
|
93
|
-
:variant="statusVariantMap[
|
|
92
|
+
:content="data.status"
|
|
93
|
+
:variant="statusVariantMap[data.status]"
|
|
94
94
|
size="s"
|
|
95
95
|
/>
|
|
96
96
|
</template>
|
|
@@ -328,5 +328,5 @@ All visual properties are customizable through CSS custom properties. Each varia
|
|
|
328
328
|
|
|
329
329
|
- VcButton calls `e.preventDefault()` on click to support `link` variant pattern. Form submit buttons must use `type="submit"` to bypass this.
|
|
330
330
|
- `VcButtonGroup` integration is via provide/inject (`vcButtonGroupSize` injection key in `framework/injection-keys.ts`).
|
|
331
|
-
- Size aliases `xs`/`base` are kept for
|
|
331
|
+
- Size aliases `xs`/`base` are kept for backward compatibility — slated for removal in v3.
|
|
332
332
|
<!-- internal:end -->
|
|
@@ -19,11 +19,31 @@ A scrollable content wrapper that fills its parent, provides configurable paddin
|
|
|
19
19
|
|
|
20
20
|
## Basic Usage
|
|
21
21
|
|
|
22
|
+
The most common form is a bare `<VcContainer>` wrapping the blade's body — it fills the parent, scrolls when content overflows, and applies a 16px default padding.
|
|
23
|
+
|
|
24
|
+
```vue
|
|
25
|
+
<VcContainer>
|
|
26
|
+
<p>Scrollable content goes here...</p>
|
|
27
|
+
</VcContainer>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
When the contained child already manages its own padding (a `VcDataTable`, for example), set `:no-padding="true"` so the wrapper does not stack extra space around it:
|
|
31
|
+
|
|
32
|
+
```vue
|
|
33
|
+
<VcContainer :no-padding="true">
|
|
34
|
+
<VcDataTable :items="items">
|
|
35
|
+
<VcColumn id="name" title="Name" />
|
|
36
|
+
</VcDataTable>
|
|
37
|
+
</VcContainer>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `shadow` prop adds an inset shadow as a scroll cue. Use it for content that genuinely overflows by a long way (long forms, free-text editors); the default no-shadow rendering is preferable everywhere else.
|
|
41
|
+
|
|
22
42
|
::storybook id="layout-vccontainer--with-shadow" height="300"
|
|
23
43
|
|
|
24
44
|
```vue
|
|
25
45
|
<VcContainer shadow>
|
|
26
|
-
<p>
|
|
46
|
+
<p>Long-form content that benefits from a scroll cue...</p>
|
|
27
47
|
</VcContainer>
|
|
28
48
|
```
|
|
29
49
|
|
|
@@ -72,13 +72,29 @@ function openDetails() {
|
|
|
72
72
|
|
|
73
73
|
### Inline Action in a Table Cell
|
|
74
74
|
|
|
75
|
+
For row actions in a `VcDataTable`, the framework's `:row-actions` builder is the recommended path — it renders a consistent action menu per row without an extra column declaration:
|
|
76
|
+
|
|
77
|
+
```vue
|
|
78
|
+
<VcDataTable :items="items" :row-actions="actionBuilder" row-actions-position="column" />
|
|
79
|
+
|
|
80
|
+
<script setup lang="ts">
|
|
81
|
+
import type { TableAction } from "@vc-shell/framework";
|
|
82
|
+
|
|
83
|
+
function actionBuilder(item: Item): TableAction[] {
|
|
84
|
+
return [
|
|
85
|
+
{ icon: "lucide-pencil", title: "Edit", clickHandler: () => editItem(item) },
|
|
86
|
+
{ icon: "lucide-copy", title: "Copy", clickHandler: () => duplicateItem(item) },
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Inline `VcLink` in a cell still fits non-action navigation (open another blade from a name, jump to a docs URL):
|
|
93
|
+
|
|
75
94
|
```vue
|
|
76
|
-
<VcColumn id="
|
|
77
|
-
<template #
|
|
78
|
-
<
|
|
79
|
-
<VcLink @click="editItem(row)">Edit</VcLink>
|
|
80
|
-
<VcLink @click="duplicateItem(row)">Copy</VcLink>
|
|
81
|
-
</div>
|
|
95
|
+
<VcColumn id="name" title="Name">
|
|
96
|
+
<template #body="{ data }">
|
|
97
|
+
<VcLink @click="openItem(data.id)">{{ data.name }}</VcLink>
|
|
82
98
|
</template>
|
|
83
99
|
</VcColumn>
|
|
84
100
|
```
|
|
@@ -52,7 +52,7 @@ The last row automatically renders at 60% width for a natural paragraph feel.
|
|
|
52
52
|
### Avatar Placeholder
|
|
53
53
|
|
|
54
54
|
```vue
|
|
55
|
-
<VcSkeleton variant="circle"
|
|
55
|
+
<VcSkeleton variant="circle" width="48px" :height="48" />
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
::storybook id="layout-vcskeleton--card-skeleton" height="450"
|
|
@@ -93,7 +93,7 @@ The last row automatically renders at 60% width for a natural paragraph feel.
|
|
|
93
93
|
>
|
|
94
94
|
<VcSkeleton
|
|
95
95
|
variant="circle"
|
|
96
|
-
|
|
96
|
+
width="40px"
|
|
97
97
|
:height="40"
|
|
98
98
|
/>
|
|
99
99
|
<div class="tw-flex-1">
|