diff --git a/web-common/src/features/charts/ChartMenuItems.svelte b/web-common/src/features/charts/ChartMenuItems.svelte index 88d38aaf4ef..7128ed12085 100644 --- a/web-common/src/features/charts/ChartMenuItems.svelte +++ b/web-common/src/features/charts/ChartMenuItems.svelte @@ -1,20 +1,21 @@ diff --git a/web-common/src/features/charts/selectors.ts b/web-common/src/features/charts/selectors.ts index 7668eb0a49c..3b1dfcea474 100644 --- a/web-common/src/features/charts/selectors.ts +++ b/web-common/src/features/charts/selectors.ts @@ -1,13 +1,21 @@ +import { getRouteFromName } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { ResourceKind, useResource, } from "@rilldata/web-common/features/entity-management/resource-selectors"; +import { EntityType } from "@rilldata/web-common/features/entity-management/types"; import { useMainEntityFiles } from "../entity-management/file-selectors"; export function useChartFileNames(instanceId: string) { return useMainEntityFiles(instanceId, "charts"); } +export function useChartRoutes(instanceId: string) { + return useMainEntityFiles(instanceId, "charts", (name) => + getRouteFromName(name, EntityType.Chart), + ); +} + export const useChart = (instanceId: string, chartName: string) => { return useResource(instanceId, chartName, ResourceKind.Chart); }; diff --git a/web-common/src/features/custom-dashboards/CustomDashboardMenuItems.svelte b/web-common/src/features/custom-dashboards/CustomDashboardMenuItems.svelte index 8b6b57e2a8f..7bc0563639d 100644 --- a/web-common/src/features/custom-dashboards/CustomDashboardMenuItems.svelte +++ b/web-common/src/features/custom-dashboards/CustomDashboardMenuItems.svelte @@ -1,22 +1,21 @@ diff --git a/web-common/src/features/custom-dashboards/selectors.ts b/web-common/src/features/custom-dashboards/selectors.ts index ee8c27cd88c..931691b7a5f 100644 --- a/web-common/src/features/custom-dashboards/selectors.ts +++ b/web-common/src/features/custom-dashboards/selectors.ts @@ -1,5 +1,13 @@ +import { getRouteFromName } from "@rilldata/web-common/features/entity-management/entity-mappers"; +import { EntityType } from "@rilldata/web-common/features/entity-management/types"; import { useMainEntityFiles } from "../entity-management/file-selectors"; export function useCustomDashboardFileNames(instanceId: string) { return useMainEntityFiles(instanceId, "custom-dashboards"); } + +export function useCustomDashboardRoutes(instanceId: string) { + return useMainEntityFiles(instanceId, "custom-dashboards", (name) => + getRouteFromName(name, EntityType.Dashboard), + ); +} diff --git a/web-common/src/features/dashboards/DashboardAssets.svelte b/web-common/src/features/dashboards/DashboardAssets.svelte index c8669b78101..6985c92032f 100644 --- a/web-common/src/features/dashboards/DashboardAssets.svelte +++ b/web-common/src/features/dashboards/DashboardAssets.svelte @@ -7,6 +7,7 @@ import Model from "@rilldata/web-common/components/icons/Model.svelte"; import { useDashboardFileNames, + useDashboardRoutes, useValidDashboards, } from "@rilldata/web-common/features/dashboards/selectors"; import { deleteFileArtifact } from "@rilldata/web-common/features/entity-management/actions"; @@ -53,6 +54,7 @@ $: sourceNames = useSourceFileNames(instanceId); $: modelNames = useModelFileNames(instanceId); $: dashboardNames = useDashboardFileNames(instanceId); + $: dashboardRoutes = useDashboardRoutes(instanceId); $: dashboards = useValidDashboards(instanceId); const MetricsSourceSelectionError = ( @@ -168,9 +170,12 @@ ); await deleteFileArtifact( instanceId, - dashboardName, + getFileAPIPathFromNameAndType( + dashboardName, + EntityType.MetricsDefinition, + ), EntityType.MetricsDefinition, - $dashboardNames?.data ?? [], + $dashboardRoutes?.data ?? [], ); // redirect to model when metric is deleted diff --git a/web-common/src/features/dashboards/selectors.ts b/web-common/src/features/dashboards/selectors.ts index 8fa0590c9b1..217de3d4952 100644 --- a/web-common/src/features/dashboards/selectors.ts +++ b/web-common/src/features/dashboards/selectors.ts @@ -1,4 +1,5 @@ import { filterExpressions } from "@rilldata/web-common/features/dashboards/stores/filter-utils"; +import { getRouteFromName } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { useMainEntityFiles } from "@rilldata/web-common/features/entity-management/file-selectors"; import { ResourceKind, @@ -6,6 +7,7 @@ import { useFilteredResources, useResource, } from "@rilldata/web-common/features/entity-management/resource-selectors"; +import { EntityType } from "@rilldata/web-common/features/entity-management/types"; import { V1Expression, V1MetricsViewSpec, @@ -26,6 +28,12 @@ export function useDashboardFileNames(instanceId: string) { return useMainEntityFiles(instanceId, "dashboards"); } +export function useDashboardRoutes(instanceId: string) { + return useMainEntityFiles(instanceId, "dashboards", (name) => + getRouteFromName(name, EntityType.MetricsDefinition), + ); +} + export function useDashboard(instanceId: string, metricViewName: string) { return useResource(instanceId, metricViewName, ResourceKind.MetricsView); } diff --git a/web-common/src/features/entity-management/RenameAssetModal.svelte b/web-common/src/features/entity-management/RenameAssetModal.svelte index 1af900e0285..48854c97c44 100644 --- a/web-common/src/features/entity-management/RenameAssetModal.svelte +++ b/web-common/src/features/entity-management/RenameAssetModal.svelte @@ -9,7 +9,11 @@ import * as yup from "yup"; import { runtime } from "../../runtime-client/runtime-store"; import { renameFileArtifact } from "./actions"; - import { getLabel, getRouteFromName } from "./entity-mappers"; + import { + getFileAPIPathFromNameAndType, + getLabel, + getRouteFromName, + } from "./entity-mappers"; import { INVALID_NAME_MESSAGE, VALID_NAME_PATTERN, @@ -50,8 +54,8 @@ try { await renameFileArtifact( runtimeInstanceId, - currentAssetName, - values.newName, + getFileAPIPathFromNameAndType(currentAssetName, entityType), + getFileAPIPathFromNameAndType(values.newName, entityType), entityType, ); goto(getRouteFromName(values.newName, entityType), { diff --git a/web-common/src/features/entity-management/actions.ts b/web-common/src/features/entity-management/actions.ts index d57d1f51251..45309f16bda 100644 --- a/web-common/src/features/entity-management/actions.ts +++ b/web-common/src/features/entity-management/actions.ts @@ -1,5 +1,6 @@ import { goto } from "$app/navigation"; import { notifications } from "@rilldata/web-common/components/notifications"; +import { extractFileName } from "@rilldata/web-common/features/sources/extract-file-name"; import { appScreen } from "@rilldata/web-common/layout/app-store"; import { runtimeServiceDeleteFile, @@ -7,26 +8,24 @@ import { } from "@rilldata/web-common/runtime-client"; import { httpRequestQueue } from "@rilldata/web-common/runtime-client/http-client"; import { get } from "svelte/store"; -import { - getFileAPIPathFromNameAndType, - getLabel, - getRouteFromName, - removeLeadingSlash, -} from "./entity-mappers"; +import { getLabel, removeLeadingSlash } from "./entity-mappers"; import { getNextEntityName } from "./name-utils"; import type { EntityType } from "./types"; export async function renameFileArtifact( instanceId: string, - fromName: string, - toName: string, + fromPath: string, + toPath: string, type: EntityType, ) { await runtimeServiceRenameFile(instanceId, { - fromPath: getFileAPIPathFromNameAndType(fromName, type), - toPath: getFileAPIPathFromNameAndType(toName, type), + fromPath, + toPath, }); + const fromName = extractFileName(fromPath); + const toName = extractFileName(toPath); + httpRequestQueue.removeByName(fromName); notifications.send({ message: `Renamed ${getLabel(type)} ${fromName} to ${toName}`, @@ -35,14 +34,14 @@ export async function renameFileArtifact( export async function deleteFileArtifact( instanceId: string, - name: string, + filePath: string, type: EntityType, - names: Array, + allPaths: Array, showNotification = true, ) { - const path = getFileAPIPathFromNameAndType(name, type); + const name = extractFileName(filePath); try { - await runtimeServiceDeleteFile(instanceId, removeLeadingSlash(path)); + await runtimeServiceDeleteFile(instanceId, removeLeadingSlash(filePath)); httpRequestQueue.removeByName(name); if (showNotification) { @@ -50,9 +49,7 @@ export async function deleteFileArtifact( } if (get(appScreen)?.name === name) { - const route = getRouteFromName(getNextEntityName(names, name), type); - - await goto(route); + await goto(getNextEntityName(allPaths, name)); } } catch (err) { console.error(err); diff --git a/web-common/src/features/entity-management/file-selectors.ts b/web-common/src/features/entity-management/file-selectors.ts index 3ef9916b5ed..08829f50b7b 100644 --- a/web-common/src/features/entity-management/file-selectors.ts +++ b/web-common/src/features/entity-management/file-selectors.ts @@ -7,6 +7,7 @@ import { createRuntimeServiceListFiles } from "@rilldata/web-common/runtime-clie export function useMainEntityFiles( instanceId: string, prefix: "sources" | "models" | "dashboards" | "charts" | "custom-dashboards", + transform = (name: string) => name, ) { let extension: string; switch (prefix) { @@ -40,7 +41,9 @@ export function useMainEntityFiles( }) .map((filePath) => { // Remove the directory and extension from the filePath to get the file name - return filePath.replace(`/${prefix}/`, "").replace(extension, ""); + return transform( + filePath.replace(`/${prefix}/`, "").replace(extension, ""), + ); }) // Sort the file names alphabetically in a case-insensitive manner .sort((fileNameA, fileNameB) => diff --git a/web-common/src/features/metrics-views/workspace/MetricsWorkspaceHeader.svelte b/web-common/src/features/metrics-views/workspace/MetricsWorkspaceHeader.svelte index 0c6f43b40bf..2f353ed19b8 100644 --- a/web-common/src/features/metrics-views/workspace/MetricsWorkspaceHeader.svelte +++ b/web-common/src/features/metrics-views/workspace/MetricsWorkspaceHeader.svelte @@ -2,6 +2,7 @@ import { goto } from "$app/navigation"; import { notifications } from "@rilldata/web-common/components/notifications"; import { renameFileArtifact } from "@rilldata/web-common/features/entity-management/actions"; + import { getFileAPIPathFromNameAndType } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { INVALID_NAME_MESSAGE, VALID_NAME_PATTERN, @@ -39,7 +40,12 @@ try { const toName = e.target.value; const type = EntityType.MetricsDefinition; - await renameFileArtifact(runtimeInstanceId, metricsDefName, toName, type); + await renameFileArtifact( + runtimeInstanceId, + getFileAPIPathFromNameAndType(metricsDefName, type), + getFileAPIPathFromNameAndType(toName, type), + type, + ); goto(`/dashboard/${toName}/edit`, { replaceState: true }); } catch (err) { console.error(err.response.data.message); diff --git a/web-common/src/features/models/navigation/ModelMenuItems.svelte b/web-common/src/features/models/navigation/ModelMenuItems.svelte index 2d3ff0cde9b..d3cc263f881 100644 --- a/web-common/src/features/models/navigation/ModelMenuItems.svelte +++ b/web-common/src/features/models/navigation/ModelMenuItems.svelte @@ -2,7 +2,10 @@ import Cancel from "@rilldata/web-common/components/icons/Cancel.svelte"; import EditIcon from "@rilldata/web-common/components/icons/EditIcon.svelte"; import Explore from "@rilldata/web-common/components/icons/Explore.svelte"; - import { getFilePathFromNameAndType } from "@rilldata/web-common/features/entity-management/entity-mappers"; + import { + getFileAPIPathFromNameAndType, + getFilePathFromNameAndType, + } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { getFileHasErrors } from "@rilldata/web-common/features/entity-management/resources-store"; import { EntityType } from "@rilldata/web-common/features/entity-management/types"; import { BehaviourEventMedium } from "@rilldata/web-common/metrics/service/BehaviourEventTypes"; @@ -14,7 +17,7 @@ import { runtime } from "../../../runtime-client/runtime-store"; import { deleteFileArtifact } from "../../entity-management/actions"; import { useCreateDashboardFromTableUIAction } from "../../metrics-views/ai-generation/generateMetricsView"; - import { useModel, useModelFileNames } from "../selectors"; + import { useModel, useModelRoutes } from "../selectors"; import NavigationMenuItem from "@rilldata/web-common/layout/navigation/NavigationMenuItem.svelte"; import NavigationMenuSeparator from "@rilldata/web-common/layout/navigation/NavigationMenuSeparator.svelte"; @@ -25,7 +28,7 @@ const queryClient = useQueryClient(); const dispatch = createEventDispatcher(); - $: modelNames = useModelFileNames($runtime.instanceId); + $: modelRoutes = useModelRoutes($runtime.instanceId); $: modelHasError = getFileHasErrors( queryClient, $runtime.instanceId, @@ -45,12 +48,12 @@ ); const handleDeleteModel = async (modelName: string) => { - if ($modelNames.data) { + if ($modelRoutes.data) { await deleteFileArtifact( $runtime.instanceId, - modelName, + getFileAPIPathFromNameAndType(modelName, EntityType.Model), EntityType.Model, - $modelNames.data, + $modelRoutes.data, ); } }; diff --git a/web-common/src/features/models/selectors.ts b/web-common/src/features/models/selectors.ts index 46295288fc4..aca313741e5 100644 --- a/web-common/src/features/models/selectors.ts +++ b/web-common/src/features/models/selectors.ts @@ -1,3 +1,4 @@ +import { getRouteFromName } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { useMainEntityFiles } from "@rilldata/web-common/features/entity-management/file-selectors"; import { ResourceKind, @@ -5,6 +6,7 @@ import { useFilteredResources, useResource, } from "@rilldata/web-common/features/entity-management/resource-selectors"; +import { EntityType } from "@rilldata/web-common/features/entity-management/types"; import { V1ListFilesResponse, createRuntimeServiceGetFile, @@ -31,6 +33,12 @@ export function useModelFileNames(instanceId: string) { return useMainEntityFiles(instanceId, "models"); } +export function useModelRoutes(instanceId: string) { + return useMainEntityFiles(instanceId, "models", (name) => + getRouteFromName(name, EntityType.Model), + ); +} + export function useModel(instanceId: string, name: string) { return useResource(instanceId, name, ResourceKind.Model); } diff --git a/web-common/src/features/models/workspace/ModelWorkspaceHeader.svelte b/web-common/src/features/models/workspace/ModelWorkspaceHeader.svelte index 0434792ab53..e825670d955 100644 --- a/web-common/src/features/models/workspace/ModelWorkspaceHeader.svelte +++ b/web-common/src/features/models/workspace/ModelWorkspaceHeader.svelte @@ -14,6 +14,7 @@ import { useGetDashboardsForModel } from "../../dashboards/selectors"; import { renameFileArtifact } from "../../entity-management/actions"; import { + getFileAPIPathFromNameAndType, getFilePathFromNameAndType, getRouteFromName, } from "../../entity-management/entity-mappers"; @@ -86,8 +87,8 @@ const entityType = EntityType.Model; await renameFileArtifact( runtimeInstanceId, - modelName, - toName, + getFileAPIPathFromNameAndType(modelName, entityType), + getFileAPIPathFromNameAndType(toName, entityType), entityType, ); await goto(getRouteFromName(toName, entityType), { @@ -114,7 +115,7 @@ - + {@const collapse = width < 800} { describe("should extract and sanitise table name", () => { for (const variation of TestCases) { it(variation.title, () => { - expect(sanitizeEntityName(extractTableName(variation.path))).toBe( + expect(sanitizeEntityName(extractFileName(variation.path))).toBe( variation.expectedFileName, ); }); diff --git a/web-common/src/features/sources/modal/file-upload.ts b/web-common/src/features/sources/modal/file-upload.ts index 735513178db..3312a0b679b 100644 --- a/web-common/src/features/sources/modal/file-upload.ts +++ b/web-common/src/features/sources/modal/file-upload.ts @@ -11,7 +11,7 @@ import { } from "@rilldata/web-common/features/sources/modal/possible-file-extensions"; import { importOverlayVisible } from "@rilldata/web-common/layout/overlay-store"; import { runtimeServiceFileUpload } from "@rilldata/web-common/runtime-client/manual-clients"; -import { getTableNameFromFile } from "../extract-table-name"; +import { getTableNameFromFile } from "web-common/src/features/sources/extract-file-name"; import { DuplicateActions, duplicateSourceAction, diff --git a/web-common/src/features/sources/navigation/SourceMenuItems.svelte b/web-common/src/features/sources/navigation/SourceMenuItems.svelte index 54c7cb029ad..2ed7713eb86 100644 --- a/web-common/src/features/sources/navigation/SourceMenuItems.svelte +++ b/web-common/src/features/sources/navigation/SourceMenuItems.svelte @@ -5,14 +5,17 @@ import Import from "@rilldata/web-common/components/icons/Import.svelte"; import Model from "@rilldata/web-common/components/icons/Model.svelte"; import RefreshIcon from "@rilldata/web-common/components/icons/RefreshIcon.svelte"; - import { getFilePathFromNameAndType } from "@rilldata/web-common/features/entity-management/entity-mappers"; + import { + getFileAPIPathFromNameAndType, + getFilePathFromNameAndType, + } from "@rilldata/web-common/features/entity-management/entity-mappers"; import { getFileHasErrors } from "@rilldata/web-common/features/entity-management/resources-store"; import { useModelFileNames } from "@rilldata/web-common/features/models/selectors"; import { useIsLocalFileConnector, useSource, - useSourceFileNames, useSourceFromYaml, + useSourceRoutes, } from "@rilldata/web-common/features/sources/selectors"; import { appScreen } from "@rilldata/web-common/layout/app-store"; import { overlay } from "@rilldata/web-common/layout/overlay-store"; @@ -66,7 +69,7 @@ $: sourceFromYaml = useSourceFromYaml($runtime.instanceId, filePath); - $: sourceNames = useSourceFileNames($runtime.instanceId); + $: sourceRoutes = useSourceRoutes($runtime.instanceId); $: modelNames = useModelFileNames($runtime.instanceId); $: createDashboardFromTable = useCreateDashboardFromTableUIAction( @@ -79,9 +82,9 @@ const handleDeleteSource = async (tableName: string) => { await deleteFileArtifact( runtimeInstanceId, - tableName, + getFileAPIPathFromNameAndType(tableName, EntityType.Table), EntityType.Table, - $sourceNames.data ?? [], + $sourceRoutes.data ?? [], ); }; diff --git a/web-common/src/features/sources/selectors.ts b/web-common/src/features/sources/selectors.ts index b6ec232199a..962ddd8f9d1 100644 --- a/web-common/src/features/sources/selectors.ts +++ b/web-common/src/features/sources/selectors.ts @@ -13,7 +13,10 @@ import { import type { CreateQueryResult, QueryClient } from "@tanstack/svelte-query"; import { Readable, derived } from "svelte/store"; import { parse } from "yaml"; -import { getFilePathFromNameAndType } from "../entity-management/entity-mappers"; +import { + getFilePathFromNameAndType, + getRouteFromName, +} from "../entity-management/entity-mappers"; import { EntityType } from "../entity-management/types"; export type SourceFromYaml = { @@ -34,6 +37,12 @@ export function useSourceFileNames(instanceId: string) { return useMainEntityFiles(instanceId, "sources"); } +export function useSourceRoutes(instanceId: string) { + return useMainEntityFiles(instanceId, "sources", (name) => + getRouteFromName(name, EntityType.Table), + ); +} + export function useSource(instanceId: string, name: string) { return useResource(instanceId, name, ResourceKind.Source); } diff --git a/web-common/src/features/sources/sourceUtils.ts b/web-common/src/features/sources/sourceUtils.ts index 915616d92e2..954e9b89108 100644 --- a/web-common/src/features/sources/sourceUtils.ts +++ b/web-common/src/features/sources/sourceUtils.ts @@ -4,7 +4,10 @@ import type { } from "@rilldata/web-common/runtime-client"; import { getFilePathFromNameAndType } from "../entity-management/entity-mappers"; import { EntityType } from "../entity-management/types"; -import { extractFileExtension, sanitizeEntityName } from "./extract-table-name"; +import { + extractFileExtension, + sanitizeEntityName, +} from "@rilldata/web-common/features/sources/extract-file-name"; export function compileCreateSourceYAML( values: Record, diff --git a/web-common/src/features/sources/workspace/SourceWorkspaceHeader.svelte b/web-common/src/features/sources/workspace/SourceWorkspaceHeader.svelte index 3fa05b0f4b3..ba6b241ba87 100644 --- a/web-common/src/features/sources/workspace/SourceWorkspaceHeader.svelte +++ b/web-common/src/features/sources/workspace/SourceWorkspaceHeader.svelte @@ -103,8 +103,8 @@ const entityType = EntityType.Table; await renameFileArtifact( runtimeInstanceId, - sourceName, - toName, + getFilePathFromNameAndType(sourceName, entityType), + getFilePathFromNameAndType(toName, entityType), entityType, ); goto(getRouteFromName(toName, entityType), { @@ -205,7 +205,7 @@ {/if} - +