Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 12 additions & 5 deletions src/renderer/actions/local-sync/common-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ export function isNewEntityName(name: string, baseString: string): boolean {
const escapedBase = baseString.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

// Pattern: exact match OR base string followed by one or more digits
const pattern = new RegExp(`^${escapedBase}(\\d+)?$`);
// Case-insensitive to align with case-insensitive filesystems (macOS/Windows)
const pattern = new RegExp(`^${escapedBase}(\\d+)?$`, 'i');

return pattern.test(name);
}
Expand All @@ -358,17 +359,23 @@ export function isNewEntityName(name: string, baseString: string): boolean {
* @returns The next available name variant (e.g., 'Untitled1', 'Untitled2')
*/
export function getAlternateName(baseName: string, existingNames: Set<string>): string {
if(!existingNames.has(baseName)) {
// Treat existing names in a case-insensitive way to avoid clashes on
// case-insensitive filesystems while preserving the original casing
const lowerExisting = new Set(Array.from(existingNames).map((n) => n.toLowerCase()));
const baseLower = baseName.toLowerCase();

if (!lowerExisting.has(baseLower)) {
return baseName;
}

let counter = 1;
let candidateName = `${baseName}${counter}`;
while (existingNames.has(candidateName)) {

while (lowerExisting.has(candidateName.toLowerCase())) {
counter++;
candidateName = `${baseName}${counter}`;
}

return candidateName;
}

Expand Down
37 changes: 16 additions & 21 deletions src/renderer/actions/local-sync/fs-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -787,10 +787,11 @@ export class FsManager {
id: collectionId || getIdFromPath(this.rootPath),
type: "folder",
});
const sanitizedName = sanitizeFsResourceName(content.name);

const newName = getNewNameIfQuickCreate({
name: sanitizeFsResourceName(content.name),
baseName: "Untitled request",
name: sanitizedName,
baseName: sanitizedName,
parentPath: getNormalizedPath(parentFolderResource.path),
});

Expand Down Expand Up @@ -1302,16 +1303,10 @@ export class FsManager {
return folderCreationResult;
}

let newName = getNewNameIfQuickCreate({
name: sanitizeFsResourceName(environmentName),
baseName: "New Environment",
parentPath: getNormalizedPath(environmentFolderPath),
});

// re-used to handle name conflicts by appending a number when an environment with the same name already exists during import
newName = getNewNameIfQuickCreate({
name: sanitizeFsResourceName(environmentName),
baseName: sanitizeFsResourceName(environmentName),
const sanitizedEnvName = sanitizeFsResourceName(environmentName);
const newName = getNewNameIfQuickCreate({
name: sanitizedEnvName,
baseName: sanitizedEnvName,
parentPath: getNormalizedPath(environmentFolderPath),
});

Expand Down Expand Up @@ -1487,16 +1482,16 @@ export class FsManager {
throw new Error(`Could not find path for id ${collection.collectionId}`);
}

//Figure out an alternate name only for the root collection being imported
if (!collection.collectionId.length) {
const newName = getNewNameIfQuickCreate({
name: sanitizeFsResourceName(collection.name),
baseName: collection.name,
parentPath: getNormalizedPath(parentPath),
});
const sanitizedName = sanitizeFsResourceName(collection.name);

collection.name = newName;
}
// Handle name conflicts for imported/duplicated collections (root and nested)
const newName = getNewNameIfQuickCreate({
name: sanitizedName,
baseName: sanitizedName,
parentPath: getNormalizedPath(parentPath),
});

collection.name = newName;

const path = appendPath(
parentPath,
Expand Down