Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
8a6a2f6
canvas resource DAG
royendo Jan 27, 2026
769ef52
Update ResourceGraphOverlay.svelte
royendo Jan 27, 2026
1058a08
overwrite source as model
royendo Jan 27, 2026
98b6a7b
Merge branch 'main' into feat/dag-canvas
royendo Jan 28, 2026
94b8fcc
https://www.loom.com/share/f21f8e222af24cc78f843d87d0611d0e
royendo Jan 28, 2026
4e8954b
bring back source, rename to source model. change logic for model pag…
royendo Jan 28, 2026
d3c6ef3
code review fixes/ prettier
royendo Jan 28, 2026
548bede
code qual
royendo Jan 28, 2026
92b53a6
code qual
royendo Jan 28, 2026
600ce9f
cherry pick dag-canvas into branch
royendo Jan 28, 2026
0a04220
Node Badges!
royendo Feb 5, 2026
8bb2889
prettier + functionality
royendo Feb 6, 2026
f9178b2
Merge branch 'main' into feat/dag-changes
royendo Feb 6, 2026
582356d
variant tooltip
royendo Feb 6, 2026
b3ffeeb
SIDEBARRR
royendo Feb 6, 2026
e264299
Merge branch 'main' into feat/dag-changes
royendo Feb 6, 2026
f6a2676
Update GraphInspector.svelte
royendo Feb 6, 2026
b98548e
styling and button fixes
royendo Feb 6, 2026
8c0ebaf
connector fix
royendo Feb 6, 2026
5158421
search and filter
royendo Feb 6, 2026
87d1a97
Update +page.svelte
royendo Feb 7, 2026
53ed800
design
royendo Feb 7, 2026
7f495a1
local PR change review
royendo Feb 9, 2026
1b4db0b
Merge branch 'main' into feat/dag-changes
royendo Feb 9, 2026
4c1cedd
code qual
royendo Feb 9, 2026
2b0b36c
web code qual
royendo Feb 9, 2026
cf5dc60
Update connector-icon-mapping.ts
royendo Feb 9, 2026
eda7c17
fix
royendo Feb 9, 2026
898fc6a
new node page,
royendo Feb 13, 2026
0473b86
Merge branch 'main' into feat/dag-changes
royendo Feb 13, 2026
125ba76
describe node
royendo Feb 13, 2026
20bca57
hide lineage button when on lineage view
royendo Feb 13, 2026
9e61404
prettier
royendo Feb 13, 2026
e32ef95
local PR reivew
royendo Feb 13, 2026
121c8c5
round2
royendo Feb 13, 2026
5475e43
round3
royendo Feb 13, 2026
641eef8
clean up
royendo Feb 13, 2026
2acdb79
Merge branch 'main' into feat/dag-changes
royendo Feb 17, 2026
2d29e12
similar UI as rill cloud resources
royendo Feb 17, 2026
d8f174f
nit behavioral changes, dont show ..., rmeove lineage
royendo Feb 17, 2026
807d10e
remove connector from DAG, it makes it very confusing
royendo Feb 17, 2026
1a71317
code qual
royendo Feb 17, 2026
2ab88ab
must + should fixe
royendo Feb 17, 2026
e8cd30e
nit, dont default to metrics for views, add OK
royendo Feb 18, 2026
790fa14
PR review fixes
royendo Feb 18, 2026
061b728
Merge branch 'main' into feat/dag-changes
royendo Feb 18, 2026
d84d8d9
more contexual nodes, better formatting of describe
royendo Feb 18, 2026
c46b13a
remove --preview, just --preview-locked is enough
royendo Feb 18, 2026
a8a5eee
Pr reiview fixes
royendo Feb 18, 2026
57f8e74
fix overlay CSS
royendo Feb 18, 2026
5f11941
prettier / code qual
royendo Feb 18, 2026
c1ff8ed
Update ResourceGraphOverlay.svelte
royendo Feb 18, 2026
b338ac7
Fixes 1-8
royendo Feb 19, 2026
dfbb115
web code qual
royendo Feb 19, 2026
361f563
missed code qual
royendo Feb 19, 2026
79aae23
nit describe fix
royendo Feb 19, 2026
cd45ed8
olap connector node
royendo Feb 20, 2026
285db57
filter and dropdown fixes
royendo Feb 20, 2026
29a40a7
rmeove node anchors, add some connector info
royendo Feb 20, 2026
69f342e
fix duck --> model, only top level
royendo Feb 20, 2026
44a1683
node fixes, upgrades
royendo Feb 20, 2026
1c3c16f
additional hover states
royendo Feb 20, 2026
cdd0b28
Resource, Web code qual, prettier, fix redirect to Graph
royendo Feb 20, 2026
5439bd3
first pass
royendo Feb 27, 2026
b0dad6e
Merge branch 'main' into feat/dag-changes
royendo Feb 27, 2026
235ca3b
simplify UI, clean up
royendo Mar 2, 2026
4c35236
PR review fixes
royendo Mar 2, 2026
c711a5c
CSS changes, simplify UI
royendo Mar 2, 2026
d6b56d1
disconnect filter from DAG, only dropdown
royendo Mar 2, 2026
d476219
web code
royendo Mar 2, 2026
259a2fe
prettier, code qual
royendo Mar 2, 2026
3f678de
IA and UX review
royendo Mar 2, 2026
375a7b1
prettier
royendo Mar 2, 2026
0ff5eee
Update ResourceNode.svelte
royendo Mar 2, 2026
564dabf
more reviewers
royendo Mar 2, 2026
a474a64
remove warn icon from error/warn state
royendo Mar 2, 2026
0af9211
UX review fixes
royendo Mar 3, 2026
aa67f67
clean up
royendo Mar 3, 2026
212bd67
DAG tool bar consistnecy
royendo Mar 5, 2026
d2268e9
unify resources and DAG pages options, search filters, refresh
royendo Mar 5, 2026
17f16b8
wrap trees, materialized
royendo Mar 5, 2026
a3e5eae
remove connector from all views expect explicit
royendo Mar 5, 2026
749bf8b
see other connectors, change css for loading
royendo Mar 5, 2026
75fe70e
prettier
royendo Mar 5, 2026
1fdaaa4
ux/code local passes
royendo Mar 5, 2026
76878e4
Merge branch 'main' into feat/dag-changes
royendo Mar 6, 2026
c390982
fix checks
royendo Mar 6, 2026
c954cd3
Update ConnectorMenuItems.svelte
royendo Mar 6, 2026
be15053
web code qual
royendo Mar 6, 2026
291e139
min node width, set max view of graph to width of container, dynamic …
royendo Mar 6, 2026
7cb3873
review fixes
royendo Mar 6, 2026
ff44104
Make graph navigation configurable via Svelte context
royendo Mar 13, 2026
b84500e
Hide "Go to Resource" when no openFile handler is provided
royendo Mar 13, 2026
219617d
Remove horizontal padding from graph toolbar bar
royendo Mar 13, 2026
160e485
Remove file path hover tooltip from graph nodes
royendo Mar 13, 2026
52f763d
in rill cloud ;)
royendo Mar 13, 2026
74ee987
fix default view
royendo Mar 14, 2026
99091e3
prettier
royendo Mar 14, 2026
c94cfe8
Merge branch 'main' into feat/dag-changes
royendo Mar 14, 2026
c148220
code wual
royendo Mar 16, 2026
af9e33e
first pass
royendo Mar 24, 2026
3625cce
node name show full; move DAG next to AI first class citizen
royendo Mar 24, 2026
0a11276
only icon and additional legend
royendo Mar 24, 2026
2c09d2b
close on scroll;
royendo Mar 24, 2026
5287633
Merge remote-tracking branch 'origin/main' into feat/dag-changes
royendo Mar 24, 2026
35590df
migrate to svelte
royendo Mar 24, 2026
606c34b
revert to orignal right click modal
royendo Mar 24, 2026
95244bf
close modal on drag event
royendo Mar 24, 2026
07b62a3
fix url in modal
royendo Mar 24, 2026
e81ad39
fix status filter;
royendo Mar 24, 2026
66ee7c1
web fix
royendo Mar 24, 2026
1eaa45f
code qual
royendo Mar 24, 2026
d578811
qa fixes; refresh not updating UI; remove reconcile/error modal and r…
royendo Mar 25, 2026
4faa3a9
Update ResourceGraph.svelte
royendo Mar 25, 2026
81951c7
Merge branch 'main' into feat/dag-changes
royendo Mar 25, 2026
1a5a9a9
Merge branch 'main' into feat/dag-changes
royendo Mar 25, 2026
b9401c9
nit for siloed nodes clean up view; show isolated node toggle
royendo Mar 25, 2026
d3c3d94
prettier
royendo Mar 25, 2026
8de5b13
Update ContentContainer.svelte
royendo Mar 25, 2026
f879cab
Update ContentContainer.svelte
royendo Mar 25, 2026
ae6df13
Di Feedback
royendo Mar 26, 2026
a923e0b
fix
royendo Mar 26, 2026
acfa23f
Update GraphCanvas.svelte
royendo Mar 26, 2026
523e6f2
dag final fixes
royendo Mar 26, 2026
e6808b4
local code review
royendo Mar 26, 2026
52af5b0
round 2
royendo Mar 26, 2026
ee79a0f
prettier
royendo Mar 26, 2026
83d1823
remove debug
royendo Mar 31, 2026
8ac5719
Update GraphCanvas.svelte
royendo Mar 31, 2026
537f25f
Merge branch 'main' into feat/dag-changes
royendo Mar 31, 2026
8d30298
Merge branch 'main' into feat/dag-changes
royendo Apr 3, 2026
15b0ac5
Merge branch 'main' into feat/dag-changes
royendo Apr 6, 2026
f0526ec
code qual
royendo Apr 6, 2026
28cffd7
Merge branch 'main' into feat/dag-changes
royendo Apr 8, 2026
e61058c
connector
royendo Apr 8, 2026
91cde30
TODO
royendo Apr 8, 2026
5d68436
TODO
royendo Apr 8, 2026
9d3695d
remove double icons
royendo Apr 9, 2026
a693baf
Merge branch 'main' into feat/dag-changes
royendo Apr 9, 2026
2a3525c
remove icon
royendo Apr 9, 2026
0c047b8
Merge branch 'main' into feat/dag-changes
royendo Apr 17, 2026
e9f70e7
fix edge cases where no dashboard, default to metrics instead
royendo Apr 17, 2026
4791098
Merge `main` into `feat/dag-changes`
royendo Apr 27, 2026
c7ed53d
revert: remove "Open in editor" `NodeToolbar` from `ResourceNode`
royendo Apr 27, 2026
6d074bd
fix: hide connector nodes from the resource graph canvas
royendo Apr 27, 2026
bd125bc
fix: resolve refs by name when `kind` is missing in resource graph
royendo Apr 27, 2026
ee9d153
fix: import `goto` in `MetricsViewMenuItems` and `SourceMenuItems`
royendo Apr 27, 2026
7a050f4
fix Edit button regression with --preview mode
royendo Apr 27, 2026
68bba35
Benjamin feedback, remove canvas parsing
royendo Apr 28, 2026
0759c35
Update graph-builder.spec.ts
royendo Apr 28, 2026
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
Prev Previous commit
Next Next commit
local PR change review
  • Loading branch information
royendo committed Feb 9, 2026
commit 7f495a1267a397de623d2a7977c4bfa1fb99b22b
16 changes: 6 additions & 10 deletions runtime/parser/parse_canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,11 @@ func (p *Parser) parseCanvas(node *Node) error {
// Collect metrics view refs from components for direct Canvas -> MetricsView links in the DAG
// This must be done BEFORE calling insertResource so the refs are included
metricsViewRefs := make(map[ResourceName]bool)
// Extract from inline components
// Pre-compute set of inline component names for O(1) lookup
inlineComponentNames := make(map[string]bool, len(inlineComponentDefs))
for _, def := range inlineComponentDefs {
inlineComponentNames[def.name] = true
// Also extract metrics view refs from inline components
for _, ref := range def.refs {
if ref.Kind == ResourceKindMetricsView {
metricsViewRefs[ref] = true
Expand All @@ -274,15 +277,8 @@ func (p *Parser) parseCanvas(node *Node) error {
for _, row := range tmp.Rows {
for _, item := range row.Items {
if item.Component != "" {
// Check if this is an external component (not inline)
isInline := false
for _, def := range inlineComponentDefs {
if def.name == item.Component {
isInline = true
break
}
}
if !isInline {
// Check if this is an external component (not inline) - O(1) lookup
if !inlineComponentNames[item.Component] {
// Look up the external component
componentName := ResourceName{Kind: ResourceKindComponent, Name: item.Component}
if component, ok := p.Resources[componentName.Normalized()]; ok {
Expand Down
52 changes: 52 additions & 0 deletions web-common/src/components/tooltip/ConditionalTooltip.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!--
@component
ConditionalTooltip - A wrapper that optionally applies a Tooltip.

Use this when you need to conditionally show a tooltip on content without
duplicating the inner markup. When `showTooltip` is false, the content
renders directly without any wrapper.

@example
<ConditionalTooltip showTooltip={hasError} location="top">
<div>Content that may or may not have a tooltip</div>
<TooltipContent slot="tooltip-content">
Tooltip message here
</TooltipContent>
</ConditionalTooltip>
-->
<script lang="ts">
import Tooltip from "./Tooltip.svelte";
import type {
Alignment,
Location,
} from "@rilldata/web-common/lib/place-element";

/** Whether to show the tooltip. When false, content renders without a wrapper. */
export let showTooltip: boolean;

// Tooltip props (pass-through)
export let location: Location = "bottom";
export let alignment: Alignment = "middle";
export let distance = 0;
export let pad = 8;
export let suppress = false;
export let activeDelay = 200;
export let hideDelay = 0;
</script>

{#if showTooltip}
<Tooltip
{location}
{alignment}
{distance}
{pad}
{suppress}
{activeDelay}
{hideDelay}
>
<slot />
<slot name="tooltip-content" slot="tooltip-content" />
</Tooltip>
{:else}
<slot />
{/if}
171 changes: 171 additions & 0 deletions web-common/src/features/connectors/connector-type-detector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* Connector type detection utilities.
*
* Provides centralized logic for detecting cloud storage connector types
* from file paths, URLs, and SQL content. Used by the resource graph and
* inspector components.
*/

/**
* Known cloud storage connector types that can be detected from paths/URLs.
*/
export type CloudConnectorType =
| "s3"
| "gcs"
| "azure"
| "https"
| "local_file";

/**
* Cloud storage URL prefixes mapped to their connector types.
* Uses startsWith for prefix matching.
*/
const PATH_PREFIX_MAP: Record<string, CloudConnectorType> = {
"s3://": "s3",
"s3a://": "s3",
"gs://": "gcs",
"gcs://": "gcs",
"azure://": "azure",
"az://": "azure",
"abfs://": "azure",
"abfss://": "azure",
"https://": "https",
"http://": "https",
};

/**
* Common data file extensions for HTTP URL detection.
* Used to differentiate data URLs from documentation links.
*/
const DATA_FILE_EXTENSIONS = [
".parquet",
".csv",
".json",
".ndjson",
".jsonl",
".xlsx",
".xls",
".tsv",
];

/**
* DuckDB read functions that indicate local file access.
*/
const DUCKDB_READ_FUNCTIONS = [
"read_parquet(",
"read_csv(",
"read_json(",
"read_ndjson(",
];

/**
* Detect connector type from a path/URL prefix.
*
* Checks if the path starts with a known cloud storage prefix.
* Use this for direct paths like "s3://bucket/file.parquet".
*
* @param path - The path or URL to check
* @returns The detected connector type, or undefined if no match
*
* @example
* detectConnectorFromPath("s3://bucket/file.parquet") // "s3"
* detectConnectorFromPath("gs://bucket/file.csv") // "gcs"
* detectConnectorFromPath("azure://container/file.json") // "azure"
* detectConnectorFromPath("https://example.com/data.csv") // "https"
* detectConnectorFromPath("/local/file.csv") // undefined
*/
export function detectConnectorFromPath(
path: string | null | undefined,
): CloudConnectorType | undefined {
if (!path) return undefined;

const lowerPath = path.toLowerCase();

for (const [prefix, connectorType] of Object.entries(PATH_PREFIX_MAP)) {
if (lowerPath.startsWith(prefix)) {
return connectorType;
}
}

return undefined;
}

/**
* Detect connector type from content that may contain embedded URLs.
*
* Searches the content for cloud storage URL patterns anywhere in the string.
* Use this for SQL queries or other content that may embed URLs.
*
* For HTTP URLs, only matches if the URL contains a data file extension
* to avoid false positives from documentation links.
*
* Also detects DuckDB read functions that indicate local file access.
*
* @param content - The content to search (e.g., SQL query)
* @returns The detected connector type, or undefined if no match
*
* @example
* detectConnectorFromContent("SELECT * FROM read_parquet('s3://bucket/file.parquet')") // "s3"
* detectConnectorFromContent("SELECT * FROM read_json('https://api.example.com/data.json')") // "https"
* detectConnectorFromContent("SELECT * FROM read_csv('/local/file.csv')") // "local_file"
* detectConnectorFromContent("SELECT * FROM other_model") // undefined
*/
export function detectConnectorFromContent(
content: string | null | undefined,
): CloudConnectorType | undefined {
if (!content) return undefined;

const normalized = content.toLowerCase();

// Check for cloud storage URL patterns (using includes for embedded URLs)
if (normalized.includes("s3://") || normalized.includes("s3a://")) {
return "s3";
}
if (normalized.includes("gs://") || normalized.includes("gcs://")) {
return "gcs";
}
if (
normalized.includes("azure://") ||
normalized.includes("az://") ||
normalized.includes("abfs://") ||
normalized.includes("abfss://")
) {
return "azure";
}

// For HTTP(S), only match if it looks like a data file URL
const httpMatch = normalized.match(/https?:\/\/[^\s'"]+/g);
if (httpMatch) {
for (const url of httpMatch) {
if (DATA_FILE_EXTENSIONS.some((ext) => url.includes(ext))) {
return "https";
}
}
}

// Check for DuckDB read functions (indicates local file access)
for (const func of DUCKDB_READ_FUNCTIONS) {
if (normalized.includes(func)) {
return "local_file";
}
}

return undefined;
}

/**
* Detect connector type by checking multiple sources in priority order.
*
* Convenience function that tries path detection first, then content detection.
* Useful when you have both a direct path and SQL content to check.
*
* @param path - A direct path/URL to check first
* @param content - Content to search if path doesn't match
* @returns The detected connector type, or undefined if no match
*/
export function detectConnector(
path: string | null | undefined,
content: string | null | undefined,
): CloudConnectorType | undefined {
return detectConnectorFromPath(path) ?? detectConnectorFromContent(content);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import { onDestroy } from "svelte";
import { UI_CONFIG, FIT_VIEW_CONFIG } from "../shared/config";
import { isGraphExpanded } from "../inspector/graph-inspector-store";
import type { ResourceStatusFilter } from "../shared/types";

export let resources: V1Resource[] | undefined;
export let isLoading = false;
Expand All @@ -37,7 +38,7 @@
export let showControls = true;
export let enableExpansion = true;
export let searchQuery = "";
export let statusFilter: "all" | "pending" | "errored" = "all";
export let statusFilter: ResourceStatusFilter = "all";

// New props for modularity
export let onExpandedChange: ((id: string | null) => void) | null = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors";
import type { ResourceNodeData } from "../shared/types";
import { V1ReconcileStatus } from "@rilldata/web-common/runtime-client";
import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte";
import ConditionalTooltip from "@rilldata/web-common/components/tooltip/ConditionalTooltip.svelte";
import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte";

export let id: string;
Expand Down Expand Up @@ -75,66 +75,14 @@
$: routeHighlighted = (data as any)?.routeHighlighted === true;
</script>

{#if hasError}
<Tooltip location="top" distance={8} activeDelay={150}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="node"
class:selected
class:route-highlighted={routeHighlighted}
class:error={hasError}
class:root={data?.isRoot}
style:--node-accent={color}
style:width={width ? `${width}px` : undefined}
style:height={height ? `${height}px` : undefined}
data-kind={kind}
role="button"
tabindex="0"
>
<Handle
id="target"
type="target"
position={Position.Top}
isConnectable={isConnectable ?? true}
/>
<Handle
id="source"
type="source"
position={Position.Bottom}
isConnectable={isConnectable ?? true}
/>

<div class="icon-wrapper" style={`background:${color}20`}>
<svelte:component this={icon} size="16px" {color} />
</div>
<div class="details">
<p class="title" title={data?.label}>{data?.label}</p>
<p class="meta">
{#if kind}
{displayResourceKind(kind)}
{:else}
Unknown
{/if}
</p>
<p class="status error">{effectiveStatusLabel}</p>
</div>
</div>
<TooltipContent slot="tooltip-content" maxWidth="420px" variant="light">
<div class="error-tooltip-content">
<span class="error-tooltip-title">Error</span>
<pre class="error-tooltip-message">{data?.resource?.meta
?.reconcileError}</pre>
</div>
</TooltipContent>
</Tooltip>
{:else}
<ConditionalTooltip showTooltip={hasError} location="top" distance={8} activeDelay={150}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="node"
class:selected
class:route-highlighted={routeHighlighted}
class:error={hasError}
class:root={data?.isRoot}
style:--node-accent={color}
style:width={width ? `${width}px` : undefined}
Expand Down Expand Up @@ -169,11 +117,18 @@
{/if}
</p>
{#if effectiveStatusLabel}
<p class="status">{effectiveStatusLabel}</p>
<p class="status" class:error={hasError}>{effectiveStatusLabel}</p>
{/if}
</div>
</div>
{/if}
<TooltipContent slot="tooltip-content" maxWidth="420px" variant="light">
<div class="error-tooltip-content">
<span class="error-tooltip-title">Error</span>
<pre class="error-tooltip-message">{data?.resource?.meta
?.reconcileError}</pre>
</div>
</TooltipContent>
</ConditionalTooltip>

<style lang="postcss">
.node {
Expand Down
Loading