Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 101 additions & 4 deletions client/src/components/ContentNavigator/ContentDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With drag and drop, at the moment, we call moveItem for each item dragged, and we call closeFileIfOpen for one item. And, newUri should be returned after the item is moved.

Is there an issue where the newUri is wrong? If that's the case, this should be happening at the model level

// 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\//,
"",
);
Comment on lines +732 to +735
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern /\/compute\/sessions\/[a-zA-Z0-9-]*\/files\// appears to be hardcoded for a specific URI structure. This makes the code brittle and dependent on a particular URI format. Consider extracting this pattern as a constant with documentation explaining the expected URI structure, or making it more flexible to handle variations in the URI structure.

Copilot uses AI. Check for mistakes.
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,
Expand Down
Loading