From 88f62ef4da05703e4ae47530b93d65d7d507cd5f Mon Sep 17 00:00:00 2001
From: Anshul Khandelwal <12948312+k-anshul@users.noreply.github.com>
Date: Wed, 22 Jul 2026 21:42:52 +0530
Subject: [PATCH 1/3] Refresh trigger for all resources in resource listing
---
.../status/resource-table/ActionsCell.svelte | 25 +++++++---
.../ProjectResourcesTable.svelte | 4 +-
.../tests/project-status-refresh.spec.ts | 49 ++++++++++++++++---
.../projects/status/ActionsCell.svelte | 49 ++++++++++---------
.../RefreshResourceConfirmDialog.svelte | 10 ++--
.../resources/ResourcesFilterableTable.svelte | 5 +-
web-common/src/lib/i18n/messages/en.json | 2 +
web-common/src/lib/i18n/messages/es.json | 2 +
8 files changed, 104 insertions(+), 42 deletions(-)
diff --git a/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte b/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
index 2200f8947688..496c2c66a351 100644
--- a/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
+++ b/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
@@ -23,7 +23,7 @@
export let onClickRefreshDialog: (
resourceName: string,
resourceKind: string,
- refreshType: "full" | "incremental",
+ refreshType: "refresh" | "full" | "incremental",
) => void;
export let onClickRefreshErroredPartitions: (resourceName: string) => void;
export let onClickViewSpec: (
@@ -39,8 +39,6 @@
export let onDropdownOpenChange: (isOpen: boolean) => void;
$: isModel = resourceKind === ResourceKind.Model;
- $: isSource = resourceKind === ResourceKind.Source;
- $: canRefresh = isModel || isSource;
$: actions = isModel ? getAvailableModelActions(resource) : [];
$: isPartitioned = actions.includes("viewPartitions");
@@ -93,10 +91,9 @@
{/if}
-
- {#if canRefresh}
-
+
+ {#if isModel}
{#if hasErroredPartitions}
@@ -153,6 +150,22 @@
>
{/if}
+ {:else}
+
+
+
+ onClickRefreshDialog(resourceName, resourceKind, "refresh")}
+ >
+
+
+ {m.status_action_refresh()}
+
+
+ {refreshTooltip}
+
{/if}
diff --git a/web-admin/src/features/projects/status/resource-table/ProjectResourcesTable.svelte b/web-admin/src/features/projects/status/resource-table/ProjectResourcesTable.svelte
index 9fa8ec702837..1b438cca7870 100644
--- a/web-admin/src/features/projects/status/resource-table/ProjectResourcesTable.svelte
+++ b/web-admin/src/features/projects/status/resource-table/ProjectResourcesTable.svelte
@@ -35,7 +35,7 @@
let isConfirmDialogOpen = false;
let dialogResourceName = "";
let dialogResourceKind = "";
- let dialogRefreshType: "full" | "incremental" = "full";
+ let dialogRefreshType: "refresh" | "full" | "incremental" = "refresh";
let isSpecDialogOpen = false;
let specResourceName = "";
@@ -61,7 +61,7 @@
const openRefreshDialog = (
resourceName: string,
resourceKind: string,
- refreshType: "full" | "incremental",
+ refreshType: "refresh" | "full" | "incremental",
) => {
dialogResourceName = resourceName;
dialogResourceKind = resourceKind;
diff --git a/web-admin/tests/project-status-refresh.spec.ts b/web-admin/tests/project-status-refresh.spec.ts
index 1bf69cea68ce..5289c36b7855 100644
--- a/web-admin/tests/project-status-refresh.spec.ts
+++ b/web-admin/tests/project-status-refresh.spec.ts
@@ -35,14 +35,11 @@ test.describe("Project Status - Resource Refresh (openrtb)", () => {
).toBeVisible();
});
- test("should show Full Refresh option for sources", async ({ adminPage }) => {
- // Wait for the source row to be visible before interacting
- // Look for bids_data_raw source which should be in the openrtb test project
+ test("should show only Refresh for sources", async ({ adminPage }) => {
await expect(adminPage.getByText("bids_data_raw")).toBeVisible({
timeout: 60_000,
});
- // Find a source row and click its actions menu
const sourceRow = adminPage.locator(".row").filter({
hasText: "bids_data_raw",
});
@@ -50,12 +47,52 @@ test.describe("Project Status - Resource Refresh (openrtb)", () => {
.getByRole("button", { name: "Open resource actions" })
.click();
- // Verify "Full Refresh" is visible
+ await expect(
+ adminPage.getByRole("menuitem", { name: "Refresh", exact: true }),
+ ).toBeVisible();
await expect(
adminPage.getByRole("menuitem", { name: "Full Refresh" }),
+ ).not.toBeVisible();
+ await expect(
+ adminPage.getByRole("menuitem", { name: "Incremental Refresh" }),
+ ).not.toBeVisible();
+
+ await adminPage
+ .getByRole("menuitem", { name: "Refresh", exact: true })
+ .click();
+ await expect(adminPage.getByRole("alertdialog")).toBeVisible();
+ await expect(
+ adminPage.getByRole("heading", { name: /Refresh bids_data_raw/ }),
).toBeVisible();
+ await expect(
+ adminPage.getByText(
+ "Refreshing this resource will update all dependent resources.",
+ ),
+ ).toBeVisible();
+ await expect(
+ adminPage.getByText(/Warning.*re-ingest ALL data/),
+ ).toHaveCount(0);
+ await adminPage.getByRole("button", { name: "Cancel" }).click();
+ });
+
+ test("should show only Refresh for metrics views", async ({ adminPage }) => {
+ await expect(adminPage.getByText("auction_metrics")).toBeVisible({
+ timeout: 60_000,
+ });
+
+ const metricsViewRow = adminPage.locator(".row").filter({
+ hasText: "auction_metrics",
+ });
+ await metricsViewRow
+ .getByRole("button", { name: "Open resource actions" })
+ .click();
- // Incremental Refresh should NOT be visible for sources
+ await expect(
+ adminPage.getByRole("menuitem", { name: "Refresh", exact: true }),
+ ).toBeVisible();
+ await expect(
+ adminPage.getByRole("menuitem", { name: "Full Refresh" }),
+ ).not.toBeVisible();
await expect(
adminPage.getByRole("menuitem", { name: "Incremental Refresh" }),
).not.toBeVisible();
diff --git a/web-common/src/features/projects/status/ActionsCell.svelte b/web-common/src/features/projects/status/ActionsCell.svelte
index 5a7bf284b087..3a436a4bed69 100644
--- a/web-common/src/features/projects/status/ActionsCell.svelte
+++ b/web-common/src/features/projects/status/ActionsCell.svelte
@@ -29,32 +29,33 @@
$: isLoading = $triggerMutation.isPending;
+ $: isModel = resourceKind === ResourceKind.Model;
$: supportsIncremental =
- resourceKind === ResourceKind.Model &&
- resource?.model?.spec?.incremental === true;
+ isModel && resource?.model?.spec?.incremental === true;
- async function handleRefresh(refreshType: "full" | "incremental") {
+ async function handleRefresh(
+ refreshType: "refresh" | "full" | "incremental",
+ ) {
if (isLoading) return;
try {
- const body =
- resourceKind === ResourceKind.Model
- ? {
- models: [
- {
- model: resourceName,
- full: refreshType === "full",
- },
- ],
- }
- : {
- resources: [
- {
- kind: resourceKind,
- name: resourceName,
- },
- ],
- };
+ const body = isModel
+ ? {
+ models: [
+ {
+ model: resourceName,
+ full: refreshType === "full",
+ },
+ ],
+ }
+ : {
+ resources: [
+ {
+ kind: resourceKind,
+ name: resourceName,
+ },
+ ],
+ };
await $triggerMutation.mutateAsync(body);
@@ -89,7 +90,7 @@
class="font-normal flex items-center"
disabled={isLoading}
onclick={() => {
- handleRefresh("full");
+ handleRefresh(isModel ? "full" : "refresh");
}}
>
@@ -97,7 +98,9 @@
{isLoading
? m.status_refreshing()
- : m.status_action_full_refresh()}
diff --git a/web-common/src/features/projects/status/RefreshResourceConfirmDialog.svelte b/web-common/src/features/projects/status/RefreshResourceConfirmDialog.svelte
index 3a335df794c9..4a55be35e6f0 100644
--- a/web-common/src/features/projects/status/RefreshResourceConfirmDialog.svelte
+++ b/web-common/src/features/projects/status/RefreshResourceConfirmDialog.svelte
@@ -13,7 +13,7 @@
export let open = false;
export let name: string;
export let onRefresh: () => Promise | void;
- export let refreshType: "full" | "incremental" = "full";
+ export let refreshType: "refresh" | "full" | "incremental" = "full";
let isRefreshing = false;
@@ -45,15 +45,19 @@
{refreshType === "full"
? m.status_action_full_refresh()
- : m.status_action_incremental_refresh()}
+ : refreshType === "incremental"
+ ? m.status_action_incremental_refresh()
+ : m.status_action_refresh()}
{truncateName(name)}?
{#if refreshType === "full"}
{m.status_full_refresh_warning()}
- {:else}
+ {:else if refreshType === "incremental"}
{m.status_incremental_refresh_description()}
+ {:else}
+ {m.status_refresh_description()}
{/if}
diff --git a/web-common/src/features/resources/ResourcesFilterableTable.svelte b/web-common/src/features/resources/ResourcesFilterableTable.svelte
index b01eb6d16686..a7a533e60122 100644
--- a/web-common/src/features/resources/ResourcesFilterableTable.svelte
+++ b/web-common/src/features/resources/ResourcesFilterableTable.svelte
@@ -194,8 +194,9 @@
resourceName: row.original.meta?.name?.name ?? "",
canRefresh:
!isRowReconciling &&
- (row.original.meta?.name?.kind === ResourceKind.Model ||
- row.original.meta?.name?.kind === ResourceKind.Source),
+ filterableTypes.includes(
+ row.original.meta?.name?.kind as ResourceKind,
+ ),
resource: row.original,
onRefresh: onRefetch,
onDescribe: handleDescribe,
diff --git a/web-common/src/lib/i18n/messages/en.json b/web-common/src/lib/i18n/messages/en.json
index 5df177470ab4..99a55f472802 100644
--- a/web-common/src/lib/i18n/messages/en.json
+++ b/web-common/src/lib/i18n/messages/en.json
@@ -1653,6 +1653,7 @@
"status_action_describe": "Describe",
"status_action_full_refresh": "Full Refresh",
"status_action_incremental_refresh": "Incremental Refresh",
+ "status_action_refresh": "Refresh",
"status_action_refresh_errored_partitions": "Refresh Errored Partitions",
"status_action_view_logs": "View Logs",
"status_action_view_partitions": "View Partitions",
@@ -1795,6 +1796,7 @@
"status_refresh_all_confirm_title": "Refresh all sources and models?",
"status_refresh_all_sources_models": "Refresh all sources and models",
"status_refresh_errored_confirm_body": "This will re-execute all partitions that failed during their last run. The refresh will happen in the background.",
+ "status_refresh_description": "Refreshing this resource will update all dependent resources.",
"status_refresh_errored_confirm_title": "Refresh Errored Partitions for {modelName}?",
"status_refreshing": "Refreshing...",
"status_resource_reconciling": "Resource is currently being reconciled",
diff --git a/web-common/src/lib/i18n/messages/es.json b/web-common/src/lib/i18n/messages/es.json
index 089440a67a01..0b92095c49b5 100644
--- a/web-common/src/lib/i18n/messages/es.json
+++ b/web-common/src/lib/i18n/messages/es.json
@@ -1662,6 +1662,7 @@
"status_action_describe": "Describir",
"status_action_full_refresh": "Actualización completa",
"status_action_incremental_refresh": "Actualización incremental",
+ "status_action_refresh": "Actualizar",
"status_action_refresh_errored_partitions": "Actualizar particiones con error",
"status_action_view_logs": "Ver registros",
"status_action_view_partitions": "Ver particiones",
@@ -1804,6 +1805,7 @@
"status_refresh_all_confirm_title": "¿Actualizar todas las fuentes y modelos?",
"status_refresh_all_sources_models": "Actualizar todas las fuentes y modelos",
"status_refresh_errored_confirm_body": "Se reejecutarán todas las particiones que fallaron en su última ejecución. La actualización se realizará en segundo plano.",
+ "status_refresh_description": "Actualizar este recurso actualizará todos los recursos dependientes.",
"status_refresh_errored_confirm_title": "¿Actualizar particiones con error de {modelName}?",
"status_refreshing": "Actualizando...",
"status_resource_reconciling": "El recurso se está reconciliando",
From 75ecfd9ba99aa8f89dcce204d5865a1eb07b9aee Mon Sep 17 00:00:00 2001
From: Anshul Khandelwal <12948312+k-anshul@users.noreply.github.com>
Date: Wed, 22 Jul 2026 22:16:20 +0530
Subject: [PATCH 2/3] no refresh for alerts and reports
---
.../status/resource-table/ActionsCell.svelte | 10 +++++++---
.../resources/ResourcesFilterableTable.svelte | 3 ++-
.../src/features/resources/resource-filter-utils.ts | 13 +++++++++++++
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte b/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
index 496c2c66a351..94088d974133 100644
--- a/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
+++ b/web-admin/src/features/projects/status/resource-table/ActionsCell.svelte
@@ -5,6 +5,7 @@
import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte";
import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte";
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors";
+ import { refreshableTypes } from "@rilldata/web-common/features/resources/resource-filter-utils";
import type { V1Resource } from "@rilldata/web-common/runtime-client";
import {
RefreshCcwIcon,
@@ -39,6 +40,7 @@
export let onDropdownOpenChange: (isOpen: boolean) => void;
$: isModel = resourceKind === ResourceKind.Model;
+ $: canRefresh = refreshableTypes.includes(resourceKind as ResourceKind);
$: actions = isModel ? getAvailableModelActions(resource) : [];
$: isPartitioned = actions.includes("viewPartitions");
@@ -91,9 +93,9 @@
{/if}
-
-
{#if isModel}
+
+
{#if hasErroredPartitions}
@@ -150,7 +152,9 @@
>
{/if}
- {:else}
+ {:else if canRefresh}
+
+
Date: Wed, 22 Jul 2026 22:47:46 +0530
Subject: [PATCH 3/3] fix test
---
.../tests/project-status-refresh.spec.ts | 49 ++++++++++---------
1 file changed, 27 insertions(+), 22 deletions(-)
diff --git a/web-admin/tests/project-status-refresh.spec.ts b/web-admin/tests/project-status-refresh.spec.ts
index 5289c36b7855..cd2dd6e9d744 100644
--- a/web-admin/tests/project-status-refresh.spec.ts
+++ b/web-admin/tests/project-status-refresh.spec.ts
@@ -35,11 +35,16 @@ test.describe("Project Status - Resource Refresh (openrtb)", () => {
).toBeVisible();
});
- test("should show only Refresh for sources", async ({ adminPage }) => {
+ test("should show Full Refresh option for sources", async ({ adminPage }) => {
+ // Wait for the source row to be visible before interacting
+ // Look for bids_data_raw source which should be in the openrtb test project.
+ // NOTE: `type: source` files are parsed into models (defined_as_source), so
+ // this row is a model and shows the full/incremental refresh actions.
await expect(adminPage.getByText("bids_data_raw")).toBeVisible({
timeout: 60_000,
});
+ // Find a source row and click its actions menu
const sourceRow = adminPage.locator(".row").filter({
hasText: "bids_data_raw",
});
@@ -47,32 +52,15 @@ test.describe("Project Status - Resource Refresh (openrtb)", () => {
.getByRole("button", { name: "Open resource actions" })
.click();
- await expect(
- adminPage.getByRole("menuitem", { name: "Refresh", exact: true }),
- ).toBeVisible();
+ // Verify "Full Refresh" is visible
await expect(
adminPage.getByRole("menuitem", { name: "Full Refresh" }),
- ).not.toBeVisible();
+ ).toBeVisible();
+
+ // Incremental Refresh should NOT be visible for sources
await expect(
adminPage.getByRole("menuitem", { name: "Incremental Refresh" }),
).not.toBeVisible();
-
- await adminPage
- .getByRole("menuitem", { name: "Refresh", exact: true })
- .click();
- await expect(adminPage.getByRole("alertdialog")).toBeVisible();
- await expect(
- adminPage.getByRole("heading", { name: /Refresh bids_data_raw/ }),
- ).toBeVisible();
- await expect(
- adminPage.getByText(
- "Refreshing this resource will update all dependent resources.",
- ),
- ).toBeVisible();
- await expect(
- adminPage.getByText(/Warning.*re-ingest ALL data/),
- ).toHaveCount(0);
- await adminPage.getByRole("button", { name: "Cancel" }).click();
});
test("should show only Refresh for metrics views", async ({ adminPage }) => {
@@ -96,6 +84,23 @@ test.describe("Project Status - Resource Refresh (openrtb)", () => {
await expect(
adminPage.getByRole("menuitem", { name: "Incremental Refresh" }),
).not.toBeVisible();
+
+ await adminPage
+ .getByRole("menuitem", { name: "Refresh", exact: true })
+ .click();
+ await expect(adminPage.getByRole("alertdialog")).toBeVisible();
+ await expect(
+ adminPage.getByRole("heading", { name: /Refresh auction_metrics/ }),
+ ).toBeVisible();
+ await expect(
+ adminPage.getByText(
+ "Refreshing this resource will update all dependent resources.",
+ ),
+ ).toBeVisible();
+ await expect(
+ adminPage.getByText(/Warning.*re-ingest ALL data/),
+ ).toHaveCount(0);
+ await adminPage.getByRole("button", { name: "Cancel" }).click();
});
test("should not show Incremental Refresh for non-incremental models", async ({