Skip to content

Commit b5d6ec7

Browse files
committed
feat: add workspace name support for WebDAV connections and improve directory resource handling
1 parent 6c566a9 commit b5d6ec7

3 files changed

Lines changed: 63 additions & 12 deletions

File tree

packages/extension-webdav/src/webdav-client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export interface WebDAVConnectionInfo {
22
url: string;
33
username?: string;
44
password?: string;
5+
/** Workspace root label (composite path prefix); defaults to webdav1, webdav2, … */
6+
name?: string;
57
}
68

79
export interface WebDAVResource {

packages/extension-webdav/src/webdav-extension.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,41 @@ import { LyraWebDAVConnect } from "./webdav-connect";
3333
// Import commands (registers themselves)
3434
import './webdav-commands';
3535

36+
async function getNextWebdavWorkspaceName(): Promise<string> {
37+
const folders = await workspaceService.getFolders();
38+
const used = new Set(folders.filter((f) => f.type === 'webdav').map((f) => f.name));
39+
let n = 1;
40+
while (used.has(`webdav${n}`)) {
41+
n += 1;
42+
}
43+
return `webdav${n}`;
44+
}
45+
3646
// Register WebDAV as a workspace contribution
3747
workspaceService.registerContribution({
3848
type: 'webdav',
3949
name: 'webdav',
40-
50+
4151
canHandle(input: any): boolean {
4252
// Accept any connection info with a URL (credentials are optional for public/shared folders)
4353
return input && typeof input === 'object' && 'url' in input && typeof input.url === 'string';
4454
},
45-
55+
4656
async connect(input: WebDAVConnectionInfo) {
57+
const name =
58+
typeof input.name === 'string' && input.name.trim().length > 0
59+
? input.name.trim()
60+
: await getNextWebdavWorkspaceName();
4761
const client = new WebDAVClient(input);
4862
const rootResource: WebDAVResource = {
4963
href: input.url,
5064
displayName: extractWorkspaceNameFromUrl(input.url),
5165
isDirectory: true
5266
};
53-
return new WebDAVDirectoryResource(client, rootResource, undefined, input);
67+
return new WebDAVDirectoryResource(client, rootResource, undefined, { ...input, name });
5468
},
55-
56-
async restore(data: WebDAVConnectionInfo) {
69+
70+
async restore(data: WebDAVConnectionInfo & { name?: string }) {
5771
if (!data || !data.url) {
5872
return undefined;
5973
}
@@ -64,20 +78,24 @@ workspaceService.registerContribution({
6478
username: data.username,
6579
password: data.password ? decodePassword(data.password) : undefined
6680
};
81+
const name =
82+
typeof data.name === 'string' && data.name.trim().length > 0
83+
? data.name.trim()
84+
: await getNextWebdavWorkspaceName();
6785

6886
const client = new WebDAVClient(restored);
6987
const rootResource: WebDAVResource = {
7088
href: data.url,
7189
displayName: extractWorkspaceNameFromUrl(data.url),
7290
isDirectory: true
7391
};
74-
return new WebDAVDirectoryResource(client, rootResource, undefined, restored);
92+
return new WebDAVDirectoryResource(client, rootResource, undefined, { ...restored, name });
7593
} catch (error) {
7694
logger.error('Failed to restore WebDAV workspace:', error);
7795
return undefined;
7896
}
7997
},
80-
98+
8199
async persist(workspace) {
82100
if (workspace instanceof WebDAVDirectoryResource) {
83101
const connectionInfo = workspace.getConnectionInfo();
@@ -87,6 +105,7 @@ workspaceService.registerContribution({
87105

88106
return {
89107
url: connectionInfo.url,
108+
name: workspace.getName(),
90109
...(connectionInfo.username !== undefined ? { username: connectionInfo.username } : {}),
91110
...(connectionInfo.password !== undefined ? { password: encodePassword(connectionInfo.password) } : {})
92111
};

packages/extension-webdav/src/webdav-filesys.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,26 @@ export class WebDAVDirectoryResource extends Directory {
9595
private parent?: Directory;
9696
private children?: Map<string, Resource>;
9797
private connectionInfo?: WebDAVConnectionInfo;
98+
/** Workspace root label only; nested dirs use {@link WebDAVResource.displayName}. */
99+
private rootFolderDisplayName?: string;
98100

99101
constructor(client: WebDAVClient, resource: WebDAVResource, parent?: Directory, connectionInfo?: WebDAVConnectionInfo) {
100102
super();
101103
this.client = client;
102104
this.resource = resource;
103105
this.parent = parent;
104106
this.connectionInfo = connectionInfo;
107+
if (!parent) {
108+
const n = connectionInfo?.name?.trim();
109+
this.rootFolderDisplayName =
110+
n && n.length > 0 ? n : extractLeafNameFromUrl(connectionInfo?.url ?? resource.href);
111+
}
105112
}
106113

107114
getName(): string {
115+
if (this.rootFolderDisplayName !== undefined) {
116+
return this.rootFolderDisplayName;
117+
}
108118
return this.resource.displayName;
109119
}
110120

@@ -219,18 +229,28 @@ export class WebDAVDirectoryResource extends Directory {
219229
}
220230

221231
async rename(newName: string): Promise<void> {
222-
if (this.getName() === newName) {
232+
const trimmed = String(newName ?? '').trim();
233+
if (!trimmed || this.getName() === trimmed) {
234+
return;
235+
}
236+
237+
if (!this.parent) {
238+
this.rootFolderDisplayName = trimmed;
239+
if (this.connectionInfo) {
240+
this.connectionInfo = { ...this.connectionInfo, name: trimmed };
241+
}
242+
await workspaceService.updateFolderName(this, trimmed);
223243
return;
224244
}
225245

226246
const pathParts = this.resource.href.split('/').filter(Boolean);
227-
pathParts[pathParts.length - 1] = newName;
247+
pathParts[pathParts.length - 1] = trimmed;
228248
const newPath = '/' + pathParts.join('/') + '/';
229-
249+
230250
await this.client.moveResource(this.resource.href, newPath);
231251
this.resource.href = newPath;
232-
this.resource.displayName = newName;
233-
252+
this.resource.displayName = trimmed;
253+
234254
publish(TOPIC_WORKSPACE_CHANGED, workspaceService.getWorkspaceSync() ?? this.getWorkspace());
235255
}
236256

@@ -263,3 +283,13 @@ export class WebDAVDirectoryResource extends Directory {
263283
}
264284
}
265285

286+
function extractLeafNameFromUrl(url: string): string {
287+
try {
288+
const urlObj = new URL(url);
289+
const pathParts = urlObj.pathname.split('/').filter(Boolean);
290+
return pathParts[pathParts.length - 1] || 'workspace';
291+
} catch {
292+
return 'workspace';
293+
}
294+
}
295+

0 commit comments

Comments
 (0)