@raclettejs/core 0.1.34 → 0.1.36-canary.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.
- package/CHANGELOG.md +30 -1
- package/dist/cli.js +86 -82
- package/dist/cli.js.map +3 -3
- package/package.json +5 -5
- package/services/.dockerignore +2 -0
- package/services/backend/.dockerignore +3 -1
- package/services/backend/src/core/payload/payloadTypes.ts +1 -0
- package/services/backend/src/core/pluginSystem/configGenerator/index.ts +12 -11
- package/services/backend/src/core/pluginSystem/pluginFastifyInstance.ts +28 -3
- package/services/backend/src/core/pluginSystem/pluginLoader.ts +11 -2
- package/services/backend/src/core/pluginSystem/pluginTypes.ts +39 -1
- package/services/backend/src/core/sockets/createSystemEventHandlers.ts +4 -4
- package/services/backend/src/core/sockets/socketManager.ts +80 -32
- package/services/backend/src/core/sockets/socketTypes.ts +6 -0
- package/services/backend/src/core/validation/schemaGenerator.ts +10 -3
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/project.service.ts +1 -1
- package/services/backend/src/corePlugins/raclette__core/backend/index.ts +0 -2
- package/services/backend/src/modules/authentication/index.ts +15 -23
- package/services/backend/src/shared/helper/adminTag.ts +34 -0
- package/services/backend/src/shared/types/plugins/index.ts +1 -9
- package/services/backend/src/utils/request.utils.ts +1 -1
- package/services/frontend/.dockerignore +3 -1
- package/services/frontend/provision/entrypoint.sh +2 -2
- package/services/frontend/src/core/helpers/devMode.ts +1 -3
- package/services/frontend/src/core/lib/data/dataApi.ts +27 -16
- package/services/frontend/src/core/lib/data/queryApi.ts +17 -8
- package/services/frontend/src/core/lib/data/responseTypeHandler.ts +17 -8
- package/services/frontend/src/core/lib/data/writeDataHandler.ts +3 -1
- package/services/frontend/src/core/lib/dataHelper.ts +51 -12
- package/services/frontend/src/core/lib/eventWhitelist.ts +2 -0
- package/services/frontend/src/core/lib/httpClient.ts +16 -2
- package/services/frontend/src/core/lib/logger.ts +2 -3
- package/services/frontend/src/core/lib/userNotifier.ts +20 -0
- package/services/frontend/src/core/lib/workSessionUrl.ts +16 -0
- package/services/frontend/src/core/main.ts +82 -15
- package/services/frontend/src/core/setup/socketBootstrap.ts +83 -0
- package/services/frontend/src/core/setup/socketClient.ts +39 -39
- package/services/frontend/src/core/setup/socketEvents.ts +152 -158
- package/services/frontend/src/core/setup/socketRegistry.ts +19 -0
- package/services/frontend/src/core/store/index.ts +2 -4
- package/services/frontend/src/core/types/DataApi.ts +10 -2
- package/services/frontend/src/core/types/PluginRegistrar.ts +1 -1
- package/services/frontend/src/orchestrator/ProductOrchestrator.vue +15 -1
- package/services/frontend/src/orchestrator/assets/styles/layers.css +4 -1
- package/services/frontend/src/orchestrator/components/dataTable/BaseDataTable.vue +267 -35
- package/services/frontend/src/orchestrator/components/menu/ServerStatus.vue +11 -2
- package/services/frontend/src/orchestrator/composables/useVueQueryObservableHelper.ts +12 -7
- package/services/frontend/src/orchestrator/composables/useVueWriteOperationHelper.ts +12 -6
- package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +2 -4
- package/services/frontend/src/orchestrator/i18n/de-DE.json +1 -0
- package/services/frontend/src/orchestrator/i18n/en-EU.json +1 -0
- package/services/frontend/src/orchestrator/i18n/sk.json +1 -0
- package/services/frontend/src/orchestrator/i18n/tl-TL.json +1 -0
- package/services/frontend/src/orchestrator/index.ts +7 -24
- package/services/frontend/src/orchestrator/lib/queryParamsSource.ts +48 -0
- package/services/frontend/src/orchestrator/main.ts +2 -2
- package/services/frontend/src/orchestrator/router/index.ts +0 -19
- package/services/frontend/src/orchestrator/router/registerEventHandlers.ts +29 -0
- package/services/frontend/src/orchestrator/router/routeStore.ts +92 -17
- package/services/frontend/src/orchestrator/router/routes.ts +5 -0
- package/services/frontend/src/orchestrator/setup/application.ts +11 -2
- package/services/frontend/src/orchestrator/types/DataApi.ts +19 -0
- package/services/frontend/src/orchestrator/types/PluginApi.ts +4 -7
- package/services/frontend/src/orchestrator/types/Widgets.ts +2 -0
- package/services/frontend/src/orchestrator/types/index.ts +1 -0
- package/templates/docker-compose.yml +1 -4
- package/templates/fs.yml +1 -1
- package/package/dist/index.js +0 -452
- package/services/backend/.yarn/install-state.gz +0 -0
- package/services/backend/dist/core/eventBus/index.js +0 -7
- package/services/backend/dist/core/pluginSystem/configGenerator/index.js +0 -346
- package/services/backend/dist/core/sockets/index.js +0 -95
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/events/index.js +0 -31
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/index.js +0 -48
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/routes/index.js +0 -15
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/events/index.js +0 -22
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/index.js +0 -51
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/routes/index.js +0 -19
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/events/index.js +0 -22
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/index.js +0 -48
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.js +0 -19
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/events/index.js +0 -31
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/index.js +0 -49
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/routes/index.js +0 -16
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/events/index.js +0 -39
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/index.js +0 -50
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/routes/index.js +0 -19
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/events/index.js +0 -31
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/index.js +0 -51
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/routes/index.js +0 -21
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/events/index.js +0 -31
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/index.js +0 -48
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.js +0 -15
- package/services/backend/dist/corePlugins/raclette__core/backend/index.js +0 -34
- package/services/backend/dist/domains/index.js +0 -11
- package/services/backend/dist/domains/system/index.js +0 -11
- package/services/backend/dist/domains/system/routes/index.js +0 -17
- package/services/backend/dist/helpers/index.js +0 -14
- package/services/backend/dist/index.js +0 -3
- package/services/backend/dist/modules/authentication/index.js +0 -253
- package/services/backend/dist/shared/types/core/index.js +0 -8
- package/services/backend/dist/shared/types/dataTypes/index.js +0 -6
- package/services/backend/dist/shared/types/index.js +0 -8
- package/services/backend/dist/shared/types/plugins/index.js +0 -8
- package/services/backend/dist/types/index.js +0 -12
- package/services/backend/dist/utils/index.js +0 -2
- package/services/frontend/.yarn/install-state.gz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, type Ref } from "vue"
|
|
2
|
-
import
|
|
2
|
+
import { isDevelopmentMode } from "@racletteCore/helpers/devMode"
|
|
3
3
|
import log from "@racletteCore/lib/logger"
|
|
4
4
|
|
|
5
5
|
export type OnAllWidgetsReady = (callback: () => void) => void
|
|
@@ -24,9 +24,7 @@ export function createWidgetLifecycleManager(
|
|
|
24
24
|
const readyCallbacks = new Set<() => void>()
|
|
25
25
|
const observers = new Map<string, MutationObserver>()
|
|
26
26
|
|
|
27
|
-
const DEV_MODE =
|
|
28
|
-
getEnvVariable("RACLETTE_DEBUG_MODE") === "true" ||
|
|
29
|
-
!getEnvVariable("RACLETTE_DEBUG_MODE")
|
|
27
|
+
const DEV_MODE = isDevelopmentMode()
|
|
30
28
|
|
|
31
29
|
const checkAllReady = () => {
|
|
32
30
|
if (renderedWidgets.value.size === totalWidgets && !allWidgetsReady.value) {
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"socket_status_0": "Server nicht verbunden",
|
|
141
141
|
"socket_status_1": "Server verbunden",
|
|
142
142
|
"socket_status_2": "Verbindung zum Server wird hergestellt...",
|
|
143
|
+
"app_loading": "Anwendungsinhalt wird geladen",
|
|
143
144
|
"dataSynced$displayName$type": "{type} \"{displayName}\" wurde synchronisiert",
|
|
144
145
|
"dataCreate$displayName$type": "{type} \"{displayName}\" wurde erstellt",
|
|
145
146
|
"dataUpdate$displayName$type": "{type} \"{displayName}\" wurde aktualisiert",
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"socket_status_0": "Server not connected",
|
|
141
141
|
"socket_status_1": "Server connected",
|
|
142
142
|
"socket_status_2": "Connecting to server...",
|
|
143
|
+
"app_loading": "Loading application content",
|
|
143
144
|
"dataSynced$displayName$type": "{type} \"{displayName}\" has been synchronized",
|
|
144
145
|
"dataCreate$displayName$type": "{type} \"{displayName}\" has been created",
|
|
145
146
|
"dataUpdate$displayName$type": "{type} \"{displayName}\" has been updated",
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"socket_status_0": "Server nie je pripojený",
|
|
141
141
|
"socket_status_1": "Server je pripojený",
|
|
142
142
|
"socket_status_2": "Pripájanie k serveru...",
|
|
143
|
+
"app_loading": "Načítava sa obsah aplikácie",
|
|
143
144
|
"dataSynced$displayName$type": "{type} \"{displayName}\" bol synchronizovaný",
|
|
144
145
|
"dataCreate$displayName$type": "{type} \"{displayName}\" bol vytvorený",
|
|
145
146
|
"dataUpdate$displayName$type": "{type} \"{displayName}\" bol aktualizovaný",
|
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
"socket_status_0": "Qun Qapbogh",
|
|
111
111
|
"socket_status_1": "Qun QaptaH",
|
|
112
112
|
"socket_status_2": "QunDaq QaptaH…",
|
|
113
|
+
"app_loading": "App SeHlaw Loading",
|
|
113
114
|
"dataSynced$displayName$type": "{type} “{displayName}” QaptaH",
|
|
114
115
|
"dataCreate$displayName$type": "{type} “{displayName}” botlhutlh",
|
|
115
116
|
"dataUpdate$displayName$type": "{type} “{displayName}” Qapla’",
|
|
@@ -1,41 +1,20 @@
|
|
|
1
1
|
import type { App as VueApp } from "vue"
|
|
2
2
|
import createRacletteApp, { corePluginApi } from "@racletteCore/main"
|
|
3
|
+
import { extractSessionIdFromUrl } from "@racletteCore/lib/workSessionUrl"
|
|
3
4
|
import { createVueApp, createLoginVueApp } from "./main"
|
|
4
5
|
import { initApp } from "./setup/application"
|
|
5
|
-
import { validate } from "uuid"
|
|
6
6
|
export * from "./exports"
|
|
7
7
|
|
|
8
8
|
const VUE_MOUNTING_ELEMENT = "#app"
|
|
9
9
|
let currentApp: VueApp | undefined
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Check if URL matches :workSession/id={uuid} pattern and extract sessionId
|
|
13
|
-
* Supports racletteJS route format: /:workSession/id={uuid}
|
|
14
|
-
*/
|
|
15
|
-
const extractSessionIdFromUrl = (): string | null => {
|
|
16
|
-
const path = window.location.pathname + (window.location.hash || "")
|
|
17
|
-
// Match /:workSession/id={uuid} pattern
|
|
18
|
-
// The route parser will handle this, but we need to extract it here for bootstrapping
|
|
19
|
-
const workSessionMatch = path.match(/\/:workSession\/id=([^/&#]+)/)
|
|
20
|
-
|
|
21
|
-
if (workSessionMatch && workSessionMatch[1]) {
|
|
22
|
-
const sessionId = workSessionMatch[1]
|
|
23
|
-
// Validate UUID format
|
|
24
|
-
if (validate(sessionId)) {
|
|
25
|
-
return sessionId
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return null
|
|
30
|
-
}
|
|
31
|
-
|
|
32
11
|
const startApp = async () => {
|
|
33
12
|
try {
|
|
34
13
|
// Check if URL indicates a work session
|
|
35
14
|
const sessionId = extractSessionIdFromUrl()
|
|
36
15
|
|
|
37
16
|
const res = await createRacletteApp({
|
|
38
|
-
requireAuth: !sessionId,
|
|
17
|
+
requireAuth: !sessionId,
|
|
39
18
|
sessionId: sessionId || undefined,
|
|
40
19
|
})
|
|
41
20
|
|
|
@@ -47,7 +26,11 @@ const startApp = async () => {
|
|
|
47
26
|
if (!res.authenticated && !sessionId) {
|
|
48
27
|
const noUsers = res.code === "RCLT_DB_NO_USERS"
|
|
49
28
|
if (res.login) {
|
|
50
|
-
currentApp = await createLoginVueApp(
|
|
29
|
+
currentApp = await createLoginVueApp(
|
|
30
|
+
VUE_MOUNTING_ELEMENT,
|
|
31
|
+
res.login,
|
|
32
|
+
noUsers,
|
|
33
|
+
)
|
|
51
34
|
}
|
|
52
35
|
} else {
|
|
53
36
|
currentApp = await createVueApp(VUE_MOUNTING_ELEMENT)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isRef, toValue, type MaybeRefOrGetter } from "vue"
|
|
2
|
+
import type {
|
|
3
|
+
CustomStoreActionParams,
|
|
4
|
+
QueryParamsInput,
|
|
5
|
+
} from "@racletteCore/types"
|
|
6
|
+
import { isDevelopmentMode } from "@racletteCore/helpers/devMode"
|
|
7
|
+
import log from "@racletteCore/lib/logger"
|
|
8
|
+
import type { VueQueryParamsInput } from "../types/DataApi"
|
|
9
|
+
|
|
10
|
+
function isPlainParamsObject(
|
|
11
|
+
value: unknown,
|
|
12
|
+
): value is CustomStoreActionParams {
|
|
13
|
+
return value != null && typeof value === "object" && !Array.isArray(value)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function warnInvalidQueryParams(context: string, value: unknown): void {
|
|
17
|
+
if (!isDevelopmentMode()) return
|
|
18
|
+
const kind =
|
|
19
|
+
value == null ? String(value) : Array.isArray(value) ? "array" : typeof value
|
|
20
|
+
log.warning(
|
|
21
|
+
"Invalid query params",
|
|
22
|
+
`${context}: expected a plain object, got ${kind}. Using {}.`,
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize Vue reactive params into core {@link QueryParamsInput}:
|
|
28
|
+
* a plain object snapshot, or a subscriber re-read on each `execute()`.
|
|
29
|
+
*/
|
|
30
|
+
export function toQueryParamsSource(
|
|
31
|
+
params?: VueQueryParamsInput,
|
|
32
|
+
): QueryParamsInput {
|
|
33
|
+
if (params == null) return {}
|
|
34
|
+
|
|
35
|
+
if (typeof params === "function" || isRef(params)) {
|
|
36
|
+
return () => {
|
|
37
|
+
const resolved = toValue(params as MaybeRefOrGetter)
|
|
38
|
+
if (isPlainParamsObject(resolved)) return resolved
|
|
39
|
+
warnInvalidQueryParams("Reactive params subscriber", resolved)
|
|
40
|
+
return {}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (isPlainParamsObject(params)) return params
|
|
45
|
+
|
|
46
|
+
warnInvalidQueryParams("Query params", params)
|
|
47
|
+
return {}
|
|
48
|
+
}
|
|
@@ -12,12 +12,12 @@ import log from "@racletteCore/lib/logger"
|
|
|
12
12
|
import { initPluginRegistration } from "@racletteCore/main"
|
|
13
13
|
let loginVueApp: VueApp<Element> | undefined
|
|
14
14
|
|
|
15
|
-
export const createVueApp = async (el: string): VueApp => {
|
|
16
|
-
// unmount login vue app, if exists
|
|
15
|
+
export const createVueApp = async (el: string): Promise<VueApp> => {
|
|
17
16
|
if (loginVueApp) {
|
|
18
17
|
loginVueApp.unmount()
|
|
19
18
|
loginVueApp = undefined
|
|
20
19
|
}
|
|
20
|
+
|
|
21
21
|
const vueApp = createApp(App)
|
|
22
22
|
const { i18nInstance, instanceAdapter, dateLocale } = await initI18n()
|
|
23
23
|
await initPluginRegistration()
|
|
@@ -4,32 +4,13 @@
|
|
|
4
4
|
import { createRouter, createWebHistory } from "vue-router"
|
|
5
5
|
import { afterEach, beforeEach } from "./routerHooks"
|
|
6
6
|
import routes from "./routes"
|
|
7
|
-
import { $eventbus } from "@racletteCore/main"
|
|
8
|
-
|
|
9
|
-
// create router instance
|
|
10
7
|
|
|
11
8
|
const router = createRouter({
|
|
12
9
|
history: createWebHistory(),
|
|
13
10
|
routes,
|
|
14
11
|
})
|
|
15
12
|
|
|
16
|
-
/* Rooter hooks */
|
|
17
13
|
router.beforeEach(beforeEach)
|
|
18
14
|
router.afterEach(afterEach)
|
|
19
|
-
$eventbus.on("backend/error", (error) => {
|
|
20
|
-
if (error.name === "AxiosError") {
|
|
21
|
-
const errorResponse = error.response?.data
|
|
22
|
-
if (errorResponse?.code === "FST_JWT_AUTHORIZATION_TOKEN_EXPIRED") {
|
|
23
|
-
// Capture current route path (including query and hash)
|
|
24
|
-
const currentUrl = router.currentRoute.value.fullPath
|
|
25
|
-
// Redirect to login with the current URL as a query param
|
|
26
|
-
if (window.location.href !== window.location.origin + "/login") {
|
|
27
|
-
window.location.href =
|
|
28
|
-
window.location.origin + "/login?redirect=" + currentUrl
|
|
29
|
-
}
|
|
30
15
|
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
16
|
export default router
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Router } from "vue-router"
|
|
2
|
+
import type EventEmitter from "@racletteCore/lib/eventEmitter"
|
|
3
|
+
import { applyCompositionSlotsFromRoute } from "./routeStore"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wire router reactions to the global event bus.
|
|
7
|
+
* Kept separate from router creation so it can be invoked from initApp (testable).
|
|
8
|
+
*/
|
|
9
|
+
export const registerRouterEventHandlers = (
|
|
10
|
+
router: Router,
|
|
11
|
+
eventbus: EventEmitter,
|
|
12
|
+
) => {
|
|
13
|
+
eventbus.on("ui/syncRouteCompositions", () => {
|
|
14
|
+
applyCompositionSlotsFromRoute(router.currentRoute.value)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
eventbus.on("backend/error", (error) => {
|
|
18
|
+
if (error.name === "AxiosError") {
|
|
19
|
+
const errorResponse = error.response?.data
|
|
20
|
+
if (errorResponse?.code === "FST_JWT_AUTHORIZATION_TOKEN_EXPIRED") {
|
|
21
|
+
const currentUrl = router.currentRoute.value.fullPath
|
|
22
|
+
if (window.location.href !== window.location.origin + "/login") {
|
|
23
|
+
window.location.href =
|
|
24
|
+
window.location.origin + "/login?redirect=" + currentUrl
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type CompositionSlot,
|
|
7
7
|
} from "@racletteOrchestrator/router/routeParserHelper"
|
|
8
8
|
import { getCompositionIdByPath } from "@racletteCore/store/reducers/compositions/selectors"
|
|
9
|
+
import logger from "@racletteCore/lib/logger"
|
|
9
10
|
|
|
10
11
|
// TODO: find better filename
|
|
11
12
|
|
|
@@ -35,6 +36,12 @@ export const dispatchSetCompositionAs = (
|
|
|
35
36
|
},
|
|
36
37
|
})
|
|
37
38
|
}
|
|
39
|
+
} else {
|
|
40
|
+
logger.warning(
|
|
41
|
+
"compositionNotFound",
|
|
42
|
+
`No composition for path "${compositionPath}" (slot "${slot}"). ` +
|
|
43
|
+
"Route may be ahead of socket bootstrap or the composition was removed.",
|
|
44
|
+
)
|
|
38
45
|
}
|
|
39
46
|
} else {
|
|
40
47
|
$store.dispatch({
|
|
@@ -99,36 +106,82 @@ const getCompositionSlotChanges = (
|
|
|
99
106
|
return { toRemove, toAdd, toUpdate }
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Same slot name, different composition path — swap in one `setCompositionAs`
|
|
111
|
+
* instead of unset + set (avoids a frame with no active composition).
|
|
112
|
+
*/
|
|
113
|
+
const partitionSlotChanges = (
|
|
114
|
+
toRemove: CompositionSlot[],
|
|
115
|
+
toAdd: CompositionSlot[],
|
|
105
116
|
) => {
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const
|
|
117
|
+
const replacements: CompositionSlot[] = []
|
|
118
|
+
const stillToRemove: CompositionSlot[] = []
|
|
119
|
+
const stillToAdd: CompositionSlot[] = []
|
|
109
120
|
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
undefined,
|
|
113
|
-
!hasToPageIdParameter,
|
|
121
|
+
const addBySlotName = new Map(
|
|
122
|
+
toAdd.map((slot) => [slot.slotName, slot]),
|
|
114
123
|
)
|
|
115
124
|
|
|
116
|
-
const
|
|
117
|
-
|
|
125
|
+
for (const removed of toRemove) {
|
|
126
|
+
const replacement = addBySlotName.get(removed.slotName)
|
|
127
|
+
if (replacement) {
|
|
128
|
+
replacements.push(replacement)
|
|
129
|
+
addBySlotName.delete(removed.slotName)
|
|
130
|
+
} else {
|
|
131
|
+
stillToRemove.push(removed)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
stillToAdd.push(...addBySlotName.values())
|
|
136
|
+
|
|
137
|
+
return { replacements, stillToRemove, stillToAdd }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const getCompositionSlotsForRoute = (
|
|
141
|
+
route: RouteLocationNormalized,
|
|
142
|
+
options?: { useDefaultSlotFallback?: boolean },
|
|
143
|
+
) => {
|
|
144
|
+
const hasPageIdParameter = Boolean(route.params.pageId?.length)
|
|
145
|
+
const useDefaultSlotFallback =
|
|
146
|
+
options?.useDefaultSlotFallback ?? !hasPageIdParameter
|
|
147
|
+
|
|
148
|
+
return parseRouteToCompositionSlots(
|
|
149
|
+
route.fullPath,
|
|
118
150
|
undefined,
|
|
119
|
-
|
|
151
|
+
useDefaultSlotFallback,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const applyCompositionSlots = (slots: CompositionSlot[]) => {
|
|
156
|
+
slots.forEach((slot) =>
|
|
157
|
+
dispatchSetCompositionAs(slot.slotName, slot.slotValue, slot.slotParams),
|
|
120
158
|
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const updateActiveCompositions = (
|
|
162
|
+
to: RouteLocationNormalized,
|
|
163
|
+
from: RouteLocationNormalized,
|
|
164
|
+
) => {
|
|
165
|
+
const isInitialRouting = from.name === undefined
|
|
166
|
+
|
|
167
|
+
const compositionSlots = getCompositionSlotsForRoute(to)
|
|
168
|
+
const beforeCompositionSlots = getCompositionSlotsForRoute(from, {
|
|
169
|
+
useDefaultSlotFallback:
|
|
170
|
+
!isInitialRouting && !Boolean(from.params.pageId?.length),
|
|
171
|
+
})
|
|
121
172
|
|
|
122
173
|
const { toRemove, toAdd, toUpdate } = getCompositionSlotChanges(
|
|
123
174
|
beforeCompositionSlots,
|
|
124
175
|
compositionSlots,
|
|
125
176
|
)
|
|
126
177
|
|
|
127
|
-
|
|
128
|
-
|
|
178
|
+
const { replacements, stillToRemove, stillToAdd } = partitionSlotChanges(
|
|
179
|
+
toRemove,
|
|
180
|
+
toAdd,
|
|
181
|
+
)
|
|
129
182
|
|
|
130
|
-
//
|
|
131
|
-
|
|
183
|
+
// Same slot, new composition path — set directly (no unset in between)
|
|
184
|
+
replacements.forEach((slot) =>
|
|
132
185
|
dispatchSetCompositionAs(slot.slotName, slot.slotValue, slot.slotParams),
|
|
133
186
|
)
|
|
134
187
|
|
|
@@ -149,6 +202,14 @@ export const updateActiveCompositions = (
|
|
|
149
202
|
})
|
|
150
203
|
}
|
|
151
204
|
})
|
|
205
|
+
|
|
206
|
+
// New slots (slot name was not active before)
|
|
207
|
+
stillToAdd.forEach((slot) =>
|
|
208
|
+
dispatchSetCompositionAs(slot.slotName, slot.slotValue, slot.slotParams),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
// Slots removed without a replacement on the same slot name
|
|
212
|
+
stillToRemove.forEach((slot) => dispatchSetCompositionAs(slot.slotName))
|
|
152
213
|
}
|
|
153
214
|
|
|
154
215
|
export const handleRouteChange = (
|
|
@@ -183,3 +244,17 @@ export const getDefaultSlotValue = (url: string) =>
|
|
|
183
244
|
parseRouteToCompositionSlots(url, undefined, true).find(
|
|
184
245
|
(slot) => slot.slotName === DEFAULT_SLOT_NAME,
|
|
185
246
|
)?.slotValue
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Re-apply composition slots from the current route without a navigation event.
|
|
250
|
+
* Used after socket project bootstrap clears ui.page while the URL is unchanged.
|
|
251
|
+
*/
|
|
252
|
+
export const applyCompositionSlotsFromRoute = (
|
|
253
|
+
route: RouteLocationNormalized,
|
|
254
|
+
) => {
|
|
255
|
+
if (route.name !== "app.space.page") {
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
applyCompositionSlots(getCompositionSlotsForRoute(route))
|
|
260
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RouteRecordRaw } from "vue-router"
|
|
2
2
|
import ProductOrchestrator from "../ProductOrchestrator.vue"
|
|
3
3
|
import useAuthentication from "@racletteOrchestrator/composables/useAuthentication"
|
|
4
|
+
import { $store } from "@racletteCore"
|
|
4
5
|
|
|
5
6
|
const routes: Readonly<RouteRecordRaw[]> = [
|
|
6
7
|
{
|
|
@@ -17,6 +18,10 @@ const routes: Readonly<RouteRecordRaw[]> = [
|
|
|
17
18
|
const { clearCookies } = useAuthentication()
|
|
18
19
|
|
|
19
20
|
clearCookies()
|
|
21
|
+
|
|
22
|
+
// Clear project context so a later socket re-join cannot light-rejoin on stale state.
|
|
23
|
+
$store.dispatch({ type: "projectInit" })
|
|
24
|
+
$store.dispatch({ type: "project/set", payload: { _id: null } })
|
|
20
25
|
|
|
21
26
|
if (window.location.href !== window.location.origin + "/login") {
|
|
22
27
|
window.location.href = window.location.origin + "/login"
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { CorePluginApi } from "@racletteCore"
|
|
2
|
+
import router from "@racletteOrchestrator/router"
|
|
3
|
+
import { registerRouterEventHandlers } from "@racletteOrchestrator/router/registerEventHandlers"
|
|
4
|
+
|
|
5
|
+
let routerHandlersRegistered = false
|
|
6
|
+
|
|
7
|
+
export const initApp = async (corePluginApi: CorePluginApi) => {
|
|
8
|
+
if (!routerHandlersRegistered) {
|
|
9
|
+
registerRouterEventHandlers(router, corePluginApi.$eventbus)
|
|
10
|
+
routerHandlersRegistered = true
|
|
11
|
+
}
|
|
3
12
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from "vue"
|
|
2
|
+
import type {
|
|
3
|
+
CustomStoreActionParams,
|
|
4
|
+
CustomStoreActionsPayload,
|
|
5
|
+
} from "@racletteCore/types"
|
|
6
|
+
|
|
7
|
+
/** Params accepted by Vue plugin `$data` methods (refs/computed/getters allowed). */
|
|
8
|
+
export type VueQueryParamsInput =
|
|
9
|
+
| MaybeRefOrGetter<CustomStoreActionParams | undefined>
|
|
10
|
+
| CustomStoreActionParams
|
|
11
|
+
| undefined
|
|
12
|
+
|
|
13
|
+
/** Vue orchestrator payload — extends core with reactive `params`. */
|
|
14
|
+
export type VueStoreActionsPayload = Omit<
|
|
15
|
+
CustomStoreActionsPayload,
|
|
16
|
+
"params"
|
|
17
|
+
> & {
|
|
18
|
+
params?: MaybeRefOrGetter<CustomStoreActionParams | undefined>
|
|
19
|
+
}
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import type { useI18n } from "vue-i18n"
|
|
2
2
|
import type { ComputedRef, Ref } from "vue"
|
|
3
|
-
import type { CorePluginApi } from "@racletteCore/
|
|
4
|
-
import type {
|
|
5
|
-
CustomStoreActionsPayload,
|
|
6
|
-
PluginStoreApi,
|
|
7
|
-
} from "@racletteCore/types"
|
|
3
|
+
import type { PluginStoreApi, CorePluginApi } from "@racletteCore/types"
|
|
4
|
+
import type { VueQueryParamsInput, VueStoreActionsPayload } from "./DataApi"
|
|
8
5
|
import type { Query } from "@racletteCore/store/reducers/queries/reducers"
|
|
9
6
|
import type { actionId } from "@racletteCore"
|
|
10
7
|
import type { Socket } from "socket.io-client"
|
|
11
8
|
import type { User } from "@shared/types"
|
|
12
9
|
// TODO: finalize types
|
|
13
10
|
// TODO: generate this type from index.ts in the plugin & extend it globally
|
|
14
|
-
export type PluginMethod = (payload?:
|
|
11
|
+
export type PluginMethod = (payload?: VueStoreActionsPayload) => {
|
|
15
12
|
isLoading: Boolean
|
|
16
13
|
response: Ref<unknown>
|
|
17
14
|
error: Ref<unknown>
|
|
18
15
|
data: ComputedRef<unknown>
|
|
19
16
|
dataArr: Array<ComputedRef<unknown>>
|
|
20
17
|
execute: (
|
|
21
|
-
params?:
|
|
18
|
+
params?: VueQueryParamsInput,
|
|
22
19
|
) => Promise<{ response: any; result: any }>
|
|
23
20
|
// query and uuids only provided from queryObservableHelper
|
|
24
21
|
query?: ComputedRef<Query>
|
|
@@ -54,6 +54,8 @@ export type WidgetDeclaration = Omit<
|
|
|
54
54
|
RegisteredWidgetDeclaration,
|
|
55
55
|
"pluginKey" | "author" | "name" // name will be extracted via filename, cannot be overwritten
|
|
56
56
|
> & {
|
|
57
|
+
title: string
|
|
58
|
+
description?: string
|
|
57
59
|
color?: string
|
|
58
60
|
icon?: string
|
|
59
61
|
images?: string[]
|
|
@@ -56,7 +56,7 @@ services:
|
|
|
56
56
|
MONGO_HOST=${RACLETTE_MONGODB_HOST:-mongodb://mongodb:${RACLETTE_MONGODB_PORT:-27017}/${RACLETTE_MONGODB_DATABASE:-raclette}}
|
|
57
57
|
- >-
|
|
58
58
|
CACHE_URL=${RACLETTE_CACHE_URL:-redis://cache:${RACLETTE_CACHE_PORT:-6379}}
|
|
59
|
-
- RACLETTE_DEBUG_MODE
|
|
59
|
+
- RACLETTE_DEBUG_MODE=${RACLETTE_DEBUG_MODE:-true}
|
|
60
60
|
- RACLETTE_APP_PATH=/home/shookie/core-dev/@raclettejs/playground
|
|
61
61
|
volumes:
|
|
62
62
|
- yarn-cache:/usr/local/share/.cache/yarn
|
|
@@ -111,9 +111,6 @@ services:
|
|
|
111
111
|
- RACLETTE_DEBUG_MODE=${RACLETTE_DEBUG_MODE:-true}
|
|
112
112
|
- >-
|
|
113
113
|
RACLETTE_SERVER_BASE_URL=${RACLETTE_SERVER_BASE_URL:-http://localhost:${RACLETTE_SERVER_PORT:-8082}}
|
|
114
|
-
- >-
|
|
115
|
-
RACLETTE_SOCKET_URL=${RACLETTE_SOCKET_URL:-http://localhost:${RACLETTE_SERVER_PORT:-8082}}
|
|
116
|
-
- RACLETTE_DEBUG_MODE=true
|
|
117
114
|
- RACLETTE_APP_PATH=/home/shookie/core-dev/@raclettejs/playground
|
|
118
115
|
volumes:
|
|
119
116
|
- yarn-cache:/usr/local/share/.cache/yarn
|
package/templates/fs.yml
CHANGED
|
@@ -17,7 +17,7 @@ patterns:
|
|
|
17
17
|
ext: ["**/*.vue", "**/*.ts", "**/*.js", "**/*.json", "**/*.css", "**/*.scss"]
|
|
18
18
|
pkg: ["**/package.json", "**/yarn.lock"] # changes here require new install anyway
|
|
19
19
|
# always added when globbing, config.root is also always added
|
|
20
|
-
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/.prettierrc", "**/eslint.config.js"]
|
|
20
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/.prettierrc", "**/eslint.config.js", "**/.yarnrc.yml", "**/.yarn/**"]
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
mappings:
|