@raclettejs/core 0.1.37 → 0.1.39

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 (32) hide show
  1. package/CHANGELOG.md +22 -9
  2. package/dist/cli.js +1 -1
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +2 -2
  5. package/services/backend/package.json +1 -1
  6. package/services/frontend/src/core/lib/scheduleTask.ts +35 -0
  7. package/services/frontend/src/core/store/index.ts +5 -1
  8. package/services/frontend/src/core/store/reducers/compositionSlots/reducers.ts +1 -5
  9. package/services/frontend/src/core/store/reducers/data/reducers.ts +101 -65
  10. package/services/frontend/src/core/store/reducers/metaReducer.ts +23 -0
  11. package/services/frontend/src/core/store/reducers/notifications/reducers.ts +39 -47
  12. package/services/frontend/src/core/store/reducers/queries/effects.ts +55 -2
  13. package/services/frontend/src/core/store/reducers/queries/reducers.ts +60 -62
  14. package/services/frontend/src/core/store/reducers/queriesCache/effects.ts +105 -0
  15. package/services/frontend/src/core/store/reducers/queriesCache/index.ts +2 -1
  16. package/services/frontend/src/core/store/reducers/queriesCache/queryCacheHelper.ts +79 -9
  17. package/services/frontend/src/core/store/reducers/queriesCache/reducers.ts +95 -100
  18. package/services/frontend/src/orchestrator/components/CompositionLoadingState.vue +28 -0
  19. package/services/frontend/src/orchestrator/components/composition/CompositionOverlay.vue +5 -7
  20. package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +171 -39
  21. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTable.vue +311 -54
  22. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTableConfirmDeleteBtn.vue +27 -0
  23. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTableFilterDrawerShell.vue +72 -0
  24. package/services/frontend/src/orchestrator/components/index.ts +4 -0
  25. package/services/frontend/src/orchestrator/composables/index.ts +1 -0
  26. package/services/frontend/src/orchestrator/composables/useBaseDataTableDeleteConfirm.ts +23 -0
  27. package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +53 -23
  28. package/services/frontend/src/orchestrator/constants/widgetSlotType.ts +4 -0
  29. package/services/frontend/src/orchestrator/i18n/de-DE.json +7 -1
  30. package/services/frontend/src/orchestrator/i18n/en-EU.json +7 -1
  31. package/services/frontend/src/orchestrator/i18n/sk.json +7 -1
  32. package/services/frontend/src/orchestrator/router/routerHooks/afterEach.ts +15 -9
@@ -1,6 +1,7 @@
1
1
  import { ref, type Ref } from "vue"
2
2
  import { isDevelopmentMode } from "@racletteCore/helpers/devMode"
3
3
  import log from "@racletteCore/lib/logger"
4
+ import { scheduleAfterPaint } from "@racletteCore/lib/scheduleTask"
4
5
 
5
6
  export type OnAllWidgetsReady = (callback: () => void) => void
6
7
 
@@ -26,6 +27,12 @@ export function createWidgetLifecycleManager(
26
27
 
27
28
  const DEV_MODE = isDevelopmentMode()
28
29
 
30
+ const markReadyIfNoWidgets = () => {
31
+ if (totalWidgets === 0) {
32
+ allWidgetsReady.value = true
33
+ }
34
+ }
35
+
29
36
  const checkAllReady = () => {
30
37
  if (renderedWidgets.value.size === totalWidgets && !allWidgetsReady.value) {
31
38
  allWidgetsReady.value = true
@@ -43,22 +50,46 @@ export function createWidgetLifecycleManager(
43
50
  }
44
51
 
45
52
  const hasVisibleContent = (element: HTMLElement): boolean => {
46
- // Check if element has any child nodes
47
53
  if (element.childNodes.length === 0) {
48
54
  return false
49
55
  }
50
56
 
51
- // Check if element has visible dimensions
52
- const rect = element.getBoundingClientRect()
53
- if (rect.width === 0 && rect.height === 0) {
54
- return false
57
+ const text = element.textContent?.trim()
58
+ if (text?.length) {
59
+ return true
60
+ }
61
+
62
+ // DOM-only checks — avoid getBoundingClientRect / offset* (forced reflow).
63
+ return (
64
+ element.children.length > 0 ||
65
+ element.querySelector(
66
+ "table, img, canvas, svg, video, iframe, input, button, select, textarea, [role='row']",
67
+ ) !== null
68
+ )
69
+ }
70
+
71
+ const scheduleContentCheck = (
72
+ element: HTMLElement,
73
+ onReady: () => void,
74
+ ): (() => void) => {
75
+ let scheduled = false
76
+
77
+ const runCheck = () => {
78
+ scheduled = false
79
+ if (hasVisibleContent(element)) {
80
+ onReady()
81
+ }
55
82
  }
56
83
 
57
- // Check for text content or child elements
58
- const hasTextContent = element.textContent?.trim().length > 0
59
- const hasChildElements = element.children.length > 0
84
+ const scheduleCheck = () => {
85
+ if (scheduled) {
86
+ return
87
+ }
88
+ scheduled = true
89
+ scheduleAfterPaint(runCheck)
90
+ }
60
91
 
61
- return hasTextContent || hasChildElements
92
+ return scheduleCheck
62
93
  }
63
94
 
64
95
  const registerWidgetAsRendered = (id: string) => {
@@ -96,30 +127,25 @@ export function createWidgetLifecycleManager(
96
127
  }
97
128
 
98
129
  const observeWidgetRendering = (id: string, element: HTMLElement) => {
99
- // Check immediately if content is already rendered
100
- if (hasVisibleContent(element)) {
130
+ let observer: MutationObserver | null = null
131
+
132
+ const markReady = () => {
133
+ observer?.disconnect()
134
+ observer = null
135
+ observers.delete(id)
101
136
  registerWidgetAsRendered(id)
102
- return
103
137
  }
104
138
 
105
- // Otherwise, observe for changes
106
- const observer = new MutationObserver(() => {
107
- if (hasVisibleContent(element)) {
108
- registerWidgetAsRendered(id)
109
- observer.disconnect()
110
- observers.delete(id)
111
- }
112
- })
139
+ const scheduleCheck = scheduleContentCheck(element, markReady)
113
140
 
141
+ observer = new MutationObserver(scheduleCheck)
114
142
  observer.observe(element, {
115
143
  childList: true,
116
144
  subtree: true,
117
145
  characterData: true,
118
- attributes: true,
119
- attributeFilter: ["style", "class"],
120
146
  })
121
-
122
147
  observers.set(id, observer)
148
+ scheduleCheck()
123
149
 
124
150
  if (DEV_MODE) {
125
151
  log.widgets(
@@ -151,11 +177,15 @@ export function createWidgetLifecycleManager(
151
177
  allWidgetsReady.value = false
152
178
  readyCallbacks.clear()
153
179
 
180
+ markReadyIfNoWidgets()
181
+
154
182
  if (DEV_MODE) {
155
183
  log.widgets("useWidgetLifecycle", "🔄 Widget lifecycle manager reset")
156
184
  }
157
185
  }
158
186
 
187
+ markReadyIfNoWidgets()
188
+
159
189
  return {
160
190
  createLifecycleHooks,
161
191
  allWidgetsReady,
@@ -0,0 +1,4 @@
1
+ /** Composition slot type from `WidgetsLayoutLoader` (`page` | `modal` | `inline`). */
2
+ export const WIDGET_SLOT_TYPE_KEY = Symbol("widgetSlotType")
3
+
4
+ export type WidgetSlotType = "page" | "modal" | "inline"
@@ -42,8 +42,14 @@
42
42
  "resetFilters": "Filter zurücksetzen",
43
43
  "applyFilters": "Filter anwenden",
44
44
  "actionsMenu": "Tabellenaktionen",
45
+ "actions": "Aktionen",
45
46
  "enableExportMode": "Exportmodus aktivieren",
46
- "disableExportMode": "Exportmodus deaktivieren"
47
+ "disableExportMode": "Exportmodus deaktivieren",
48
+ "confirmDeleteTitle": "Löschung bestätigen",
49
+ "confirmDeleteMessage": "Möchten Sie {name} wirklich löschen?",
50
+ "confirmHardDeleteMessage": "Möchten Sie {name} wirklich endgültig löschen?",
51
+ "delete": "Löschen",
52
+ "activeModesTooltip": "Aktiv: {modes}"
47
53
  },
48
54
  "dataExporter": {
49
55
  "lines": "Zeilen",
@@ -42,8 +42,14 @@
42
42
  "resetFilters": "Reset filters",
43
43
  "applyFilters": "Apply filters",
44
44
  "actionsMenu": "Table actions",
45
+ "actions": "Actions",
45
46
  "enableExportMode": "Enable export mode",
46
- "disableExportMode": "Disable export mode"
47
+ "disableExportMode": "Disable export mode",
48
+ "confirmDeleteTitle": "Confirm deletion",
49
+ "confirmDeleteMessage": "Are you sure you want to delete {name}?",
50
+ "confirmHardDeleteMessage": "Are you sure you want to permanently delete {name}?",
51
+ "delete": "Delete",
52
+ "activeModesTooltip": "Active: {modes}"
47
53
  },
48
54
  "dataExporter": {
49
55
  "lines": "Lines",
@@ -42,8 +42,14 @@
42
42
  "resetFilters": "Obnoviť filtre",
43
43
  "applyFilters": "Použiť filtre",
44
44
  "actionsMenu": "Akcie tabuľky",
45
+ "actions": "Akcie",
45
46
  "enableExportMode": "Zapnúť režim exportu",
46
- "disableExportMode": "Vypnúť režim exportu"
47
+ "disableExportMode": "Vypnúť režim exportu",
48
+ "confirmDeleteTitle": "Potvrdiť vymazanie",
49
+ "confirmDeleteMessage": "Naozaj chcete vymazať {name}?",
50
+ "confirmHardDeleteMessage": "Naozaj chcete natrvalo vymazať {name}?",
51
+ "delete": "Vymazať",
52
+ "activeModesTooltip": "Aktívne: {modes}"
47
53
  },
48
54
  "dataExporter": {
49
55
  "lines": "riadky",
@@ -1,5 +1,6 @@
1
1
  import { loadingHold } from "@racletteCore/store/state"
2
2
  import { $store } from "@racletteCore"
3
+ import { scheduleAfterPaint } from "@racletteCore/lib/scheduleTask"
3
4
  import type { RouteLocationNormalized } from "vue-router"
4
5
  import { handleRouteChange } from "../routeStore"
5
6
 
@@ -10,16 +11,21 @@ import { handleRouteChange } from "../routeStore"
10
11
  * removeLoading Animation
11
12
  */
12
13
  export default (to: RouteLocationNormalized, from: RouteLocationNormalized) => {
14
+ scheduleAfterPaint(() => {
15
+ handleRouteChange(to, from)
16
+ })
17
+
13
18
  const loading = $store.getState(["ui", "loading"])
14
19
  if (loading) {
15
- setTimeout(
16
- () =>
17
- $store.dispatch({
18
- type: "ui/update",
19
- payload: { loading: false },
20
- }),
21
- loadingHold,
22
- )
20
+ setTimeout(() => {
21
+ scheduleAfterPaint(() => {
22
+ if ($store.getState(["ui", "loading"])) {
23
+ $store.dispatch({
24
+ type: "ui/update",
25
+ payload: { loading: false },
26
+ })
27
+ }
28
+ })
29
+ }, loadingHold)
23
30
  }
24
- handleRouteChange(to, from)
25
31
  }