@vc-shell/framework 1.1.21 → 1.1.23

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 (222) 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/useKeyboardNavigation/index.ts +52 -10
  7. package/core/composables/useLanguages/index.ts +78 -78
  8. package/core/plugins/modularity/index.ts +17 -6
  9. package/core/services/global-search-service/index.ts +36 -0
  10. package/dist/core/composables/useAppInsights/index.d.ts +5 -2
  11. package/dist/core/composables/useAppInsights/index.d.ts.map +1 -1
  12. package/dist/core/composables/useBladeRegistry/index.d.ts +48 -0
  13. package/dist/core/composables/useBladeRegistry/index.d.ts.map +1 -0
  14. package/dist/core/composables/useDynamicProperties/index.d.ts +12 -9
  15. package/dist/core/composables/useDynamicProperties/index.d.ts.map +1 -1
  16. package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
  17. package/dist/core/composables/useKeyboardNavigation/index.d.ts.map +1 -1
  18. package/dist/core/plugins/modularity/index.d.ts.map +1 -1
  19. package/dist/core/services/global-search-service/index.d.ts +10 -0
  20. package/dist/core/services/global-search-service/index.d.ts.map +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts +7 -12
  23. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  24. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts +15 -0
  25. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts.map +1 -0
  26. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts +11 -0
  27. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts.map +1 -0
  28. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts +15 -0
  29. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts.map +1 -0
  30. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.d.ts +6 -0
  31. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.d.ts.map +1 -0
  32. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts +28 -0
  33. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts.map +1 -0
  34. package/dist/shared/components/blade-navigation/plugin.d.ts.map +1 -1
  35. package/dist/shared/components/blade-navigation/types/index.d.ts +5 -5
  36. package/dist/shared/components/blade-navigation/types/index.d.ts.map +1 -1
  37. package/dist/shared/components/notification-template/notification-template.vue.d.ts +2 -2
  38. package/dist/shared/components/notification-template/notification-template.vue.d.ts.map +1 -1
  39. package/dist/shared/components/notifications/components/notification-container/index.d.ts +6 -6
  40. package/dist/shared/components/notifications/components/notification-container/index.d.ts.map +1 -1
  41. package/dist/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts +2 -2
  42. package/dist/shared/modules/dynamic/index.d.ts.map +1 -1
  43. package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts +2 -2
  44. package/dist/shared/pages/InvitePage/components/invite/Invite.vue.d.ts +1 -1
  45. package/dist/shared/pages/InvitePage/components/invite/Invite.vue.d.ts.map +1 -1
  46. package/dist/shared/pages/ResetPasswordPage/components/reset-password/ResetPassword.vue.d.ts +1 -1
  47. package/dist/shared/pages/ResetPasswordPage/components/reset-password/ResetPassword.vue.d.ts.map +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/dist/ui/components/atoms/vc-badge/vc-badge.vue.d.ts +1 -1
  50. package/dist/ui/components/atoms/vc-badge/vc-badge.vue.d.ts.map +1 -1
  51. package/dist/ui/components/atoms/vc-container/vc-container.vue.d.ts +2 -2
  52. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts +1 -1
  53. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
  54. package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts +1 -1
  55. package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts.map +1 -1
  56. package/dist/ui/components/atoms/vc-progress/vc-progress.vue.d.ts +1 -1
  57. package/dist/ui/components/atoms/vc-progress/vc-progress.vue.d.ts.map +1 -1
  58. package/dist/ui/components/molecules/vc-editor/vc-editor.vue.d.ts +2 -2
  59. package/dist/ui/components/molecules/vc-file-upload/vc-file-upload.vue.d.ts +2 -2
  60. package/dist/ui/components/molecules/vc-file-upload/vc-file-upload.vue.d.ts.map +1 -1
  61. package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts +2 -2
  62. package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts.map +1 -1
  63. package/dist/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue.d.ts +2 -0
  64. package/dist/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue.d.ts.map +1 -1
  65. package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts +1 -1
  66. package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts.map +1 -1
  67. package/dist/ui/components/molecules/vc-rating/vc-rating.vue.d.ts +1 -1
  68. package/dist/ui/components/molecules/vc-rating/vc-rating.vue.d.ts.map +1 -1
  69. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue.d.ts +1 -1
  70. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue.d.ts.map +1 -1
  71. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  72. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-base-button.vue.d.ts +1 -1
  73. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue.d.ts +1 -1
  74. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue.d.ts.map +1 -1
  75. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-circle-button.vue.d.ts +1 -1
  76. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-circle-button.vue.d.ts.map +1 -1
  77. package/dist/ui/components/organisms/vc-blade/vc-blade.backupsb.d.ts +3 -3
  78. package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts +1 -1
  79. package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
  80. package/dist/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue.d.ts.map +1 -1
  81. package/dist/ui/components/organisms/vc-gallery/_internal/vc-gallery-item/vc-gallery-item.vue.d.ts +2 -2
  82. package/dist/ui/components/organisms/vc-gallery/_internal/vc-gallery-preview/vc-gallery-preview.vue.d.ts +1 -1
  83. package/dist/ui/components/organisms/vc-gallery/_internal/vc-gallery-preview/vc-gallery-preview.vue.d.ts.map +1 -1
  84. package/dist/ui/components/organisms/vc-gallery/vc-gallery.vue.d.ts +3 -3
  85. package/dist/ui/components/organisms/vc-gallery/vc-gallery.vue.d.ts.map +1 -1
  86. package/dist/ui/components/organisms/vc-popup/vc-popup.vue.d.ts +1 -1
  87. package/dist/ui/components/organisms/vc-popup/vc-popup.vue.d.ts.map +1 -1
  88. package/dist/ui/components/organisms/vc-table/_internal/vc-table-counter/vc-table-counter.vue.d.ts +1 -1
  89. package/dist/ui/components/organisms/vc-table/_internal/vc-table-counter/vc-table-counter.vue.d.ts.map +1 -1
  90. package/package.json +4 -4
  91. package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +199 -597
  92. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.ts +151 -0
  93. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.ts +243 -0
  94. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.ts +93 -0
  95. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeWatchers.ts +90 -0
  96. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.ts +150 -0
  97. package/shared/components/blade-navigation/plugin.ts +17 -12
  98. package/shared/components/blade-navigation/types/index.ts +2 -4
  99. package/shared/components/notification-template/notification-template.vue +2 -2
  100. package/shared/modules/dynamic/index.ts +2 -8
  101. package/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.vue +4 -0
  102. package/ui/components/organisms/vc-app/vc-app.vue +11 -6
  103. package/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue +10 -1
  104. package/dist/apl-B2DGVGxc.js +0 -76
  105. package/dist/asciiarmor-2LVJmxlE.js +0 -34
  106. package/dist/asn1-jKiBa2Ya.js +0 -95
  107. package/dist/asterisk-DS281yxp.js +0 -271
  108. package/dist/brainfuck-C_p9pTT8.js +0 -34
  109. package/dist/clike-DGTaUp48.js +0 -620
  110. package/dist/clojure-CCKyeQKf.js +0 -800
  111. package/dist/cmake-CuaCgAKt.js +0 -28
  112. package/dist/cobol-BlTKFDRj.js +0 -72
  113. package/dist/coffeescript-BVCvwO8I.js +0 -179
  114. package/dist/commonlisp-D_kxz07b.js +0 -75
  115. package/dist/crystal-D309uH6_.js +0 -217
  116. package/dist/css-BkF-NPzE.js +0 -1553
  117. package/dist/cypher-BMq4Fwjl.js +0 -68
  118. package/dist/d-BZcgY6La.js +0 -127
  119. package/dist/diff-Cg9d_RX2.js +0 -18
  120. package/dist/dockerfile-DIy8NleC.js +0 -194
  121. package/dist/dtd-CtLokQ-U.js +0 -84
  122. package/dist/dylan-QYeExnWK.js +0 -234
  123. package/dist/ebnf-DUPDuY4r.js +0 -78
  124. package/dist/ecl-CiXN-g_D.js +0 -121
  125. package/dist/eiffel-yQhjl4T1.js +0 -110
  126. package/dist/elm-CNT9vbN0.js +0 -108
  127. package/dist/erlang-CFOYdy9e.js +0 -487
  128. package/dist/factor-DDOC7X6P.js +0 -65
  129. package/dist/fcl-CPC2WYrI.js +0 -103
  130. package/dist/forth-BmxRyE9S.js +0 -60
  131. package/dist/fortran-9bvPyrOW.js +0 -442
  132. package/dist/framework.js +0 -290
  133. package/dist/gas-cpmYfFX2.js +0 -183
  134. package/dist/gherkin-CJuwpceU.js +0 -34
  135. package/dist/groovy-DZeT_VM-.js +0 -146
  136. package/dist/haskell-Bvt3Qq1t.js +0 -375
  137. package/dist/haxe-70NVW1pR.js +0 -359
  138. package/dist/http-D9LttvKF.js +0 -44
  139. package/dist/idl-B6TRFYjl.js +0 -947
  140. package/dist/index-0xMdBsaq.js +0 -611
  141. package/dist/index-B6RKUVy8.js +0 -134
  142. package/dist/index-BXAxQnpt.js +0 -71
  143. package/dist/index-Ba3wq-Du.js +0 -147479
  144. package/dist/index-BgMVbUF5.js +0 -249
  145. package/dist/index-CE1KKIYQ.js +0 -268
  146. package/dist/index-CSMBCpee.js +0 -75
  147. package/dist/index-DCiQjA10.js +0 -58
  148. package/dist/index-DLIwas3l.js +0 -93
  149. package/dist/index-DwOkUUXE.js +0 -288
  150. package/dist/index-DwsB54rD.js +0 -308
  151. package/dist/index-Dyg1bSFn.js +0 -341
  152. package/dist/index-GpoS3tMh.js +0 -137
  153. package/dist/index-J_8wNmd3.js +0 -98
  154. package/dist/index-VLNTEhMQ.js +0 -156
  155. package/dist/index-WZKioztF.js +0 -299
  156. package/dist/index-_7O686wp.js +0 -538
  157. package/dist/index.css +0 -9
  158. package/dist/javascript-C2yteZeJ.js +0 -691
  159. package/dist/jinja2-DnB6dQmV.js +0 -154
  160. package/dist/julia-DpvXAuO6.js +0 -241
  161. package/dist/livescript-CanGTf8u.js +0 -272
  162. package/dist/lua-XplVlWi_.js +0 -217
  163. package/dist/mathematica-jaRHnSxC.js +0 -35
  164. package/dist/mbox-BctzC1hL.js +0 -76
  165. package/dist/mirc-CFBPAOaF.js +0 -72
  166. package/dist/mllike-BSnXJBGA.js +0 -272
  167. package/dist/modelica-vUgVs--1.js +0 -93
  168. package/dist/mscgen-Cpl0NYLN.js +0 -104
  169. package/dist/mumps-CQoS1kWX.js +0 -25
  170. package/dist/nginx-zDPm3Z74.js +0 -89
  171. package/dist/nsis-fePjrhq7.js +0 -62
  172. package/dist/ntriples-CsNjv2QF.js +0 -79
  173. package/dist/octave-C8PmmSRH.js +0 -143
  174. package/dist/oz-Ce8aN8oE.js +0 -151
  175. package/dist/pascal-De0D6mP7.js +0 -77
  176. package/dist/perl-B4bSCe1C.js +0 -915
  177. package/dist/pig-D24Z8EXi.js +0 -54
  178. package/dist/powershell-DkYVfTzP.js +0 -249
  179. package/dist/properties-Dn9wna3M.js +0 -26
  180. package/dist/protobuf-BPIjwpzm.js +0 -49
  181. package/dist/pug-CwAQJzGR.js +0 -248
  182. package/dist/puppet-nyd4dhjf.js +0 -45
  183. package/dist/python-BkR3uSy8.js +0 -313
  184. package/dist/q-DXjKs-tC.js +0 -83
  185. package/dist/r-LKEuhEGI.js +0 -104
  186. package/dist/rpm-IznJm2Xc.js +0 -57
  187. package/dist/ruby-CcYfvIk6.js +0 -228
  188. package/dist/sas-7E8yHoCW.js +0 -105
  189. package/dist/scheme-DjibxsNh.js +0 -124
  190. package/dist/shared/modules/dynamic/components/fields/storybook/pages/DynamicRender.d.ts +0 -110
  191. package/dist/shared/modules/dynamic/components/fields/storybook/pages/DynamicRender.d.ts.map +0 -1
  192. package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts +0 -147
  193. package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts.map +0 -1
  194. package/dist/shell-C0C2sNA_.js +0 -182
  195. package/dist/sieve-Bwz7vjP5.js +0 -72
  196. package/dist/simple-mode-B0dvCdAA.js +0 -89
  197. package/dist/smalltalk-Bhddl2pB.js +0 -48
  198. package/dist/solr-BNlsLglM.js +0 -41
  199. package/dist/sparql-FarWu_Gb.js +0 -197
  200. package/dist/spreadsheet-C-cy4P5N.js +0 -49
  201. package/dist/sql-CfG5lQ3l.js +0 -282
  202. package/dist/stex-Du4h4KAU.js +0 -129
  203. package/dist/stylus-CAdqWld3.js +0 -250
  204. package/dist/swift-DSxqR9R6.js +0 -230
  205. package/dist/tcl-xfoLljhY.js +0 -81
  206. package/dist/textile-D1AWE-pc.js +0 -295
  207. package/dist/tiddlywiki-5wqsXtSk.js +0 -155
  208. package/dist/tiki-__Kn3CeS.js +0 -181
  209. package/dist/toml-BHiuTcfn.js +0 -49
  210. package/dist/troff-D2UO-fKf.js +0 -35
  211. package/dist/ttcn-Bsa4sfRm.js +0 -123
  212. package/dist/ttcn-cfg-Bac_acMi.js +0 -88
  213. package/dist/turtle-xwJUxoPV.js +0 -80
  214. package/dist/vb-c2kQGd6-.js +0 -74
  215. package/dist/vbscript-1f_Dhg5H.js +0 -324
  216. package/dist/velocity-DJd0pTTC.js +0 -96
  217. package/dist/verilog-CiS1jyi5.js +0 -262
  218. package/dist/vhdl-T9HkrbI2.js +0 -106
  219. package/dist/webidl-CjfDENEo.js +0 -155
  220. package/dist/xquery-BUQdORAS.js +0 -422
  221. package/dist/yacas-C0absKBh.js +0 -73
  222. package/dist/z80-Pki2zAjW.js +0 -61
@@ -1,19 +1,10 @@
1
- import { computed, getCurrentInstance, inject, warn, Component, isVNode, h, shallowRef, ComputedRef, watch } from "vue";
1
+ import { computed, getCurrentInstance, inject, warn, Component, ComputedRef } from "vue";
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
- import { createSharedComposable, reactifyObject, reactiveComputed, toValue, watchDebounced } from "@vueuse/core";
3
+ import { createSharedComposable } from "@vueuse/core";
4
4
  import * as _ from "lodash-es";
5
- import {
6
- RouteLocationNormalized,
7
- useRoute,
8
- NavigationFailure,
9
- RouteRecordName,
10
- RouteParams,
11
- Router,
12
- LocationQuery,
13
- RouteParamsGeneric,
14
- RouteRecordNameGeneric,
15
- } from "vue-router";
16
- import { bladeNavigationInstance } from "../../plugin";
5
+ import { RouteLocationNormalized, useRoute, NavigationFailure, RouteLocationRaw } from "vue-router";
6
+ import { bladeNavigationInstance as globalBladeNavigationPluginInstanceFallback } from "../../plugin";
7
+ import { useBladeRegistry, IBladeRegistry } from "../../../../../core/composables/useBladeRegistry";
17
8
  import {
18
9
  BladeComponentInternalInstance,
19
10
  BladeNavigationPlugin,
@@ -21,646 +12,257 @@ import {
21
12
  IBladeEvent,
22
13
  IParentCallArgs,
23
14
  BladeInstanceConstructor,
24
- BladeRoutesRecord,
25
- ExtractedBladeOptions,
15
+ CoreBladeAdditionalSettings,
26
16
  } from "../../types";
27
17
  import { navigationViewLocation } from "../../../../../injection-keys";
28
18
  import { useAppInsights, usePermissions } from "../../../../../core/composables";
29
- import { notification } from "./../../../notifications";
19
+ import { notification as notificationService } from "./../../../notifications";
30
20
  import "core-js/actual/array/find-last";
31
21
  import "core-js/actual/array/find-last-index";
32
22
  import { i18n } from "../../../../../core/plugins/i18n";
33
23
 
24
+ // Internal modules
25
+ import { _createBladeStateManagement } from "./internal/bladeState";
26
+ import { _createRouterUtils } from "./internal/routerUtils";
27
+ import { _createBladeActions } from "./internal/bladeActions";
28
+ import { _createBladeRouteResolver } from "./internal/bladeRouteResolver";
29
+ import { _createBladeWatchers } from "./internal/bladeWatchers";
30
+
34
31
  interface IUseBladeNavigation {
35
32
  readonly blades: ComputedRef<BladeVNode[]>;
36
- readonly currentBladeNavigationData: ComputedRef<BladeVNode["props"]["navigation"]>;
33
+ readonly activeWorkspace: ComputedRef<BladeVNode | undefined>;
34
+ readonly currentBladeNavigationData: ComputedRef<BladeVNode["props"]["navigation"] | undefined>;
37
35
  openBlade: <Blade extends Component>(
38
- { blade, param, options, onOpen, onClose, replaceCurrentBlade }: IBladeEvent<Blade>,
36
+ args: IBladeEvent<Blade>,
39
37
  isWorkspace?: boolean,
40
38
  ) => Promise<void | NavigationFailure>;
41
39
  closeBlade: (index: number) => Promise<boolean>;
42
- goToRoot: () => {
43
- name: RouteRecordNameGeneric;
44
- params: RouteParamsGeneric;
45
- };
40
+ goToRoot: () => RouteLocationRaw;
46
41
  onParentCall: (parentExposedMethods: Record<string, any>, args: IParentCallArgs) => void;
47
42
  onBeforeClose: (cb: () => Promise<boolean | undefined>) => void;
48
- resolveBladeByName: (name: string) => BladeInstanceConstructor;
49
- routeResolver: (to: RouteLocationNormalized) =>
50
- | Promise<
51
- | {
52
- name: RouteRecordName | undefined;
53
- params: RouteParams;
54
- }
55
- | undefined
56
- >
57
- | undefined;
43
+ resolveBladeByName: (name: string) => BladeInstanceConstructor | undefined;
44
+ routeResolver: (to: RouteLocationNormalized) => Promise<RouteLocationRaw | undefined> | RouteLocationRaw | undefined;
58
45
  setNavigationQuery: (query: Record<string, string | number>) => void;
59
46
  getNavigationQuery: () => Record<string, string | number> | undefined;
60
47
  }
61
48
 
62
- const activeWorkspace = shallowRef<BladeVNode>();
63
- const mainRouteBaseParamURL = shallowRef<string>();
64
-
65
- const utils = (router: Router) => {
66
- const route = useRoute();
67
- const routes = router.getRoutes();
68
-
69
- function parseUrl(url: string) {
70
- // remove parts of url that does not contain workspace, blade or param - everything before workspace
71
- const parts = url.split("/");
72
- const workspaceIndex = parts.findIndex((part) => {
73
- const route = routes.find(
74
- (r) => r.path.endsWith("/" + part) && (r.components?.default as BladeVNode)?.type?.isWorkspace,
75
- );
76
-
77
- return route !== undefined;
78
- });
79
- const cleanUrl = "/" + parts.slice(workspaceIndex).join("/");
80
-
81
- const urlRegex = /^\/([a-zA-Z0-9_-]+)(?:\/([a-zA-Z0-9_-]+))?(?:\/([a-zA-Z0-9_-]+))?$/;
82
- const match = cleanUrl.match(urlRegex);
83
-
84
- if (!match) {
85
- return undefined;
86
- }
87
-
88
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
89
- const [_, workspace, blade, param] = match;
90
-
91
- return {
92
- workspace,
93
- blade: blade || undefined,
94
- param: param || undefined,
95
- };
96
- }
97
-
98
- function parseWorkspaceUrl(path: string): string {
99
- // Object.values(route.params)[0] will always be base path of the app
100
- mainRouteBaseParamURL.value = "/" + (Object.values(route.params)?.[0] ?? "");
101
-
102
- const pathWithoutBase = path.startsWith(mainRouteBaseParamURL.value)
103
- ? path.slice(mainRouteBaseParamURL.value.length)
104
- : path;
105
- const segments = pathWithoutBase.split("/").filter(Boolean);
106
- const workspaceUrl = segments.slice(0, 1).join("/");
107
- return "/" + workspaceUrl;
108
- }
109
-
110
- function getURLQuery() {
111
- if (route.query && Object.keys(route.query).length) {
112
- return {
113
- params: new URLSearchParams(route.query as Record<string, string>).toString(),
114
- obj: route.query,
115
- };
116
- }
117
-
118
- const [, query] = window.location.href.split("#")[1].split("?");
119
- const params = new URLSearchParams(query).toString();
120
-
121
- return { params, obj: Object.fromEntries(new URLSearchParams(query)) };
122
- }
123
-
124
- return {
125
- parseUrl,
126
- parseWorkspaceUrl,
127
- getURLQuery,
128
- routes,
129
- };
130
- };
131
-
49
+ // --- Singleton for useBladeNavigation ---
132
50
  const useBladeNavigationSingleton = createSharedComposable(() => {
133
51
  const route = useRoute();
134
- const { setupPageTracking } = useAppInsights();
135
-
136
- const instance = getCurrentInstance() as BladeComponentInternalInstance;
137
- const navigationInstance =
138
- (instance !== null && inject<BladeNavigationPlugin>("bladeNavigationPlugin")) || bladeNavigationInstance;
139
- const router = navigationInstance?.router;
140
-
141
- const { parseUrl, parseWorkspaceUrl, getURLQuery } = utils(router);
142
-
143
- watch(
144
- () => route.path,
145
- async (newVal, oldVal) => {
146
- const workspaceUrl = parseWorkspaceUrl(newVal);
147
-
148
- const wsRouteComponent = getWorkspaceRouteComponent(workspaceUrl);
149
-
150
- if (wsRouteComponent !== undefined) {
151
- if (isVNode(wsRouteComponent) && wsRouteComponent.type.isBlade) {
152
- updateActiveWorkspace(wsRouteComponent);
153
- } else {
154
- await handleNonBladePage(oldVal);
155
- }
156
- }
157
- },
158
- { immediate: true },
159
- );
160
-
161
- async function handleNonBladePage(oldVal?: string) {
162
- const isPrevented = await closeBlade(0);
163
- if (!isPrevented) {
164
- navigationInstance.blades.value = [];
165
- activeWorkspace.value = undefined;
166
- } else {
167
- if (oldVal) router.push({ path: oldVal });
168
- }
169
- }
170
-
171
- function updateActiveWorkspace(wsRouteComponent: BladeVNode) {
172
- if (wsRouteComponent.props?.navigation) {
173
- wsRouteComponent.props.navigation.idx = 0;
174
- }
175
- navigationInstance.blades.value[0] = wsRouteComponent;
176
- activeWorkspace.value = wsRouteComponent;
177
- closeBlade(1);
178
- }
179
-
180
- function getWorkspaceRouteComponent(workspaceUrl: string) {
181
- return (
182
- (route?.matched?.[1]?.components?.default as BladeVNode) ??
183
- (router.resolve({ path: workspaceUrl })?.matched?.[1]?.components?.default as BladeVNode)
184
- );
185
- }
52
+ const injectedPlugin = inject<BladeNavigationPlugin>("bladeNavigationPlugin");
53
+ const router = injectedPlugin?.router || globalBladeNavigationPluginInstanceFallback.router;
186
54
 
187
- watchDebounced(
188
- navigationInstance.blades,
189
- async (newVal) => {
190
- const workspace = navigationInstance.blades.value[0];
191
- const lastBlade = getLastItemWithUrl(newVal);
192
-
193
- if (workspace?.type?.url) {
194
- const url = constructUrl(workspace, lastBlade);
195
- if (url) {
196
- updateRouterHistory(url, lastBlade?.type.name);
197
- }
198
- }
199
- },
200
- { deep: true, debounce: 1 },
201
- );
202
-
203
- function getLastItemWithUrl(newVal: BladeVNode[]) {
204
- for (let i = newVal.length - 1; i > 0; i--) {
205
- if (newVal[i].type.url) {
206
- return newVal[i];
207
- }
208
- }
55
+ if (!router) {
56
+ throw new Error("[@vc-shell/framework#useBladeNavigation] Vue Router instance is not available.");
209
57
  }
210
58
 
211
- function constructUrl(workspace: BladeVNode, lastBlade?: BladeVNode) {
212
- const wsBladeUrl = workspace?.type.url;
213
- const lastBladeUrl = lastBlade?.type.url;
214
- const param = lastBlade?.props?.param;
215
- const parsedWorkspaceUrl = parseUrl(wsBladeUrl || "")?.workspace;
216
-
217
- if (lastBlade && wsBladeUrl && parsedWorkspaceUrl) {
218
- return "/" + parsedWorkspaceUrl + lastBladeUrl + (param ? "/" + param : "");
219
- } else {
220
- return wsBladeUrl;
221
- }
222
- }
59
+ const bladeRegistry: IBladeRegistry = useBladeRegistry();
223
60
 
224
- function updateRouterHistory(url: string, name?: string) {
225
- const params = getURLQuery().params;
61
+ // Base modules initialization
62
+ const bladeState = _createBladeStateManagement(router);
63
+ const routerUtils = _createRouterUtils(router, route);
226
64
 
227
- const fullUrl =
228
- (mainRouteBaseParamURL.value && !url.startsWith(mainRouteBaseParamURL.value) ? mainRouteBaseParamURL.value : "") +
229
- url +
230
- (params ? "?" + params : "");
231
-
232
- router.options.history.replace(fullUrl);
233
-
234
- if (name) {
235
- setupPageTracking.afterEach({ name: name, fullPath: fullUrl });
236
- }
237
- }
238
-
239
- async function closeBlade(index: number) {
240
- console.debug(`[@vc-shell/framework#useBladeNavigation] - closeBlade called.`);
65
+ const { setupPageTracking } = useAppInsights();
66
+ const { hasAccess } = usePermissions();
67
+ const currentInstance = getCurrentInstance() as BladeComponentInternalInstance | null;
241
68
 
242
- if (navigationInstance.blades.value.length === 0) {
243
- return false;
69
+ function ensureBladeComponent<Blade extends Component>(
70
+ bladeInput: BladeInstanceConstructor<Blade> | { name: string } | null | undefined,
71
+ ): BladeInstanceConstructor<Blade> {
72
+ if (!bladeInput) {
73
+ throw new Error("ensureBladeComponent: bladeInput cannot be null or undefined.");
244
74
  }
245
-
246
- try {
247
- const children = navigationInstance.blades.value.slice(index).reverse();
248
- let isPrevented = false;
249
- for (let i = 0; i < children.length; i++) {
250
- const element = children[i];
251
-
252
- if (element.props?.navigation?.onBeforeClose) {
253
- const result = await element.props.navigation.onBeforeClose();
254
-
255
- if (result === false) {
256
- isPrevented = true;
257
- console.debug(`[@vc-shell/framework#useBladeNavigation] - Navigation is prevented`);
258
- }
259
- // we use break here to prevent running onBeforeClose for all children, cause it can be prevented by first child
260
- break;
261
- }
75
+ if (typeof bladeInput === "object" && "name" in bladeInput) {
76
+ if (!bladeInput.name) {
77
+ throw new Error("ensureBladeComponent: bladeInput.name cannot be empty when resolving by name.");
262
78
  }
263
-
264
- if (!isPrevented) {
265
- const prevBlade = navigationInstance.blades.value[index - 1];
266
-
267
- if (index > 0 && prevBlade?.props?.navigation?.isVisible === false) {
268
- prevBlade.props.navigation.isVisible = true;
269
- }
270
-
271
- // Clear param of table blade when closing child blade to prevent table row selection from being preserved
272
- if (
273
- prevBlade &&
274
- prevBlade.props.navigation.idx === 0 &&
275
- toValue(prevBlade.props?.param) === toValue(navigationInstance.blades.value[index]?.props?.param)
276
- ) {
277
- prevBlade.props.param = undefined;
278
- }
279
-
280
- navigationInstance.blades.value.splice(index);
79
+ const resolvedComponent = bladeRegistry.getBladeComponent(bladeInput.name);
80
+ if (!resolvedComponent) {
81
+ throw new Error(
82
+ `ensureBladeComponent: Failed to resolve blade by name '${bladeInput.name}' via BladeRegistry. Blade component not registered or plugin issue.`,
83
+ );
281
84
  }
282
-
283
- return isPrevented;
284
- } finally {
285
- console.debug(`[@vc-shell/framework#useBladeNavigation] - closeBlade finished.`);
85
+ return resolvedComponent as BladeInstanceConstructor<Blade>;
286
86
  }
87
+ return bladeInput as BladeInstanceConstructor<Blade>;
287
88
  }
288
89
 
289
- return {
290
- navigationInstance,
90
+ const bladeActions = _createBladeActions(
291
91
  router,
292
92
  route,
293
- closeBlade,
93
+ bladeState,
94
+ routerUtils,
95
+ ensureBladeComponent,
96
+ hasAccess,
97
+ notificationService,
98
+ i18n,
294
99
  setupPageTracking,
295
- };
296
- });
297
-
298
- export function useBladeNavigation(): IUseBladeNavigation {
299
- const navigationView = inject(navigationViewLocation, undefined) as BladeVNode;
300
-
301
- const { hasAccess } = usePermissions();
302
-
303
- const instance = getCurrentInstance() as BladeComponentInternalInstance;
304
-
305
- const { router, route, navigationInstance, closeBlade, setupPageTracking } = useBladeNavigationSingleton();
306
-
307
- const { parseUrl, getURLQuery, routes: routerRoutes } = utils(router);
308
- const mainRoute = routerRoutes.find((r) => r.meta?.root);
309
- if (!mainRoute) {
310
- throw new Error("Main route not found");
311
- }
312
-
313
- async function openWorkspace<Blade extends Component>(
314
- { blade, param, options }: IBladeEvent<Blade>,
315
- query: LocationQuery | undefined = undefined,
316
- params: RouteParams = {},
317
- replace = false,
318
- ) {
319
- const createdComponent = h(
320
- blade,
321
- reactifyObject({
322
- // param: computed(() => {
323
- // const isChildWithSameParamOpened = navigationInstance.blades.value.some(
324
- // (x) => x.props?.param === toValue(param),
325
- // );
326
- // if (isChildWithSameParamOpened) {
327
- // return toValue(param);
328
- // }
329
- // return undefined;
330
- // }) as unknown as string,
331
- param,
332
- options,
333
- navigation: {
334
- idx: 0,
335
- },
336
- }),
337
- ) as BladeVNode;
100
+ );
338
101
 
339
- try {
340
- const isPrevented = await closeBlade(0);
102
+ const routeResolverInstance = _createBladeRouteResolver(
103
+ router,
104
+ route,
105
+ bladeRegistry,
106
+ routerUtils,
107
+ bladeActions,
108
+ bladeState,
109
+ ensureBladeComponent,
110
+ hasAccess,
111
+ );
341
112
 
342
- if (!isPrevented && createdComponent.type?.url) {
343
- if (hasAccess(blade.permissions)) {
344
- if (
345
- hasAccess(blade.permissions) &&
346
- navigationInstance.blades.value.length > 0 &&
347
- navigationInstance.blades.value[0].type.url === createdComponent.type.url
348
- ) {
349
- return;
350
- }
351
- navigationInstance.blades.value = [createdComponent];
352
- // Find the route with the matching URL and update the components.default property with the new component
353
- const wsroute = routerRoutes.find((r) => r.path.endsWith(createdComponent.type?.url as string));
354
- if (wsroute && wsroute.components) {
355
- wsroute.components.default = createdComponent;
356
- }
113
+ _createBladeWatchers(router, route, bladeState, routerUtils, setupPageTracking);
357
114
 
358
- return await router.push({
359
- name: wsroute?.name,
360
- params: { ...params, ...route.params },
361
- query,
362
- replace,
363
- });
364
- } else {
365
- notification.error(i18n.global.t("PERMISSION_MESSAGES.ACCESS_RESTRICTED"), {
366
- timeout: 3000,
367
- });
368
- }
115
+ return {
116
+ blades: bladeState.blades,
117
+ activeWorkspace: bladeState.activeWorkspace,
118
+ _internal_openBlade: bladeActions.openBlade,
119
+ closeBlade: bladeState.removeBladesStartingFrom,
120
+ goToRoot: routerUtils.goToRoot,
121
+ routeResolver: routeResolverInstance,
122
+ onParentCall: async (parentExposedMethods: Record<string, any>, args: IParentCallArgs) => {
123
+ if (args.method && parentExposedMethods && typeof parentExposedMethods[args.method] === "function") {
124
+ const method = parentExposedMethods[args.method];
125
+ const result = await method(args.args);
126
+ if (typeof args.callback === "function") args.callback(result);
127
+ } else {
128
+ console.error(
129
+ `No such method: ${args.method}. Please, add method with name ${args.method} and use defineExpose to expose it in parent blade`,
130
+ );
369
131
  }
370
- } catch (e) {
371
- console.error(e);
372
- throw new Error(`Opening workspace '${blade?.type?.name || "Unknown"}' is prevented`);
373
- }
374
- }
375
-
376
- async function openBlade<Blade extends Component>(
377
- { blade, param, options, onOpen, onClose, replaceCurrentBlade = false }: IBladeEvent<Blade>,
378
- isWorkspace = false,
379
- ) {
380
- if (!blade) {
381
- throw new Error("You should pass blade component as openBlade argument");
382
- }
383
-
384
- if (isWorkspace) {
385
- return await openWorkspace({ blade, param, options });
386
- }
387
-
388
- try {
389
- const instanceComponent = navigationView || activeWorkspace.value;
390
-
391
- if (!(isVNode(instanceComponent) || activeWorkspace.value)) {
392
- throw new Error("No workspace found");
132
+ },
133
+ onBeforeClose: (cb: () => Promise<boolean | undefined>) => {
134
+ const targetBlade = bladeState.activeWorkspace.value;
135
+ if (targetBlade && targetBlade.props.navigation) {
136
+ targetBlade.props.navigation.onBeforeClose = cb;
137
+ } else {
138
+ warn("Singleton onBeforeClose: Could not identify a target blade (e.g., active workspace).");
393
139
  }
394
-
395
- const instanceComponentIndex = findInstanceComponentIndex(instanceComponent);
396
- const instanceComponentChild =
397
- instanceComponentIndex >= 0 ? navigationInstance.blades.value[instanceComponentIndex + 1] : undefined;
398
-
399
- let isPrevented = false;
400
-
401
- if (instanceComponentChild) {
402
- isPrevented = await closeBlade(instanceComponentChild.props?.navigation?.idx);
140
+ },
141
+ setNavigationQuery: (query: Record<string, string | number>) => {
142
+ if (!currentInstance) {
143
+ warn("Singleton's setNavigationQuery called in a context without a component instance.");
144
+ return;
403
145
  }
404
-
405
- const currentBladeIdx = instanceComponent.props?.navigation?.idx ?? 0;
406
-
407
- const bladeNode = createBladeNode<Blade>({
408
- blade,
409
- currentBladeIdx,
410
- options,
411
- param,
412
- onClose,
413
- onOpen,
414
- });
415
-
416
- if (!isPrevented) {
417
- if (hasAccess(blade.permissions)) {
418
- if (replaceCurrentBlade) {
419
- navigationInstance.blades.value[currentBladeIdx].props.navigation.isVisible = false;
420
- }
421
- setupPageTracking.beforeEach({ name: bladeNode.type.name! });
422
- navigationInstance.blades.value.push(bladeNode);
423
- } else {
424
- notification.error(i18n.global.t("PERMISSION_MESSAGES.ACCESS_RESTRICTED"), { timeout: 3000 });
425
- }
146
+ const typeName = (currentInstance.vnode.type as CoreBladeAdditionalSettings).name?.toLowerCase();
147
+ if (
148
+ typeName &&
149
+ bladeState.activeWorkspace.value &&
150
+ bladeState.activeWorkspace.value.props.navigation?.idx === 0
151
+ ) {
152
+ const namedQuery = _.mapKeys(_.mapValues(query, String), (v, k) => `${typeName}_${k}`);
153
+ const cleanQuery = _.omitBy(namedQuery, _.isNil);
154
+ router.options.history.replace(
155
+ decodeURIComponent(
156
+ `${window.location.hash.substring(1).split("?")[0]}?${new URLSearchParams(cleanQuery).toString()}`,
157
+ ),
158
+ );
426
159
  }
427
- } catch (e) {
428
- console.error(e);
429
- }
430
- }
431
-
432
- function findInstanceComponentIndex(instanceComponent: BladeVNode) {
433
- return _.findLastIndex(navigationInstance.blades.value, (x) => _.isEqual(x.type, instanceComponent.type));
434
- }
435
-
436
- function createBladeNode<Blade extends Component>(args: {
437
- blade: BladeInstanceConstructor<Blade>;
438
- currentBladeIdx: number;
439
- options: ExtractedBladeOptions<InstanceType<BladeInstanceConstructor<Blade>>["$props"], "options"> | undefined;
440
- param?: string;
441
- onClose?: () => void;
442
- onOpen?: () => void;
443
- }) {
444
- const { blade, currentBladeIdx, options, param, onClose, onOpen } = args;
445
- return h(
446
- blade,
447
- Object.assign(
448
- {},
449
- reactiveComputed(() => ({ options, param })),
450
- {
451
- navigation: {
452
- onClose,
453
- onOpen,
454
- idx: currentBladeIdx + 1,
455
- },
456
- },
457
- ),
458
- ) as BladeVNode;
459
- }
460
-
461
- async function onParentCall(parentExposedMethods: Record<string, any>, args: IParentCallArgs) {
462
- console.debug(`vc-app#onParentCall({ method: ${args.method} }) called.`);
463
-
464
- if (args.method && parentExposedMethods && typeof parentExposedMethods[args.method] === "function") {
465
- const method = parentExposedMethods[args.method];
466
- const result = await method(args.args);
467
-
468
- if (typeof args.callback === "function") {
469
- args.callback(result);
160
+ },
161
+ getNavigationQuery: () => {
162
+ if (!currentInstance) {
163
+ warn("Singleton's getNavigationQuery called in a context without a component instance.");
164
+ return undefined;
470
165
  }
471
- } else {
472
- console.error(
473
- `No such method: ${args.method}. Please, add method with name ${args.method} and use defineExpose to expose it in parent blade`,
474
- );
475
- }
476
- }
477
-
478
- function resolveBladeByName(name: string): BladeInstanceConstructor {
479
- if (!instance) {
480
- warn("resolveComponentByName can only be used in setup().");
166
+ const typeName = (currentInstance.vnode.type as CoreBladeAdditionalSettings).name?.toLowerCase();
167
+ if (
168
+ typeName &&
169
+ bladeState.activeWorkspace.value &&
170
+ bladeState.activeWorkspace.value.props.navigation?.idx === 0
171
+ ) {
172
+ const queryKeys = Object.keys(route.query);
173
+ const bladeQueryKeys = queryKeys.filter((key) => key.startsWith(typeName));
174
+ const namedQuery = _.mapKeys(_.pick(route.query, bladeQueryKeys), (v, k) => k.replace(`${typeName}_`, ""));
175
+
176
+ const result: Record<string, string | number> = {};
177
+ for (const [key, value] of Object.entries(namedQuery)) {
178
+ const numValue = Number(value);
179
+ result[key] = isNaN(numValue) ? (value as string) : numValue;
180
+ }
181
+ return result;
182
+ }
183
+ return undefined;
184
+ },
185
+ currentBladeNavigationData: computed(() => {
186
+ return bladeState.activeWorkspace.value?.props?.navigation ?? undefined;
187
+ }),
188
+ };
189
+ });
481
190
 
482
- return null as unknown as BladeInstanceConstructor;
191
+ export function useBladeNavigation(): IUseBladeNavigation {
192
+ const singleton = useBladeNavigationSingleton() as typeof useBladeNavigationSingleton extends () => infer R
193
+ ? R
194
+ : never;
195
+ const currentCallingInstance = getCurrentInstance() as BladeComponentInternalInstance | null;
196
+ const bladeRegistry = useBladeRegistry();
197
+
198
+ const currentBladeNavigationData = computed(() => {
199
+ if (!currentCallingInstance) return undefined;
200
+ const viewNode = (currentCallingInstance as any).provides[navigationViewLocation as any] as BladeVNode | undefined;
201
+ if (
202
+ !viewNode &&
203
+ singleton.activeWorkspace.value &&
204
+ currentCallingInstance.vnode &&
205
+ _.isEqual(currentCallingInstance.vnode.type, singleton.activeWorkspace.value.type)
206
+ ) {
207
+ return singleton.activeWorkspace.value.props?.navigation;
483
208
  }
209
+ return viewNode?.props?.navigation;
210
+ });
484
211
 
485
- if (!name) {
486
- throw new Error("Blade name is required.");
212
+ const onBeforeClose = (cb: () => Promise<boolean | undefined>) => {
213
+ if (!currentCallingInstance) {
214
+ warn("onBeforeClose called outside of a component setup context.");
215
+ return;
487
216
  }
488
-
489
- const components = instance?.appContext.components;
490
- if (components[name]) {
491
- return components[name] as BladeInstanceConstructor;
217
+ const viewNode = (currentCallingInstance as any).provides[navigationViewLocation as any] as BladeVNode | undefined;
218
+ const targetBlade = singleton.blades.value.find(
219
+ (b) =>
220
+ (b && viewNode && _.isEqual(b, viewNode)) ||
221
+ (b &&
222
+ b.props?.navigation?.idx === 0 &&
223
+ currentCallingInstance.vnode &&
224
+ _.isEqual(b.type, currentCallingInstance.vnode.type)),
225
+ );
226
+ if (targetBlade && targetBlade.props.navigation) {
227
+ targetBlade.props.navigation.onBeforeClose = cb;
492
228
  } else {
493
- throw new Error(`Blade '${name}' not found.`);
494
- }
495
- }
496
-
497
- function routeResolver(to: RouteLocationNormalized) {
498
- if (!hasNecessaryRoute(to)) {
499
- return generateRoute(to, navigationInstance.internalRoutes);
229
+ warn("Context-specific onBeforeClose: Could not identify the target blade in the global list.");
500
230
  }
501
- }
502
-
503
- function hasNecessaryRoute(to: RouteLocationNormalized) {
504
- return routerRoutes.find((route) => route.path === to.path);
505
- }
506
-
507
- /**
508
- * Generates and handles navigation for dynamic routes based on the provided route information.
509
- *
510
- * Supports App component URLs with variable like '/:userId?'.
511
- * @link https://router.vuejs.org/guide/essentials/dynamic-matching.html
512
- *
513
- * @param to - The target route.
514
- * @param routes - The array of BladeRoutesRecord containing the registered routes.
515
- */
516
- async function generateRoute(to: RouteLocationNormalized, routes: BladeRoutesRecord[]) {
517
- // Extract parameters excluding "pathMatch". This is necessary if a variable is used as the App component URL, for example, /:userId?
518
- const params = Object.fromEntries(Object.entries(to.params).filter(([key]) => key !== "pathMatch"));
519
-
520
- // Get the raw path of the main route.
521
- const parentRawPath = routerRoutes.find((route) => route.name === mainRoute?.name)?.path;
522
-
523
- // Determine the parent path based on the parameters.
524
- const parentPath =
525
- parentRawPath && parentRawPath.includes(Object.keys(params)[0]) ? `/${Object.values(params)[0]}` : "";
526
-
527
- // Set the base param value.
528
- mainRouteBaseParamURL.value = parentPath;
529
-
530
- // Parse the URL to extract relevant route information.
531
- const parsedRoutes = parseUrl(parentPath !== "/" ? to.path.slice(parentPath.length) : to.path);
532
-
533
- if (parsedRoutes !== undefined) {
534
- const { workspace, blade, param } = parsedRoutes;
535
-
536
- // Find the registered route component.
537
- const registeredWorkspaceComponent = routes.find((route) => route.route === `/${workspace}`)?.component;
538
- const registeredRouteComponent = routes.find((route) => route.route === `/${blade}`)?.component;
231
+ };
539
232
 
540
- if (!hasAccess(registeredWorkspaceComponent?.type.permissions) || !registeredWorkspaceComponent) {
541
- return goToRoot();
233
+ return {
234
+ blades: singleton.blades,
235
+ activeWorkspace: singleton.activeWorkspace,
236
+ openBlade: <Blade extends Component>(
237
+ args: IBladeEvent<Blade>,
238
+ isWorkspace?: boolean,
239
+ ): Promise<void | NavigationFailure> => {
240
+ let sourceBladeInstanceForOpening: BladeVNode | undefined = undefined;
241
+ if (currentCallingInstance) {
242
+ sourceBladeInstanceForOpening = (currentCallingInstance as any).provides[navigationViewLocation as any] as
243
+ | BladeVNode
244
+ | undefined;
542
245
  }
543
246
 
544
- // Open the workspace component or workspace route.
545
- if (registeredRouteComponent?.type.isWorkspace) {
546
- await openWorkspace(
547
- {
548
- blade: registeredRouteComponent as unknown as BladeInstanceConstructor,
549
- },
550
- undefined,
551
- undefined,
552
- true,
553
- );
554
- return { name: registeredRouteComponent?.type.name, params };
247
+ if (!sourceBladeInstanceForOpening) {
248
+ sourceBladeInstanceForOpening = singleton.activeWorkspace.value;
555
249
  }
556
250
 
557
- // Open the workspace component with param or workspace route.
558
- if (registeredWorkspaceComponent) {
559
- await openWorkspace(
560
- reactifyObject({
561
- blade: registeredWorkspaceComponent as unknown as BladeInstanceConstructor,
562
- param: computed(() => {
563
- if (registeredRouteComponent?.type.moduleUid === registeredWorkspaceComponent.type.moduleUid) {
564
- return param;
565
- }
566
- return undefined;
567
- }) as unknown as string,
568
- }),
569
- getURLQuery().obj,
570
- params,
571
- true,
572
- );
573
-
574
- // Open the route if it's routable.
575
- if (
576
- registeredRouteComponent?.type.routable &&
577
- registeredWorkspaceComponent.type.moduleUid === registeredRouteComponent.type.moduleUid
578
- ) {
579
- await openBlade({
580
- blade: registeredRouteComponent as unknown as BladeInstanceConstructor,
581
- param: param,
582
- });
583
- }
584
-
585
- return { name: registeredWorkspaceComponent?.type.name, params, query: to.query };
586
- }
587
- } else {
588
- return goToRoot();
589
- }
590
- }
591
-
592
- function goToRoot() {
593
- const mainRoute = routerRoutes.find((route) => route.meta?.root);
594
- const mainRouteAlias = routerRoutes.find((route) => route.aliasOf?.path === mainRoute?.path) || mainRoute;
595
- return { name: mainRouteAlias?.name, params: route.params };
596
- }
597
-
598
- const currentBladeNavigationData = computed(() => navigationView?.props?.navigation ?? undefined);
599
-
600
- function onBeforeClose(cb: () => Promise<boolean | undefined>) {
601
- const instanceComponent = navigationView;
602
-
603
- const currentBlade = navigationInstance.blades.value.find((x: any) => _.isEqual(x, instanceComponent));
604
-
605
- if (currentBlade) {
606
- currentBlade.props.navigation.onBeforeClose = cb;
607
- }
608
- }
609
-
610
- function setNavigationQuery(query: Record<string, string | number>) {
611
- const typeName = instance.vnode.type.name?.toLowerCase();
612
- if (typeName && instance.vnode.props.navigation.idx === 0) {
613
- // add blade name to query keys
614
- const namedQuery = _.mapKeys(
615
- _.mapValues(query, (value) => value?.toString()),
616
- (value, key) => typeName + "_" + key,
617
- );
618
- const cleanQuery = _.omitBy(namedQuery, _.isNil);
619
-
620
- router.options.history.replace(
621
- decodeURIComponent(
622
- `${window.location.hash.substring(1).split("?")[0]}?${new URLSearchParams(cleanQuery).toString()}`,
623
- ),
624
- );
625
- }
626
- }
627
-
628
- function getNavigationQuery() {
629
- const typeName = instance.vnode.type.name?.toLowerCase();
630
- if (typeName && instance.vnode.props.navigation.idx === 0) {
631
- const queryKeys = Array.from(Object.keys(route.query));
632
- const bladeQueryKeys = queryKeys.filter((key) => key.startsWith(typeName));
633
-
634
- const namedQuery = _.mapKeys(_.pick(route.query, bladeQueryKeys), (value, key) =>
635
- key.replace(typeName + "_", ""),
636
- ) as Record<string, string | number>;
637
-
638
- const obj: typeof namedQuery = {};
639
- for (const [key, value] of Object.entries(namedQuery)) {
640
- const numValue = Number(value);
641
-
642
- if (!isNaN(numValue)) {
643
- obj[key] = numValue;
644
- } else {
645
- obj[key] = value;
646
- }
251
+ if (typeof singleton._internal_openBlade === "function") {
252
+ return singleton._internal_openBlade(args, isWorkspace, sourceBladeInstanceForOpening);
253
+ } else {
254
+ console.error("Internal _internal_openBlade method not found on singleton.");
255
+ return Promise.reject(new Error("Blade navigation internal error."));
647
256
  }
648
-
649
- return obj;
650
- }
651
- }
652
-
653
- return {
654
- blades: computed(() => navigationInstance.blades.value),
655
- openBlade,
656
- closeBlade,
657
- goToRoot,
658
- onParentCall,
659
- resolveBladeByName,
660
- routeResolver,
257
+ },
258
+ closeBlade: singleton.closeBlade,
259
+ goToRoot: singleton.goToRoot,
260
+ onParentCall: singleton.onParentCall,
261
+ resolveBladeByName: (name: string) => bladeRegistry.getBladeComponent(name),
262
+ routeResolver: singleton.routeResolver,
661
263
  currentBladeNavigationData,
662
264
  onBeforeClose,
663
- setNavigationQuery,
664
- getNavigationQuery,
265
+ setNavigationQuery: singleton.setNavigationQuery,
266
+ getNavigationQuery: singleton.getNavigationQuery,
665
267
  };
666
268
  }