Give a connector node an icon that is not a code icon
A device read over a proprietary protocol was showing the fallback used for a function node. A connector's type cannot be in the built-in icon map — that is the point of it being a connector — so they share a plug. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011LF61rxW1FG5YCD2J9YqjY
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/** Screenshot the dashboard and the flow canvas as a user will find them. */
|
||||
import { mkdir } from "node:fs/promises"
|
||||
import { chromium } from "@playwright/test"
|
||||
|
||||
const APP_URL = process.env.APP_URL || "http://app.localhost"
|
||||
const OUT = process.env.SCREENSHOT_DIR || "screenshots"
|
||||
const browser = await chromium.launch()
|
||||
|
||||
for (const theme of ["light", "dark"]) {
|
||||
const dir = `${OUT}/${theme}`
|
||||
await mkdir(dir, { recursive: true })
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
colorScheme: theme,
|
||||
})
|
||||
await context.addInitScript((t) => {
|
||||
localStorage.setItem("fluksio-ui-theme", t)
|
||||
}, theme)
|
||||
const page = await context.newPage()
|
||||
|
||||
await page.goto(`${APP_URL}/login`, { waitUntil: "networkidle" })
|
||||
await page.getByTestId("email-input").fill(process.env.FIRST_SUPERUSER)
|
||||
await page
|
||||
.getByTestId("password-input")
|
||||
.fill(process.env.FIRST_SUPERUSER_PASSWORD)
|
||||
await page.getByRole("button", { name: /log in/i }).click()
|
||||
await page.waitForURL(`${APP_URL}/`, { timeout: 15000 })
|
||||
|
||||
await page.goto(`${APP_URL}/dashboards/aircon`, { waitUntil: "networkidle" })
|
||||
await page.waitForTimeout(2500)
|
||||
await page.screenshot({ path: `${dir}/live-dashboard.png` })
|
||||
|
||||
await page.goto(`${APP_URL}/flows/aircon`, { waitUntil: "networkidle" })
|
||||
await page.keyboard.press("Escape")
|
||||
await page.waitForTimeout(2500)
|
||||
await page.screenshot({ path: `${dir}/live-flow.png` })
|
||||
|
||||
console.log(` ${theme}: done`)
|
||||
await context.close()
|
||||
}
|
||||
await browser.close()
|
||||
@@ -303,6 +303,18 @@ function FlowEditorInner({
|
||||
[nodeTypeInfo],
|
||||
)
|
||||
|
||||
// Which types came from an installed connector rather than the engine. They
|
||||
// cannot be in the icon map, so they share one.
|
||||
const pluginTypes = useMemo(
|
||||
() =>
|
||||
new Set(
|
||||
(nodeTypeInfo ?? [])
|
||||
.filter((info) => info.plugin)
|
||||
.map((info) => info.type),
|
||||
),
|
||||
[nodeTypeInfo],
|
||||
)
|
||||
|
||||
const issuesByNode = useMemo(() => {
|
||||
const map = new Map<string, string[]>()
|
||||
for (const issue of issues) {
|
||||
@@ -328,11 +340,20 @@ function FlowEditorInner({
|
||||
flow: flowName,
|
||||
typeLabel:
|
||||
typeLabels.get(definition?.type ?? "") ?? definition?.type ?? "",
|
||||
isPlugin: pluginTypes.has(definition?.type ?? ""),
|
||||
issueText: nodeIssues.join("\n"),
|
||||
} satisfies FlowNodeData,
|
||||
}
|
||||
}),
|
||||
[canvasNodes, definitions, flowName, issuesByNode, selectedId, typeLabels],
|
||||
[
|
||||
canvasNodes,
|
||||
definitions,
|
||||
flowName,
|
||||
issuesByNode,
|
||||
pluginTypes,
|
||||
selectedId,
|
||||
typeLabels,
|
||||
],
|
||||
)
|
||||
|
||||
// A cheap fingerprint of the wiring: it changes when a name does, but not
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Globe,
|
||||
Merge,
|
||||
Play,
|
||||
Plug,
|
||||
Radio,
|
||||
Shuffle,
|
||||
Split,
|
||||
@@ -58,6 +59,7 @@ export type FlowNodeData = {
|
||||
definition: NodeDef_Input
|
||||
flow: string
|
||||
typeLabel: string
|
||||
isPlugin?: boolean
|
||||
issueText: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
@@ -101,10 +103,15 @@ function PortHandles({
|
||||
}
|
||||
|
||||
function FlowNodeComponent({ data, selected }: NodeProps) {
|
||||
const { definition, flow, typeLabel, issueText } = data as FlowNodeData
|
||||
const { definition, flow, typeLabel, isPlugin, issueText } =
|
||||
data as FlowNodeData
|
||||
const live = useNodeStatus(`${flow}.${definition.id}`)
|
||||
const emits = useNodeEmits(`${flow}.${definition.id}`)
|
||||
const Icon = NODE_ICONS[definition.type as keyof typeof NODE_ICONS] ?? Code2
|
||||
const Icon =
|
||||
NODE_ICONS[definition.type as keyof typeof NODE_ICONS] ??
|
||||
// A connector's own type cannot be in the map above, and a device is
|
||||
// not a piece of code.
|
||||
(isPlugin ? Plug : Code2)
|
||||
|
||||
// Whatever is wrong — it failed to load, it failed to run, or the graph
|
||||
// around it does not add up — is the same red dot with the same explanation.
|
||||
|
||||
Reference in New Issue
Block a user