From 802bd3b05d5000c19595f08a471a1cd2326594f9 Mon Sep 17 00:00:00 2001 From: tariku Date: Wed, 19 Nov 2025 08:49:57 -0500 Subject: [PATCH 1/2] fix: reopens files that were opened when dragging and dropping files or folders Signed-off-by: tariku --- .../ContentNavigator/ContentDataProvider.ts | 105 +++++++++++++++++- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/client/src/components/ContentNavigator/ContentDataProvider.ts b/client/src/components/ContentNavigator/ContentDataProvider.ts index edaaae8e2..fcc731aff 100644 --- a/client/src/components/ContentNavigator/ContentDataProvider.ts +++ b/client/src/components/ContentNavigator/ContentDataProvider.ts @@ -667,20 +667,117 @@ class ContentDataProvider if (!targetUri) { return false; } - const closing = closeFileIfOpen(item); - if (!(await closing)) { + const closedFiles = await closing; + if (!closedFiles) { return false; } const newUri = await this.model.moveTo(item, targetUri); - if (closing !== true) { - commands.executeCommand("vscode.open", newUri); + if (Array.isArray(closedFiles) && closedFiles.length > 0) { + // Reopen only the files that were closed + for (const closedFileUri of closedFiles) { + // Calculate the new URI for each closed file + const newFileUri = this.calculateNewFileUri( + closedFileUri, + item, + newUri, + ); + if (newFileUri) { + commands.executeCommand("vscode.open", newFileUri); + } + } } return !!newUri; } + private calculateNewFileUri( + closedFileUri: Uri, + movedItem: ContentItem, + newItemUri: boolean | Uri, + ): Uri | null { + if (typeof newItemUri === "boolean" || !newItemUri) { + return null; + } + + const isFolder = getIsContainer(movedItem); + + // If the moved item is a file and matches the closed file, return the new URI + if ( + !isFolder && + closedFileUri.toString() === movedItem.vscUri?.toString() + ) { + return newItemUri; + } + + // If the moved item is a folder, calculate the new path for files within it + if (isFolder && movedItem.vscUri) { + const extractPathFromUri = (uri: string): string => { + try { + const queryStart = uri.indexOf("?"); + if (queryStart === -1) { + return ""; + } + + const queryString = uri.substring(queryStart + 1); + + const decodedQuery = decodeURIComponent(queryString); + const idMatch = decodedQuery.match(/id=(.+)/); + if (!idMatch || !idMatch[1]) { + return ""; + } + const uriWithoutPrefix = idMatch[1].replace( + /\/compute\/sessions\/[a-zA-Z0-9-]*\/files\//, + "", + ); + try { + return decodeURIComponent(uriWithoutPrefix); + } catch { + return uriWithoutPrefix; + } + } catch { + return ""; + } + }; + + const oldBasePath = extractPathFromUri(movedItem.vscUri.toString()); + const closedFilePath = extractPathFromUri(closedFileUri.toString()); + + // Check if the closed file was inside the moved folder + if ( + oldBasePath && + closedFilePath && + closedFilePath.startsWith(oldBasePath + "~fs~") + ) { + try { + const relativePath = closedFilePath.substring(oldBasePath.length); + const filename = relativePath.replace(/^~fs~/, ""); + const newUriStr = newItemUri.toString(); + // Extract and modify the query to append the filename path + const queryMatch = newUriStr.match(/\?(.+)$/); + if (!queryMatch) { + return null; + } + + const decodedQuery = decodeURIComponent(queryMatch[1]); + const newQuery = decodedQuery.replace( + /(\/files\/[^&]*)/, + `$1~fs~${filename}`, + ); + + return Uri.parse( + `sasServer:/${filename}?${encodeURIComponent(newQuery)}`, + ); + } catch { + return null; + } + } + } + + return null; + } + private async handleContentItemDrop( target: ContentItem, item: ContentItem, From af2da9a983bb187b7cf3f5fd501d99fdc6b9d733 Mon Sep 17 00:00:00 2001 From: tariku Date: Fri, 21 Nov 2025 12:38:15 -0500 Subject: [PATCH 2/2] chore: refactor and print console.error on error Signed-off-by: tariku --- .../ContentNavigator/ContentDataProvider.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/client/src/components/ContentNavigator/ContentDataProvider.ts b/client/src/components/ContentNavigator/ContentDataProvider.ts index fcc731aff..e94368cec 100644 --- a/client/src/components/ContentNavigator/ContentDataProvider.ts +++ b/client/src/components/ContentNavigator/ContentDataProvider.ts @@ -60,6 +60,8 @@ import { isContainer as getIsContainer, } from "./utils"; +const SAS_FILE_SEPARATOR = "~fs~"; + class ContentDataProvider implements TreeDataProvider, @@ -684,7 +686,7 @@ class ContentDataProvider newUri, ); if (newFileUri) { - commands.executeCommand("vscode.open", newFileUri); + await commands.executeCommand("vscode.open", newFileUri); } } } @@ -733,10 +735,12 @@ class ContentDataProvider ); try { return decodeURIComponent(uriWithoutPrefix); - } catch { + } catch (error) { + console.error("Failed to decode URI component:", error); return uriWithoutPrefix; } - } catch { + } catch (error) { + console.error("Failed to extract path from URI:", error); return ""; } }; @@ -748,7 +752,7 @@ class ContentDataProvider if ( oldBasePath && closedFilePath && - closedFilePath.startsWith(oldBasePath + "~fs~") + closedFilePath.startsWith(oldBasePath + SAS_FILE_SEPARATOR) ) { try { const relativePath = closedFilePath.substring(oldBasePath.length); @@ -767,9 +771,10 @@ class ContentDataProvider ); return Uri.parse( - `sasServer:/${filename}?${encodeURIComponent(newQuery)}`, + `${newItemUri.scheme}:/${filename}?${encodeURIComponent(newQuery)}`, ); - } catch { + } catch (error) { + console.error("Failed to construct new file URI:", error); return null; } }