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 ({