@raclettejs/core 0.1.39 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -1
- package/dist/cli.js +104 -104
- package/dist/cli.js.map +4 -4
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
- package/services/backend/package.json +1 -1
- package/services/frontend/eslint.config.js +31 -9
- package/services/frontend/src/core/setup/socketBootstrap.ts +4 -3
- package/services/frontend/src/core/store/state.ts +2 -7
- package/services/frontend/src/core/store/types/index.ts +2 -0
- package/services/frontend/src/orchestrator/ProductOrchestrator.vue +33 -22
- package/services/frontend/src/orchestrator/components/LoadingWidgetState.vue +7 -3
- package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +179 -195
- package/services/frontend/src/orchestrator/components/dataExport/DataExporter.vue +79 -24
- package/services/frontend/src/orchestrator/components/dataTable/BaseDataTable.vue +27 -14
- package/services/frontend/src/orchestrator/components/dataTable/BaseDataTableGroupSelectCheckbox.vue +42 -0
- package/services/frontend/src/orchestrator/components/index.ts +2 -0
- package/services/frontend/src/orchestrator/components/menu/ServerStatus.vue +2 -4
- package/services/frontend/src/orchestrator/components/menu/UserMenu.vue +1 -1
- package/services/frontend/src/orchestrator/components/welcomeScreen/AdminWelcomeScreen.vue +1 -1
- package/services/frontend/src/orchestrator/composables/index.ts +1 -0
- package/services/frontend/src/orchestrator/composables/useAppLoadingCoordinator.ts +77 -0
- package/services/frontend/src/orchestrator/composables/usePageNavigation.ts +1 -1
- package/services/frontend/src/orchestrator/composables/useUiState.ts +2 -0
- package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +65 -76
- package/services/frontend/src/orchestrator/composables/useWidgets/helperFunctions.ts +7 -4
- package/services/frontend/src/orchestrator/constants/index.ts +2 -0
- package/services/frontend/src/orchestrator/constants/widgetSlot.ts +7 -0
- package/services/frontend/src/orchestrator/exports.ts +1 -0
- package/services/frontend/src/orchestrator/helpers/staticWidgetRegistry.ts +9 -44
- package/services/frontend/src/orchestrator/helpers/widgetLayoutHelper.ts +37 -0
- package/services/frontend/src/orchestrator/helpers/widgetLoader.ts +0 -1
- package/services/frontend/src/orchestrator/helpers/widgetSlotHelper.ts +20 -0
- package/services/frontend/src/orchestrator/helpers/widgetVisuals.ts +11 -12
- package/services/frontend/src/orchestrator/helpers/wrapWidgetWithLifecycle.ts +32 -0
- package/services/frontend/src/orchestrator/router/routerHooks/afterEach.ts +1 -20
- package/services/frontend/src/orchestrator/types/Widgets.ts +12 -6
- package/src/types.ts +7 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="tw:relative tw:
|
|
3
|
+
class="tw:relative tw:min-h-fit tw:max-w-full"
|
|
4
4
|
:class="{
|
|
5
5
|
'tw:min-h-[200px]': showLoadingOverlay,
|
|
6
6
|
'tw:p-4':
|
|
@@ -32,59 +32,68 @@
|
|
|
32
32
|
class="tw:max-w-full tw:self-start"
|
|
33
33
|
:class="{ 'tw:h-full': slotLayout === 'full' }"
|
|
34
34
|
>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
>
|
|
41
|
-
<v-row
|
|
42
|
-
:no-gutters="slotLayout === 'default' || slotLayout === 'full'"
|
|
43
|
-
:class="[{ 'tw:h-full': slotLayout === 'full' }, rowClasses]"
|
|
35
|
+
<v-col
|
|
36
|
+
v-for="(column, colIndex) in props.widgetsLayout"
|
|
37
|
+
:key="colIndex"
|
|
38
|
+
:cols="getGridCols(props.widgetsLayout.length)"
|
|
39
|
+
:class="{ 'tw:h-full': slotLayout === 'full' }"
|
|
44
40
|
>
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class="tw:w-full tw:flex tw:flex-wrap"
|
|
49
|
-
appear
|
|
41
|
+
<v-row
|
|
42
|
+
:no-gutters="slotLayout === 'default' || slotLayout === 'full'"
|
|
43
|
+
:class="[{ 'tw:h-full': slotLayout === 'full' }, rowClasses]"
|
|
50
44
|
>
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'transition-delay': `${slotIndex * 50}ms`,
|
|
57
|
-
...(slotLayout === 'default' || slotLayout === 'full'
|
|
58
|
-
? { padding: '0px' }
|
|
59
|
-
: {}),
|
|
60
|
-
}"
|
|
45
|
+
<TransitionGroup
|
|
46
|
+
name="grid-item"
|
|
47
|
+
tag="div"
|
|
48
|
+
class="tw:flex tw:w-full tw:flex-wrap"
|
|
49
|
+
appear
|
|
61
50
|
>
|
|
62
|
-
<
|
|
63
|
-
|
|
51
|
+
<v-col
|
|
52
|
+
v-for="(slot, slotIndex) in column"
|
|
53
|
+
v-show="slot.widget"
|
|
54
|
+
:key="`${gridKey}-${colIndex}-${slotIndex}`"
|
|
55
|
+
:cols="getSlotCols(slot)"
|
|
56
|
+
:style="{
|
|
57
|
+
'transition-delay': `${slotIndex * 50}ms`,
|
|
58
|
+
...(slotLayout === 'default' || slotLayout === 'full'
|
|
59
|
+
? { padding: '0px' }
|
|
60
|
+
: {}),
|
|
61
|
+
}"
|
|
62
|
+
>
|
|
63
|
+
<div
|
|
64
64
|
v-if="slot.widget"
|
|
65
|
-
:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
65
|
+
:ref="
|
|
66
|
+
shouldTrackReadiness
|
|
67
|
+
? (el) => bindWidgetContainer(slot.widget!.uuid, el)
|
|
68
|
+
: undefined
|
|
69
|
+
"
|
|
70
|
+
:class="widgetContainerClasses"
|
|
71
|
+
class="tw:h-full"
|
|
72
|
+
>
|
|
73
|
+
<component
|
|
74
|
+
:is="getSlotWidget(slot.widget)"
|
|
75
|
+
:uuid="slot.widget.uuid"
|
|
76
|
+
:class="[
|
|
77
|
+
hasSpacing &&
|
|
78
|
+
widgetStates[slot.widget.uuid].config
|
|
79
|
+
?.allowPaddingOverride
|
|
80
|
+
? 'tw:p-4'
|
|
81
|
+
: '',
|
|
82
|
+
]"
|
|
83
|
+
v-bind="{
|
|
84
|
+
...widgetStates[slot.widget.uuid].config,
|
|
85
|
+
...widgetStates[slot.widget.uuid].public,
|
|
86
|
+
...routeParams,
|
|
87
|
+
compositionName: currentRouteConfig?.slotValue,
|
|
88
|
+
slotType,
|
|
89
|
+
}"
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</v-col>
|
|
93
|
+
</TransitionGroup>
|
|
94
|
+
</v-row>
|
|
95
|
+
</v-col>
|
|
96
|
+
</v-row>
|
|
88
97
|
</Transition>
|
|
89
98
|
</div>
|
|
90
99
|
|
|
@@ -118,38 +127,67 @@ import {
|
|
|
118
127
|
computed,
|
|
119
128
|
onMounted,
|
|
120
129
|
onUnmounted,
|
|
121
|
-
nextTick,
|
|
122
130
|
provide,
|
|
123
131
|
toRef,
|
|
124
132
|
type Component,
|
|
125
|
-
type ComponentPublicInstance,
|
|
126
133
|
} from "vue"
|
|
127
134
|
import { widgetLoader } from "@racletteOrchestrator/helpers/widgetLoader"
|
|
135
|
+
import { wrapWidgetWithLifecycle } from "@racletteOrchestrator/helpers/wrapWidgetWithLifecycle"
|
|
136
|
+
import {
|
|
137
|
+
cleanRouteParams,
|
|
138
|
+
countWidgetsInLayout,
|
|
139
|
+
getWidgetsLayoutSignature,
|
|
140
|
+
} from "@racletteOrchestrator/helpers/widgetLayoutHelper"
|
|
128
141
|
import { WIDGET_SLOT_TYPE_KEY } from "@racletteOrchestrator/constants/widgetSlotType"
|
|
129
142
|
import { useDisplay } from "vuetify"
|
|
130
143
|
import useStateSubscriber from "@racletteOrchestrator/composables/useStateSubscriber"
|
|
131
144
|
import useRouteState from "@racletteOrchestrator/composables/useRouteState"
|
|
132
|
-
import {
|
|
133
|
-
|
|
145
|
+
import {
|
|
146
|
+
createWidgetLifecycleManager,
|
|
147
|
+
type WidgetLifecycleManager,
|
|
148
|
+
} from "@racletteOrchestrator/composables/useWidgetLifecycle"
|
|
134
149
|
import CompositionLoadingState from "@racletteOrchestrator/components/CompositionLoadingState.vue"
|
|
150
|
+
import ErrorWidgetState from "@racletteOrchestrator/components/ErrorWidgetState.vue"
|
|
151
|
+
import { createEnhancedError } from "@racletteOrchestrator/helpers/widgetUtils"
|
|
152
|
+
import log from "@racletteCore/lib/logger"
|
|
135
153
|
|
|
136
154
|
const props = withDefaults(
|
|
137
155
|
defineProps<{
|
|
138
156
|
widgetsLayout: Composition["widgetsLayout"]
|
|
139
157
|
slotType: string
|
|
140
158
|
slotLayout: string
|
|
159
|
+
/**
|
|
160
|
+
* Observe widget slot containers for readiness. Defaults to page slots and
|
|
161
|
+
* modal overlays (`revealWhenReady`).
|
|
162
|
+
*/
|
|
163
|
+
trackReadiness?: boolean
|
|
164
|
+
/** When true, show a local loading overlay until widgets are ready (modals). */
|
|
141
165
|
revealWhenReady?: boolean
|
|
142
166
|
loadingSize?: number | string
|
|
143
167
|
loadingStrokeWidth?: number | string
|
|
144
168
|
}>(),
|
|
145
169
|
{
|
|
170
|
+
trackReadiness: undefined,
|
|
146
171
|
revealWhenReady: false,
|
|
147
172
|
loadingSize: 32,
|
|
148
173
|
loadingStrokeWidth: 3,
|
|
149
174
|
},
|
|
150
175
|
)
|
|
151
176
|
|
|
152
|
-
|
|
177
|
+
const emit = defineEmits<{
|
|
178
|
+
"all-widgets-ready": [ready: boolean]
|
|
179
|
+
}>()
|
|
180
|
+
|
|
181
|
+
const shouldTrackReadiness = computed(
|
|
182
|
+
() =>
|
|
183
|
+
props.trackReadiness ??
|
|
184
|
+
(props.slotType === "page" || props.revealWhenReady),
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
provide(
|
|
188
|
+
WIDGET_SLOT_TYPE_KEY,
|
|
189
|
+
toRef(() => props.slotType),
|
|
190
|
+
)
|
|
153
191
|
|
|
154
192
|
const { compositionSlots } = useRouteState()
|
|
155
193
|
|
|
@@ -164,7 +202,7 @@ const widgetContainerClasses = computed(() => {
|
|
|
164
202
|
case "spaced":
|
|
165
203
|
return `${baseClasses} tw:rounded-lg`
|
|
166
204
|
case "card":
|
|
167
|
-
return `${baseClasses} tw:rounded-lg tw:shadow-lg hover:
|
|
205
|
+
return `${baseClasses} tw:rounded-lg tw:shadow-lg tw:hover:shadow-xl tw:transition-shadow tw:duration-200`
|
|
168
206
|
case "border":
|
|
169
207
|
return `${baseClasses} tw:rounded-lg tw:border tw:border-gray-300 tw:dark:border-gray-700`
|
|
170
208
|
default:
|
|
@@ -176,49 +214,36 @@ const hasSpacing = computed(() =>
|
|
|
176
214
|
["spaced", "card", "border"].includes(props.slotLayout),
|
|
177
215
|
)
|
|
178
216
|
|
|
179
|
-
const rowClasses = computed(() =>
|
|
180
|
-
return hasSpacing.value ? "tw:gap-2" : ""
|
|
181
|
-
})
|
|
217
|
+
const rowClasses = computed(() => (hasSpacing.value ? "tw:gap-2" : ""))
|
|
182
218
|
|
|
183
219
|
const { mdAndDown } = useDisplay()
|
|
184
|
-
|
|
185
220
|
const { state: widgetStates } = useStateSubscriber("widgets")
|
|
186
|
-
const routeParams = computed(() => {
|
|
187
|
-
const cleanedParams = {}
|
|
188
|
-
if (currentRouteConfig.value?.slotParams) {
|
|
189
|
-
for (const [key, value] of Object.entries(
|
|
190
|
-
currentRouteConfig.value.slotParams,
|
|
191
|
-
)) {
|
|
192
|
-
if (isDefined(value) && value !== "undefined") {
|
|
193
|
-
cleanedParams[key] = value
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
221
|
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
const routeParams = computed(() =>
|
|
223
|
+
cleanRouteParams(currentRouteConfig.value?.slotParams),
|
|
224
|
+
)
|
|
200
225
|
|
|
201
|
-
// Create a reactive key that changes when widgetsLayout changes
|
|
202
226
|
const gridKey = ref(0)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
props.widgetsLayout.reduce(
|
|
207
|
-
(sum, column) => sum + column.filter((slot) => slot.widget).length,
|
|
208
|
-
0,
|
|
209
|
-
),
|
|
227
|
+
const totalWidgets = computed(() => countWidgetsInLayout(props.widgetsLayout))
|
|
228
|
+
const widgetsLayoutSignature = computed(() =>
|
|
229
|
+
getWidgetsLayoutSignature(props.widgetsLayout),
|
|
210
230
|
)
|
|
211
231
|
|
|
212
|
-
|
|
213
|
-
const lifecycleManager = ref(
|
|
214
|
-
createWidgetLifecycleManager(totalWidgets.value),
|
|
215
|
-
)
|
|
232
|
+
const lifecycleManager = ref<WidgetLifecycleManager | null>(null)
|
|
216
233
|
const allWidgetsReady = ref(false)
|
|
217
234
|
let stopReadyWatch: (() => void) | null = null
|
|
218
235
|
|
|
219
|
-
const
|
|
236
|
+
const syncLifecycleManager = () => {
|
|
220
237
|
stopReadyWatch?.()
|
|
221
|
-
|
|
238
|
+
lifecycleManager.value?.reset()
|
|
239
|
+
|
|
240
|
+
if (!shouldTrackReadiness.value) {
|
|
241
|
+
lifecycleManager.value = null
|
|
242
|
+
allWidgetsReady.value = true
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const manager = createWidgetLifecycleManager(totalWidgets.value)
|
|
222
247
|
stopReadyWatch = watch(
|
|
223
248
|
manager.allWidgetsReady,
|
|
224
249
|
(ready) => {
|
|
@@ -229,58 +254,49 @@ const attachLifecycleManager = (widgetCount: number) => {
|
|
|
229
254
|
lifecycleManager.value = manager
|
|
230
255
|
}
|
|
231
256
|
|
|
232
|
-
|
|
257
|
+
syncLifecycleManager()
|
|
258
|
+
|
|
259
|
+
watch(shouldTrackReadiness, syncLifecycleManager)
|
|
260
|
+
|
|
261
|
+
watch(
|
|
262
|
+
allWidgetsReady,
|
|
263
|
+
(ready) => {
|
|
264
|
+
if (shouldTrackReadiness.value) {
|
|
265
|
+
emit("all-widgets-ready", ready)
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
{ immediate: true },
|
|
269
|
+
)
|
|
233
270
|
|
|
234
271
|
const isContentReady = computed(
|
|
235
272
|
() =>
|
|
236
|
-
!props.revealWhenReady ||
|
|
237
|
-
totalWidgets.value === 0 ||
|
|
238
|
-
allWidgetsReady.value,
|
|
273
|
+
!props.revealWhenReady || totalWidgets.value === 0 || allWidgetsReady.value,
|
|
239
274
|
)
|
|
240
275
|
|
|
241
276
|
const showLoadingOverlay = computed(
|
|
242
277
|
() => props.revealWhenReady && !isContentReady.value,
|
|
243
278
|
)
|
|
244
279
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (!
|
|
249
|
-
return
|
|
280
|
+
/** Observe widget slot containers when readiness tracking is active. */
|
|
281
|
+
const bindWidgetContainer = (uuid: string, el: Element | null) => {
|
|
282
|
+
const manager = lifecycleManager.value
|
|
283
|
+
if (!manager) {
|
|
284
|
+
return
|
|
250
285
|
}
|
|
251
286
|
|
|
252
|
-
|
|
253
|
-
return target
|
|
254
|
-
}
|
|
287
|
+
const hooks = manager.createLifecycleHooks(uuid)
|
|
255
288
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return
|
|
289
|
+
if (!el) {
|
|
290
|
+
hooks.onWidgetUnmounted()
|
|
291
|
+
return
|
|
259
292
|
}
|
|
260
293
|
|
|
261
|
-
if (
|
|
262
|
-
|
|
294
|
+
if (el instanceof HTMLElement) {
|
|
295
|
+
hooks.onWidgetContainerMounted(el)
|
|
263
296
|
}
|
|
264
|
-
|
|
265
|
-
return null
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const isWidgetLoadingPlaceholder = (
|
|
269
|
-
target: Element | ComponentPublicInstance | null,
|
|
270
|
-
): boolean => {
|
|
271
|
-
if (!target || target instanceof HTMLElement) {
|
|
272
|
-
return false
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const componentName =
|
|
276
|
-
target.$.type?.name ?? (target.$options?.name as string | undefined)
|
|
277
|
-
|
|
278
|
-
return (
|
|
279
|
-
componentName === "LoadingWidgetState" || componentName === "ErrorWidgetState"
|
|
280
|
-
)
|
|
281
297
|
}
|
|
282
298
|
|
|
283
|
-
//
|
|
299
|
+
// TODO: Should cacheKey include shouldTrackReadiness (or other props) when we support toggling it at runtime?
|
|
284
300
|
const widgetComponentCache = new Map<string, Component>()
|
|
285
301
|
|
|
286
302
|
const getSlotWidget = (widget: WidgetBase) => {
|
|
@@ -289,67 +305,31 @@ const getSlotWidget = (widget: WidgetBase) => {
|
|
|
289
305
|
if (!widgetComponentCache.has(cacheKey)) {
|
|
290
306
|
try {
|
|
291
307
|
const originalComponent = widgetLoader(widget)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const widgetRoot = ref<Element | ComponentPublicInstance | null>(null)
|
|
301
|
-
|
|
302
|
-
const reportRendered = () => {
|
|
303
|
-
nextTick(() => {
|
|
304
|
-
const instance = widgetRoot.value
|
|
305
|
-
if (isWidgetLoadingPlaceholder(instance)) {
|
|
306
|
-
return
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const element = resolveWidgetElement(instance)
|
|
310
|
-
if (element) {
|
|
311
|
-
onWidgetRendered(element)
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
onMounted(reportRendered)
|
|
317
|
-
|
|
318
|
-
onUnmounted(() => {
|
|
319
|
-
onWidgetUnmounted()
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
return () =>
|
|
323
|
-
h(
|
|
324
|
-
originalComponent,
|
|
325
|
-
{
|
|
326
|
-
...props,
|
|
327
|
-
onAllWidgetsReady,
|
|
328
|
-
ref: (instance: Element | ComponentPublicInstance | null) => {
|
|
329
|
-
widgetRoot.value = instance
|
|
330
|
-
if (instance) {
|
|
331
|
-
reportRendered()
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
},
|
|
335
|
-
context.slots,
|
|
336
|
-
)
|
|
337
|
-
},
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
widgetComponentCache.set(cacheKey, wrappedComponent)
|
|
308
|
+
const component = shouldTrackReadiness.value
|
|
309
|
+
? wrapWidgetWithLifecycle(
|
|
310
|
+
widget,
|
|
311
|
+
originalComponent,
|
|
312
|
+
() => lifecycleManager.value,
|
|
313
|
+
)
|
|
314
|
+
: originalComponent
|
|
315
|
+
widgetComponentCache.set(cacheKey, component)
|
|
341
316
|
} catch (error) {
|
|
342
|
-
|
|
343
|
-
|
|
317
|
+
const enhancedError = createEnhancedError(error, widget)
|
|
318
|
+
log.widgets("Error creating widget component", {
|
|
319
|
+
pluginKey: widget.pluginKey,
|
|
320
|
+
name: widget.name,
|
|
321
|
+
error: enhancedError.message,
|
|
322
|
+
})
|
|
344
323
|
widgetComponentCache.set(cacheKey, {
|
|
345
324
|
name: "ComponentCreationError",
|
|
346
325
|
setup() {
|
|
347
326
|
return () =>
|
|
348
|
-
h(
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
327
|
+
h(ErrorWidgetState, {
|
|
328
|
+
uuid: widget.uuid,
|
|
329
|
+
pluginKey: widget.pluginKey,
|
|
330
|
+
widgetName: widget.name,
|
|
331
|
+
error: enhancedError,
|
|
332
|
+
})
|
|
353
333
|
},
|
|
354
334
|
})
|
|
355
335
|
}
|
|
@@ -358,29 +338,33 @@ const getSlotWidget = (widget: WidgetBase) => {
|
|
|
358
338
|
return widgetComponentCache.get(cacheKey)
|
|
359
339
|
}
|
|
360
340
|
|
|
361
|
-
const getGridCols = (rowLength) =>
|
|
341
|
+
const getGridCols = (rowLength: number) =>
|
|
342
|
+
mdAndDown.value ? 12 : 12 / rowLength
|
|
362
343
|
|
|
363
|
-
const getSlotCols = (slot
|
|
344
|
+
const getSlotCols = (slot: { column: number }) =>
|
|
345
|
+
mdAndDown.value ? 12 : slot.column
|
|
364
346
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
()
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
lifecycleManager.value.reset()
|
|
371
|
-
|
|
372
|
-
// Clear component cache to force re-wrapping with new lifecycle manager
|
|
373
|
-
widgetComponentCache.clear()
|
|
347
|
+
const resetLayout = () => {
|
|
348
|
+
widgetComponentCache.clear()
|
|
349
|
+
syncLifecycleManager()
|
|
350
|
+
gridKey.value++
|
|
351
|
+
}
|
|
374
352
|
|
|
375
|
-
|
|
353
|
+
watch(widgetsLayoutSignature, (next, prev) => {
|
|
354
|
+
if (!prev || next === prev) {
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
resetLayout()
|
|
358
|
+
})
|
|
376
359
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
)
|
|
360
|
+
onMounted(() => {
|
|
361
|
+
if (shouldTrackReadiness.value) {
|
|
362
|
+
emit("all-widgets-ready", allWidgetsReady.value)
|
|
363
|
+
}
|
|
364
|
+
})
|
|
382
365
|
|
|
383
366
|
onUnmounted(() => {
|
|
384
367
|
stopReadyWatch?.()
|
|
368
|
+
lifecycleManager.value?.reset()
|
|
385
369
|
})
|
|
386
370
|
</script>
|