@raclettejs/core 0.1.23 → 0.1.25
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 +41 -0
- package/bin/cli.js +2 -2
- package/dist/cli.js +136 -155
- package/dist/cli.js.map +4 -4
- package/dist/index.js +15 -16
- package/dist/index.js.map +4 -4
- package/package.json +24 -22
- package/services/backend/.yarn/install-state.gz +0 -0
- package/services/backend/dist/core/eventBus/index.js +7 -0
- package/services/backend/dist/core/pluginSystem/configGenerator/index.js +346 -0
- package/services/backend/dist/core/sockets/index.js +95 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/routes/index.js +15 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/events/index.js +22 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/index.js +51 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/events/index.js +22 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/index.js +49 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/routes/index.js +16 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/events/index.js +39 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/index.js +50 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/index.js +51 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/routes/index.js +21 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.js +15 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/index.js +34 -0
- package/services/backend/dist/domains/index.js +11 -0
- package/services/backend/dist/domains/system/index.js +11 -0
- package/services/backend/dist/domains/system/routes/index.js +17 -0
- package/services/backend/dist/helpers/index.js +14 -0
- package/services/backend/dist/index.js +3 -0
- package/services/backend/dist/modules/authentication/index.js +253 -0
- package/services/backend/dist/shared/types/core/index.js +8 -0
- package/services/backend/dist/shared/types/dataTypes/index.js +6 -0
- package/services/backend/dist/shared/types/index.js +8 -0
- package/services/backend/dist/shared/types/plugins/index.js +8 -0
- package/services/backend/dist/types/index.js +12 -0
- package/services/backend/dist/utils/index.js +2 -0
- package/services/backend/package.json +20 -18
- package/services/backend/src/core/contracting/contractRegistrar.ts +1 -1
- package/services/backend/src/core/pluginSystem/configGenerator/generatorTypes.ts +1 -0
- package/services/backend/src/core/pluginSystem/configGenerator/index.ts +2 -2
- package/services/backend/src/core/pluginSystem/pluginLoader.ts +99 -44
- package/services/backend/src/core/pluginSystem/pluginTypes.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/index.ts +2 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patchOwn.ts +68 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/user.model.ts +1 -1
- package/services/backend/src/corePlugins/raclette__core/frontend/generated-config.ts +12 -0
- package/services/backend/src/shared/schemas/core/Account.schema.ts +10 -10
- package/services/backend/src/shared/schemas/core/Composition.schema.ts +25 -22
- package/services/backend/src/shared/schemas/core/CompositionCreate.schema.ts +19 -16
- package/services/backend/src/shared/schemas/core/CompositionUpdate.schema.ts +19 -16
- package/services/backend/src/shared/schemas/core/InteractionLink.schema.ts +15 -15
- package/services/backend/src/shared/schemas/core/InteractionLinkCreate.schema.ts +9 -9
- package/services/backend/src/shared/schemas/core/InteractionLinkUpdate.schema.ts +9 -9
- package/services/backend/src/shared/schemas/core/Project.schema.ts +28 -6
- package/services/backend/src/shared/schemas/core/ProjectCreate.schema.ts +22 -0
- package/services/backend/src/shared/schemas/core/ProjectUpdate.schema.ts +25 -0
- package/services/backend/src/shared/schemas/core/Tag.schema.ts +11 -9
- package/services/backend/src/shared/schemas/core/TagCreate.schema.ts +1 -3
- package/services/backend/src/shared/schemas/core/TagUpdate.schema.ts +1 -0
- package/services/backend/src/shared/schemas/core/Trigger.schema.ts +3 -3
- package/services/backend/src/shared/schemas/core/User.schema.ts +18 -18
- package/services/backend/src/shared/schemas/core/UserCreate.schema.ts +9 -9
- package/services/backend/src/shared/schemas/core/Widget.schema.ts +5 -5
- package/services/backend/src/shared/schemas/core/WidgetLayout.schema.ts +9 -9
- package/services/backend/src/shared/types/core/Composition.types.ts +1 -0
- package/services/backend/src/shared/types/core/CompositionCreate.types.ts +1 -0
- package/services/backend/src/shared/types/core/CompositionUpdate.types.ts +1 -0
- package/services/backend/src/shared/types/core/Project.types.ts +4 -0
- package/services/backend/src/shared/types/core/ProjectCreate.types.ts +4 -0
- package/services/backend/src/shared/types/core/ProjectUpdate.types.ts +4 -1
- package/services/backend/src/shared/types/core/Tag.types.ts +1 -1
- package/services/backend/src/shared/types/core/TagCreate.types.ts +0 -1
- package/services/backend/src/shared/types/core/index.ts +4 -0
- package/services/backend/src/shared/types/plugins/index.ts +1 -1
- package/services/backend/tsconfig.json +1 -0
- package/services/backend/yarn.lock +797 -935
- package/services/frontend/.yarn/install-state.gz +0 -0
- package/services/frontend/eslint.config.js +9 -0
- package/services/frontend/index.html +3 -3
- package/services/frontend/package.json +30 -28
- package/services/frontend/src/core/setup/plugin-system/discovery/app-plugins.ts +43 -4
- package/services/frontend/src/orchestrator/ProductOrchestrator.vue +10 -11
- package/services/frontend/src/orchestrator/assets/styles/layers.css +11 -0
- package/services/frontend/src/orchestrator/assets/styles/tailwindStyles.css +5 -11
- package/services/frontend/src/orchestrator/assets/styles/vuetifyStyles.scss +0 -4
- package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +5 -18
- package/services/frontend/src/orchestrator/composables/useWidgets/helperFunctions.ts +54 -5
- package/services/frontend/src/orchestrator/helpers/index.ts +1 -0
- package/services/frontend/src/orchestrator/helpers/widgetVisuals.ts +71 -0
- package/services/frontend/src/orchestrator/setup/vuetify.ts +2 -0
- package/services/frontend/src/orchestrator/types/Widgets.ts +5 -1
- package/services/frontend/vite.config.ts +24 -10
- package/services/frontend/yarn.lock +0 -5224
|
Binary file
|
|
@@ -6,6 +6,15 @@ import globals from "globals"
|
|
|
6
6
|
export default [
|
|
7
7
|
...parentConfig,
|
|
8
8
|
|
|
9
|
+
{
|
|
10
|
+
files: ["**/*.{ts,tsx}"],
|
|
11
|
+
languageOptions: {
|
|
12
|
+
parserOptions: {
|
|
13
|
+
project: "./tsconfig.app.json",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
|
|
9
18
|
// Vue config
|
|
10
19
|
...pluginVue.configs["flat/recommended"],
|
|
11
20
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<html class="tw:overscroll-none">
|
|
2
|
+
<html class="tw:h-full tw:overscroll-none tw:overflow-hidden">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" href="/favicon.png" />
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
</script>
|
|
12
12
|
</head>
|
|
13
13
|
|
|
14
|
-
<body class="tw:overscroll-none">
|
|
15
|
-
<div id="app"></div>
|
|
14
|
+
<body class="tw:h-full tw:overscroll-none tw:overflow-hidden">
|
|
15
|
+
<div id="app" class="tw:h-full"></div>
|
|
16
16
|
<script type="module" src="/src/orchestrator/index.ts"></script>
|
|
17
17
|
</body>
|
|
18
18
|
</html>
|
|
@@ -18,44 +18,46 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@date-io/date-fns": "3.2.1",
|
|
20
20
|
"@mdi/font": "7.4.47",
|
|
21
|
-
"@sinclair/typebox": "0.34.
|
|
22
|
-
"@tailwindcss/vite": "4.
|
|
23
|
-
"@tsconfig/node20": "20.1.
|
|
24
|
-
"@vueuse/core": "14.1
|
|
25
|
-
"@vueuse/rxjs": "14.1
|
|
26
|
-
"axios": "1.13.
|
|
21
|
+
"@sinclair/typebox": "0.34.48",
|
|
22
|
+
"@tailwindcss/vite": "4.2.2",
|
|
23
|
+
"@tsconfig/node20": "20.1.9",
|
|
24
|
+
"@vueuse/core": "14.2.1",
|
|
25
|
+
"@vueuse/rxjs": "14.2.1",
|
|
26
|
+
"axios": "1.13.6",
|
|
27
27
|
"date-fns": "4.1.0",
|
|
28
|
-
"esm": "3.
|
|
28
|
+
"esm": "^3.2.25",
|
|
29
29
|
"interactjs": "1.10.27",
|
|
30
30
|
"mini-rx-store": "6.1.2",
|
|
31
|
-
"nanoid": "5.1.
|
|
32
|
-
"ramda": "0.
|
|
33
|
-
"rxjs": "7.
|
|
34
|
-
"sass": "1.
|
|
35
|
-
"socket.io-client": "4.
|
|
36
|
-
"tailwindcss": "4.
|
|
31
|
+
"nanoid": "5.1.7",
|
|
32
|
+
"ramda": "0.32.0",
|
|
33
|
+
"rxjs": "7.8.2",
|
|
34
|
+
"sass": "1.98.0",
|
|
35
|
+
"socket.io-client": "^4.8.3",
|
|
36
|
+
"tailwindcss": "4.2.2",
|
|
37
37
|
"uuid": "13.0.0",
|
|
38
|
-
"vue": "3.5.
|
|
39
|
-
"vue-i18n": "11.
|
|
38
|
+
"vue": "3.5.30",
|
|
39
|
+
"vue-i18n": "11.3.0",
|
|
40
40
|
"vue-router": "4.6.3",
|
|
41
|
-
"vuetify": "
|
|
41
|
+
"vuetify": "4.0.5"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "24.5.1",
|
|
45
45
|
"@types/ramda": "0.31.1",
|
|
46
|
-
"@vitejs/plugin-vue": "6.0.
|
|
47
|
-
"@vue/tsconfig": "0.
|
|
46
|
+
"@vitejs/plugin-vue": "6.0.5",
|
|
47
|
+
"@vue/tsconfig": "0.9.0",
|
|
48
48
|
"eslint": "9.35.0",
|
|
49
|
-
"eslint
|
|
49
|
+
"@eslint/js": "9.35.0",
|
|
50
|
+
"eslint-config-prettier": "9.1.2",
|
|
50
51
|
"eslint-plugin-import": "2.32.0",
|
|
51
|
-
"eslint-plugin-prefer-arrow-functions": "3.
|
|
52
|
-
"eslint-plugin-tailwindcss": "
|
|
53
|
-
"eslint-plugin-vue": "
|
|
54
|
-
"globals": "
|
|
55
|
-
"prettier": "3.
|
|
56
|
-
"typescript": "5.9.
|
|
52
|
+
"eslint-plugin-prefer-arrow-functions": "3.9.1",
|
|
53
|
+
"eslint-plugin-tailwindcss": "3.18.2",
|
|
54
|
+
"eslint-plugin-vue": "9.33.0",
|
|
55
|
+
"globals": "17.4.0",
|
|
56
|
+
"prettier": "3.8.1",
|
|
57
|
+
"typescript": "5.9.3",
|
|
57
58
|
"vite": "7.1.5",
|
|
58
|
-
"
|
|
59
|
-
"vue-
|
|
59
|
+
"vite-plugin-vuetify": "2.1.3",
|
|
60
|
+
"vue-eslint-parser": "9.4.3",
|
|
61
|
+
"vue-tsc": "3.2.6"
|
|
60
62
|
}
|
|
61
|
-
}
|
|
63
|
+
}
|
|
@@ -3,6 +3,45 @@ import logger from "@racletteCore/lib/logger"
|
|
|
3
3
|
import { validatePluginMetadata } from "../utils/operations"
|
|
4
4
|
import type { DiscoveredPlugin, PluginType } from "../types"
|
|
5
5
|
|
|
6
|
+
/** Keys are known at build time; covers both `…/frontend/` and `…/src/frontend/`. */
|
|
7
|
+
const appPluginFrontendIndexKeys = new Set(
|
|
8
|
+
Object.keys(
|
|
9
|
+
import.meta.glob(
|
|
10
|
+
[
|
|
11
|
+
"/src/plugins/**/frontend/index.ts",
|
|
12
|
+
"/src/workbenchPlugins/**/frontend/index.ts",
|
|
13
|
+
],
|
|
14
|
+
{ eager: false },
|
|
15
|
+
),
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
function resolveAppPluginFrontendPath(
|
|
20
|
+
pluginPath: string,
|
|
21
|
+
metadata: { frontendDir?: string },
|
|
22
|
+
): string {
|
|
23
|
+
const explicit = metadata.frontendDir?.replace(/^\.\//, "")
|
|
24
|
+
if (explicit) {
|
|
25
|
+
return `${pluginPath}/${explicit}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const direct = `${pluginPath}/frontend`
|
|
29
|
+
const underSrc = `${pluginPath}/src/frontend`
|
|
30
|
+
const directIndex = `${direct}/index.ts`
|
|
31
|
+
const srcIndex = `${underSrc}/index.ts`
|
|
32
|
+
|
|
33
|
+
const hasDirect = appPluginFrontendIndexKeys.has(directIndex)
|
|
34
|
+
const hasUnderSrc = appPluginFrontendIndexKeys.has(srcIndex)
|
|
35
|
+
|
|
36
|
+
if (hasDirect && hasUnderSrc) {
|
|
37
|
+
return direct
|
|
38
|
+
}
|
|
39
|
+
if (hasUnderSrc) {
|
|
40
|
+
return underSrc
|
|
41
|
+
}
|
|
42
|
+
return direct
|
|
43
|
+
}
|
|
44
|
+
|
|
6
45
|
/**
|
|
7
46
|
* Discover app/user plugins using static glob pattern with exclusions
|
|
8
47
|
*/
|
|
@@ -22,7 +61,9 @@ export const discoverAppPlugins = async (): Promise<DiscoveredPlugin[]> => {
|
|
|
22
61
|
|
|
23
62
|
for (const configPath of Object.keys(configModules)) {
|
|
24
63
|
try {
|
|
25
|
-
const
|
|
64
|
+
const loadConfig = configModules[configPath]
|
|
65
|
+
if (!loadConfig) continue
|
|
66
|
+
const configModule = await loadConfig()
|
|
26
67
|
const metadata = (configModule as any)?.default || configModule
|
|
27
68
|
|
|
28
69
|
if (!validatePluginMetadata(metadata)) {
|
|
@@ -31,9 +72,7 @@ export const discoverAppPlugins = async (): Promise<DiscoveredPlugin[]> => {
|
|
|
31
72
|
}
|
|
32
73
|
|
|
33
74
|
const pluginPath = configPath.replace(/\/raclette\.plugin\.ts$/, "")
|
|
34
|
-
const
|
|
35
|
-
metadata.frontendDir?.replace(/^\.\//, "") || "frontend"
|
|
36
|
-
const frontendPath = `${pluginPath}/${frontendRelativePath}`
|
|
75
|
+
const frontendPath = resolveAppPluginFrontendPath(pluginPath, metadata)
|
|
37
76
|
|
|
38
77
|
const pluginKey = generatePluginKey(metadata.name, metadata.author)
|
|
39
78
|
|
|
@@ -62,7 +62,10 @@
|
|
|
62
62
|
/>
|
|
63
63
|
|
|
64
64
|
<!-- Main content -->
|
|
65
|
-
<v-main
|
|
65
|
+
<v-main
|
|
66
|
+
class="tw:flex tw:flex-col tw:min-h-0 tw:overflow-y-auto tw:h-screen"
|
|
67
|
+
id="appMainContent"
|
|
68
|
+
>
|
|
66
69
|
<div class="tw:w-full tw-h-1 tw:top-[49px]">
|
|
67
70
|
<v-progress-linear
|
|
68
71
|
:height="2"
|
|
@@ -76,13 +79,11 @@
|
|
|
76
79
|
<template v-else>
|
|
77
80
|
<WidgetsLayoutLoader
|
|
78
81
|
v-if="widgetsLayout"
|
|
79
|
-
class="tw:
|
|
82
|
+
class="tw:min-h-0 tw:pb-0"
|
|
80
83
|
:class="{ '!tw:invisible': loading }"
|
|
81
84
|
:widgets-layout="widgetsLayout"
|
|
82
85
|
slot-type="page"
|
|
83
86
|
:slot-layout="slotLayout"
|
|
84
|
-
@scroll.passive="onScroll($event)"
|
|
85
|
-
:max-height="availableComponentHeight"
|
|
86
87
|
/>
|
|
87
88
|
|
|
88
89
|
<v-empty-state
|
|
@@ -104,7 +105,7 @@
|
|
|
104
105
|
ref="appFooter"
|
|
105
106
|
border-thin
|
|
106
107
|
v-if="configService.getPleaseLetUsAdvertiseOurselves()"
|
|
107
|
-
class="tw:items-center tw:text-center tw:flex tw:flex-col tw:border-t
|
|
108
|
+
class="tw:items-center tw:text-center tw:flex tw:flex-col tw:border-t tw:grow-0! tw:mt-auto"
|
|
108
109
|
>
|
|
109
110
|
<a
|
|
110
111
|
href="https://www.raclettejs.com"
|
|
@@ -174,8 +175,10 @@ const appFooterRef = useTemplateRef("appFooter")
|
|
|
174
175
|
const availableComponentHeight = ref(0)
|
|
175
176
|
|
|
176
177
|
const updateAvailableHeight = () => {
|
|
177
|
-
const appbarHeight =
|
|
178
|
-
|
|
178
|
+
const appbarHeight =
|
|
179
|
+
(appAppbarRef.value?.$el as HTMLElement | undefined)?.offsetHeight || 0
|
|
180
|
+
const appFooterHeight =
|
|
181
|
+
(appFooterRef.value?.$el as HTMLElement | undefined)?.offsetHeight || 0
|
|
179
182
|
const progressBarHeight = 2 // Progress bar height
|
|
180
183
|
const borderAndPadding = 8 // Border and padding buffer
|
|
181
184
|
availableComponentHeight.value =
|
|
@@ -239,7 +242,6 @@ const checkImageExists = async (url: string): Promise<boolean> => {
|
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
244
|
|
|
242
|
-
const showScrollToTopBtn = ref(false)
|
|
243
245
|
const isDevelopment = ref(false)
|
|
244
246
|
|
|
245
247
|
const setTheme = (theme: "dark" | "light") => {
|
|
@@ -253,9 +255,6 @@ const setTheme = (theme: "dark" | "light") => {
|
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
const onScroll = (e) =>
|
|
257
|
-
(showScrollToTopBtn.value = e.currentTarget.scrollTop > 0)
|
|
258
|
-
|
|
259
258
|
onMounted(async () => {
|
|
260
259
|
setTheme(theme.value)
|
|
261
260
|
vuetifyLocale.current.value = locale.value
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
@source "../../../../index.html";
|
|
2
2
|
@source "/**/*.{vue,js,ts,jsx,tsx,html}";
|
|
3
|
-
/* vite aliase? */
|
|
4
|
-
/* @source "@racletteOrchestrator" */
|
|
5
3
|
|
|
6
|
-
@import "tailwindcss" prefix(tw);
|
|
4
|
+
@import "tailwindcss/theme" layer(tailwind-theme) prefix(tw);
|
|
5
|
+
@import "tailwindcss/preflight" layer(tailwind-reset) prefix(tw);
|
|
6
|
+
@import "tailwindcss/utilities" layer(tailwind-utilities) prefix(tw);
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/* @import "tailwindcss/theme.css" layer(theme) prefix(tw); */
|
|
11
|
-
/* @import "tailwindcss/preflight.css" layer(base) prefix(tw); */
|
|
12
|
-
/* @import "tailwindcss/utilities.css" layer(utilities) prefix(tw); */
|
|
13
|
-
|
|
14
|
-
/* enable dark mode via class */
|
|
15
|
-
@custom-variant dark (&:where(.dark, .dark *));
|
|
8
|
+
@custom-variant light (&:where(.v-theme--light, .v-theme--light *));
|
|
9
|
+
@custom-variant dark (&:where(.v-theme--dark, .v-theme--dark *));
|
|
16
10
|
|
|
17
11
|
/* safelist for the resizing in the composition editor */
|
|
18
12
|
@source inline('tw:col-span-{1..12}');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="tw:
|
|
3
|
+
class="tw:max-w-full tw:bg-gray-50 tw:dark:bg-[#252525] tw:min-h-fit"
|
|
4
4
|
:class="{
|
|
5
5
|
'tw:p-4':
|
|
6
6
|
slotLayout !== 'default' &&
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
>
|
|
31
31
|
<v-row
|
|
32
32
|
:no-gutters="slotLayout === 'default' || slotLayout === 'full'"
|
|
33
|
-
:class="{ 'tw:h-full': slotLayout === 'full',
|
|
33
|
+
:class="[{ 'tw:h-full': slotLayout === 'full' }, rowClasses]"
|
|
34
34
|
>
|
|
35
35
|
<TransitionGroup
|
|
36
36
|
name="grid-item"
|
|
@@ -44,17 +44,12 @@
|
|
|
44
44
|
:cols="getSlotCols(slot)"
|
|
45
45
|
:style="{
|
|
46
46
|
'transition-delay': `${slotIndex * 50}ms`,
|
|
47
|
-
'max-height': `${maxWidgetHeight}px`,
|
|
48
47
|
...(slotLayout === 'default' || slotLayout === 'full'
|
|
49
48
|
? { padding: '0px' }
|
|
50
49
|
: {}),
|
|
51
50
|
}"
|
|
52
51
|
>
|
|
53
|
-
<div
|
|
54
|
-
:class="widgetContainerClasses"
|
|
55
|
-
class="tw:h-full"
|
|
56
|
-
:style="{ 'max-height': `${maxWidgetHeight}px` }"
|
|
57
|
-
>
|
|
52
|
+
<div :class="widgetContainerClasses" class="tw:h-full">
|
|
58
53
|
<component
|
|
59
54
|
v-if="slot.widget"
|
|
60
55
|
:is="getSlotWidget(slot.widget)"
|
|
@@ -108,11 +103,8 @@ const props = withDefaults(
|
|
|
108
103
|
widgetsLayout: Composition["widgetsLayout"]
|
|
109
104
|
slotType: string
|
|
110
105
|
slotLayout: string
|
|
111
|
-
maxHeight?: number
|
|
112
106
|
}>(),
|
|
113
|
-
{
|
|
114
|
-
maxHeight: 0,
|
|
115
|
-
},
|
|
107
|
+
{},
|
|
116
108
|
)
|
|
117
109
|
|
|
118
110
|
const { compositionSlots } = useRouteState()
|
|
@@ -122,7 +114,7 @@ const currentRouteConfig = computed(() =>
|
|
|
122
114
|
)
|
|
123
115
|
|
|
124
116
|
const widgetContainerClasses = computed(() => {
|
|
125
|
-
const baseClasses = "tw:h-auto tw:overflow-
|
|
117
|
+
const baseClasses = "tw:h-auto tw:overflow-visible"
|
|
126
118
|
|
|
127
119
|
switch (props.slotLayout) {
|
|
128
120
|
case "spaced":
|
|
@@ -165,11 +157,6 @@ const routeParams = computed(() => {
|
|
|
165
157
|
// Create a reactive key that changes when widgetsLayout changes
|
|
166
158
|
const gridKey = ref(0)
|
|
167
159
|
|
|
168
|
-
// Calculate max height per widget based on grid layout
|
|
169
|
-
const maxWidgetHeight = computed(() => {
|
|
170
|
-
return Math.min(props.maxHeight, 2400)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
160
|
// Calculate total number of widgets
|
|
174
161
|
const totalWidgets = computed(() => {
|
|
175
162
|
return props.widgetsLayout.reduce((sum, column) => sum + column.length, 0)
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import { forEachObjIndexed } from "ramda"
|
|
6
6
|
import type { ConfigurableParameters, WidgetConf } from "@racletteOrchestrator"
|
|
7
7
|
import { generatePluginKey } from "@shared/helper/pluginHelper"
|
|
8
|
-
import type { PluginMetadata
|
|
8
|
+
import type { PluginMetadata } from "@core"
|
|
9
|
+
import type { RegisteredWidgetDeclaration, WidgetDeclaration } from "@racletteOrchestrator"
|
|
10
|
+
import { normalizeWidgetVisuals } from "@racletteOrchestrator/helpers"
|
|
9
11
|
|
|
10
12
|
// Plugin metadata files (unchanged)
|
|
11
13
|
const RACLETTE_PLUGIN_FILES = import.meta.glob<{
|
|
@@ -14,6 +16,43 @@ const RACLETTE_PLUGIN_FILES = import.meta.glob<{
|
|
|
14
16
|
eager: true,
|
|
15
17
|
})
|
|
16
18
|
|
|
19
|
+
const EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS = new Set(
|
|
20
|
+
Object.keys(
|
|
21
|
+
import.meta.glob(
|
|
22
|
+
"@racletteCore/../../external-app-plugins/**/frontend/index.ts",
|
|
23
|
+
{
|
|
24
|
+
eager: false,
|
|
25
|
+
},
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function resolveExternalPluginFrontendPath(
|
|
31
|
+
pluginDir: string,
|
|
32
|
+
metadata: PluginMetadata,
|
|
33
|
+
): string {
|
|
34
|
+
const explicit = metadata.frontendDir?.replace(/^\.\//, "")
|
|
35
|
+
if (explicit) {
|
|
36
|
+
return `${pluginDir}/${explicit}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const direct = `${pluginDir}/frontend`
|
|
40
|
+
const underSrc = `${pluginDir}/src/frontend`
|
|
41
|
+
const directIndex = `${direct}/index.ts`
|
|
42
|
+
const srcIndex = `${underSrc}/index.ts`
|
|
43
|
+
|
|
44
|
+
const hasDirect = EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS.has(directIndex)
|
|
45
|
+
const hasUnderSrc = EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS.has(srcIndex)
|
|
46
|
+
|
|
47
|
+
if (hasDirect && hasUnderSrc) {
|
|
48
|
+
return direct
|
|
49
|
+
}
|
|
50
|
+
if (hasUnderSrc) {
|
|
51
|
+
return underSrc
|
|
52
|
+
}
|
|
53
|
+
return direct
|
|
54
|
+
}
|
|
55
|
+
|
|
17
56
|
// Discover widget Vue files to get widget names
|
|
18
57
|
const WIDGET_COMPONENT_FILES = import.meta.glob(
|
|
19
58
|
[
|
|
@@ -63,7 +102,11 @@ export const getWidgetDeclacations = () => {
|
|
|
63
102
|
|
|
64
103
|
// Find all widget component files for this plugin
|
|
65
104
|
const pluginDir = pluginPath.replace("/raclette.plugin.ts", "")
|
|
66
|
-
const
|
|
105
|
+
const frontendPath = resolveExternalPluginFrontendPath(
|
|
106
|
+
pluginDir,
|
|
107
|
+
pluginMetadata,
|
|
108
|
+
)
|
|
109
|
+
const widgetPattern = `${frontendPath}/widgets/`
|
|
67
110
|
|
|
68
111
|
// Look through all discovered widget Vue files to find ones belonging to this plugin
|
|
69
112
|
Object.keys(WIDGET_COMPONENT_FILES).forEach((componentPath) => {
|
|
@@ -91,7 +134,9 @@ export const getWidgetDeclacations = () => {
|
|
|
91
134
|
}
|
|
92
135
|
|
|
93
136
|
// Extract details and config (handle both default export and named exports)
|
|
94
|
-
const details = setupModule.details || setupModule.default?.details
|
|
137
|
+
const details = (setupModule.details || setupModule.default?.details) as
|
|
138
|
+
| WidgetDeclaration
|
|
139
|
+
| undefined
|
|
95
140
|
const config = setupModule.config || setupModule.default?.config
|
|
96
141
|
|
|
97
142
|
if (!details) {
|
|
@@ -101,8 +146,10 @@ export const getWidgetDeclacations = () => {
|
|
|
101
146
|
return
|
|
102
147
|
}
|
|
103
148
|
|
|
149
|
+
const normalizedVisuals = normalizeWidgetVisuals(details, widgetName)
|
|
104
150
|
const registeredWidget: RegisteredWidgetDeclaration = {
|
|
105
151
|
...details,
|
|
152
|
+
...normalizedVisuals,
|
|
106
153
|
pluginKey,
|
|
107
154
|
author: pluginMetadata.author,
|
|
108
155
|
name: widgetName,
|
|
@@ -169,11 +216,13 @@ const findSetupPathForWidget = (
|
|
|
169
216
|
return null
|
|
170
217
|
}
|
|
171
218
|
|
|
172
|
-
const [pluginPath] = pluginEntry
|
|
219
|
+
const [pluginPath, pluginModule] = pluginEntry
|
|
173
220
|
const pluginDir = pluginPath.replace("/raclette.plugin.ts", "")
|
|
221
|
+
const metadata = pluginModule.default
|
|
222
|
+
const frontendPath = resolveExternalPluginFrontendPath(pluginDir, metadata)
|
|
174
223
|
|
|
175
224
|
// Look for a Vue file with this widget name to find the directory structure
|
|
176
|
-
const widgetPattern = `${
|
|
225
|
+
const widgetPattern = `${frontendPath}/widgets/`
|
|
177
226
|
const widgetVueFile = Object.keys(WIDGET_COMPONENT_FILES).find(
|
|
178
227
|
(path) =>
|
|
179
228
|
path.includes(widgetPattern) && path.endsWith(`${widgetName}Widget.vue`),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export type WidgetVisualInput = {
|
|
2
|
+
title?: string
|
|
3
|
+
color?: string
|
|
4
|
+
icon?: string
|
|
5
|
+
images?: string[]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type WidgetVisuals = {
|
|
9
|
+
color: string
|
|
10
|
+
icon: string
|
|
11
|
+
images: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const getHashValue = (value: string) =>
|
|
15
|
+
value.split("").reduce((acc, char) => acc * 31 + char.charCodeAt(0), 7)
|
|
16
|
+
|
|
17
|
+
export const generateColorFromName = (name: string): string => {
|
|
18
|
+
// Same input name -> same output color (stable across reloads/environments).
|
|
19
|
+
const normalizedName = name.trim().toLowerCase() || "widget"
|
|
20
|
+
const hash = Math.abs(getHashValue(normalizedName))
|
|
21
|
+
// Spread widgets over the full color wheel.
|
|
22
|
+
const hue = hash % 360
|
|
23
|
+
// Keep saturation/lightness in a readable mid-range to avoid too grey or too neon colors.
|
|
24
|
+
const saturation = 55 + (hash % 18) // 55..72
|
|
25
|
+
const lightness = 42 + (hash % 16) // 42..57
|
|
26
|
+
return `hsl(${hue} ${saturation}% ${lightness}%)`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const getWidgetInitials = (name: string): string => {
|
|
30
|
+
const parts = name
|
|
31
|
+
.trim()
|
|
32
|
+
.split(/\s+/)
|
|
33
|
+
.filter(Boolean)
|
|
34
|
+
|
|
35
|
+
if (parts.length === 0) {
|
|
36
|
+
return "W"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (parts.length === 1) {
|
|
40
|
+
return parts[0].slice(0, 2).toUpperCase()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return `${parts[0][0]}${parts[1][0]}`.toUpperCase()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const normalizeWidgetVisuals = (
|
|
47
|
+
details: WidgetVisualInput,
|
|
48
|
+
widgetName: string,
|
|
49
|
+
): WidgetVisuals => {
|
|
50
|
+
// Prefer plugin-provided values; only fallback when field is missing/empty.
|
|
51
|
+
const normalizedColor =
|
|
52
|
+
typeof details.color === "string" && details.color.trim().length > 0
|
|
53
|
+
? details.color
|
|
54
|
+
: generateColorFromName(details.title || widgetName)
|
|
55
|
+
|
|
56
|
+
const normalizedIcon =
|
|
57
|
+
typeof details.icon === "string" && details.icon.trim().length > 0
|
|
58
|
+
? details.icon
|
|
59
|
+
: ""
|
|
60
|
+
|
|
61
|
+
const normalizedImages = Array.isArray(details.images)
|
|
62
|
+
// Ignore invalid/empty entries to keep consumers simple.
|
|
63
|
+
? details.images.filter((image) => typeof image === "string" && image.trim())
|
|
64
|
+
: []
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
color: normalizedColor,
|
|
68
|
+
icon: normalizedIcon,
|
|
69
|
+
images: normalizedImages,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -53,4 +53,8 @@ export type RegisteredWidgetDeclaration = {
|
|
|
53
53
|
export type WidgetDeclaration = Omit<
|
|
54
54
|
RegisteredWidgetDeclaration,
|
|
55
55
|
"pluginKey" | "author" | "name" // name will be extracted via filename, cannot be overwritten
|
|
56
|
-
>
|
|
56
|
+
> & {
|
|
57
|
+
color?: string
|
|
58
|
+
icon?: string
|
|
59
|
+
images?: string[]
|
|
60
|
+
}
|
|
@@ -3,6 +3,7 @@ import vue from "@vitejs/plugin-vue"
|
|
|
3
3
|
import path from "path"
|
|
4
4
|
import { componentPathPlugin } from "./vite-plugin-component-path"
|
|
5
5
|
import tailwindcss from "@tailwindcss/vite"
|
|
6
|
+
import Vuetify, { transformAssetUrls } from "vite-plugin-vuetify"
|
|
6
7
|
|
|
7
8
|
export default defineConfig({
|
|
8
9
|
server: {
|
|
@@ -17,27 +18,40 @@ export default defineConfig({
|
|
|
17
18
|
target: "es2023",
|
|
18
19
|
rollupOptions: {
|
|
19
20
|
output: {
|
|
20
|
-
manualChunks: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
manualChunks: (id) => {
|
|
22
|
+
if (id.includes("node_modules/vuetify")) {
|
|
23
|
+
return "vuetify"
|
|
24
|
+
}
|
|
25
|
+
if (
|
|
26
|
+
id.includes("node_modules/vue") ||
|
|
27
|
+
id.includes("node_modules/vue-router")
|
|
28
|
+
) {
|
|
29
|
+
return "vue-vendor"
|
|
30
|
+
}
|
|
31
|
+
return undefined
|
|
27
32
|
},
|
|
28
33
|
},
|
|
29
|
-
maxParallelFileOps: 1,
|
|
30
34
|
},
|
|
31
35
|
},
|
|
32
36
|
optimizeDeps: {
|
|
33
|
-
include: ["vue", "vue-router"
|
|
37
|
+
include: ["vue", "vue-router"],
|
|
34
38
|
exclude: [
|
|
39
|
+
"vuetify",
|
|
35
40
|
"virtual:plugin-key",
|
|
36
41
|
"virtual:plugin-setup",
|
|
37
42
|
"@racletteOrchestrator/composables/usePluginApi",
|
|
38
43
|
],
|
|
39
44
|
},
|
|
40
|
-
plugins: [
|
|
45
|
+
plugins: [
|
|
46
|
+
vue({
|
|
47
|
+
template: { transformAssetUrls },
|
|
48
|
+
}),
|
|
49
|
+
componentPathPlugin(),
|
|
50
|
+
tailwindcss(),
|
|
51
|
+
Vuetify({
|
|
52
|
+
autoImport: true,
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
41
55
|
resolve: {
|
|
42
56
|
extensions: [".js", ".ts", ".vue"],
|
|
43
57
|
alias: {
|