@vc-shell/framework 1.1.22 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/core/composables/useAppInsights/index.ts +11 -1
  3. package/core/composables/useBladeRegistry/index.ts +176 -0
  4. package/core/composables/useDynamicProperties/index.ts +380 -255
  5. package/core/composables/useErrorHandler/index.ts +2 -3
  6. package/core/composables/useLanguages/index.ts +78 -78
  7. package/core/plugins/modularity/index.ts +17 -6
  8. package/core/services/global-search-service/index.ts +36 -0
  9. package/dist/core/composables/useAppInsights/index.d.ts +5 -2
  10. package/dist/core/composables/useAppInsights/index.d.ts.map +1 -1
  11. package/dist/core/composables/useBladeRegistry/index.d.ts +48 -0
  12. package/dist/core/composables/useBladeRegistry/index.d.ts.map +1 -0
  13. package/dist/core/composables/useDynamicProperties/index.d.ts +11 -9
  14. package/dist/core/composables/useDynamicProperties/index.d.ts.map +1 -1
  15. package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
  16. package/dist/core/plugins/modularity/index.d.ts.map +1 -1
  17. package/dist/core/services/global-search-service/index.d.ts +10 -0
  18. package/dist/core/services/global-search-service/index.d.ts.map +1 -0
  19. package/dist/framework.js +1 -1
  20. package/dist/{index-BQtOyLub.js → index-BLmjssqE.js} +1 -1
  21. package/dist/{index-C_zSZ2pX.js → index-BYcoxn-f.js} +1 -1
  22. package/dist/{index-wjw1DwqR.js → index-BbuBDu8A.js} +1 -1
  23. package/dist/{index-DqDgL4W3.js → index-BnqqEJTE.js} +1 -1
  24. package/dist/{index--KQZx7Nr.js → index-Br7ZwtRW.js} +1 -1
  25. package/dist/{index-DwjKpYAo.js → index-CGL9e-cM.js} +1 -1
  26. package/dist/{index-DoHQrH4a.js → index-CIzLBvgg.js} +1 -1
  27. package/dist/{index-DFdFt54f.js → index-CLAYu8Qj.js} +1 -1
  28. package/dist/{index-BxrA7EzT.js → index-CRwMOCjN.js} +1 -1
  29. package/dist/{index-DL0-yUXC.js → index-Cmbxdwnl.js} +1 -1
  30. package/dist/{index-Bf4s6An9.js → index-Cxkjjuah.js} +1 -1
  31. package/dist/{index-xCbUzsUb.js → index-DAnceKLv.js} +1 -1
  32. package/dist/{index-BAngL0ix.js → index-Dk1K3-27.js} +1 -1
  33. package/dist/{index-d16x5dY_.js → index-DoArZBIw.js} +1 -1
  34. package/dist/{index-C-y5H4_R.js → index-DvenBxy6.js} +45753 -45502
  35. package/dist/{index-DI3UVoln.js → index-cuex9jil.js} +1 -1
  36. package/dist/{index--F0eI_oT.js → index-eOG-NNYN.js} +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts +7 -12
  39. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  40. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts +15 -0
  41. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts.map +1 -0
  42. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts +11 -0
  43. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts.map +1 -0
  44. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts +15 -0
  45. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts.map +1 -0
  46. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.d.ts +6 -0
  47. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.d.ts.map +1 -0
  48. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts +28 -0
  49. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts.map +1 -0
  50. package/dist/shared/components/blade-navigation/plugin.d.ts.map +1 -1
  51. package/dist/shared/components/blade-navigation/types/index.d.ts +5 -5
  52. package/dist/shared/components/blade-navigation/types/index.d.ts.map +1 -1
  53. package/dist/shared/components/notification-template/notification-template.vue.d.ts +2 -2
  54. package/dist/shared/components/notification-template/notification-template.vue.d.ts.map +1 -1
  55. package/dist/shared/modules/dynamic/components/fields/storybook/pages/DynamicRender.d.ts +1 -9
  56. package/dist/shared/modules/dynamic/components/fields/storybook/pages/DynamicRender.d.ts.map +1 -1
  57. package/dist/shared/modules/dynamic/index.d.ts.map +1 -1
  58. package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts +2 -18
  59. package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue.d.ts +2 -0
  62. package/dist/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue.d.ts.map +1 -1
  63. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  64. package/dist/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue.d.ts.map +1 -1
  65. package/package.json +4 -4
  66. package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +199 -597
  67. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.ts +151 -0
  68. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.ts +243 -0
  69. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.ts +93 -0
  70. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.ts +90 -0
  71. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.ts +150 -0
  72. package/shared/components/blade-navigation/plugin.ts +17 -12
  73. package/shared/components/blade-navigation/types/index.ts +2 -4
  74. package/shared/components/notification-template/notification-template.vue +2 -2
  75. package/shared/modules/dynamic/index.ts +2 -8
  76. package/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue +4 -0
  77. package/ui/components/organisms/vc-app/vc-app.vue +11 -6
  78. package/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue +10 -1
@@ -0,0 +1,150 @@
1
+ import { computed, shallowRef, Ref, markRaw, watch } from "vue";
2
+ import { RouteLocationNormalized, Router, LocationQuery, RouteRecordNameGeneric, RouteParamsGeneric } from "vue-router";
3
+ import type { BladeVNode } from "../../../types";
4
+
5
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
6
+
7
+ // --- Router and URL Utilities Module ---
8
+ export function _createRouterUtils(router: Router, route: RouteLocationNormalized) {
9
+ const mainRouteBaseParamURL: Ref<string | undefined> = shallowRef<string>();
10
+ const routes = markRaw(router.getRoutes());
11
+
12
+ function _updateMainRouteBaseParamURL() {
13
+ const firstParamValue = Object.values(route.params)?.[0] ?? "";
14
+ mainRouteBaseParamURL.value = "/" + firstParamValue;
15
+ }
16
+ // Initial calculation
17
+ _updateMainRouteBaseParamURL();
18
+ // Update when route params change, as this might affect the base URL
19
+ watch(() => route.params, _updateMainRouteBaseParamURL, { deep: true });
20
+
21
+ function parseUrlParams(
22
+ url: string,
23
+ currentRouteParams: RouteParamsGeneric,
24
+ ): { workspace?: string; blade?: string; param?: string } | undefined {
25
+ let pathSegments = url.split("/").filter(Boolean);
26
+
27
+ const firstParamFromCurrentRoute = Object.values(currentRouteParams)?.[0];
28
+ let basePathFromCurrentRoute: string | undefined;
29
+
30
+ if (typeof firstParamFromCurrentRoute === "string" && firstParamFromCurrentRoute) {
31
+ basePathFromCurrentRoute = "/" + firstParamFromCurrentRoute;
32
+ }
33
+
34
+ // If the URL starts with the determined base path (like a UUID tenant ID from currentRouteParams),
35
+ // we should parse the segments *after* it for workspace, blade, param.
36
+ if (basePathFromCurrentRoute && basePathFromCurrentRoute !== "/" && url.startsWith(basePathFromCurrentRoute)) {
37
+ const baseSegmentsCount = basePathFromCurrentRoute.split("/").filter(Boolean).length;
38
+ pathSegments = pathSegments.slice(baseSegmentsCount);
39
+ }
40
+ // Now, pathSegments should contain parts of the URL after the base parameter,
41
+ // e.g., ["workspace-name", "blade-name", "item-id"] or ["workspace-name"], etc.
42
+
43
+ if (pathSegments.length === 0) {
44
+ // This means the path was likely just the base parameter itself (e.g., "/some-uuid/")
45
+ // or an empty path "/".
46
+ // parseUrlParams returns undefined for workspace, blade, param in this case.
47
+ // routeResolver will handle this, typically by navigating to a default workspace or root.
48
+ return { workspace: undefined, blade: undefined, param: undefined };
49
+ }
50
+
51
+ // The first segment after the base is potentially the workspace.
52
+ // The second is potentially the blade.
53
+ // The third is potentially the param.
54
+ // Validation of these segments against actual components happens later in routeResolver.
55
+ const workspace = pathSegments[0];
56
+ const blade = pathSegments[1];
57
+ const param = pathSegments[2];
58
+
59
+ return { workspace, blade, param };
60
+ }
61
+
62
+ function parseWorkspaceUrlPath(path: string): string {
63
+ _updateMainRouteBaseParamURL(); // Ensure base URL is current
64
+ const pathWithoutBase = path.startsWith(mainRouteBaseParamURL.value || "###") // Use unlikely string if base is undefined
65
+ ? path.slice((mainRouteBaseParamURL.value || "").length)
66
+ : path;
67
+ const segments = pathWithoutBase.split("/").filter(Boolean);
68
+ const workspaceUrl = segments.slice(0, 1).join("/");
69
+ return "/" + workspaceUrl;
70
+ }
71
+
72
+ function getURLQuery(): { params: string; obj: LocationQuery } {
73
+ if (route.query && Object.keys(route.query).length) {
74
+ return {
75
+ params: new URLSearchParams(route.query as Record<string, string>).toString(),
76
+ obj: route.query,
77
+ };
78
+ }
79
+ // Fallback for scenarios where route.query might not be populated (e.g., initial load before router is fully ready)
80
+ const hash = window.location.hash || "#";
81
+ const queryPart = hash.split("?")[1] || "";
82
+ const params = new URLSearchParams(queryPart).toString();
83
+ return { params, obj: Object.fromEntries(new URLSearchParams(queryPart)) };
84
+ }
85
+
86
+ function constructBladePath(workspace: BladeVNode, lastBlade?: BladeVNode): string | undefined {
87
+ const wsBladeUrl = workspace?.type.url;
88
+
89
+ if (!wsBladeUrl) {
90
+ return undefined;
91
+ }
92
+
93
+ // Normalize workspace URL (e.g., "products" -> "/products")
94
+ // Ensure basePath starts with a slash and does not end with one (unless it's just "/")
95
+ let basePath = wsBladeUrl.startsWith("/") ? wsBladeUrl : "/" + wsBladeUrl;
96
+ if (basePath.endsWith("/") && basePath.length > 1) {
97
+ basePath = basePath.slice(0, -1);
98
+ }
99
+
100
+ if (lastBlade && lastBlade.type.url && lastBlade.type.url !== wsBladeUrl) {
101
+ // This is a child blade different from the workspace
102
+ let childPathSegment = lastBlade.type.url;
103
+ const param = lastBlade.props?.param;
104
+
105
+ // Normalize childPathSegment (e.g., "details" -> "/details")
106
+ if (!childPathSegment.startsWith("/")) {
107
+ childPathSegment = "/" + childPathSegment;
108
+ }
109
+
110
+ let fullPath = basePath + childPathSegment;
111
+
112
+ if (param) {
113
+ fullPath += "/" + String(param);
114
+ }
115
+ return fullPath;
116
+ } else {
117
+ // This is just the workspace, or lastBlade is the workspace itself, or lastBlade has no distinct URL.
118
+ // The param should be taken from lastBlade if it's the one defining the current end of the path,
119
+ // otherwise from the workspace's own props.
120
+ const param = lastBlade ? lastBlade.props?.param : workspace.props?.param;
121
+ if (param) {
122
+ return basePath + "/" + String(param);
123
+ }
124
+ return basePath;
125
+ }
126
+ }
127
+
128
+ function getResolvedRouteComponent(path: string): BladeVNode | undefined {
129
+ return router.resolve({ path })?.matched?.[1]?.components?.default as BladeVNode | undefined;
130
+ }
131
+
132
+ return {
133
+ mainRouteBaseParamURL: computed(() => mainRouteBaseParamURL.value),
134
+ parseUrlParams,
135
+ parseWorkspaceUrlPath,
136
+ getURLQuery,
137
+ constructBladePath,
138
+ getResolvedRouteComponent,
139
+ allRoutes: routes,
140
+ goToRoot: () => {
141
+ const mainRoute = routes.find((r) => r.meta?.root);
142
+ const mainRouteAlias = routes.find((r) => r.aliasOf?.path === mainRoute?.path) || mainRoute;
143
+ if (mainRouteAlias?.name) {
144
+ return { name: mainRouteAlias.name as RouteRecordNameGeneric, params: route.params as RouteParamsGeneric };
145
+ }
146
+ console.error("goToRoot: Main route or its alias with a name not found!");
147
+ return { path: "/" };
148
+ },
149
+ };
150
+ }
@@ -1,7 +1,7 @@
1
1
  import { Router } from "vue-router";
2
- import { App, inject, ref } from "vue";
2
+ import { App, ref } from "vue";
3
3
  import * as components from "./components";
4
- import { BladeNavigationPlugin, BladeRoutesRecord } from "./types";
4
+ import { BladeNavigationPlugin } from "./types";
5
5
 
6
6
  // Declare globally
7
7
  declare module "@vue/runtime-core" {
@@ -14,22 +14,27 @@ export let bladeNavigationInstance: BladeNavigationPlugin;
14
14
 
15
15
  export const VcBladeNavigationComponent = {
16
16
  install(app: App, args: { router: Router }) {
17
- // Register components
17
+ // Register framework's own blade UI components like VcBladeNavigation
18
18
  Object.entries(components).forEach(([componentName, component]) => {
19
19
  app.component(componentName, component);
20
20
  });
21
21
 
22
- const internalRoutes = app.runWithContext(() => inject("bladeRoutes")) as BladeRoutesRecord[];
23
-
24
- // Plugin
25
- const bladeNavigationPlugin: BladeNavigationPlugin = {
22
+ // The plugin instance primarily provides the router.
23
+ // Blade resolution is now handled by useBladeNavigation via useBladeRegistry.
24
+ const bladeNavigationPluginData: BladeNavigationPlugin = {
26
25
  router: args.router,
27
- internalRoutes,
28
- blades: ref([]),
26
+ // blades: ref([]), // This state was for useBladeNavigation, it should manage its own state internally or via its singleton.
27
+ // If blades ref is truly global and shared, it needs careful consideration.
28
+ // For now, assuming blade state management is within useBladeNavigationSingleton.
29
29
  };
30
30
 
31
- app.config.globalProperties.$bladeNavigationPlugin = bladeNavigationPlugin;
32
- bladeNavigationInstance = bladeNavigationPlugin;
33
- app.provide("bladeNavigationPlugin", bladeNavigationPlugin);
31
+ // This global instance is used as a fallback in useBladeNavigation.
32
+ // It should contain at least what useBladeNavigation might try to access from it.
33
+ // Primarily, the router.
34
+ bladeNavigationInstance = bladeNavigationPluginData;
35
+
36
+ // Provide the plugin instance (mainly for the router) for useBladeNavigation to inject.
37
+ // useBladeNavigation can then also useBladeRegistry() independently.
38
+ app.provide("bladeNavigationPlugin", bladeNavigationPluginData);
34
39
  },
35
40
  };
@@ -80,7 +80,7 @@ export type BladeInstanceConstructor<T extends Component = Component> = Extracto
80
80
  CoreBladeAdditionalSettings;
81
81
 
82
82
  export interface IBladeEvent<T extends Component = Component> {
83
- blade: BladeInstanceConstructor<T>;
83
+ blade: BladeInstanceConstructor<T> | { name: string } | undefined;
84
84
  options?: ExtractedBladeOptions<InstanceType<BladeInstanceConstructor<T>>["$props"], "options">;
85
85
  param?: string;
86
86
  onOpen?: () => void;
@@ -90,12 +90,10 @@ export interface IBladeEvent<T extends Component = Component> {
90
90
 
91
91
  export interface BladeNavigationPlugin {
92
92
  router: Router;
93
- internalRoutes: BladeRoutesRecord[];
94
- blades: Ref<BladeVNode[]>;
95
93
  }
96
94
 
97
95
  export interface BladeRoutesRecord {
98
- component: BladeVNode;
96
+ component: BladeInstanceConstructor;
99
97
  name: string;
100
98
  isWorkspace: boolean;
101
99
  route: string;
@@ -30,13 +30,13 @@
30
30
  <script setup lang="ts">
31
31
  import { computed } from "vue";
32
32
  import moment from "moment";
33
- import { PushNotification } from "../../../core/api/platform";
33
+ import { IPushNotification } from "../../../core/api/platform";
34
34
 
35
35
  export interface Props {
36
36
  color?: string;
37
37
  icon?: string;
38
38
  title: string;
39
- notification: PushNotification;
39
+ notification: IPushNotification;
40
40
  }
41
41
 
42
42
  const props = defineProps<Props>();
@@ -55,18 +55,12 @@ const createBladeInstanceConstructor = (
55
55
  existingComposables?: { [key: string]: (...args: any[]) => any },
56
56
  existingMixins?: ((...args: any[]) => any)[],
57
57
  ) => {
58
- if (json.settings.url) {
59
- const rawUrl = json.settings.url as `/${string}`;
60
- bladeComponent.url = rawUrl;
61
- }
62
-
63
- if (json.settings.permissions) {
64
- bladeComponent.permissions = json.settings.permissions;
65
- }
66
58
 
67
59
  return defineComponent({
68
60
  ...bladeComponent,
69
61
  name: bladeName,
62
+ url: json.settings.url ? (json.settings.url as `/${string}`) : undefined,
63
+ permissions: json.settings.permissions,
70
64
  isWorkspace: "isWorkspace" in json.settings && json.settings.isWorkspace,
71
65
  menuItem: ("menuItem" in json.settings && json.settings.menuItem) ?? undefined,
72
66
  moduleUid: args.moduleUid,
@@ -11,6 +11,8 @@
11
11
  :required="required"
12
12
  :model-value="option"
13
13
  :tooltip="tooltip"
14
+ :multilanguage="multilanguage"
15
+ :current-language="currentLanguage"
14
16
  @update:model-value="$emit('update:option', $event)"
15
17
  >
16
18
  <template #option="scope">
@@ -202,6 +204,8 @@ export interface Props {
202
204
  * Default: text
203
205
  */
204
206
  inputType?: "text" | "password" | "email" | "tel" | "number" | "integer" | "url" | "time" | "date" | "datetime-local";
207
+ multilanguage?: boolean;
208
+ currentLanguage?: string;
205
209
  }
206
210
 
207
211
  export interface Emits {
@@ -192,12 +192,17 @@ const onMenuItemClick = function (item: MenuItem) {
192
192
  console.debug(`vc-app#onMenuItemClick() called.`);
193
193
 
194
194
  if (item.routeId) {
195
- openBlade(
196
- {
197
- blade: resolveBladeByName(item.routeId),
198
- },
199
- true,
200
- );
195
+ const bladeComponent = resolveBladeByName(item.routeId);
196
+ if (bladeComponent) {
197
+ openBlade(
198
+ {
199
+ blade: bladeComponent,
200
+ },
201
+ true,
202
+ );
203
+ } else {
204
+ console.error(`Blade component with routeId '${item.routeId}' not found.`);
205
+ }
201
206
  } else if (!item.routeId && item.url) {
202
207
  const menuRoute = routes.find((r) => {
203
208
  return "/" + r.path.split("/").filter((part) => part !== "")[1] === item.url || r.path === item.url;
@@ -199,6 +199,8 @@
199
199
  option-label="displayName"
200
200
  option-value="id"
201
201
  input-type="number"
202
+ :multilanguage="multilanguage"
203
+ :current-language="currentLanguage"
202
204
  :label="computedProperty.displayName"
203
205
  :placeholder="computedProperty.placeholder"
204
206
  :required="computedProperty.required"
@@ -213,7 +215,7 @@
213
215
  @keydown.enter.stop.prevent="scope.toggleHandler"
214
216
  @keydown.space.stop.prevent="scope.toggleHandler"
215
217
  >
216
- {{ measurementOptions?.find((e) => e.id === measureUnit)?.displaySymbol }}
218
+ {{ measurementSymbol }}
217
219
  </button>
218
220
  </template>
219
221
  </VcInputDropdown>
@@ -318,6 +320,13 @@ watch(
318
320
  },
319
321
  );
320
322
 
323
+ const measurementSymbol = computed(() => {
324
+ const option = measurementOptions.value.find((x) => x.id === measureUnit.value);
325
+ const displaySymbol = option?.displaySymbol;
326
+ const localizedSymbol = option?.localizedSymbol.values[props.currentLanguage as string];
327
+ return localizedSymbol ? localizedSymbol : displaySymbol;
328
+ });
329
+
321
330
  const computedProperty = computed(() => {
322
331
  const rules: IValidationRules = {};
323
332
  if (props.required) {