@raclettejs/core 0.1.10 → 0.1.12

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 (96) hide show
  1. package/CHANGELOG.md +59 -2
  2. package/dist/cli.js +104 -104
  3. package/dist/cli.js.map +7 -0
  4. package/dist/index.js +4 -4
  5. package/dist/index.js.map +7 -0
  6. package/package.json +32 -31
  7. package/services/backend/package.json +35 -45
  8. package/services/backend/src/core/payload/payloadTypes.ts +7 -0
  9. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.get.ts +1 -1
  10. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.getAll.ts +1 -1
  11. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.model.ts +5 -0
  12. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.schema.ts +1 -0
  13. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.service.ts +1 -1
  14. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.get.ts +1 -1
  15. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.getAll.ts +1 -1
  16. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/helpers/payload.ts +6 -2
  17. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.get.ts +1 -1
  18. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.getAll.ts +1 -1
  19. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.get.ts +1 -1
  20. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.getAll.ts +1 -1
  21. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/index.ts +2 -1
  22. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.get.ts +1 -1
  23. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.getAll.ts +6 -2
  24. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/tag.service.ts +22 -1
  25. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.get.ts +1 -1
  26. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.getAll.ts +1 -1
  27. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.remove.ts +3 -0
  28. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/user.service.ts +1 -2
  29. package/services/backend/src/corePlugins/raclette__core/frontend/generated-config.ts +12 -12
  30. package/services/backend/src/domains/index.ts +3 -0
  31. package/services/backend/src/domains/system/collections.service.ts +119 -0
  32. package/services/backend/src/domains/system/index.ts +8 -0
  33. package/services/backend/src/domains/system/routes/index.ts +5 -0
  34. package/services/backend/src/domains/system/routes/route.collection.getAll.ts +61 -0
  35. package/services/backend/src/domains/system/routes/route.collection.remove.ts +93 -0
  36. package/services/backend/src/types/custom-fastify.d.ts +1 -0
  37. package/services/backend/src/utils/request.utils.ts +28 -1
  38. package/services/backend/yarn.lock +431 -1180
  39. package/services/frontend/package.json +29 -40
  40. package/services/frontend/src/core/constants/ApiClient.ts +6 -1
  41. package/services/frontend/src/core/lib/data/dataApi.ts +8 -1
  42. package/services/frontend/src/core/lib/data/fetchDataHandler.ts +58 -27
  43. package/services/frontend/src/core/lib/data/queryApi.ts +29 -8
  44. package/services/frontend/src/core/lib/data/responseTypeHandler.ts +27 -4
  45. package/services/frontend/src/core/lib/data/writeDataHandler.ts +1 -1
  46. package/services/frontend/src/core/lib/dataHelper.ts +8 -1
  47. package/services/frontend/src/core/lib/easteregg.ts +1 -1
  48. package/services/frontend/src/core/lib/eventEmitter.ts +1 -0
  49. package/services/frontend/src/core/lib/eventWhitelist.ts +11 -1
  50. package/services/frontend/src/core/lib/logger.ts +11 -3
  51. package/services/frontend/src/core/lib/userNotifier.ts +17 -17
  52. package/services/frontend/src/core/main.ts +3 -3
  53. package/services/frontend/src/core/setup/plugin-system/api/wrappers.ts +18 -1
  54. package/services/frontend/src/core/setup/plugin-system/registration/index.ts +1 -1
  55. package/services/frontend/src/core/setup/socketClient.ts +2 -2
  56. package/services/frontend/src/core/setup/socketEvents.ts +2 -2
  57. package/services/frontend/src/core/store/reducers/compositions/selectors.ts +2 -2
  58. package/services/frontend/src/core/store/reducers/data/index.ts +1 -1
  59. package/services/frontend/src/core/store/reducers/data/reducers.ts +3 -3
  60. package/services/frontend/src/core/store/reducers/queries/effects.ts +20 -1
  61. package/services/frontend/src/core/store/reducers/queries/index.ts +1 -0
  62. package/services/frontend/src/core/store/reducers/queries/reducers.ts +28 -1
  63. package/services/frontend/src/core/store/reducers/queriesCache/queryCacheHelper.ts +5 -4
  64. package/services/frontend/src/core/store/reducers/queriesCache/reducers.ts +4 -3
  65. package/services/frontend/src/core/store/state.ts +1 -1
  66. package/services/frontend/src/core/types/ApiClient.ts +1 -1
  67. package/services/frontend/src/core/types/DataApi.ts +4 -0
  68. package/services/frontend/src/core/types/Queries.ts +1 -0
  69. package/services/frontend/src/orchestrator/ProductOrchestrator.vue +19 -7
  70. package/services/frontend/src/orchestrator/WelcomeScreen.vue +39 -41
  71. package/services/frontend/src/orchestrator/assets/styles/tailwindStyles.css +3 -0
  72. package/services/frontend/src/orchestrator/assets/styles/themes/dark.ts +2 -2
  73. package/services/frontend/src/orchestrator/assets/styles/vuetifyStyles.scss +0 -1
  74. package/services/frontend/src/orchestrator/components/composition/CompositionOverlay.vue +11 -2
  75. package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +167 -58
  76. package/services/frontend/src/orchestrator/components/menu/DevIndicator.vue +122 -7
  77. package/services/frontend/src/orchestrator/components/menu/UserMenu.vue +38 -20
  78. package/services/frontend/src/orchestrator/components/snackbar/SnackStack.vue +17 -5
  79. package/services/frontend/src/orchestrator/composables/useCurrentComposition.ts +32 -4
  80. package/services/frontend/src/orchestrator/composables/usePageNavigation.ts +5 -1
  81. package/services/frontend/src/orchestrator/composables/usePluginApi.ts +125 -26
  82. package/services/frontend/src/orchestrator/composables/useRouteState.ts +0 -1
  83. package/services/frontend/src/orchestrator/composables/useVueQueryObservableHelper.ts +2 -0
  84. package/services/frontend/src/orchestrator/composables/useVueWriteOperationHelper.ts +5 -3
  85. package/services/frontend/src/orchestrator/composables/useWidgets/helperFunctions.ts +4 -1
  86. package/services/frontend/src/orchestrator/helpers/loginUserNotifications.ts +1 -1
  87. package/services/frontend/src/orchestrator/helpers/uiHelper.ts +1 -1
  88. package/services/frontend/src/orchestrator/i18n/de-DE.json +2 -1
  89. package/services/frontend/src/orchestrator/i18n/en-EU.json +2 -1
  90. package/services/frontend/src/orchestrator/i18n/sk.json +2 -1
  91. package/services/frontend/src/orchestrator/i18n/tl-TL.json +1 -1
  92. package/services/frontend/src/orchestrator/router/routeParserHelper.ts +4 -1
  93. package/services/frontend/src/orchestrator/router/routeStore.ts +78 -11
  94. package/services/frontend/tsconfig.app.json +1 -0
  95. package/services/frontend/yarn.lock +796 -1872
  96. package/yarn.lock +435 -618
@@ -93,10 +93,10 @@ const createRacletteApp = async (
93
93
  store.dispatch({ type: "user/set", payload: user })
94
94
 
95
95
  // does the core really need to communicate with itself via eventbus?
96
- eventbus.emit("socket_joinRoom")
96
+ eventbus.emit("socket/join/room")
97
97
 
98
98
  return new Promise<CreateAppResponse>(async (resolve, reject) => {
99
- eventbus.on("ui_setupProject", (spaceId: string) => {
99
+ eventbus.on("ui/setupProject", (spaceId: string) => {
100
100
  resolve({
101
101
  authenticated: true,
102
102
  setupComplete: true,
@@ -152,7 +152,7 @@ const generateLoginCallback =
152
152
 
153
153
  store.dispatch({ type: "user/set", payload: response.data.user })
154
154
 
155
- eventbus.emit("socket_joinRoom")
155
+ eventbus.emit("socket/join/room")
156
156
 
157
157
  // Return success with token & redirect function
158
158
  return {
@@ -27,12 +27,29 @@ export const wrapFileApi = (
27
27
  }
28
28
 
29
29
  export const wrapEventbusApi = (
30
+ plugin: RegisteredPlugin,
30
31
  $eventbus: any,
31
32
  pluginApi: Partial<PluginApi>,
32
33
  ): any => {
33
34
  if ($eventbus && !pluginApi.$eventbus) {
34
35
  const $pluginEventbus = new EventEmitter(false, false)
35
- $pluginEventbus.global = $eventbus
36
+ $pluginEventbus.global = {
37
+ on: (event: string, listener: Function) => {
38
+ return $eventbus.on(event, listener)
39
+ },
40
+ once: (event: string, listener: Function) => {
41
+ return $eventbus.once(event, listener)
42
+ },
43
+ emit: (event: string, payload: object) => {
44
+ return $eventbus.emit(event, {
45
+ sender: plugin.pluginKey,
46
+ data: payload,
47
+ })
48
+ },
49
+ isValid: (event: string) => {
50
+ return $eventbus.isValid(event)
51
+ },
52
+ }
36
53
  return $pluginEventbus
37
54
  }
38
55
  return pluginApi
@@ -113,7 +113,7 @@ export const loadAndRegisterPlugin = async (
113
113
 
114
114
  if (corePluginApi.$eventbus) {
115
115
  currentPlugin.initEventbus = () =>
116
- wrapEventbusApi(corePluginApi.$eventbus, pluginApi)
116
+ wrapEventbusApi(plugin, corePluginApi.$eventbus, pluginApi)
117
117
  }
118
118
 
119
119
  const handleOperations = handlePluginOperations(
@@ -6,7 +6,7 @@ import log from "@racletteCore/lib/logger"
6
6
  import { getUserToken } from "./sessionHandler"
7
7
  import configService from "@racletteCore/lib/configService"
8
8
  const registerSocketClient = ($socket, $eventbus) => {
9
- $eventbus.on("socket_joinRoom", (roomId?: string) => {
9
+ $eventbus.on("socket/join/room", (roomId?: string) => {
10
10
  const { requireAuthentication } = configService.getConfig()?.global ?? {
11
11
  requireAuthentication: true,
12
12
  }
@@ -25,7 +25,7 @@ const registerSocketClient = ($socket, $eventbus) => {
25
25
  $socket.emit("join", { roomId, token })
26
26
  })
27
27
 
28
- $eventbus.on("socket_leaveRoom", (roomId) => {
28
+ $eventbus.on("socket/leave/room", (roomId) => {
29
29
  log.socket("emitLeave", { roomId })
30
30
  $socket.emit("leave", roomId)
31
31
  })
@@ -206,7 +206,7 @@ const registerSocketEvents = ($socket, $store, $eventbus) => {
206
206
  })
207
207
  await setupSpace(compositions, interactionLinks, projectConfig)
208
208
 
209
- $eventbus.emit("ui_setupProject", roomId)
209
+ $eventbus.emit("ui/setupProject", roomId)
210
210
  })
211
211
  // Reset all store states which are project dependent.
212
212
  $store.dispatch({
@@ -263,7 +263,7 @@ const registerSocketEvents = ($socket, $store, $eventbus) => {
263
263
  isOwnRequest: appSessionId === $socket.appSessionId,
264
264
  })
265
265
  handleServerItem(payload, true, false)
266
- $eventbus.emit("socket_dataUpdated", { offline: false, body })
266
+ $eventbus.emit("socket/data/update", { offline: false, body })
267
267
  })
268
268
 
269
269
  /**
@@ -21,8 +21,8 @@ type LocaleObject = {
21
21
  // TODO: outsource to a better place
22
22
  const getLocalizedName = (localeObject: LocaleObject) => {
23
23
  const locale = $store.getState(["ui", "locale"])
24
-
25
- const localeName = localeObject[locale]
24
+ const localeName =
25
+ localeObject[locale] || localeObject[locale.split("-")?.[0]]
26
26
 
27
27
  if (localeName) {
28
28
  return localeName
@@ -6,7 +6,7 @@ import reducerFromMap from "@racletteCore/lib/reducerFromMap"
6
6
  const reducerMap = {
7
7
  init: reducers.init,
8
8
  projectInit: reducers.projectInit,
9
- "data/push": reducers.dataPush,
9
+ "data/push": reducers.dataRead,
10
10
  "data/create": reducers.dataCreate,
11
11
  "data/update": reducers.dataUpdate,
12
12
  "data/deleteFromCache": reducers.deleteFromCache,
@@ -134,7 +134,7 @@ const updateDataCache = (oldCache, newItems) => {
134
134
  oldItem,
135
135
  )
136
136
  }
137
- // we will always delete the offline flag as this function will only be called by the dataPush which retrieves synced backend items
137
+ // we will always delete the offline flag as this function will only be called by the dataRead which retrieves synced backend items
138
138
  if (newCache[item._id]) {
139
139
  delete newCache[item._id]._offline
140
140
  }
@@ -189,7 +189,7 @@ const dataAddFromServer = (state, action) => {
189
189
  * @param {Array} action.payload - An array of items to be added to the state. Each item is an object that must contain an `_id` property.
190
190
  * @returns {Object} - Returns the new state after pushing the data from the action payload.
191
191
  */
192
- const dataPush = (state, action) => {
192
+ const dataRead = (state, action) => {
193
193
  const { payload } = action
194
194
 
195
195
  // early return if no data
@@ -540,7 +540,7 @@ const addRequestedFor = (state, action) => {
540
540
  export {
541
541
  init,
542
542
  projectInit,
543
- dataPush,
543
+ dataRead,
544
544
  dataUpdate,
545
545
  dataMove,
546
546
  dataCreate,
@@ -34,7 +34,26 @@ const queriesEffects = (store) => {
34
34
  }),
35
35
  ignoreElements(),
36
36
  )
37
- return [queriesAddExecute, queriesExecute]
37
+ const queryiesSetCacheKey = actions$.pipe(
38
+ ofType("queries/setCacheKey"),
39
+ distinctUntilChanged((prev, curr) => !store.hasChanges(prev, curr)),
40
+
41
+ tap((action) => {
42
+ const updatedQuery = action?.actionResult?.updated || null
43
+ if (updatedQuery) {
44
+ const { item, itemBefore } = updatedQuery
45
+ const { actionId } = action
46
+ if (itemBefore.cacheKey && itemBefore.cacheKey !== item.cacheKey) {
47
+ store.dispatch({
48
+ type: "queriesCache/remove",
49
+ payload: { cacheKey: itemBefore.cacheKey, actionId },
50
+ })
51
+ }
52
+ }
53
+ }),
54
+ ignoreElements(),
55
+ )
56
+ return [queriesAddExecute, queriesExecute, queryiesSetCacheKey]
38
57
  }
39
58
 
40
59
  export default queriesEffects
@@ -15,6 +15,7 @@ const reducerMap = {
15
15
  "queries/updateItems": reducers.updateQueryItems,
16
16
  "queries/update": reducers.updateQuery,
17
17
  "queries/update/loading": reducers.queriesUpdateLoading,
18
+ "queries/setCacheKey": reducers.queryiesSetCacheKey,
18
19
  }
19
20
 
20
21
  const queriesReducers = reducerFromMap(reducerMap)
@@ -10,6 +10,8 @@ export type Query = {
10
10
  target: string
11
11
  actionId: string
12
12
  params: Record<string, any>
13
+ options: Record<string, any>
14
+ config: Record<string, any>
13
15
  loading?: boolean
14
16
  backend?: Record<string, any>
15
17
  uuids?: Array<string>
@@ -56,6 +58,12 @@ const updateQuery = (state, action) => {
56
58
  if (payload.target) {
57
59
  query.target = payload.target
58
60
  }
61
+ if (payload.options) {
62
+ query.options = payload.options
63
+ }
64
+ if (payload.config) {
65
+ query.config = payload.config
66
+ }
59
67
  if (payload.pageItems) {
60
68
  const uuids = []
61
69
  const results = payload.pageItems || null
@@ -83,7 +91,9 @@ const updateQuery = (state, action) => {
83
91
  query.params = mergeDeepRight(query.params || {}, payload.params)
84
92
  }
85
93
  }
86
-
94
+ if (payload.cacheKey) {
95
+ query.cacheKey = payload.cacheKey
96
+ }
87
97
  if (payload.backend) {
88
98
  if (payload.reset) {
89
99
  query.backend = payload.backend
@@ -98,7 +108,19 @@ const updateQuery = (state, action) => {
98
108
 
99
109
  return queries
100
110
  }
111
+ const queryiesSetCacheKey = (state, action) => {
112
+ let queries = structuredClone(state)
113
+ const payload = action.payload
114
+ const { actionId, cacheKey } = payload
115
+ if (!actionId || !state[actionId]) {
116
+ return state
117
+ }
101
118
 
119
+ queries[actionId] = { ...queries[actionId], cacheKey }
120
+ action.actionResult.updated.itemBefore = state[actionId]
121
+ action.actionResult.updated.item = queries[actionId]
122
+ return queries
123
+ }
102
124
  const queriesUpdateLoading = (state, action) => {
103
125
  const payload = action.payload
104
126
  const actionId = payload.actionId
@@ -175,11 +197,15 @@ const queriesAdd = (state, action) => {
175
197
  const params: CustomStoreActionParams = payload.params || {}
176
198
  const actionId = payload.actionId
177
199
  const target = payload.target
200
+ const config = payload.config || {}
201
+ const options = payload.options || {}
178
202
 
179
203
  const query: Query = {
180
204
  target,
181
205
  params,
182
206
  actionId,
207
+ options,
208
+ config,
183
209
  }
184
210
 
185
211
  action.actionResult.added.push(query)
@@ -216,6 +242,7 @@ const queriesRemove = (state, action) => {
216
242
  }
217
243
 
218
244
  export {
245
+ queryiesSetCacheKey,
219
246
  queriesExecute,
220
247
  queriesAdd,
221
248
  queriesRemove,
@@ -2,7 +2,7 @@ import createStableHash from "@racletteCore/lib/createStableHash"
2
2
  import { $store } from "@racletteCore"
3
3
  import log from "@racletteCore/lib/logger"
4
4
 
5
- const isParentResultFresh = (cacheKey: string): boolean => {
5
+ const isParentResultFresh = (cacheKey: string, ttl: number = 1000): boolean => {
6
6
  const queriesState = $store.getState("queriesCache")
7
7
  const currentTimeStamp = new Date().getTime()
8
8
  const parentQuery = queriesState[cacheKey]
@@ -15,16 +15,17 @@ const isParentResultFresh = (cacheKey: string): boolean => {
15
15
  ) {
16
16
  log.store(
17
17
  "queryCacheHelper",
18
- `the cache with hash ${cacheKey} has not been executed yet or is still fetching`,
18
+ `cache #${cacheKey} has not been executed yet or is still fetching`,
19
+ parentQuery,
19
20
  )
20
21
  return false
21
22
  }
22
23
 
23
- const isParentResultFresh = parentQuery.lastFetched + 1000 >= currentTimeStamp
24
+ const isParentResultFresh = parentQuery.lastFetched + ttl >= currentTimeStamp
24
25
 
25
26
  log.store(
26
27
  "queryCacheHelper",
27
- `the cache with hash ${cacheKey} is ${isParentResultFresh ? "fresh" : "outdated"}`,
28
+ `cache #${cacheKey} is ${isParentResultFresh ? "fresh" : "stale"} for ttl of ${ttl}ms`,
28
29
  )
29
30
 
30
31
  return isParentResultFresh
@@ -22,7 +22,7 @@ const getAffectedCacheQuery = (state, actionId) => {
22
22
  })
23
23
  return state[removedQueryCacheKey]
24
24
  }
25
- const getChildQueries = (cacheKey: string): Array => {
25
+ const getChildQueries = (cacheKey: string): Array<Record<string, object>> => {
26
26
  const queries = $store.getState("queries")
27
27
  const childQueries = []
28
28
  Object.values(queries).forEach((query) => {
@@ -107,6 +107,7 @@ const cacheRemove = (state, action) => {
107
107
 
108
108
  return newState
109
109
  }
110
+
110
111
  const cacheChildRemove = (state, action) => {
111
112
  const newState = structuredClone(state)
112
113
  const { actionId } = action.payload
@@ -118,7 +119,7 @@ const cacheChildRemove = (state, action) => {
118
119
  }
119
120
  const childQueries = getChildQueries(affectedCacheQuery.cacheKey)
120
121
  if (childQueries.length === 1) {
121
- // if the action which is currently deleted is the last one needing this cache, we will give it a 3sek grace period before we remove the cache
122
+ // if the action which is currently deleted is the last one needing this cache, we will give it a 2sek grace period before we remove the cache
122
123
  newState[affectedCacheQuery.cacheKey].deleted = true
123
124
  if (deleteTimeouts[affectedCacheQuery.cacheKey]) {
124
125
  clearTimeout(deleteTimeouts[affectedCacheQuery.cacheKey])
@@ -129,7 +130,7 @@ const cacheChildRemove = (state, action) => {
129
130
  type: "queriesCache/remove",
130
131
  payload: { cacheKey: affectedCacheQuery.cacheKey, actionId },
131
132
  })
132
- }, 1000)
133
+ }, 2000)
133
134
  }
134
135
  delete cacheMap[actionId]
135
136
  return newState
@@ -155,7 +155,7 @@ const storePatterns = {
155
155
  // a deeper abstractation level for widgets which are used as tools.
156
156
  // ie. type:''add' create a folder called 'add' and create a default.vue
157
157
  // or FACE.vue containing your add logic for a given widget
158
- type: false,
158
+ workingState: {},
159
159
  version: "0.0.0",
160
160
  },
161
161
  tools: {
@@ -11,7 +11,7 @@ export const cudOperationTypesList = [
11
11
  ] as const
12
12
 
13
13
  export const readOperationTypesList = [
14
- "dataPush",
14
+ "dataRead",
15
15
  "dataAdd",
16
16
  "dataSync",
17
17
  ] as const
@@ -7,12 +7,14 @@ export type CustomStoreActionOptions = {
7
7
  notify?: boolean // default true, disables notification/snackbar
8
8
  responseType?: string // i.e stream
9
9
  mode?: string //i.e cors for streaming
10
+ useCache?: boolean
10
11
  }
11
12
 
12
13
  export type CustomStoreActionsPayload = {
13
14
  id?: String // if set this will used as the final namespace giver for the actionId, if not it will be a nanoId
14
15
  params?: CustomStoreActionParams
15
16
  options?: CustomStoreActionOptions
17
+ config?: any
16
18
  }
17
19
  export type QueryApiQuery = QueryState & {
18
20
  execute: (params?: Record<string, any>) => Promise<any>
@@ -23,6 +25,8 @@ export type DataApiMethods = {
23
25
  response: Object
24
26
  isLoading: Boolean
25
27
  execute: Function
28
+ clear: Function
29
+ remove: Function
26
30
  }
27
31
  export type QueryMethods = DataApiMethods & {
28
32
  uuids: Array<string>
@@ -1 +1,2 @@
1
1
  export type actionId = string
2
+ export type pluginKey = string
@@ -77,6 +77,8 @@
77
77
  class="tw:overflow-y-auto! tw:pb-0"
78
78
  :class="{ '!tw:invisible': loading }"
79
79
  :widgets-layout="widgetsLayout"
80
+ slot-type="page"
81
+ :slot-layout="slotLayout"
80
82
  @scroll.passive="onScroll($event)"
81
83
  />
82
84
 
@@ -133,11 +135,10 @@ import { useRoute } from "vue-router"
133
135
  import useUiState from "./composables/useUiState"
134
136
  import useRouteState from "./composables/useRouteState"
135
137
  import CompositionOverlay from "./components/composition/CompositionOverlay.vue"
136
- import { useTitle } from "@vueuse/core"
138
+ import { useTitle, useLocalStorage } from "@vueuse/core"
137
139
  import loginUserNotifications from "./helpers/loginUserNotifications"
138
140
  import configService from "@racletteCore/lib/configService"
139
141
  import { isDevelopmentMode } from "@racletteCore/helpers/devMode"
140
- import { useLocalStorage } from "@vueuse/core"
141
142
  import useDragAndDrop from "./composables/useDragAndDrop"
142
143
  import { useCurrentComposition } from "./composables"
143
144
  import WidgetsLayoutLoader from "./components/composition/WidgetsLayoutLoader.vue"
@@ -151,7 +152,7 @@ const { loading, theme, locale, landingPage, availableInterfaces } =
151
152
  useUiState()
152
153
  useRouteState()
153
154
  const { isDraggingOrResizingAnything } = useDragAndDrop()
154
- const { widgetsLayout } = useCurrentComposition()
155
+ const { widgetsLayout, slotLayout } = useCurrentComposition()
155
156
 
156
157
  const showWelcomeScreen = computed(() => {
157
158
  const isDynamicPage = route.name === "app.space.page"
@@ -208,20 +209,31 @@ const checkImageExists = async (url: string): Promise<boolean> => {
208
209
  const showScrollToTopBtn = ref(false)
209
210
  const isDevelopment = ref(false)
210
211
 
212
+ const setTheme = (theme: "dark" | "light") => {
213
+ vuetifyTheme.change(theme)
214
+
215
+ // tailwind support
216
+ if (theme === "dark") {
217
+ document.body.classList.add("dark")
218
+ } else {
219
+ document.body.classList.remove("dark")
220
+ }
221
+ }
222
+
211
223
  const onScroll = (e) =>
212
224
  (showScrollToTopBtn.value = e.currentTarget.scrollTop > 0)
213
225
 
214
226
  onMounted(async () => {
215
- vuetifyTheme.change(theme.value)
227
+ setTheme(theme.value)
216
228
  vuetifyLocale.current.value = locale.value
217
- isDevelopment.value = isDevelopmentMode()
229
+ isDevelopment.value = true || isDevelopmentMode()
218
230
  logoExists.value = await checkImageExists(logoSrc.value)
219
231
  // check if we have a message from checkToken to display as a snackbar
220
232
  loginUserNotifications()
221
233
  })
222
234
 
223
235
  watch(theme, () => {
224
- vuetifyTheme.change(theme.value)
236
+ setTheme(theme.value)
225
237
  })
226
238
 
227
239
  // set vuetify locale here, the rest is done in setup/i18n
@@ -233,7 +245,7 @@ window
233
245
  .addEventListener("change", (event) => {
234
246
  const newColorScheme = event.matches ? "dark" : "light"
235
247
  if (userTheme.value === null) {
236
- vuetifyTheme.change(newColorScheme)
248
+ setTheme(theme.value)
237
249
  }
238
250
  })
239
251
  </script>
@@ -1,40 +1,29 @@
1
1
  <template>
2
2
  <div class="welcome-screen">
3
- <v-container>
4
- <component :is="currentComponent" />
5
- <v-row>
6
- <v-col cols="12">
7
- <h2 class="tw:text-2xl tw:font-semibold tw:mb-4">
8
- {{ $t("core.welcomeScreen.builtInFeaturesTitle") }}
9
- </h2>
10
- <v-expansion-panels flat variant="accordion">
11
- <v-expansion-panel v-for="feature in features" :key="feature.key">
12
- <v-expansion-panel-title>
13
- <v-icon :icon="feature.icon" class="tw:mr-3"></v-icon>
14
- {{ $t(`core.welcomeScreen.${feature.key}Title`) }}
15
- </v-expansion-panel-title>
16
- <v-expansion-panel-text>
17
- <div class="tw:py-2">
18
- {{ $t(`core.welcomeScreen.${feature.key}Description`) }}
19
- </div>
20
- <template v-if="feature.status">
21
- <a
22
- v-if="feature.status.link"
23
- target="_blank"
24
- :href="feature.status.link"
25
- >
26
- <v-chip
27
- v-if="feature.status"
28
- :color="feature.status.color"
29
- size="small"
30
- class="tw:mt-2"
31
- >
32
- <v-icon start :icon="feature.status.icon"></v-icon>
33
- {{ $t(`core.welcomeScreen.${feature.status.key}`) }}
34
- </v-chip>
35
- </a>
3
+ <component :is="currentComponent" />
4
+ <v-row>
5
+ <v-col cols="12">
6
+ <h2 class="tw:text-2xl tw:font-semibold tw:mb-4">
7
+ {{ $t("core.welcomeScreen.builtInFeaturesTitle") }}
8
+ </h2>
9
+ <v-expansion-panels flat variant="accordion">
10
+ <v-expansion-panel v-for="feature in features" :key="feature.key">
11
+ <v-expansion-panel-title>
12
+ <v-icon :icon="feature.icon" class="tw:mr-3"></v-icon>
13
+ {{ $t(`core.welcomeScreen.${feature.key}Title`) }}
14
+ </v-expansion-panel-title>
15
+ <v-expansion-panel-text>
16
+ <div class="tw:py-2">
17
+ {{ $t(`core.welcomeScreen.${feature.key}Description`) }}
18
+ </div>
19
+ <template v-if="feature.status">
20
+ <a
21
+ v-if="feature.status.link"
22
+ target="_blank"
23
+ :href="feature.status.link"
24
+ >
36
25
  <v-chip
37
- v-else
26
+ v-if="feature.status"
38
27
  :color="feature.status.color"
39
28
  size="small"
40
29
  class="tw:mt-2"
@@ -42,13 +31,22 @@
42
31
  <v-icon start :icon="feature.status.icon"></v-icon>
43
32
  {{ $t(`core.welcomeScreen.${feature.status.key}`) }}
44
33
  </v-chip>
45
- </template>
46
- </v-expansion-panel-text>
47
- </v-expansion-panel>
48
- </v-expansion-panels>
49
- </v-col>
50
- </v-row>
51
- </v-container>
34
+ </a>
35
+ <v-chip
36
+ v-else
37
+ :color="feature.status.color"
38
+ size="small"
39
+ class="tw:mt-2"
40
+ >
41
+ <v-icon start :icon="feature.status.icon"></v-icon>
42
+ {{ $t(`core.welcomeScreen.${feature.status.key}`) }}
43
+ </v-chip>
44
+ </template>
45
+ </v-expansion-panel-text>
46
+ </v-expansion-panel>
47
+ </v-expansion-panels>
48
+ </v-col>
49
+ </v-row>
52
50
  </div>
53
51
  </template>
54
52
 
@@ -11,6 +11,9 @@
11
11
  /* @import "tailwindcss/preflight.css" layer(base) prefix(tw); */
12
12
  /* @import "tailwindcss/utilities.css" layer(utilities) prefix(tw); */
13
13
 
14
+ /* enable dark mode via class */
15
+ @custom-variant dark (&:where(.dark, .dark *));
16
+
14
17
  /* safelist for the resizing in the composition editor */
15
18
  @source inline('tw:col-span-{1..12}');
16
19
  @source inline('tw:grid-cols-{1..12}');
@@ -4,7 +4,7 @@
4
4
  export default {
5
5
  background: "#212121",
6
6
  surface: "#212121",
7
- primary: "#148dbc",
7
+ primary: "#0b6487",
8
8
  "primary-darken-1": "#1279a2",
9
9
  "primary-darken-2": "#106689",
10
10
  "primary-darken-3": "#0e5470",
@@ -19,7 +19,7 @@ export default {
19
19
  "primary-lighten-5": "#9dd8f2",
20
20
  "primary-lighten-6": "#c4e7f7",
21
21
  "primary-lighten-7": "#ebf5fc",
22
- secondary: "#03DAC6",
22
+ secondary: "#017f73",
23
23
  "secondary-darken-1": "#02b7a6",
24
24
  "secondary-darken-2": "#029487",
25
25
  error: "#FF5252",
@@ -13,7 +13,6 @@ button,
13
13
  [type="submit"],
14
14
  [role="button"] {
15
15
  cursor: pointer;
16
- color: inherit;
17
16
  }
18
17
 
19
18
  /* Specify the pointer cursor of trigger elements */
@@ -1,6 +1,13 @@
1
1
  <template>
2
2
  <DefaultModal v-model="showModal">
3
- <WidgetsLayoutLoader v-if="widgetsLayout" :widgets-layout="widgetsLayout" />
3
+ <div class="tw:p-5 tw:h-full">
4
+ <WidgetsLayoutLoader
5
+ v-if="widgetsLayout"
6
+ :widgets-layout="widgetsLayout"
7
+ :slot-layout="slotLayout"
8
+ slot-type="modal"
9
+ />
10
+ </div>
4
11
  </DefaultModal>
5
12
  </template>
6
13
 
@@ -11,7 +18,9 @@ import { computed } from "vue"
11
18
  import useRouteState from "@racletteOrchestrator/composables/useRouteState"
12
19
  import { DEFAULT_MODAL_SLOT_NAME } from "@racletteOrchestrator/router/routeParserHelper"
13
20
 
14
- const { widgetsLayout } = useCurrentComposition(DEFAULT_MODAL_SLOT_NAME)
21
+ const { widgetsLayout, slotLayout } = useCurrentComposition(
22
+ DEFAULT_MODAL_SLOT_NAME,
23
+ )
15
24
  const { removeSlot } = useRouteState()
16
25
 
17
26
  const showModal = computed({