Shell: a picker entry can name the older variant ids it stands for

Layouts saved before Timers 1.3.0 hold 'timer:<uuid>' and 'ltc' tiles.
An entry's aliases let those tiles get the entry's slim gear settings
instead of falling back to the module's full schema.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-09-14 15:40:36 -04:00
co-authored by Claude Fable 5.1
parent 3ceac9599b
commit 70134d6dfc
4 changed files with 18 additions and 4 deletions
+5 -1
View File
@@ -501,7 +501,7 @@ module.exports = {
return config.pages.map((page) => ({ return config.pages.map((page) => ({
id: page.name, // stable id, stored with the tile id: page.name, // stable id, stored with the tile
name: page.name, // picker label AND the tile's title name: page.name, // picker label AND the tile's title
description: page.url, // optional line under the label description: page.url, // optional; the picker's tooltip
settings: { page: page.name }, // preset instance settings settings: { page: page.name }, // preset instance settings
defaultSize: { w: 4, h: 3 }, // optional per-entry size overrides defaultSize: { w: 4, h: 3 }, // optional per-entry size overrides
minSize: { w: 2, h: 2 }, minSize: { w: 2, h: 2 },
@@ -516,6 +516,10 @@ module.exports = {
so a dead upstream can't break the picker. so a dead upstream can't break the picker.
- `instanceSchema` / `instanceGroups` on an entry replace the module's for - `instanceSchema` / `instanceGroups` on an entry replace the module's for
tiles added from it — settings that fit that tile, nothing else. tiles added from it — settings that fit that tile, nothing else.
- `aliases: ['old-id', …]` on an entry names earlier variant ids it stands
for: a tile added under one of them (a layout saved by an older version of
your module) gets this entry's settings too. A tile whose variant matches
no entry and no alias falls back to the module's full `instanceSchema`.
- Entry `description`s are tooltips in the + picker now, not visible lines — - Entry `description`s are tooltips in the + picker now, not visible lines —
one short sentence. one short sentence.
- `single: true` on an entry allows at most one such tile per dashboard: the - `single: true` on an entry allows at most one such tile per dashboard: the
+3 -1
View File
@@ -1136,7 +1136,9 @@ module.exports = {
const description = src.kind === 'ltc' ? 'The incoming LTC timecode on its own' const description = src.kind === 'ltc' ? 'The incoming LTC timecode on its own'
: src.kind === 'clock' ? 'The time of day on its own' : src.kind === 'clock' ? 'The time of day on its own'
: `This ${src.label} ${KIND_WORD[t.kind] || 'timer'} on its own`; : `This ${src.label} ${KIND_WORD[t.kind] || 'timer'} on its own`;
out.push({ id: `solo:${src.id}:${t.id}`, name: t.label, description, ...oneCard, ...gearFor(src, t) }); // Layouts from before 1.3.0 hold 'timer:<uuid>' / 'ltc' — the same tiles.
const aliases = src.id === 'propresenter' ? [`timer:${t.id}`] : src.kind === 'ltc' ? ['ltc'] : [];
out.push({ id: `solo:${src.id}:${t.id}`, name: t.label, description, ...oneCard, ...gearFor(src, t), ...(aliases.length ? { aliases } : {}) });
} }
} }
return out; return out;
+4 -2
View File
@@ -1094,8 +1094,10 @@ function colorHex(value, fallback) {
Same for the groups that arrange them. */ Same for the groups that arrange them. */
function tileSchema(tile, man) { function tileSchema(tile, man) {
const own = (v) => (v && typeof v === 'object' ? v : null); const own = (v) => (v && typeof v === 'object' ? v : null);
const entry = tile?.variant && Array.isArray(man?.tiles) const variant = String(tile?.variant || '');
? man.tiles.find((e) => String(e.id) === String(tile.variant)) const entry = variant && Array.isArray(man?.tiles)
? man.tiles.find((e) => String(e.id) === variant)
|| man.tiles.find((e) => Array.isArray(e.aliases) && e.aliases.includes(variant))
: null; : null;
return { return {
schema: own(entry?.instanceSchema) || own(man?.instanceSchema) || {}, schema: own(entry?.instanceSchema) || own(man?.instanceSchema) || {},
+6
View File
@@ -471,6 +471,12 @@ function sanitizeTileEntry(raw) {
for (const key of ['instanceSchema', 'instanceGroups']) { for (const key of ['instanceSchema', 'instanceGroups']) {
if (raw[key] && typeof raw[key] === 'object') out[key] = raw[key]; if (raw[key] && typeof raw[key] === 'object') out[key] = raw[key];
} }
// Earlier variant ids this entry stands for, so a tile added under one of
// them (a layout from an older module version) gets this entry's settings.
if (Array.isArray(raw.aliases)) {
const aliases = raw.aliases.map((a) => String(a)).filter(Boolean);
if (aliases.length) out.aliases = aliases;
}
for (const key of ['minSize', 'defaultSize']) { for (const key of ['minSize', 'defaultSize']) {
const size = raw[key]; const size = raw[key];
if (size && Number(size.w) > 0 && Number(size.h) > 0) { if (size && Number(size.w) > 0 && Number(size.h) > 0) {