@raclettejs/workbench 0.1.40 → 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 CHANGED
@@ -7,8 +7,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.1.40] - 2026-06-30 <a href="https://gitlab.com/raclettejs/core-dev/-/compare/v0.1.39...v0.1.40" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
10
+ ## [0.1.41] - 2026-07-07 <a href="https://gitlab.com/raclettejs/core-dev/-/compare/v0.1.40...v0.1.41" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
11
+
12
+
13
+ ### Changed
14
+
15
+ - Share Valkey default DB across app, workbench, and core containers, with per-role overrides and improved widget loading coordination.
16
+
17
+ **Cache / Valkey**
18
+ - Add `services.cache.db` (shared default) and `services.cache.dbs` (`app`, `workbench`, `core`) to `raclette.config.js`; workbench reads cache settings from the starting app via `RACLETTE_APP_PATH`.
19
+ - Add `cacheUrl` helpers and Docker Compose `CACHE_URL` generation with correct DB suffix resolution; `RACLETTE_CACHE_URL` remains a full override.
20
+ - Default all stacks to DB `0` so app and workbench share the same Valkey namespace unless configured otherwise.
21
+ - Remove workbench's hardcoded `services.cache.db: 1`.
11
22
 
23
+ **Frontend orchestrator**
24
+ - Gate global page loading on socket bootstrap plus page widget slot readiness (`useAppLoadingCoordinator`); remove the router `afterEach` loading timeout.
25
+ - Track widget readiness at slot-container level; inject `onAllWidgetsReady` via `wrapWidgetWithLifecycle`.
26
+ - Show modal loading overlays until modal composition slots are ready (`trackReadiness` / `revealWhenReady`).
27
+ - Render `ErrorWidgetState` for failed widgets without blocking page or modal loading.
28
+ - Reverse `interactionLinks` `sortOrder` semantics — higher values appear first.
29
+
30
+ **BaseDataTable**
31
+ - Forward `#group-header` slot with `selectionActive`; add `BaseDataTableGroupSelectCheckbox` for custom group headers.
32
+ - Fix scoped slot content detection when probing for slot content.
33
+
34
+ **Workbench**
35
+ - Localize cache list TTL labels and truncation notices (en, de, sk).
36
+ - Move Cache interaction link to footer navigation.
37
+
38
+ **Docs**
39
+ - Document `services.cache` configuration, DB resolution order, and examples.
40
+ - Add BaseDataTable FAQ, widget loading behavior guide, and interactionLinks `sortOrder` notes.
41
+
42
+ ### Updated
43
+
44
+ - Updated dependencies
45
+ - @raclettejs/core@0.1.41
46
+
47
+ ### Added
48
+
49
+ - German and Slovak `cacheList` i18n strings; localized TTL labels and truncation notices via `formatTtlLabel`
50
+
51
+ ### Updated
52
+
53
+ - interactionLinks `sortOrder` reversed: higher values appear first (see workbench docs)
54
+ - Cache interaction link moved to footer navigation
55
+ - removed hardcoded `services.cache.db: 1` from workbench defaults (inherits starting app's cache DB config)
56
+ - cache list widget uses i18n for truncation notice text
57
+
58
+ ## [0.1.40] - 2026-06-30 <a href="https://gitlab.com/raclettejs/core-dev/-/compare/v0.1.39...v0.1.40" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
12
59
 
13
60
  ### Patch Changes
14
61
 
@@ -15,7 +15,7 @@ export default [
15
15
  default: "Compositions",
16
16
  de: "Kompositionen",
17
17
  },
18
- sortOrder: 0,
18
+ sortOrder: 4,
19
19
  navigationBarType: "navItem",
20
20
  },
21
21
  },
@@ -48,7 +48,7 @@ export default [
48
48
  default: "Interaction Links",
49
49
  de: "Interaktionslinks",
50
50
  },
51
- sortOrder: 1,
51
+ sortOrder: 3,
52
52
  navigationBarType: "navItem",
53
53
  },
54
54
  },
@@ -114,7 +114,7 @@ export default [
114
114
  default: "Tags",
115
115
  de: "Tags",
116
116
  },
117
- sortOrder: 3,
117
+ sortOrder: 1,
118
118
  navigationBarType: "navItem",
119
119
  },
120
120
  },
@@ -148,7 +148,7 @@ export default [
148
148
  default: "Plugins",
149
149
  de: "Plugins",
150
150
  },
151
- sortOrder: 4,
151
+ sortOrder: 0,
152
152
  navigationBarType: "navItem",
153
153
  },
154
154
  },
@@ -175,7 +175,7 @@ export default [
175
175
  default: "Project",
176
176
  de: "Projekt",
177
177
  },
178
- sortOrder: 0,
178
+ sortOrder: 1,
179
179
  navigationBarType: "footerItem",
180
180
  },
181
181
  },
@@ -194,8 +194,8 @@ export default [
194
194
  default: "Cache",
195
195
  de: "Cache",
196
196
  },
197
- sortOrder: 5,
198
- navigationBarType: "navItem",
197
+ sortOrder: 1,
198
+ navigationBarType: "footerItem",
199
199
  },
200
200
  },
201
201
  ],
package/i18n/de-DE.json CHANGED
@@ -232,6 +232,46 @@
232
232
  "tagEdit": {
233
233
  "title": "Tag bearbeiten"
234
234
  },
235
+ "cacheList": {
236
+ "dataName": "Cache-Eintrag",
237
+ "dbLabel": "DB",
238
+ "batchSizeLabel": "Abruf-Batch",
239
+ "dbActive": "DB {db}",
240
+ "patternLabel": "Schlüsselmuster",
241
+ "patternPlaceholder": "leer = alle Schlüssel, gruppiert",
242
+ "refresh": "Aktualisieren",
243
+ "loadMore": "Mehr laden",
244
+ "truncated": "Gekürzt",
245
+ "truncatedDetailHint": "Wert wurde zur Anzeige gekürzt. Export enthält möglicherweise nicht den vollständigen gespeicherten Wert.",
246
+ "truncationNotice": "Wert wurde für den Transport gekürzt; Rest ausgelassen. Nicht als vollständige Quelle verwenden.",
247
+ "detailTtl": "TTL",
248
+ "showingCount": "{shown} von {total}",
249
+ "keyPickerLabel": "Schlüssel",
250
+ "backToList": "Zurück zur Liste",
251
+ "customizeTable": "Tabelle konfigurieren",
252
+ "configureColumns": "Spalten konfigurieren",
253
+ "deselectAll": "Alle abwählen",
254
+ "done": "Fertig",
255
+ "valueTableTitle": "Cache-Wert",
256
+ "openValueTable": "Wertetabelle öffnen",
257
+ "openValueTableFor": "Wertetabelle für {key} öffnen",
258
+ "ttlNoExpiry": "kein Ablauf",
259
+ "ttlMissing": "fehlend",
260
+ "ttlSeconds": "{seconds}s",
261
+ "tableHeaders": {
262
+ "keyGroup": "Gruppe",
263
+ "key": "Schlüssel",
264
+ "ttl": "TTL",
265
+ "value": "Wert"
266
+ },
267
+ "valueTableHeaders": {
268
+ "field": "Feld",
269
+ "entryKey": "Eintragsschlüssel",
270
+ "value": "Wert",
271
+ "index": "Index",
272
+ "raw": "Roh"
273
+ }
274
+ },
235
275
  "tagConfiguration": {
236
276
  "dividers": {
237
277
  "general": "Allgemein"
package/i18n/en-EU.json CHANGED
@@ -243,6 +243,7 @@
243
243
  "loadMore": "Load more",
244
244
  "truncated": "Truncated",
245
245
  "truncatedDetailHint": "Value was truncated for display. Export may not include the full stored value.",
246
+ "truncationNotice": "Value was cut for transport; remainder omitted. Do not treat as complete source of truth.",
246
247
  "detailTtl": "TTL",
247
248
  "showingCount": "{shown} of {total}",
248
249
  "keyPickerLabel": "Key",
@@ -254,6 +255,9 @@
254
255
  "valueTableTitle": "Cache value",
255
256
  "openValueTable": "Open value table",
256
257
  "openValueTableFor": "Open value table for {key}",
258
+ "ttlNoExpiry": "no expiry",
259
+ "ttlMissing": "missing",
260
+ "ttlSeconds": "{seconds}s",
257
261
  "tableHeaders": {
258
262
  "keyGroup": "Group",
259
263
  "key": "Key",
package/i18n/sk-SK.json CHANGED
@@ -227,6 +227,46 @@
227
227
  "tagEdit": {
228
228
  "title": "Upraviť značku"
229
229
  },
230
+ "cacheList": {
231
+ "dataName": "Položka cache",
232
+ "dbLabel": "DB",
233
+ "batchSizeLabel": "Veľkosť dávky",
234
+ "dbActive": "DB {db}",
235
+ "patternLabel": "Vzor kľúča",
236
+ "patternPlaceholder": "prázdne = všetky kľúče, zoskupené",
237
+ "refresh": "Obnoviť",
238
+ "loadMore": "Načítať viac",
239
+ "truncated": "Skrátené",
240
+ "truncatedDetailHint": "Hodnota bola skrátená na zobrazenie. Export nemusí obsahovať úplnú uloženú hodnotu.",
241
+ "truncationNotice": "Hodnota bola skrátená pri prenose; zvyšok vynechaný. Nepoužívajte ako úplný zdroj pravdy.",
242
+ "detailTtl": "TTL",
243
+ "showingCount": "{shown} z {total}",
244
+ "keyPickerLabel": "Kľúč",
245
+ "backToList": "Späť na zoznam",
246
+ "customizeTable": "Konfigurovať tabuľku",
247
+ "configureColumns": "Konfigurovať stĺpce",
248
+ "deselectAll": "Zrušiť výber všetkých",
249
+ "done": "Hotovo",
250
+ "valueTableTitle": "Hodnota cache",
251
+ "openValueTable": "Otvoriť tabuľku hodnôt",
252
+ "openValueTableFor": "Otvoriť tabuľku hodnôt pre {key}",
253
+ "ttlNoExpiry": "bez expirácie",
254
+ "ttlMissing": "chýba",
255
+ "ttlSeconds": "{seconds}s",
256
+ "tableHeaders": {
257
+ "keyGroup": "Skupina",
258
+ "key": "Kľúč",
259
+ "ttl": "TTL",
260
+ "value": "Hodnota"
261
+ },
262
+ "valueTableHeaders": {
263
+ "field": "Pole",
264
+ "entryKey": "Kľúč záznamu",
265
+ "value": "Hodnota",
266
+ "index": "Index",
267
+ "raw": "Surové"
268
+ }
269
+ },
230
270
  "tagConfiguration": {
231
271
  "dividers": {
232
272
  "general": "Všeobecné"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raclettejs/workbench",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "license": "MIT",
5
5
  "description": "racletteJS Workbench - used to configure your application, for dev and prod",
6
6
  "repository": "https://gitlab.com/raclettejs/workbench",
@@ -33,7 +33,7 @@
33
33
  ".": "./index.ts"
34
34
  },
35
35
  "dependencies": {
36
- "@raclettejs/core": "0.1.40",
36
+ "@raclettejs/core": "0.1.41",
37
37
  "@vueuse/integrations": "14.2.1",
38
38
  "fuse.js": "7.1.0",
39
39
  "three": "0.183.2",
@@ -43,7 +43,7 @@
43
43
  "@emnapi/core": "1.9.2",
44
44
  "@emnapi/runtime": "1.9.2",
45
45
  "@eslint/js": "9.35.0",
46
- "@raclettejs/types": "0.1.40",
46
+ "@raclettejs/types": "0.1.41",
47
47
  "@sinclair/typebox": "0.34.48",
48
48
  "@types/ramda": "0.31.1",
49
49
  "@vueuse/core": "14.2.1",
@@ -5,7 +5,7 @@ export type NormalizedPattern = {
5
5
  listAll: boolean
6
6
  }
7
7
 
8
- /** Explorer defaults to DB 0; raclette.config often sets cache db 1 for the app client. */
8
+ /** Explorer defaults to DB 0; per-role DB is configured on the starting app via services.cache.db / services.cache.dbs. */
9
9
  export const DEFAULT_EXPLORER_DB = 0
10
10
 
11
11
  export const parseExplorerDb = (queryDb?: number): number => {
@@ -1,7 +1,7 @@
1
1
  /** Injected into repaired JSON so viewers know the payload is incomplete. */
2
2
  export const TRUNCATION_MARKER = "__raclette_truncated__"
3
3
 
4
- const TRUNCATION_NOTICE =
4
+ const DEFAULT_TRUNCATION_NOTICE =
5
5
  "Value was cut for transport; remainder omitted. Do not treat as complete source of truth."
6
6
 
7
7
  type CacheEntryDisplaySource = {
@@ -11,10 +11,14 @@ type CacheEntryDisplaySource = {
11
11
  valueParsedFromFullValue?: boolean
12
12
  }
13
13
 
14
+ export type FormatCacheEntryDisplayOptions = {
15
+ truncationNotice?: string
16
+ }
17
+
14
18
  const prettyJson = (value: unknown): string => JSON.stringify(value, null, 2)
15
19
 
16
- const appendTruncationNotice = (body: string): string =>
17
- `${body}\n\n/* ${TRUNCATION_NOTICE} */`
20
+ const appendTruncationNotice = (body: string, truncationNotice: string): string =>
21
+ `${body}\n\n/* ${truncationNotice} */`
18
22
 
19
23
  /**
20
24
  * Close open strings/arrays/objects after an abrupt cut so JSON.parse may succeed
@@ -135,16 +139,19 @@ export const repairTruncatedJson = (raw: string): string => {
135
139
  return candidate
136
140
  }
137
141
 
138
- const withTruncationMarker = (parsed: unknown): unknown => {
142
+ const withTruncationMarker = (
143
+ parsed: unknown,
144
+ truncationNotice: string,
145
+ ): unknown => {
139
146
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
140
147
  return {
141
148
  ...parsed,
142
- [TRUNCATION_MARKER]: TRUNCATION_NOTICE,
149
+ [TRUNCATION_MARKER]: truncationNotice,
143
150
  }
144
151
  }
145
152
 
146
153
  return {
147
- [TRUNCATION_MARKER]: TRUNCATION_NOTICE,
154
+ [TRUNCATION_MARKER]: truncationNotice,
148
155
  value: parsed,
149
156
  }
150
157
  }
@@ -153,7 +160,13 @@ const withTruncationMarker = (parsed: unknown): unknown => {
153
160
  * Pretty-print a cache entry for <pre> display.
154
161
  * Recovers structure from truncated JSON when possible and always signals truncation.
155
162
  */
156
- export const formatCacheEntryDisplay = (entry: CacheEntryDisplaySource): string => {
163
+ export const formatCacheEntryDisplay = (
164
+ entry: CacheEntryDisplaySource,
165
+ options: FormatCacheEntryDisplayOptions = {},
166
+ ): string => {
167
+ const truncationNotice =
168
+ options.truncationNotice ?? DEFAULT_TRUNCATION_NOTICE
169
+
157
170
  if (!entry.truncated) {
158
171
  if (entry.valueParsed !== undefined) {
159
172
  return prettyJson(entry.valueParsed)
@@ -173,19 +186,28 @@ export const formatCacheEntryDisplay = (entry: CacheEntryDisplaySource): string
173
186
  }
174
187
 
175
188
  if (entry.valueParsed !== undefined) {
176
- return appendTruncationNotice(prettyJson(entry.valueParsed))
189
+ return appendTruncationNotice(
190
+ prettyJson(entry.valueParsed),
191
+ truncationNotice,
192
+ )
177
193
  }
178
194
 
179
195
  try {
180
- return appendTruncationNotice(prettyJson(JSON.parse(entry.value)))
196
+ return appendTruncationNotice(
197
+ prettyJson(JSON.parse(entry.value)),
198
+ truncationNotice,
199
+ )
181
200
  } catch {
182
201
  const repaired = repairTruncatedJson(entry.value)
183
202
  try {
184
203
  return appendTruncationNotice(
185
- prettyJson(withTruncationMarker(JSON.parse(repaired))),
204
+ prettyJson(
205
+ withTruncationMarker(JSON.parse(repaired), truncationNotice),
206
+ ),
207
+ truncationNotice,
186
208
  )
187
209
  } catch {
188
- return `${entry.value}\n\n… [${TRUNCATION_NOTICE}]`
210
+ return `${entry.value}\n\n… [${truncationNotice}]`
189
211
  }
190
212
  }
191
213
  }
@@ -0,0 +1,15 @@
1
+ type TtlTranslate = (
2
+ key: string,
3
+ values?: Record<string, unknown>,
4
+ ) => string
5
+
6
+ /** Format Valkey TTL for display using workbench.cacheList i18n keys. */
7
+ export const formatTtlLabel = (ttl: number, t: TtlTranslate): string => {
8
+ if (ttl === -1) {
9
+ return t("workbench.cacheList.ttlNoExpiry")
10
+ }
11
+ if (ttl === -2) {
12
+ return t("workbench.cacheList.ttlMissing")
13
+ }
14
+ return t("workbench.cacheList.ttlSeconds", { seconds: ttl })
15
+ }
@@ -96,6 +96,9 @@
96
96
  {{ $t("workbench.cacheList.dbActive", { db: activeDb }) }}
97
97
  </span>
98
98
  </template>
99
+ <template #item.ttlLabel="{ item }">
100
+ {{ formatTtlLabel(item.ttl, t) }}
101
+ </template>
99
102
  <template #item.value="{ item }">
100
103
  <code class="tw:text-xs tw:break-all tw:line-clamp-2">
101
104
  {{ displayValue(item) }}
@@ -180,7 +183,7 @@
180
183
  class="tw:text-sm tw:text-medium-emphasis tw:whitespace-nowrap"
181
184
  >
182
185
  {{ $t("workbench.cacheList.detailTtl") }}:
183
- {{ valueTableEntry.ttlLabel }}
186
+ {{ formatTtlLabel(valueTableEntry.ttl, t) }}
184
187
  ·
185
188
  {{ $t("workbench.cacheList.dbActive", { db: activeDb }) }}
186
189
  </span>
@@ -252,7 +255,7 @@
252
255
  </v-card-title>
253
256
  <v-card-subtitle>
254
257
  {{ $t("workbench.cacheList.detailTtl") }}:
255
- {{ selectedEntry.ttlLabel }}
258
+ {{ formatTtlLabel(selectedEntry.ttl, t) }}
256
259
  </v-card-subtitle>
257
260
  <v-card-text>
258
261
  <v-alert
@@ -298,6 +301,7 @@ import {
298
301
  type ValueTableHeader,
299
302
  } from "../utils/cacheValueTableRows"
300
303
  import { formatCacheEntryDisplay } from "../utils/formatCacheEntryDisplay"
304
+ import { formatTtlLabel } from "../utils/formatTtlLabel"
301
305
  import { computed, onMounted, ref } from "vue"
302
306
  import { useI18n } from "vue-i18n"
303
307
 
@@ -644,7 +648,10 @@ const displayValue = (item: CacheEntry) => {
644
648
  return item.value
645
649
  }
646
650
 
647
- const formatDetailValue = (item: CacheEntry) => formatCacheEntryDisplay(item)
651
+ const formatDetailValue = (item: CacheEntry) =>
652
+ formatCacheEntryDisplay(item, {
653
+ truncationNotice: t("workbench.cacheList.truncationNotice"),
654
+ })
648
655
 
649
656
  const formatValueTableCell = (value: string | undefined) => value ?? ""
650
657
 
@@ -51,7 +51,6 @@ export default defineRacletteConfig({
51
51
  volume: "raclette-cache",
52
52
  enabled: true,
53
53
  port: 6379,
54
- db: 1,
55
54
  },
56
55
  },
57
56