Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualize node status, show compat strings and add first Storybook story #13

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions app/DTNode.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { DataNode } from './DTNode';

const meta = {
title: 'App/DTNode',
component: DataNode,
argTypes: {
data: {
label: { control: 'text' },
baseAddr: {},
compat: {},
},
status: { control: 'radio', options: ['okay', 'disabled', undefined] },
},
} satisfies Meta<typeof DataNode>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Simple: Story = {
args: {
data: {
label: "UART",
baseAddr: "0x0c00_0000",
compat: "ns16550a",
},
status: "okay",
},
};

export const WithCompat: Story = {
args: {
data: {
label: "firmware",
compat: "raspberrypi,bcm2835-firmware",
},
},
};
154 changes: 130 additions & 24 deletions app/DTNode.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,134 @@
import { memo, useState } from "react";
import { Handle, NodeProps, Position } from "reactflow";
import compatDb from "./compat-db.json";
import genericNames from "./generic-names.json";

const style = {
// wordWrap: "break-word",
whiteSpace: "pre-wrap" as "pre-wrap", // This is weird, TypoScripto...
padding: 4,
border: "2px solid",
background: "#0c0c0c",
color: "#fff",
width: 150,
fontSize: 11,
fontFamily: "Fira Code",
type DTStatus = "okay" | "disabled";

const dotColors: Record<DTStatus, string> = {
okay: "blue",
disabled: "red"
};

export const Dot: FC<{ status?: DTStatus }> = ({ status }) => {
if (!status) {
return null;
}
const color = dotColors[status];
return (
<div className="dot" style={{ background: color }}>
<style>{`
div.dot {
width: 10px;
height: 10px;
border-radius: 100%;
}
`}</style>
</div>
);
};

const docsBaseUrl = "https://docs.kernel.org"
const drvBaseUrl = "https://elixir.bootlin.com/linux/HEAD/source/drivers";
//const drvBaseUrl = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers";
const dtBaseUrl = "https://www.kernel.org/doc/Documentation/devicetree/bindings";

type DocsCategory = "binding" | "docs" | "driver";

type DocsEntry = {
category: DocsCategory;
path: string;
};

const getBaseUrl = (category: DocsCategory): string => {
switch(category) {
case "binding": return dtBaseUrl;
case "docs": return docsBaseUrl;
case "driver": return drvBaseUrl;
}
};

const getDocUrl = (compat: string) => {
const res = compat.split(";").find((c) => !!compatDb[c]);
if (!res) {
return null;
}
const d = compatDb[res];
const baseUrl = getBaseUrl(d.category);
return `${baseUrl}/${d.path}`;
}

const Compat: FC<{ compat?: string; }> = ({ compat }) => {
if (!compat) {
return null;
}
const docUrl = getDocUrl(compat);

if (!docUrl) {
return compat;
}

return (
<a className="compat" href={docUrl} target="_blank">
{compat}
<style>{`
a.compat {
color: #cdeeff;
text-decoration: underline;
}
`}</style>
</a>
);
};

export const DataNode: FC<{ data: object; status?: DTStatus }> = ({
data,
status,
}) => {
const extraClass = genericNames.includes(data.label) ? "generic" : "";
return (
<div className="node">
<header className={extraClass}>{data.label}</header>
<main>
<span>{data.model}</span>
<span>{data.baseAddr}</span>
<Compat compat={data.compat} />
<Dot status={status} />
<span>{data.extra}</span>
</main>
<style>{`
div.node {
white-space: pre-wrap;
border: 4px solid #789789;
border-radius: 6px;
width: 250px;
font-size: 14px;
font-family: "Fira Code";
}
div.node:hover {
border-color: #987987;
border-style: dotted;
}
div.node header {
color: #0c0c0c;
background: #ccddcc;
font-weight: bold;
padding: 4px;
}
div.node header.generic {
color: #fff;
background: #850150;
}
div.node main {
color: #fff;
background: #0c0c0c;
padding: 4px;
display: flex;
flex-direction: column;
}
`}</style>
</div>
);
};

const DTNode = ({
Expand All @@ -19,27 +137,15 @@ const DTNode = ({
targetPosition = Position.Top,
sourcePosition = Position.Bottom
}: NodeProps) => {
const [hovered, setHovered] = useState(false);

const hoverOn = () => setHovered(true);
const hoverOff = () => setHovered(false);

const borderColor = hovered ? "#987987" : "#789789";
const borderStyle = hovered ? "dotted" : "solid";
const { status, ...nData } = data;
return (
<>
<Handle
type="target"
position={targetPosition}
isConnectable={isConnectable}
/>
<div
style={{...style, borderColor, borderStyle }}
onMouseEnter={hoverOn}
onMouseLeave={hoverOff}
>
{data?.label}
</div>
<DataNode data={nData} status={status} />
<Handle
type="source"
position={sourcePosition}
Expand Down
50 changes: 50 additions & 0 deletions app/compat-db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"brcm,bcm2835-aux-clock": {
"category": "binding",
"path": "clock/brcm,bcm2835-aux-clock.txt"
},
"brcm,bcm2835-aux-uart": {
"category": "binding",
"path": "serial/brcm,bcm2835-aux-uart.txt"
},
"brcm,bcm2835-pwm": {
"category": "binding",
"path": "pwm/pwm-bcm2835.yaml"
},
"brcm,bcm2835-spi": {
"category": "binding",
"path": "spi/brcm,bcm2835-spi.txt"
},
"brcm,bcm2835-thermal": {
"category": "binding",
"path": "thermal/brcm,bcm2835-thermal.yaml"
},
"brcm,bcm2835-vchiq": {
"category": "binding",
"path": "soc/bcm/brcm,bcm2835-vchiq.yaml"
},
"arm,cortex-a7": {
"category": "binding",
"path": "arm/cpus.yaml"
},
"arm,cortex-a7-pmu": {
"category": "binding",
"path": "arm/pmu.yaml"
},
"brcm,bcm2835-cprman": {
"category": "binding",
"path": "clock/brcm,bcm2835-cprman.txt"
},
"raspberrypi,bcm2835-firmware": {
"category": "binding",
"path": "arm/bcm/raspberrypi,bcm2835-firmware.yaml"
},
"spidev": {
"category": "docs",
"path": "spi/spidev.html"
},
"brcm,bcm2835-audio": {
"category": "driver",
"path": "staging/vc04_services/bcm2835-audio/bcm2835.c"
}
}
104 changes: 104 additions & 0 deletions app/generic-names.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
[
"adc",
"accelerometer",
"air-pollution-sensor",
"atm",
"audio-codec",
"audio-controller",
"backlight",
"bluetooth",
"bus",
"cache-controller",
"camera",
"can",
"charger",
"clock",
"clock-controller",
"co2-sensor",
"compact-flash",
"cpu",
"cpus",
"crypto",
"disk",
"display",
"dma-controller",
"dsi",
"dsp",
"eeprom",
"efuse",
"endpoint",
"ethernet",
"ethernet-phy",
"fdc",
"flash",
"gnss",
"gpio",
"gpu",
"gyrometer",
"hdmi",
"hwlock",
"i2c",
"i2c-mux",
"ide",
"interrupt-controller",
"iommu",
"isa",
"keyboard",
"key",
"keys",
"lcd-controller",
"led",
"leds",
"led-controller",
"light-sensor",
"lora",
"magnetometer",
"mailbox",
"mdio",
"memory",
"memory-controller",
"mmc",
"mmc-slot",
"mouse",
"nand-controller",
"nvram",
"oscillator",
"parallel",
"pc-card",
"pci",
"pcie",
"phy",
"pinctrl",
"pmic",
"pmu",
"port",
"ports",
"power-monitor",
"pwm",
"regulator",
"reset-controller",
"rng",
"rtc",
"sata",
"scsi",
"serial",
"sound",
"spi",
"spmi",
"sram-controller",
"ssi-controller",
"syscon",
"temperature-sensor",
"timer",
"touchscreen",
"tpm",
"ufshc",
"usb",
"usb-hub",
"usb-phy",
"vibrator",
"video-codec",
"vme",
"watchdog",
"wifi"
]
Loading