@vc-shell/framework 1.2.2 → 1.2.3-beta.0

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 (231) hide show
  1. package/core/composables/index.ts +2 -0
  2. package/core/composables/useAssets/index.ts +72 -28
  3. package/core/composables/useAsync/index.ts +4 -1
  4. package/core/composables/useBladeRegistry/index.ts +6 -5
  5. package/core/composables/useBreadcrumbs/index.ts +4 -1
  6. package/core/composables/useErrorHandler/index.ts +4 -1
  7. package/core/composables/useFunctions/debounce.ts +0 -1
  8. package/core/composables/useFunctions/delay.ts +0 -1
  9. package/core/composables/useFunctions/index.ts +0 -1
  10. package/core/composables/useFunctions/once.ts +0 -1
  11. package/core/composables/useFunctions/sleep.ts +0 -1
  12. package/core/composables/useFunctions/throttle.ts +0 -1
  13. package/core/composables/useGlobalSearch/index.ts +3 -3
  14. package/core/composables/useMenuService/index.ts +5 -2
  15. package/core/composables/useNotifications/index.ts +5 -2
  16. package/core/composables/useTheme/index.ts +4 -1
  17. package/core/composables/useUser/index.ts +189 -20
  18. package/core/composables/useWidgets/index.ts +5 -2
  19. package/core/constants/defaults.ts +76 -0
  20. package/core/constants/index.ts +2 -0
  21. package/core/constants/ui.ts +68 -0
  22. package/core/interceptors/index.ts +5 -2
  23. package/core/plugins/ai-agent/README.md +336 -0
  24. package/core/plugins/ai-agent/components/VcAiAgentPanel.vue +125 -0
  25. package/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue +182 -0
  26. package/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue +77 -0
  27. package/core/plugins/ai-agent/components/index.ts +1 -0
  28. package/core/plugins/ai-agent/composables/index.ts +4 -0
  29. package/core/plugins/ai-agent/composables/useAiAgent.ts +231 -0
  30. package/core/plugins/ai-agent/composables/useAiAgentContext.ts +280 -0
  31. package/core/plugins/ai-agent/constants.ts +89 -0
  32. package/core/plugins/ai-agent/index.ts +91 -0
  33. package/core/plugins/ai-agent/services/ai-agent-service.ts +598 -0
  34. package/core/plugins/ai-agent/types.ts +310 -0
  35. package/core/plugins/modularity/index.ts +8 -6
  36. package/core/plugins/modularity/loader.ts +36 -33
  37. package/core/plugins/signalR/index.ts +6 -3
  38. package/core/services/app-bar-menu-service.ts +4 -1
  39. package/core/services/dashboard-service.ts +4 -1
  40. package/core/services/index.ts +2 -0
  41. package/core/services/menu-service.ts +4 -1
  42. package/core/services/settings-menu-service.ts +4 -1
  43. package/core/services/toolbar-service.ts +18 -3
  44. package/core/services/widget-service.ts +7 -4
  45. package/core/types/index.ts +3 -0
  46. package/core/types/services.ts +194 -0
  47. package/core/utilities/errorTypes.ts +126 -0
  48. package/core/utilities/index.ts +2 -0
  49. package/core/utilities/logger.ts +120 -0
  50. package/dist/core/composables/useAssets/index.d.ts.map +1 -1
  51. package/dist/core/composables/useAsync/index.d.ts.map +1 -1
  52. package/dist/core/composables/useBladeRegistry/index.d.ts.map +1 -1
  53. package/dist/core/composables/useBreadcrumbs/index.d.ts.map +1 -1
  54. package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
  55. package/dist/core/composables/useFunctions/debounce.d.ts.map +1 -1
  56. package/dist/core/composables/useFunctions/delay.d.ts.map +1 -1
  57. package/dist/core/composables/useFunctions/index.d.ts.map +1 -1
  58. package/dist/core/composables/useFunctions/once.d.ts.map +1 -1
  59. package/dist/core/composables/useFunctions/sleep.d.ts.map +1 -1
  60. package/dist/core/composables/useFunctions/throttle.d.ts.map +1 -1
  61. package/dist/core/composables/useGlobalSearch/index.d.ts.map +1 -1
  62. package/dist/core/composables/useMenuService/index.d.ts.map +1 -1
  63. package/dist/core/composables/useNotifications/index.d.ts.map +1 -1
  64. package/dist/core/composables/useTheme/index.d.ts.map +1 -1
  65. package/dist/core/composables/useUser/index.d.ts +8 -0
  66. package/dist/core/composables/useUser/index.d.ts.map +1 -1
  67. package/dist/core/composables/useWidgets/index.d.ts.map +1 -1
  68. package/dist/core/constants/defaults.d.ts +63 -0
  69. package/dist/core/constants/defaults.d.ts.map +1 -0
  70. package/dist/core/constants/index.d.ts +2 -0
  71. package/dist/core/constants/index.d.ts.map +1 -1
  72. package/dist/core/constants/ui.d.ts +50 -0
  73. package/dist/core/constants/ui.d.ts.map +1 -0
  74. package/dist/core/interceptors/index.d.ts.map +1 -1
  75. package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts +3 -0
  76. package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts.map +1 -0
  77. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts +15 -0
  78. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts.map +1 -0
  79. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts +10 -0
  80. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts.map +1 -0
  81. package/dist/core/plugins/ai-agent/components/index.d.ts +2 -0
  82. package/dist/core/plugins/ai-agent/components/index.d.ts.map +1 -0
  83. package/dist/core/plugins/ai-agent/composables/index.d.ts +4 -0
  84. package/dist/core/plugins/ai-agent/composables/index.d.ts.map +1 -0
  85. package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts +95 -0
  86. package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts.map +1 -0
  87. package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts +55 -0
  88. package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts.map +1 -0
  89. package/dist/core/plugins/ai-agent/constants.d.ts +47 -0
  90. package/dist/core/plugins/ai-agent/constants.d.ts.map +1 -0
  91. package/dist/core/plugins/ai-agent/index.d.ts +48 -0
  92. package/dist/core/plugins/ai-agent/index.d.ts.map +1 -0
  93. package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts +45 -0
  94. package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts.map +1 -0
  95. package/dist/core/plugins/ai-agent/types.d.ts +258 -0
  96. package/dist/core/plugins/ai-agent/types.d.ts.map +1 -0
  97. package/dist/core/plugins/modularity/index.d.ts.map +1 -1
  98. package/dist/core/plugins/modularity/loader.d.ts.map +1 -1
  99. package/dist/core/plugins/signalR/index.d.ts.map +1 -1
  100. package/dist/core/services/app-bar-menu-service.d.ts.map +1 -1
  101. package/dist/core/services/dashboard-service.d.ts.map +1 -1
  102. package/dist/core/services/menu-service.d.ts.map +1 -1
  103. package/dist/core/services/settings-menu-service.d.ts.map +1 -1
  104. package/dist/core/services/toolbar-service.d.ts.map +1 -1
  105. package/dist/core/services/widget-service.d.ts.map +1 -1
  106. package/dist/core/types/index.d.ts.map +1 -1
  107. package/dist/core/types/services.d.ts +169 -0
  108. package/dist/core/types/services.d.ts.map +1 -0
  109. package/dist/core/utilities/errorTypes.d.ts +61 -0
  110. package/dist/core/utilities/errorTypes.d.ts.map +1 -0
  111. package/dist/core/utilities/index.d.ts +2 -0
  112. package/dist/core/utilities/index.d.ts.map +1 -1
  113. package/dist/core/utilities/logger.d.ts +259 -0
  114. package/dist/core/utilities/logger.d.ts.map +1 -0
  115. package/dist/framework.js +9623 -8417
  116. package/dist/index.css +1 -1
  117. package/dist/index.d.ts +19 -0
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/injection-keys.d.ts +21 -6
  120. package/dist/injection-keys.d.ts.map +1 -1
  121. package/dist/shared/components/app-switcher/composables/useAppSwitcher/index.d.ts.map +1 -1
  122. package/dist/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue.d.ts.map +1 -1
  123. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  124. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts.map +1 -1
  125. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts.map +1 -1
  126. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts.map +1 -1
  127. package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -1
  128. package/dist/shared/components/draggable-dashboard/composables/useLayoutPersistence.d.ts.map +1 -1
  129. package/dist/shared/components/notifications/composables/useContainer/index.d.ts.map +1 -1
  130. package/dist/shared/components/notifications/composables/useInstance/index.d.ts.map +1 -1
  131. package/dist/shared/components/notifications/core/notification.d.ts.map +1 -1
  132. package/dist/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue.d.ts.map +1 -1
  133. package/dist/shared/components/sign-in/useExternalProvider.d.ts.map +1 -1
  134. package/dist/shared/composables/index.d.ts +1 -0
  135. package/dist/shared/composables/index.d.ts.map +1 -1
  136. package/dist/shared/composables/useExternalWidgets.d.ts.map +1 -1
  137. package/dist/shared/composables/useMenuExpanded.d.ts.map +1 -1
  138. package/dist/shared/composables/useTableSelection.d.ts +57 -0
  139. package/dist/shared/composables/useTableSelection.d.ts.map +1 -0
  140. package/dist/shared/composables/useTableSort.d.ts.map +1 -1
  141. package/dist/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts.map +1 -1
  142. package/dist/shared/pages/LoginPage/components/login/Login.vue.d.ts.map +1 -1
  143. package/dist/shared/utilities/colorUtils.d.ts +0 -6
  144. package/dist/shared/utilities/colorUtils.d.ts.map +1 -1
  145. package/dist/tsconfig.tsbuildinfo +1 -1
  146. package/dist/ui/components/atoms/vc-banner/vc-banner.vue.d.ts.map +1 -1
  147. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts +0 -15
  148. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts.map +1 -1
  149. package/dist/ui/components/atoms/vc-container/vc-container.vue.d.ts.map +1 -1
  150. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
  151. package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
  152. package/dist/ui/components/atoms/vc-image/vc-image.vue.d.ts.map +1 -1
  153. package/dist/ui/components/atoms/vc-link/vc-link.vue.d.ts.map +1 -1
  154. package/dist/ui/components/atoms/vc-loading/vc-loading.vue.d.ts.map +1 -1
  155. package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts +0 -5
  156. package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts.map +1 -1
  157. package/dist/ui/components/atoms/vc-tooltip/vc-tooltip.vue.d.ts.map +1 -1
  158. package/dist/ui/components/atoms/vc-video/vc-video.vue.d.ts.map +1 -1
  159. package/dist/ui/components/atoms/vc-widget/vc-widget.vue.d.ts.map +1 -1
  160. package/dist/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue.d.ts.map +1 -1
  161. package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts.map +1 -1
  162. package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts.map +1 -1
  163. package/dist/ui/components/molecules/vc-toast/vc-toast.vue.d.ts.map +1 -1
  164. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  165. 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
  166. package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
  167. package/dist/ui/components/organisms/vc-login-form/vc-login-form.vue.d.ts.map +1 -1
  168. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
  169. package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts.map +1 -1
  170. package/dist/ui/components/organisms/vc-table/composables/useTableColumnResize.d.ts.map +1 -1
  171. package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts.map +1 -1
  172. package/dist/ui/components/organisms/vc-table/composables/useTableSelection.d.ts.map +1 -1
  173. package/dist/ui/components/organisms/vc-table/composables/useTableState.d.ts.map +1 -1
  174. package/dist/{vendor-lodash-es-BqkGj3Jl.js → vendor-lodash-es-SgOIjJF8.js} +2 -0
  175. package/package.json +5 -5
  176. package/shared/components/app-switcher/composables/useAppSwitcher/index.ts +4 -1
  177. package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +67 -4
  178. package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +13 -10
  179. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.ts +7 -4
  180. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.ts +4 -1
  181. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.ts +4 -1
  182. package/shared/components/change-password/change-password.vue +1 -1
  183. package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +14 -5
  184. package/shared/components/draggable-dashboard/composables/useLayoutPersistence.ts +5 -2
  185. package/shared/components/index.ts +2 -0
  186. package/shared/components/notifications/composables/useContainer/index.ts +8 -6
  187. package/shared/components/notifications/composables/useInstance/index.ts +4 -1
  188. package/shared/components/notifications/core/notification.ts +10 -7
  189. package/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue +20 -1
  190. package/shared/components/sign-in/useExternalProvider.ts +6 -4
  191. package/shared/composables/index.ts +1 -0
  192. package/shared/composables/useExternalWidgets.ts +7 -4
  193. package/shared/composables/useMenuExpanded.ts +15 -1
  194. package/shared/composables/useTableSelection.ts +151 -0
  195. package/shared/composables/useTableSort.ts +4 -4
  196. package/shared/modules/assets-manager/components/assets-manager/assets-manager.vue +6 -3
  197. package/shared/pages/LoginPage/components/login/Login.vue +4 -1
  198. package/shared/utilities/colorUtils.ts +5 -12
  199. package/ui/components/atoms/vc-banner/vc-banner.vue +4 -1
  200. package/ui/components/atoms/vc-button/vc-button.vue +2 -25
  201. package/ui/components/atoms/vc-container/vc-container.vue +12 -3
  202. package/ui/components/atoms/vc-icon/vc-icon.vue +0 -10
  203. package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +5 -2
  204. package/ui/components/atoms/vc-image/vc-image.vue +4 -1
  205. package/ui/components/atoms/vc-link/vc-link.vue +59 -54
  206. package/ui/components/atoms/vc-loading/vc-loading.vue +4 -0
  207. package/ui/components/atoms/vc-status/vc-status.vue +0 -5
  208. package/ui/components/atoms/vc-status-icon/vc-status-icon.vue +4 -4
  209. package/ui/components/atoms/vc-tooltip/vc-tooltip.vue +8 -1
  210. package/ui/components/atoms/vc-video/vc-video.vue +4 -2
  211. package/ui/components/atoms/vc-widget/vc-widget.vue +4 -1
  212. package/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue +7 -2
  213. package/ui/components/molecules/vc-input/vc-input.vue +0 -1
  214. package/ui/components/molecules/vc-pagination/vc-pagination.vue +6 -1
  215. package/ui/components/molecules/vc-rating/vc-rating.vue +1 -1
  216. package/ui/components/molecules/vc-textarea/vc-textarea.vue +1 -1
  217. package/ui/components/molecules/vc-toast/vc-toast.vue +11 -1
  218. package/ui/components/organisms/vc-app/vc-app.vue +22 -3
  219. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue +4 -1
  220. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue +14 -14
  221. package/ui/components/organisms/vc-blade/vc-blade.vue +3 -1
  222. package/ui/components/organisms/vc-login-form/vc-login-form.vue +3 -1
  223. package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +34 -2
  224. package/ui/components/organisms/vc-table/composables/useTableActions.ts +7 -10
  225. package/ui/components/organisms/vc-table/composables/useTableColumnResize.ts +4 -1
  226. package/ui/components/organisms/vc-table/composables/useTableRowReorder.ts +5 -2
  227. package/ui/components/organisms/vc-table/composables/useTableSelection.ts +26 -18
  228. package/ui/components/organisms/vc-table/composables/useTableState.ts +4 -1
  229. package/core/services/global-search-service.ts +0 -36
  230. package/dist/core/services/global-search-service.d.ts +0 -10
  231. package/dist/core/services/global-search-service.d.ts.map +0 -1
@@ -25,10 +25,10 @@ import { useLocalStorage } from "@vueuse/core";
25
25
  import { usePermissions, useToolbar } from "../../../../../../core/composables";
26
26
  import { IBladeToolbar } from "../../../../../../core/types";
27
27
  import VcBladeToolbarButtons from "./_internal/vc-blade-toolbar-buttons/vc-blade-toolbar-buttons.vue";
28
- import { BladeInstance } from "../../../../../../injection-keys";
29
28
  import { FALLBACK_BLADE_ID } from "../../../../../../core/constants";
30
29
  import { IBladeInstance } from "../../../../../../shared/components/blade-navigation/types";
31
30
  import { IToolbarItem } from "../../../../../../core/services";
31
+ import { useBlade } from "../../../../../../core/composables";
32
32
 
33
33
  export interface Props {
34
34
  items: IBladeToolbar[];
@@ -41,21 +41,17 @@ const props = withDefaults(defineProps<Props>(), {
41
41
  const slots = useSlots();
42
42
  const isExpanded = useLocalStorage("VC_BLADE_TOOLBAR_IS_EXPANDED", true);
43
43
  const { hasAccess } = usePermissions();
44
- const { registerToolbarItem, unregisterToolbarItem, getToolbarItems, clearBladeToolbarItems, updateToolbarItem } =
45
- useToolbar();
44
+ const {
45
+ registerToolbarItem,
46
+ unregisterToolbarItem,
47
+ getToolbarItems,
48
+ clearBladeToolbarItems,
49
+ updateToolbarItem,
50
+ registeredToolbarItems,
51
+ } = useToolbar();
46
52
 
47
53
  // Get the ID of the current blade
48
- const blade = inject<ComputedRef<IBladeInstance>>(
49
- BladeInstance,
50
- computed(() => ({
51
- id: FALLBACK_BLADE_ID,
52
- expandable: false,
53
- maximized: false,
54
- error: undefined,
55
- navigation: undefined,
56
- breadcrumbs: undefined,
57
- })),
58
- );
54
+ const blade = useBlade();
59
55
 
60
56
  const bladeId = computed(() => (blade.value?.id ?? FALLBACK_BLADE_ID).toLowerCase());
61
57
 
@@ -126,6 +122,10 @@ function clearToolbarItems(): void {
126
122
 
127
123
  // Filter visible items from service
128
124
  const visibleItems = computed(() => {
125
+ // Access registeredToolbarItems.length to create reactive dependency
126
+ // This ensures computed recalculates when new items are registered
127
+ void registeredToolbarItems.length;
128
+
129
129
  return getToolbarItems()
130
130
  .filter(
131
131
  (item) =>
@@ -288,8 +288,10 @@ const openErrorDetails = () => {
288
288
  }
289
289
 
290
290
  .vc-blade {
291
- @apply tw-relative tw-flex tw-shrink-0 tw-flex-col tw-overflow-hidden tw-transition-[width] tw-duration-200;
291
+ @apply tw-relative tw-flex tw-shrink-0 tw-flex-col tw-overflow-hidden;
292
292
  @apply tw-bg-[color:var(--blade-background-color)] tw-border tw-border-solid tw-border-[--blade-border-color];
293
+ // Use shared transition timing for synchronized animations with AI panel
294
+ transition: width var(--app-panel-transition-duration, 0.3s) var(--app-panel-transition-timing, cubic-bezier(0.4, 0, 0.2, 1));
293
295
 
294
296
  &__back-button {
295
297
  @apply tw-mr-[14px];
@@ -24,6 +24,7 @@
24
24
  <script lang="ts" setup>
25
25
  import { computed } from "vue";
26
26
  import { useRouter } from "vue-router";
27
+ import { createLogger } from "../../../../core/utilities";
27
28
 
28
29
  export interface Props {
29
30
  logo?: string;
@@ -57,7 +58,8 @@ const logoImageHandler = computed(() => {
57
58
 
58
59
  const version = router.currentRoute.value.meta?.appVersion;
59
60
 
60
- console.debug("Init vc-login-form");
61
+ const logger = createLogger("vc-login-form");
62
+ logger.debug("Init vc-login-form");
61
63
  </script>
62
64
 
63
65
  <style lang="scss">
@@ -290,6 +290,38 @@ import { Field } from "vee-validate";
290
290
  import type { TableItem } from "../../types";
291
291
  import { ITableColumns } from "../../../../../../core/types";
292
292
 
293
+ // Cache for sanitized HTML to avoid repeated DOMPurify calls across table cells
294
+ const sanitizedHtmlCache = new Map<string, string>();
295
+ const MAX_CACHE_SIZE = 500;
296
+
297
+ function getSanitizedHtml(html: string): string {
298
+ if (sanitizedHtmlCache.has(html)) {
299
+ return sanitizedHtmlCache.get(html)!;
300
+ }
301
+
302
+ const sanitized = DOMPurify.default.sanitize(html, {
303
+ ALLOWED_TAGS: [
304
+ "p", "br", "strong", "em", "u", "s", "h1", "h2", "h3", "h4", "h5", "h6",
305
+ "ul", "ol", "li", "blockquote", "pre", "code", "a", "img", "table",
306
+ "thead", "tbody", "tr", "th", "td", "hr", "div", "span",
307
+ ],
308
+ ALLOWED_ATTR: ["href", "src", "alt", "title", "class", "id", "colspan", "rowspan", "align", "valign"],
309
+ FORBID_TAGS: ["script", "object", "embed", "form", "input"],
310
+ FORBID_ATTR: ["onerror", "onload", "onclick", "onmouseover", "onfocus", "onblur", "style"],
311
+ });
312
+
313
+ // Limit cache size to prevent memory leaks
314
+ if (sanitizedHtmlCache.size >= MAX_CACHE_SIZE) {
315
+ const firstKey = sanitizedHtmlCache.keys().next().value;
316
+ if (firstKey !== undefined) {
317
+ sanitizedHtmlCache.delete(firstKey);
318
+ }
319
+ }
320
+
321
+ sanitizedHtmlCache.set(html, sanitized);
322
+ return sanitized;
323
+ }
324
+
293
325
  export interface Props {
294
326
  cell: ITableColumns;
295
327
  item: string | TableItem;
@@ -313,8 +345,8 @@ const value = computed((): any => _.get(props.item, props.cell.field || props.ce
313
345
  const isEditable = computed(() => props.cell.editable && props.editing);
314
346
 
315
347
  const sanitizedHtml = computed(() => {
316
- if (props.cell.type === "html") {
317
- return DOMPurify.default.sanitize(value.value as string, { USE_PROFILES: { html: true } });
348
+ if (props.cell.type === "html" && value.value) {
349
+ return getSanitizedHtml(String(value.value));
318
350
  }
319
351
  return "";
320
352
  });
@@ -20,16 +20,13 @@ export function useTableActions<T extends TableItem | string>(options: UseTableA
20
20
  const builder = unref(itemActionBuilder);
21
21
 
22
22
  if (unref(enableItemActions) && typeof builder === "function") {
23
- const populatedItems: IActionBuilderResult<T>[][] = [];
24
- for (let index = 0; index < items.length; index++) {
25
- if (typeof items[index] === "object") {
26
- const elementWithActions = await builder(items[index]);
27
- if (elementWithActions) {
28
- populatedItems.push(elementWithActions);
29
- }
30
- }
31
- }
32
- itemActions.value = populatedItems;
23
+ // Use Promise.all for parallel execution instead of sequential awaits
24
+ const actionPromises = items
25
+ .filter((item) => typeof item === "object")
26
+ .map((item) => builder(item));
27
+
28
+ const results = await Promise.all(actionPromises);
29
+ itemActions.value = results.filter((result): result is IActionBuilderResult<T>[] => !!result);
33
30
  } else {
34
31
  itemActions.value = [];
35
32
  }
@@ -1,5 +1,8 @@
1
1
  import { ref, Ref } from "vue";
2
2
  import { TableColPartial } from "../types";
3
+ import { createLogger } from "../../../../../core/utilities";
4
+
5
+ const logger = createLogger("vc-table-column-resize");
3
6
 
4
7
  export function useTableColumnResize(
5
8
  internalColumns: Ref<TableColPartial[]>,
@@ -35,7 +38,7 @@ export function useTableColumnResize(
35
38
  e.stopImmediatePropagation();
36
39
 
37
40
  if (!item.id) {
38
- console.warn("Column has no id, cannot resize:", item);
41
+ logger.warn("Column has no id, cannot resize:", item);
39
42
  return;
40
43
  }
41
44
 
@@ -1,5 +1,8 @@
1
1
  import { computed, ref, Ref } from "vue";
2
2
  import { TableItem } from "../types";
3
+ import { createLogger } from "../../../../../core/utilities";
4
+
5
+ const logger = createLogger("vc-table-row-reorder");
3
6
 
4
7
  export function useTableRowReorder<T extends TableItem | string>(
5
8
  items: Ref<T[]>,
@@ -27,7 +30,7 @@ export function useTableRowReorder<T extends TableItem | string>(
27
30
  function onRowMouseDown(event: MouseEvent) {
28
31
  if (event.currentTarget instanceof HTMLElement) {
29
32
  const row = event.currentTarget;
30
- console.log("row", row);
33
+ logger.debug("Row mousedown event", row);
31
34
  const rowRect = row.getBoundingClientRect();
32
35
 
33
36
  dragOffset.value = {
@@ -54,7 +57,7 @@ export function useTableRowReorder<T extends TableItem | string>(
54
57
  }
55
58
 
56
59
  function onRowDragStart(event: DragEvent, item: T) {
57
- console.log("onRowDragStart", event, item);
60
+ logger.debug("Row drag start", { item });
58
61
  rowDragged.value = true;
59
62
  const index = internalItems.value.indexOf(item);
60
63
  draggedRow.value = index;
@@ -1,9 +1,16 @@
1
1
  import { computed, ref, Ref, watch } from "vue";
2
2
  import { TableItem } from "../types";
3
- import * as _ from "lodash-es";
4
3
 
5
4
  type TableItemType = TableItem | string;
6
5
 
6
+ /**
7
+ * Gets a unique identifier for a table item
8
+ */
9
+ function getItemId(item: TableItemType): string {
10
+ if (typeof item === "string") return item;
11
+ return (item as TableItem).id ?? JSON.stringify(item);
12
+ }
13
+
7
14
  export interface UseTableSelectionOptions<T extends TableItemType> {
8
15
  items: Ref<T[]>;
9
16
  disableItemCheckbox?: (item: T) => boolean;
@@ -37,8 +44,11 @@ export function useTableSelection<T extends TableItemType>(options: UseTableSele
37
44
  return selection.value.length === items.value.length && (options.totalCount || 0) > items.value.length;
38
45
  });
39
46
 
47
+ // Use Set for O(1) selection lookups instead of O(n) array search with deep equality
48
+ const selectionIds = computed(() => new Set(selection.value.map(getItemId)));
49
+
40
50
  function isSelected(item: T): boolean {
41
- return selection.value.some((x) => _.isEqual(x, item));
51
+ return selectionIds.value.has(getItemId(item));
42
52
  }
43
53
 
44
54
  function handleSelectAll(): void {
@@ -52,14 +62,15 @@ export function useTableSelection<T extends TableItemType>(options: UseTableSele
52
62
  }
53
63
 
54
64
  function rowCheckbox(item: T): void {
55
- if (disabledSelection.value.includes(item)) {
65
+ const itemId = getItemId(item);
66
+ const disabledIds = new Set(disabledSelection.value.map(getItemId));
67
+
68
+ if (disabledIds.has(itemId)) {
56
69
  return;
57
70
  }
58
71
 
59
- const index = selection.value.findIndex((x) => _.isEqual(x, item));
60
-
61
- if (index !== -1) {
62
- selection.value = selection.value.filter((_, i) => i !== index);
72
+ if (selectionIds.value.has(itemId)) {
73
+ selection.value = selection.value.filter((x) => getItemId(x) !== itemId);
63
74
  } else {
64
75
  selection.value = [...selection.value, item];
65
76
  }
@@ -67,16 +78,11 @@ export function useTableSelection<T extends TableItemType>(options: UseTableSele
67
78
 
68
79
  async function handleMultiselect(items: T[]): Promise<void> {
69
80
  if (disableItemCheckbox && typeof disableItemCheckbox === "function") {
70
- const disabledMultiselect: T[] = [];
71
- for (const item of items) {
72
- if (typeof item === "object") {
73
- const element = await disableItemCheckbox(item);
74
- if (element) {
75
- disabledMultiselect.push(item);
76
- }
77
- }
78
- }
79
- disabledSelection.value = disabledMultiselect;
81
+ // Use Promise.all for parallel execution instead of sequential awaits
82
+ const objectItems = items.filter((item) => typeof item === "object");
83
+ const results = await Promise.all(objectItems.map((item) => disableItemCheckbox(item)));
84
+
85
+ disabledSelection.value = objectItems.filter((_, index) => results[index]);
80
86
  }
81
87
  }
82
88
 
@@ -84,7 +90,9 @@ export function useTableSelection<T extends TableItemType>(options: UseTableSele
84
90
  () => items.value,
85
91
  (newItems) => {
86
92
  handleMultiselect(newItems);
87
- selection.value = selection.value.filter((item) => newItems.includes(item));
93
+ // Use Set for O(1) lookups when filtering selection
94
+ const newItemIds = new Set(newItems.map(getItemId));
95
+ selection.value = selection.value.filter((item) => newItemIds.has(getItemId(item)));
88
96
  },
89
97
  { deep: true, immediate: true },
90
98
  );
@@ -4,6 +4,9 @@ import { useLocalStorage } from "@vueuse/core";
4
4
  import { cloneDeep, pick, unionBy } from "lodash-es";
5
5
  import { TableColPartial } from "../types";
6
6
  import { ITableColumns } from "../../../../../core/types";
7
+ import { createLogger } from "../../../../../core/utilities";
8
+
9
+ const logger = createLogger("vc-table-state");
7
10
 
8
11
  export interface UseTableStateOptions {
9
12
  stateKey: Ref<string, string>;
@@ -47,7 +50,7 @@ export function useTableState(options: UseTableStateOptions) {
47
50
  });
48
51
 
49
52
  function saveState() {
50
- console.debug("[@vc-shell/framework#vc-table.vue] - Save state");
53
+ logger.debug("Save state");
51
54
  const colsClone = cloneDeep(internalColumns.value);
52
55
  state.value = colsClone.map((col) => pick(col, "id", "visible", "width", "predefined", "title"));
53
56
  }
@@ -1,36 +0,0 @@
1
- import { Ref, ref } from "vue";
2
-
3
- export interface GlobalSearchState {
4
- isSearchVisible: Ref<Record<string, boolean>>;
5
- searchQuery: Ref<Record<string, string>>;
6
- toggleSearch: (bladeId: string) => void;
7
- setSearchQuery: (bladeId: string, query: string) => void;
8
- closeSearch: (bladeId: string) => void;
9
- }
10
-
11
- export function createGlobalSearchService() {
12
- const isSearchVisible = ref<Record<string, boolean>>({});
13
- const searchQuery = ref<Record<string, string>>({});
14
-
15
- const toggleSearch = (bladeId: string) => {
16
- isSearchVisible.value[bladeId] = !isSearchVisible.value[bladeId];
17
- };
18
-
19
- const setSearchQuery = (bladeId: string, query: string) => {
20
- searchQuery.value[bladeId] = query;
21
- };
22
-
23
- const closeSearch = (bladeId: string) => {
24
- isSearchVisible.value[bladeId] = false;
25
- };
26
-
27
- const state: GlobalSearchState = {
28
- isSearchVisible,
29
- searchQuery,
30
- toggleSearch,
31
- setSearchQuery,
32
- closeSearch,
33
- };
34
-
35
- return state;
36
- }
@@ -1,10 +0,0 @@
1
- import { Ref } from "vue";
2
- export interface GlobalSearchState {
3
- isSearchVisible: Ref<Record<string, boolean>>;
4
- searchQuery: Ref<Record<string, string>>;
5
- toggleSearch: (bladeId: string) => void;
6
- setSearchQuery: (bladeId: string, query: string) => void;
7
- closeSearch: (bladeId: string) => void;
8
- }
9
- export declare function createGlobalSearchService(): GlobalSearchState;
10
- //# sourceMappingURL=global-search-service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"global-search-service.d.ts","sourceRoot":"","sources":["../../../core/services/global-search-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAO,MAAM,KAAK,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,yBAAyB,sBAyBxC"}