Complete SQL diagnostics and editor accessibility
This commit is contained in:
@@ -39,6 +39,14 @@ export type DataflowDiagnostic = {
|
||||
message: string;
|
||||
node_id?: string | null;
|
||||
field?: string | null;
|
||||
source_location?: {
|
||||
start_line: number;
|
||||
start_column: number;
|
||||
end_line: number;
|
||||
end_column: number;
|
||||
start_offset?: number | null;
|
||||
end_offset?: number | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type PipelineRevision = {
|
||||
|
||||
@@ -54,6 +54,7 @@ export default function DataflowCanvas({
|
||||
onGraphChange,
|
||||
onSelectNode
|
||||
}: DataflowCanvasProps) {
|
||||
const canvasRef = useRef<HTMLDivElement | null>(null);
|
||||
const [instance, setInstance] = useState<ReactFlowInstance<DataflowFlowNode, Edge> | null>(null);
|
||||
const [proximityEdge, setProximityEdge] = useState<Edge | null>(null);
|
||||
const [selectedEdgeId, setSelectedEdgeId] = useState<string | null>(null);
|
||||
@@ -129,6 +130,24 @@ export default function DataflowCanvas({
|
||||
});
|
||||
};
|
||||
|
||||
const restoreFocusAfterRemoval = (removedNodeIds: Set<string>) => {
|
||||
const focusedNodeId = document.activeElement
|
||||
?.closest<HTMLElement>(".react-flow__node")
|
||||
?.dataset.id;
|
||||
if (!focusedNodeId || !removedNodeIds.has(focusedNodeId)) return;
|
||||
const removedIndex = graph.nodes.findIndex((node) => node.id === focusedNodeId);
|
||||
const remainingNodes = graph.nodes.filter((node) => !removedNodeIds.has(node.id));
|
||||
const nextNode = remainingNodes[Math.min(Math.max(0, removedIndex), remainingNodes.length - 1)];
|
||||
requestAnimationFrame(() => {
|
||||
const nextElement = nextNode
|
||||
? canvasRef.current?.querySelector<HTMLElement>(
|
||||
`.react-flow__node[data-id="${CSS.escape(nextNode.id)}"]`
|
||||
)
|
||||
: null;
|
||||
(nextElement ?? canvasRef.current)?.focus();
|
||||
});
|
||||
};
|
||||
|
||||
const updateEdges = (nextEdges: Edge[]) => {
|
||||
onGraphChange({
|
||||
...graph,
|
||||
@@ -206,7 +225,10 @@ export default function DataflowCanvas({
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={canvasRef}
|
||||
className="dataflow-canvas"
|
||||
tabIndex={0}
|
||||
aria-label="Dataflow graph canvas"
|
||||
onDragOver={(event) => {
|
||||
if (event.dataTransfer.types.includes("application/x-govoplan-dataflow-node")) {
|
||||
event.preventDefault();
|
||||
@@ -224,6 +246,11 @@ export default function DataflowCanvas({
|
||||
if (readOnly) return;
|
||||
const graphChanges = changes.filter((change) => change.type !== "dimensions");
|
||||
if (graphChanges.length) {
|
||||
restoreFocusAfterRemoval(new Set(
|
||||
graphChanges
|
||||
.filter((change) => change.type === "remove")
|
||||
.map((change) => change.id)
|
||||
));
|
||||
updateNodes(applyNodeChanges(graphChanges, nodes));
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -2221,7 +2221,13 @@ function DiagnosticsPanel({
|
||||
<strong>{item.code}</strong>
|
||||
<small>{item.message}</small>
|
||||
</span>
|
||||
{item.node_id ? <code>{item.node_id}</code> : null}
|
||||
{item.node_id ? (
|
||||
<code>{item.node_id}</code>
|
||||
) : item.source_location ? (
|
||||
<code>
|
||||
{item.source_location.start_line}:{item.source_location.start_column}
|
||||
</code>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
{nodeDiagnostics.map((item) => (
|
||||
|
||||
@@ -359,6 +359,11 @@
|
||||
grid-template-columns: minmax(0, 1fr) minmax(260px, 310px);
|
||||
}
|
||||
|
||||
.dataflow-canvas:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.dataflow-palette,
|
||||
.dataflow-inspector {
|
||||
min-width: 0;
|
||||
@@ -1120,7 +1125,7 @@
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.dataflow-page {
|
||||
height: calc(100vh - 94px);
|
||||
height: calc(100dvh - 115px);
|
||||
}
|
||||
|
||||
.dataflow-shell {
|
||||
@@ -1133,15 +1138,24 @@
|
||||
border-bottom: var(--border-line);
|
||||
}
|
||||
|
||||
.dataflow-workspace-toolbar {
|
||||
overflow-x: auto;
|
||||
align-items: flex-start;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
.dataflow-identity-fields,
|
||||
.dataflow-command-bar {
|
||||
flex-wrap: wrap;
|
||||
width: max-content;
|
||||
min-width: max-content;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.dataflow-name-input,
|
||||
.dataflow-description-input {
|
||||
max-width: none;
|
||||
min-width: 180px;
|
||||
width: 220px;
|
||||
min-width: 220px;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.dataflow-editor {
|
||||
|
||||
Reference in New Issue
Block a user