diff --git a/web-common/src/features/entity-management/AddAssetButton.svelte b/web-common/src/features/entity-management/AddAssetButton.svelte index 6feb6693af7..49630a071f3 100644 --- a/web-common/src/features/entity-management/AddAssetButton.svelte +++ b/web-common/src/features/entity-management/AddAssetButton.svelte @@ -23,6 +23,7 @@ import { directoryState } from "../file-explorer/directory-store"; import { createResourceFile } from "../file-explorer/new-files"; import { addSourceModal } from "../sources/modal/add-source-visibility"; + import CreateExploreDialog from "./CreateExploreDialog.svelte"; import { removeLeadingSlash } from "./entity-mappers"; import { useDirectoryNamesInDirectory, @@ -34,7 +35,6 @@ resourceIconMapping, } from "./resource-icon-mapping"; import { ResourceKind, useFilteredResources } from "./resource-selectors"; - import CreateExploreDialog from "./CreateExploreDialog.svelte"; let active = false; let showExploreDialog = false; diff --git a/web-common/src/features/entity-management/WatchResourcesClient.ts b/web-common/src/features/entity-management/WatchResourcesClient.ts index 3c2337834de..3f1245cef18 100644 --- a/web-common/src/features/entity-management/WatchResourcesClient.ts +++ b/web-common/src/features/entity-management/WatchResourcesClient.ts @@ -22,6 +22,7 @@ import { WatchRequestClient } from "@rilldata/web-common/runtime-client/watch-re import { get } from "svelte/store"; import { connectorExplorerStore } from "../connectors/connector-explorer-store"; import { sourceImportedPath } from "../sources/sources-store"; +import { isLeafResource } from "./dag-utils"; export class WatchResourcesClient { public readonly client: WatchRequestClient; @@ -34,7 +35,7 @@ export class WatchResourcesClient { this.client.on("reconnect", () => this.invalidateAllRuntimeQueries()); } - private handleWatchResourceResponse(res: V1WatchResourcesResponse) { + private async handleWatchResourceResponse(res: V1WatchResourcesResponse) { // Log resource status to the browser console during e2e tests. Currently, our e2e tests make assertions // based on these logs. However, the e2e tests really should make UI-based assertions. if (import.meta.env.VITE_PLAYWRIGHT_TEST) { @@ -185,7 +186,8 @@ export class WatchResourcesClient { // If it's a new source, show the "Source imported successfully" modal const isNewSource = res.name.kind === ResourceKind.Source && - res.resource.meta.specVersion === "1"; + res.resource.meta.specVersion === "1" && + (await isLeafResource(res.resource, this.instanceId)); // Protects against existing projects reconciling anew if (isNewSource) { const filePath = res.resource?.meta?.filePaths?.[0] as string; sourceImportedPath.set(filePath); diff --git a/web-common/src/features/entity-management/dag-utils.ts b/web-common/src/features/entity-management/dag-utils.ts new file mode 100644 index 00000000000..005e1e16368 --- /dev/null +++ b/web-common/src/features/entity-management/dag-utils.ts @@ -0,0 +1,21 @@ +import { + getRuntimeServiceListResourcesQueryKey, + runtimeServiceListResources, + type V1Resource, +} from "@rilldata/web-common/runtime-client"; +import { queryClient } from "../../lib/svelte-query/globalQueryClient"; + +export async function isLeafResource(resource: V1Resource, instanceId: string) { + const allResources = await queryClient.fetchQuery({ + queryKey: getRuntimeServiceListResourcesQueryKey(instanceId, undefined), + queryFn: () => runtimeServiceListResources(instanceId, undefined), + }); + + if (!allResources || !allResources.resources) return false; + + const hasDownstreamResource = allResources.resources.some((r: V1Resource) => + r.meta?.refs?.some((ref) => ref.name === resource.meta?.name?.name), + ); + + return !hasDownstreamResource; +} diff --git a/web-common/src/features/welcome/ProjectCards.svelte b/web-common/src/features/welcome/ProjectCards.svelte index 8b8b76fc263..192343b5f80 100644 --- a/web-common/src/features/welcome/ProjectCards.svelte +++ b/web-common/src/features/welcome/ProjectCards.svelte @@ -1,4 +1,5 @@