Show max length in item tooltips
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Maintainer-controlled web client version.
|
// Maintainer-controlled web client version.
|
||||||
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
||||||
window.CHGRID_WEB_VERSION = "2026.02.22 R144";
|
window.CHGRID_WEB_VERSION = "2026.02.22 R145";
|
||||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export type ItemPropertyValueType = 'boolean' | 'text' | 'number' | 'list' | 'so
|
|||||||
export type ItemPropertyMetadata = {
|
export type ItemPropertyMetadata = {
|
||||||
valueType?: ItemPropertyValueType;
|
valueType?: ItemPropertyValueType;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
|
maxLength?: number;
|
||||||
range?: {
|
range?: {
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
@@ -140,6 +141,12 @@ function normalizePropertyMetadataRecord(raw: Record<string, unknown> | undefine
|
|||||||
if (typeof valueObj.tooltip === 'string' && valueObj.tooltip.trim().length > 0) {
|
if (typeof valueObj.tooltip === 'string' && valueObj.tooltip.trim().length > 0) {
|
||||||
metadata.tooltip = valueObj.tooltip.trim();
|
metadata.tooltip = valueObj.tooltip.trim();
|
||||||
}
|
}
|
||||||
|
if (valueObj.maxLength !== undefined) {
|
||||||
|
const maxLength = Number(valueObj.maxLength);
|
||||||
|
if (Number.isFinite(maxLength) && maxLength > 0) {
|
||||||
|
metadata.maxLength = Math.floor(maxLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
const range = valueObj.range;
|
const range = valueObj.range;
|
||||||
if (range && typeof range === 'object') {
|
if (range && typeof range === 'object') {
|
||||||
const rangeObj = range as Record<string, unknown>;
|
const rangeObj = range as Record<string, unknown>;
|
||||||
|
|||||||
@@ -819,6 +819,10 @@ function describeItemPropertyHelp(item: WorldItem, key: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (metadata?.maxLength !== undefined) {
|
||||||
|
parts.push(`Max length: ${metadata.maxLength} characters.`);
|
||||||
|
}
|
||||||
|
|
||||||
parts.push(EDITABLE_ITEM_PROPERTY_KEYS.has(key) ? 'Editable.' : 'Read only.');
|
parts.push(EDITABLE_ITEM_PROPERTY_KEYS.has(key) ? 'Editable.' : 'Read only.');
|
||||||
return parts.join(' ');
|
return parts.join(' ');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export const welcomeMessageSchema = z.object({
|
|||||||
z.object({
|
z.object({
|
||||||
valueType: z.enum(['boolean', 'text', 'number', 'list', 'sound']).optional(),
|
valueType: z.enum(['boolean', 'text', 'number', 'list', 'sound']).optional(),
|
||||||
tooltip: z.string().optional(),
|
tooltip: z.string().optional(),
|
||||||
|
maxLength: z.number().int().positive().optional(),
|
||||||
range: z
|
range: z
|
||||||
.object({
|
.object({
|
||||||
min: z.number(),
|
min: z.number(),
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ TIME_ZONE_OPTIONS: tuple[str, ...] = (
|
|||||||
DEFAULT_PARAMS: dict = {"timeZone": DEFAULT_TIME_ZONE, "use24Hour": False}
|
DEFAULT_PARAMS: dict = {"timeZone": DEFAULT_TIME_ZONE, "use24Hour": False}
|
||||||
|
|
||||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
|
||||||
"timeZone": {"valueType": "list", "tooltip": "Timezone used when the clock speaks time."},
|
"timeZone": {"valueType": "list", "tooltip": "Timezone used when the clock speaks time."},
|
||||||
"use24Hour": {"valueType": "boolean", "tooltip": "Use 24 hour format instead of AM/PM."},
|
"use24Hour": {"valueType": "boolean", "tooltip": "Use 24 hour format instead of AM/PM."},
|
||||||
}
|
}
|
||||||
@@ -92,4 +92,3 @@ def use_item(item: WorldItem, nickname: str, clock_formatter: Callable[[dict], s
|
|||||||
self_message=f"{item.title} says {display_time}.",
|
self_message=f"{item.title} says {display_time}.",
|
||||||
others_message=f"{nickname} checks {item.title}. {item.title} says {display_time}.",
|
others_message=f"{nickname} checks {item.title}. {item.title} says {display_time}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ DEFAULT_TITLE = "Dice"
|
|||||||
DEFAULT_PARAMS: dict = {"sides": 6, "number": 2}
|
DEFAULT_PARAMS: dict = {"sides": 6, "number": 2}
|
||||||
|
|
||||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
|
||||||
"sides": {
|
"sides": {
|
||||||
"valueType": "number",
|
"valueType": "number",
|
||||||
"tooltip": "Number of sides on each die.",
|
"tooltip": "Number of sides on each die.",
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ CHANNEL_OPTIONS: tuple[str, ...] = ("stereo", "mono", "left", "right")
|
|||||||
EFFECT_OPTIONS: tuple[str, ...] = ("reverb", "echo", "flanger", "high_pass", "low_pass", "off")
|
EFFECT_OPTIONS: tuple[str, ...] = ("reverb", "echo", "flanger", "high_pass", "low_pass", "off")
|
||||||
|
|
||||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
|
||||||
"streamUrl": {"valueType": "text", "tooltip": "Audio stream URL used by this radio."},
|
"streamUrl": {"valueType": "text", "tooltip": "Audio stream URL used by this radio."},
|
||||||
"enabled": {"valueType": "boolean", "tooltip": "Turns playback on or off for this radio."},
|
"enabled": {"valueType": "boolean", "tooltip": "Turns playback on or off for this radio."},
|
||||||
"mediaVolume": {
|
"mediaVolume": {
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ DEFAULT_TITLE = "wheel"
|
|||||||
DEFAULT_PARAMS: dict = {"spaces": "yes, no"}
|
DEFAULT_PARAMS: dict = {"spaces": "yes, no"}
|
||||||
|
|
||||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"valueType": "text",
|
"valueType": "text",
|
||||||
"tooltip": "Comma-delimited list of wheel spaces. Example: yes, no, maybe.",
|
"tooltip": "Comma-delimited list of wheel spaces. Example: yes, no, maybe.",
|
||||||
|
"maxLength": 4000,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ def validate_update(_item: WorldItem, next_params: dict) -> dict:
|
|||||||
spaces_raw = next_params.get("spaces", "")
|
spaces_raw = next_params.get("spaces", "")
|
||||||
if not isinstance(spaces_raw, str):
|
if not isinstance(spaces_raw, str):
|
||||||
raise ValueError("spaces must be a comma-delimited string.")
|
raise ValueError("spaces must be a comma-delimited string.")
|
||||||
|
if len(spaces_raw) > 4000:
|
||||||
|
raise ValueError("spaces must be 4000 characters or less.")
|
||||||
spaces = [token.strip() for token in spaces_raw.split(",") if token.strip()]
|
spaces = [token.strip() for token in spaces_raw.split(",") if token.strip()]
|
||||||
if not spaces:
|
if not spaces:
|
||||||
raise ValueError("spaces must include at least one value, separated by commas.")
|
raise ValueError("spaces must include at least one value, separated by commas.")
|
||||||
@@ -65,4 +68,3 @@ def use_item(item: WorldItem, nickname: str, _clock_formatter: Callable[[dict],
|
|||||||
delayed_self_message=landed,
|
delayed_self_message=landed,
|
||||||
delayed_others_message=landed,
|
delayed_others_message=landed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ DEFAULT_PARAMS: dict = {
|
|||||||
EFFECT_OPTIONS: tuple[str, ...] = ("reverb", "echo", "flanger", "high_pass", "low_pass", "off")
|
EFFECT_OPTIONS: tuple[str, ...] = ("reverb", "echo", "flanger", "high_pass", "low_pass", "off")
|
||||||
|
|
||||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
|
||||||
"enabled": {"valueType": "boolean", "tooltip": "Turns this widget on or off."},
|
"enabled": {"valueType": "boolean", "tooltip": "Turns this widget on or off."},
|
||||||
"directional": {"valueType": "boolean", "tooltip": "If on, emitted sound favors the facing direction."},
|
"directional": {"valueType": "boolean", "tooltip": "If on, emitted sound favors the facing direction."},
|
||||||
"facing": {
|
"facing": {
|
||||||
|
|||||||
Reference in New Issue
Block a user