The bug behind this: for seventeen days the server rebuilt each saved tile from the fields it knew and dropped the rest — including `variant`, so a layout of five different timers came back from the server as five "All timers". The client had carried `variant` since multi-tile modules arrived; the server was the one that lagged, and it is the part of ProdDash that always will (a booth updates weeks after the dev machine). So the server stops deciding which tile fields exist: it checks the shape of the ones it knows, keeps any other small plain-JSON field a tile carries, drops only retired ones, stamps the file `v: 2`, and refuses a layout over a hundred tiles instead of quietly saving the first hundred. A test round-trips a fully-populated tile plus one the server has never heard of, and fails if anything is lost. Then the rule the arrangement is loaded by. A layout keeps every tile it is given; the board shows the ones whose module is installed and enabled and — for a tile added from a picker entry — whose entry is offered right now. The rest keep their place and draw nothing, and appear the moment the registry offers them again: a Service timer waits for PCO Plan, a transcript for its channel. Never the module's default in their place. Because a module's entry list can change with no event to mark it (PCO Plan comes back and, seconds later, the timers module is offering its timers again), the registry is re-read every few seconds while anything is folded away, and not at all otherwise. The timers module's placeholder card for a missing solo timer goes with this: nothing is drawn, the dot says why. Loading says what it did — "Loaded 'FOH': 9 tiles, 2 not shown — Service, #ops aren't offered right now" — with Undo in the message. Saving over a name asks first, and the server keeps the copy it replaced one back; Admin → Saved layouts gets Restore previous, which swaps the two so a restore is one restore from undone. The browser keeps one good copy of its own layout behind the live one and falls back to it when the live one will not parse. Shell 1.8.0, timers 1.4.1. The layouts already saved on the booth machines had their variants stripped before this and have to be saved again from a browser that still holds the right tiles — nothing here recovers what the files no longer contain. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
229 lines
5.4 KiB
JSON
229 lines
5.4 KiB
JSON
{
|
||
"id": "propresenter-timers",
|
||
"name": "Timers",
|
||
"version": "1.4.1",
|
||
"proddash": ">=1.4.0",
|
||
"description": "Timers, Clocks, and LTC From configured Modules",
|
||
"provides": [
|
||
"timers"
|
||
],
|
||
"permissions": [
|
||
{
|
||
"kind": "microphone",
|
||
"reason": "Decoding SMPTE LTC timecode from an audio input on this machine"
|
||
},
|
||
{
|
||
"kind": "local-network",
|
||
"reason": "Reaching ProPresenter on this network"
|
||
}
|
||
],
|
||
"client": "client.js",
|
||
"server": "server.js",
|
||
"style": "style.css",
|
||
"minSize": {
|
||
"w": 2,
|
||
"h": 1
|
||
},
|
||
"defaultSize": {
|
||
"w": 4,
|
||
"h": 3
|
||
},
|
||
"configGroups": {
|
||
"ProPresenter": {
|
||
"toggle": "ppEnabled",
|
||
"help": "The timers configured in ProPresenter, read over its network API. Enable the network in ProPresenter's Preferences › Network and enter the host and port shown there. Switch it off on a day ProPresenter isn't running and nothing is polled."
|
||
},
|
||
"LTC Timecode": {
|
||
"toggle": "ltcEnabled",
|
||
"help": "SMPTE LTC decoded from an audio input on this machine, shown as a running timecode. Pick the device and the channel the timecode arrives on; macOS has to grant ProdDash the microphone (see the launcher's Permissions)."
|
||
},
|
||
"PCO Plan": {
|
||
"toggle": "pcoEnabled",
|
||
"help": "Timers the PCO Plan module offers — service elapsed, current item, countdown to service — appear here under a PCO Plan heading when that module is installed and configured. Nothing to set up on this side."
|
||
}
|
||
},
|
||
"configSchema": {
|
||
"ppEnabled": {
|
||
"type": "switch",
|
||
"label": "ProPresenter timers",
|
||
"group": "ProPresenter",
|
||
"default": true
|
||
},
|
||
"propresenter": {
|
||
"type": "endpoint",
|
||
"label": "ProPresenter",
|
||
"group": "ProPresenter",
|
||
"default": {
|
||
"host": "",
|
||
"port": 1025
|
||
}
|
||
},
|
||
"password": {
|
||
"type": "password",
|
||
"label": "API password",
|
||
"group": "ProPresenter",
|
||
"default": "",
|
||
"help": "Only if a password is set in ProPresenter's network preferences."
|
||
},
|
||
"ltcEnabled": {
|
||
"type": "switch",
|
||
"label": "LTC timecode",
|
||
"group": "LTC Timecode",
|
||
"default": false
|
||
},
|
||
"ltcDevice": {
|
||
"type": "select",
|
||
"label": "Audio device",
|
||
"group": "LTC Timecode",
|
||
"showWhen": "ltcEnabled",
|
||
"default": "",
|
||
"optionsRoute": "/ltc/devices"
|
||
},
|
||
"ltcChannel": {
|
||
"type": "number",
|
||
"label": "Channel",
|
||
"group": "LTC Timecode",
|
||
"showWhen": "ltcEnabled",
|
||
"default": 1,
|
||
"help": "The channel on that device carrying the timecode, counted from 1."
|
||
},
|
||
"pcoEnabled": {
|
||
"type": "switch",
|
||
"label": "PCO Plan timers",
|
||
"group": "PCO Plan",
|
||
"default": true
|
||
},
|
||
"timerFont": {
|
||
"type": "select",
|
||
"label": "Timer font",
|
||
"group": "Display",
|
||
"default": "default",
|
||
"options": [
|
||
{
|
||
"value": "default",
|
||
"label": "Default (system)"
|
||
},
|
||
{
|
||
"value": "monospace",
|
||
"label": "Monospace — steadier changing digits"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"instanceGroups": {
|
||
"Show": {
|
||
"collapsed": true,
|
||
"columns": 2
|
||
},
|
||
"Clock": {
|
||
"collapsed": false,
|
||
"columns": 2
|
||
},
|
||
"Colours": {
|
||
"collapsed": true,
|
||
"columns": 2
|
||
}
|
||
},
|
||
"instanceSchema": {
|
||
"showNames": {
|
||
"type": "switch",
|
||
"label": "Names",
|
||
"default": true,
|
||
"group": "Show"
|
||
},
|
||
"showStatus": {
|
||
"type": "switch",
|
||
"label": "Status lines",
|
||
"default": true,
|
||
"group": "Show"
|
||
},
|
||
"showDetail": {
|
||
"type": "switch",
|
||
"label": "Detail lines",
|
||
"default": true,
|
||
"group": "Show"
|
||
},
|
||
"showSeconds": {
|
||
"type": "switch",
|
||
"label": "Seconds",
|
||
"default": true,
|
||
"group": "Show"
|
||
},
|
||
"leadingZeros": {
|
||
"type": "switch",
|
||
"label": "Leading zeros",
|
||
"default": false,
|
||
"group": "Show"
|
||
},
|
||
"groupBySource": {
|
||
"type": "switch",
|
||
"label": "Group by source",
|
||
"default": false,
|
||
"group": "Show"
|
||
},
|
||
"showHeadings": {
|
||
"type": "switch",
|
||
"label": "Source headings",
|
||
"default": true,
|
||
"group": "Show",
|
||
"showWhen": "groupBySource"
|
||
},
|
||
"clock24h": {
|
||
"type": "switch",
|
||
"label": "24-hour",
|
||
"default": true,
|
||
"group": "Clock"
|
||
},
|
||
"clockSeconds": {
|
||
"type": "switch",
|
||
"label": "Seconds",
|
||
"default": true,
|
||
"group": "Clock"
|
||
},
|
||
"clockDate": {
|
||
"type": "switch",
|
||
"label": "Date",
|
||
"default": false,
|
||
"group": "Clock"
|
||
},
|
||
"dateShortDay": {
|
||
"type": "switch",
|
||
"label": "Short day",
|
||
"default": false,
|
||
"group": "Clock",
|
||
"showWhen": "clockDate"
|
||
},
|
||
"dateShortMonth": {
|
||
"type": "switch",
|
||
"label": "Short month",
|
||
"default": false,
|
||
"group": "Clock",
|
||
"showWhen": "clockDate"
|
||
},
|
||
"runningColor": {
|
||
"type": "color",
|
||
"label": "Running",
|
||
"default": "#2ee59a",
|
||
"group": "Colours"
|
||
},
|
||
"warningColor": {
|
||
"type": "color",
|
||
"label": "Warning",
|
||
"default": "#f0b429",
|
||
"group": "Colours"
|
||
},
|
||
"overrunColor": {
|
||
"type": "color",
|
||
"label": "Overrun",
|
||
"default": "#f4433c",
|
||
"group": "Colours"
|
||
},
|
||
"idleColor": {
|
||
"type": "color",
|
||
"label": "Idle",
|
||
"default": "#8b98a5",
|
||
"group": "Colours"
|
||
}
|
||
}
|
||
}
|