Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
88ffa19
feat: add tags to explore and canvas dashboards for project-level org…
royendo Apr 22, 2026
e1baab5
feat: persist dashboards tag filter in URL
royendo Apr 22, 2026
cc69880
feat: add tagAsFolders feature flag for folder-style dashboard organi…
royendo Apr 22, 2026
1fd640f
fix: hide tag filter in folder mode; unify folders under one parent b…
royendo Apr 22, 2026
3f17d37
fix: hide tag pills on dashboard rows in folder mode
royendo Apr 22, 2026
9381af7
fix: restore dashboard breadcrumb and hide tag pills when tagAsFolder…
royendo Apr 22, 2026
1488ea8
fix: preserve non-explore URL params (e.g. ?tags=) across explore sta…
royendo Apr 22, 2026
98626eb
feat: always show tag folder breadcrumb on dashboard pages
royendo Apr 22, 2026
001fa6d
fix: scope dashboard breadcrumb dropdown to the active tag folder
royendo Apr 22, 2026
bf47792
Update DashboardStateSync.ts
royendo Apr 23, 2026
ab4b206
tags to top level;
royendo Apr 23, 2026
8a51dde
Merge branch 'main' into worktree-feat-project-dashboard-organization
royendo Apr 23, 2026
30acdfa
feat: tag filter for Resources and Tables pages
royendo Apr 23, 2026
3955a43
Merge remote-tracking branch 'origin/main' into worktree-feat-project…
royendo Apr 24, 2026
88bc52d
Update resource-filter-utils.spec.ts
royendo Apr 24, 2026
e4cc524
fix: declare `availableTags` before `filterGroups` reads it
royendo Apr 24, 2026
1a2b3f1
Merge remote-tracking branch 'origin/main' into worktree-feat-project…
royendo Apr 27, 2026
4546946
fix
royendo Apr 27, 2026
0b99483
fix: drop duplicate `onFilterChange` declaration in `ProjectTables`
royendo Apr 27, 2026
2c6c70f
fix: render "Not Tagged" label and add `tags` to `V1ResourceMeta`
royendo Apr 27, 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
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/alerts.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/canvas-dashboards.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/connectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/explore-dashboards.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/metrics-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
8 changes: 8 additions & 0 deletions docs/docs/reference/project-files/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down Expand Up @@ -513,6 +517,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/reports.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/project-files/themes.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ _[string]_ - Name is usually inferred from the filename, but can be specified ma

_[array of string]_ - List of resource references

### `tags`

_[array of string]_ - Tags for organizing and filtering the resource (e.g. on the project dashboards list).

### `dev`

_[object]_ - Overrides any properties in development environment.
Expand Down
3,034 changes: 1,522 additions & 1,512 deletions proto/gen/rill/runtime/v1/resources.pb.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions proto/gen/rill/runtime/v1/runtime.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7585,6 +7585,11 @@ definitions:
type: array
items:
type: string
tags:
type: array
items:
type: string
description: Tags for organizing and filtering resources. Parsed generically from any resource YAML's top-level "tags:" field.
hidden:
type: boolean
version:
Expand Down
2 changes: 2 additions & 0 deletions proto/rill/runtime/v1/resources.proto
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ message ResourceMeta {
repeated ResourceName refs = 2;
optional ResourceName owner = 3;
repeated string file_paths = 4;
// Tags for organizing and filtering resources. Parsed generically from any resource YAML's top-level "tags:" field.
repeated string tags = 19;
bool hidden = 7;
int64 version = 15;
int64 spec_version = 5;
Expand Down
6 changes: 4 additions & 2 deletions runtime/catalog_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func (c *catalogCache) list(kind, path string, withDeleted, clone bool) []*runti
// It will error if a resource with the same name already exists.
// If a soft-deleted resource exists with the same name, it will be overwritten (no longer deleted).
// The passed resource should only have its spec populated. The meta and state fields will be populated by this function.
func (c *catalogCache) create(name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths []string, hidden bool, r *runtimev1.Resource) error {
func (c *catalogCache) create(name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths, tags []string, hidden bool, r *runtimev1.Resource) error {
existing, _ := c.get(name, true, false)
if existing != nil {
if existing.Meta.DeletedOn == nil {
Expand All @@ -230,6 +230,7 @@ func (c *catalogCache) create(name *runtimev1.ResourceName, refs []*runtimev1.Re
Refs: refs,
Owner: owner,
FilePaths: paths,
Tags: tags,
Hidden: hidden,
Version: 1,
SpecVersion: 1,
Expand Down Expand Up @@ -295,7 +296,7 @@ func (c *catalogCache) clearRenamedFrom(name *runtimev1.ResourceName) error {
}

// updateMeta updates the meta fields of a resource.
func (c *catalogCache) updateMeta(name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths []string) error {
func (c *catalogCache) updateMeta(name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths, tags []string) error {
r, err := c.get(name, false, true)
if err != nil {
return err
Expand All @@ -304,6 +305,7 @@ func (c *catalogCache) updateMeta(name *runtimev1.ResourceName, refs []*runtimev
r.Meta.Refs = refs
r.Meta.Owner = owner
r.Meta.FilePaths = paths
r.Meta.Tags = tags
r.Meta.Version++
r.Meta.SpecVersion++
r.Meta.SpecUpdatedOn = timestamppb.Now()
Expand Down
19 changes: 11 additions & 8 deletions runtime/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@ func (c *Controller) Subscribe(ctx context.Context, fn SubscribeCallback) error

// Create creates a resource and enqueues it for reconciliation.
// If a resource with the same name is currently being deleted, the deletion will be cancelled.
func (c *Controller) Create(ctx context.Context, name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths []string, hidden bool, r *runtimev1.Resource) error {
// The tags parameter is stored generically on the resource's ResourceMeta for organization/filtering purposes.
func (c *Controller) Create(ctx context.Context, name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths, tags []string, hidden bool, r *runtimev1.Resource) error {
if err := c.checkRunning(); err != nil {
return err
}
Expand All @@ -515,7 +516,7 @@ func (c *Controller) Create(ctx context.Context, name *runtimev1.ResourceName, r
requeued = true
}

err := c.catalog.create(name, refs, owner, paths, hidden, r)
err := c.catalog.create(name, refs, owner, paths, tags, hidden, r)
if err != nil {
return err
}
Expand All @@ -528,7 +529,8 @@ func (c *Controller) Create(ctx context.Context, name *runtimev1.ResourceName, r

// UpdateMeta updates a resource's meta fields and enqueues it for reconciliation.
// If called from outside the resource's reconciler and the resource is currently reconciling, the current reconciler will be cancelled first.
func (c *Controller) UpdateMeta(ctx context.Context, name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths []string) error {
// The tags parameter is stored generically on the resource's ResourceMeta for organization/filtering purposes.
func (c *Controller) UpdateMeta(ctx context.Context, name *runtimev1.ResourceName, refs []*runtimev1.ResourceName, owner *runtimev1.ResourceName, paths, tags []string) error {
if err := c.checkRunning(); err != nil {
return err
}
Expand All @@ -548,7 +550,7 @@ func (c *Controller) UpdateMeta(ctx context.Context, name *runtimev1.ResourceNam
return err
}

err = c.catalog.updateMeta(name, refs, owner, paths)
err = c.catalog.updateMeta(name, refs, owner, paths, tags)
if err != nil {
return err
}
Expand All @@ -564,7 +566,8 @@ func (c *Controller) UpdateMeta(ctx context.Context, name *runtimev1.ResourceNam

// UpdateName renames a resource and updates annotations, and enqueues it for reconciliation.
// If called from outside the resource's reconciler and the resource is currently reconciling, the current reconciler will be cancelled first.
func (c *Controller) UpdateName(ctx context.Context, name, newName, owner *runtimev1.ResourceName, paths []string) error {
// The tags parameter is stored generically on the resource's ResourceMeta for organization/filtering purposes.
func (c *Controller) UpdateName(ctx context.Context, name, newName, owner *runtimev1.ResourceName, paths, tags []string) error {
if err := c.checkRunning(); err != nil {
return err
}
Expand Down Expand Up @@ -599,7 +602,7 @@ func (c *Controller) UpdateName(ctx context.Context, name, newName, owner *runti
}
c.enqueue(newName)

err = c.catalog.updateMeta(newName, r.Meta.Refs, owner, paths)
err = c.catalog.updateMeta(newName, r.Meta.Refs, owner, paths, tags)
if err != nil {
return err
}
Expand Down Expand Up @@ -968,7 +971,7 @@ func (c *Controller) safeMutateRenamed(n *runtimev1.ResourceName) error {
}

// Create a new resource with the old name, so we can delete it separately.
err = c.catalog.create(renamedFrom, r.Meta.Refs, r.Meta.Owner, r.Meta.FilePaths, r.Meta.Hidden, r)
err = c.catalog.create(renamedFrom, r.Meta.Refs, r.Meta.Owner, r.Meta.FilePaths, r.Meta.Tags, r.Meta.Hidden, r)
if err != nil {
return err
}
Expand Down Expand Up @@ -1027,7 +1030,7 @@ func (c *Controller) safeRename(from, to *runtimev1.ResourceName) error {
return err
}

err = c.catalog.create(to, r.Meta.Refs, r.Meta.Owner, r.Meta.FilePaths, r.Meta.Hidden, r)
err = c.catalog.create(to, r.Meta.Refs, r.Meta.Owner, r.Meta.FilePaths, r.Meta.Tags, r.Meta.Hidden, r)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (p *Parser) parseAlert(node *Node) error {
}

// Track alert
r, err := p.insertResource(ResourceKindAlert, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindAlert, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (p *Parser) parseAPI(node *Node) error {
}
}

r, err := p.insertResource(ResourceKindAPI, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindAPI, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/parser/parse_canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func (p *Parser) parseCanvas(node *Node) error {
}

// Track canvas
r, err := p.insertResource(ResourceKindCanvas, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindCanvas, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down Expand Up @@ -291,7 +291,7 @@ func (p *Parser) parseCanvas(node *Node) error {

// Track inline components
for _, def := range inlineComponentDefs {
r, err := p.insertResource(ResourceKindComponent, def.name, node.Paths, def.refs...)
r, err := p.insertResource(ResourceKindComponent, def.name, node.Paths, nil, def.refs...)
if err != nil {
// Normally we could return the error, but we can't do that here because we've already inserted the canvas.
// Since the component has been validated with insertDryRun in parseCanvasItemComponent, this error should never happen in practice.
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (p *Parser) parseComponent(node *Node) error {
node.Refs = append(node.Refs, refs...)

// Track component
r, err := p.insertResource(ResourceKindComponent, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindComponent, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (p *Parser) parseConnector(node *Node) error {
}

// Insert the connector
r, err := p.insertResource(ResourceKindConnector, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindConnector, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_explore.go
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling is missing in the code for unified metrics and explores in parse_metrics_view.go

Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func (p *Parser) parseExplore(node *Node) error {
}

// Track explore
r, err := p.insertResource(ResourceKindExplore, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindExplore, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
10 changes: 5 additions & 5 deletions runtime/parser/parse_metrics_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -833,13 +833,13 @@ func (p *Parser) parseMetricsView(node *Node) error {
}

// validate and insert inline explore, if true and no error is returned from the method then an explore resource is created so no error should be returned after this point
skipExplore, exploreRes, err := p.parseAndInsertInlineExplore(tmp, node.Name, node.Paths)
skipExplore, exploreRes, err := p.parseAndInsertInlineExplore(tmp, node.Name, node.Paths, node.Tags)
if err != nil {
return fmt.Errorf("failed to parse inline explore: %w", err)
}

// insert metrics view resource immediately after parsing the inline explore as it inserts the explore resource so we should not return an error now
r, err := p.insertResource(ResourceKindMetricsView, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindMetricsView, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
// If we fail to insert the metrics view, we must delete the inline explore if it was created.
if exploreRes != nil {
Expand Down Expand Up @@ -931,7 +931,7 @@ func (p *Parser) parseMetricsView(node *Node) error {
if tmp.DefaultTheme != "" {
refs = append(refs, ResourceName{Kind: ResourceKindTheme, Name: tmp.DefaultTheme})
}
e, err := p.insertResource(ResourceKindExplore, node.Name, node.Paths, refs...)
e, err := p.insertResource(ResourceKindExplore, node.Name, node.Paths, node.Tags, refs...)
if err != nil {
// We mustn't error because we have already emitted one resource.
// Since this probably means an explore has been defined separately, we can just ignore this error.
Expand Down Expand Up @@ -996,7 +996,7 @@ func (p *Parser) parseMetricsView(node *Node) error {
}

// parseAndInsertInlineExplore parses and validates the inline explore definition in a metrics view YAML. It returns true if automatic explore emission should be skipped, false otherwise.
func (p *Parser) parseAndInsertInlineExplore(tmp *MetricsViewYAML, mvName string, mvPaths []string) (bool, *Resource, error) {
func (p *Parser) parseAndInsertInlineExplore(tmp *MetricsViewYAML, mvName string, mvPaths, mvTags []string) (bool, *Resource, error) {
if tmp.Explore == nil {
return false, nil, nil
}
Expand Down Expand Up @@ -1116,7 +1116,7 @@ func (p *Parser) parseAndInsertInlineExplore(tmp *MetricsViewYAML, mvName string
name = tmp.Explore.Name
}
// Track explore
r, err := p.insertResource(ResourceKindExplore, name, mvPaths, refs...)
r, err := p.insertResource(ResourceKindExplore, name, mvPaths, mvTags, refs...)
if err != nil {
return false, nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (p *Parser) parseMigration(node *Node) error {
}

// Add resource
r, err := p.insertResource(ResourceKindMigration, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindMigration, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func (p *Parser) parseModel(ctx context.Context, node *Node) error {
}

// Insert the model
r, err := p.insertResource(ResourceKindModel, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindModel, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions runtime/parser/parse_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Node struct {
Kind ResourceKind
Name string
Refs []ResourceName
Tags []string
Paths []string
YAML *yaml.Node
YAMLOverride *yaml.Node
Expand Down Expand Up @@ -78,6 +79,8 @@ type commonYAML struct {
Namespace string `yaml:"namespace"`
// Refs are a list of other resources that this resource depends on. They are usually inferred from other fields, but can also be specified manually.
Refs []yaml.Node `yaml:"refs"`
// Tags are user-defined labels for organizing and filtering resources. Parsed generically for all resource types.
Tags []string `yaml:"tags"`
// ParserConfig enables setting file-level parser config.
ParserConfig struct {
Templating *bool `yaml:"templating"`
Expand Down Expand Up @@ -159,6 +162,7 @@ func (p *Parser) parseStem(paths []string, ymlPath, yml, sqlPath, sql string) (*
// Copy basic properties
res.Version = cfg.Version
res.Name = cfg.Name
res.Tags = cfg.Tags
res.Connector = cfg.Connector
res.SQL = cfg.SQL
res.SQLPath = ymlPath
Expand Down
2 changes: 1 addition & 1 deletion runtime/parser/parse_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func (p *Parser) parseReport(node *Node) error {
}

// Track report
r, err := p.insertResource(ResourceKindReport, node.Name, node.Paths, node.Refs...)
r, err := p.insertResource(ResourceKindReport, node.Name, node.Paths, node.Tags, node.Refs...)
if err != nil {
return err
}
Expand Down
Loading
Loading