feat: refine workbench visuals and map controls
Unify the Agent history extension with the header acrylic surface, preserve the full conversation body, and consolidate shared control and status styling. Restore map flow and SCADA controller behavior, remove obsolete rendering paths, and extend regression coverage. Button press coverage now releases outside the target so state assertions cannot accidentally toggle the control.
This commit is contained in:
@@ -22,6 +22,7 @@ export type PointLayerGroupStylePatch = {
|
||||
opacity?: number;
|
||||
radiusMultiplier?: number;
|
||||
strokeMultiplier?: number;
|
||||
iconMultiplier?: number;
|
||||
};
|
||||
|
||||
export type LayerGroupStylePatch = LineLayerGroupStylePatch | PointLayerGroupStylePatch;
|
||||
@@ -73,7 +74,7 @@ export function validateLayerGroupStylePatch(groupId: string, patch: unknown): p
|
||||
const values = patch as Record<string, unknown>;
|
||||
const allowed = geometry === "line"
|
||||
? ["color", "opacity", "widthMultiplier", "dash"]
|
||||
: ["fillColor", "strokeColor", "opacity", "radiusMultiplier", "strokeMultiplier"];
|
||||
: ["fillColor", "strokeColor", "opacity", "radiusMultiplier", "strokeMultiplier", "iconMultiplier"];
|
||||
if (Object.keys(values).some((key) => !allowed.includes(key))) return false;
|
||||
if ("color" in values && !isColor(values.color)) return false;
|
||||
if ("fillColor" in values && !isColor(values.fillColor)) return false;
|
||||
@@ -82,6 +83,7 @@ export function validateLayerGroupStylePatch(groupId: string, patch: unknown): p
|
||||
if ("widthMultiplier" in values && !inRange(values.widthMultiplier, 0.5, 3)) return false;
|
||||
if ("radiusMultiplier" in values && !inRange(values.radiusMultiplier, 0.5, 3)) return false;
|
||||
if ("strokeMultiplier" in values && !inRange(values.strokeMultiplier, 0.5, 3)) return false;
|
||||
if ("iconMultiplier" in values && !inRange(values.iconMultiplier, 0.5, 3)) return false;
|
||||
if ("dash" in values && !["original", "solid", "dashed"].includes(String(values.dash))) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -151,6 +153,14 @@ function applyPointStyle(map: MapLibreMap, groupId: "junctions" | "valves" | "re
|
||||
if (patch.strokeMultiplier !== undefined) {
|
||||
setPaint(map, coreId, "circle-stroke-width", 2 * patch.strokeMultiplier);
|
||||
}
|
||||
if (patch.iconMultiplier !== undefined && "iconSize" in POINT_DEFAULT_VISUALS[groupId]) {
|
||||
setLayout(
|
||||
map,
|
||||
`${groupId}-symbol`,
|
||||
"icon-size",
|
||||
scale(POINT_DEFAULT_VISUALS[groupId].iconSize, patch.iconMultiplier)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function resetPointStyle(map: MapLibreMap, groupId: "junctions" | "valves" | "reservoirs") {
|
||||
@@ -163,6 +173,9 @@ function resetPointStyle(map: MapLibreMap, groupId: "junctions" | "valves" | "re
|
||||
setPaint(map, `${groupId}-hover`, "circle-radius", visual.hoverRadius);
|
||||
setPaint(map, `${groupId}-selected`, "circle-radius", visual.selectedRadius);
|
||||
setPaint(map, `${groupId}-selected-outer`, "circle-radius", visual.selectedRadius);
|
||||
if ("iconSize" in visual) {
|
||||
setLayout(map, `${groupId}-symbol`, "icon-size", visual.iconSize);
|
||||
}
|
||||
}
|
||||
|
||||
function scale(value: unknown, multiplier: number): unknown {
|
||||
@@ -173,6 +186,12 @@ function setPaint(map: MapLibreMap, layerId: string, property: string, value: un
|
||||
if (map.getLayer(layerId)) map.setPaintProperty(layerId, property, (value ?? null) as never);
|
||||
}
|
||||
|
||||
function setLayout(map: MapLibreMap, layerId: string, property: string, value: unknown) {
|
||||
if (map.getLayer(layerId) && typeof map.setLayoutProperty === "function") {
|
||||
map.setLayoutProperty(layerId, property, (value ?? null) as never);
|
||||
}
|
||||
}
|
||||
|
||||
function inRange(value: unknown, min: number, max: number): value is number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value >= min && value <= max;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user