Skip to content

Commit bd38a35

Browse files
Scott DoverScott Dover
authored andcommitted
chore: implement move/paginate results/add error checking
Signed-off-by: Scott Dover <[email protected]>
1 parent fc69f56 commit bd38a35

File tree

2 files changed

+105
-25
lines changed

2 files changed

+105
-25
lines changed

client/src/components/ContentNavigator/ContentDataProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ class ContentDataProvider
502502
): Promise<void> {
503503
let success = false;
504504
let message = Messages.FileDropError;
505-
if (item.flags.isInRecycleBin) {
505+
if (item.flags?.isInRecycleBin) {
506506
message = Messages.FileDragFromTrashError;
507507
} else if (item.isReference) {
508508
message = Messages.FileDragFromFavorites;

client/src/connection/rest/RestSASServerAdapter.ts

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,31 @@ class RestSASServerAdapter implements ContentAdapter {
5454
await session.setup(true);
5555

5656
this.sessionId = session?.sessionId();
57-
this.fileSystemApi = FileSystemApi(getApiConfig());
57+
// This proxies all calls to the fileSystem api to reconnect
58+
// if we ever get a 401 (unauthorized)
59+
this.fileSystemApi = new Proxy(FileSystemApi(getApiConfig()), {
60+
get: function (target, property) {
61+
if (typeof target[property] === "function") {
62+
return new Proxy(target[property], {
63+
apply: async function (target, _this, argList) {
64+
try {
65+
return await target(...argList);
66+
} catch (error) {
67+
if (error.response?.status !== 401) {
68+
throw error;
69+
}
70+
71+
await this.connect();
72+
73+
return await target(...argList);
74+
}
75+
},
76+
});
77+
}
78+
79+
return target[property];
80+
},
81+
});
5882
}
5983

6084
public connected(): boolean {
@@ -155,18 +179,42 @@ class RestSASServerAdapter implements ContentAdapter {
155179
];
156180
}
157181

158-
const { data } = await this.fileSystemApi.getDirectoryMembers({
159-
sessionId: this.sessionId,
160-
directoryPath: this.trimComputePrefix(
161-
getLink(parentItem.links, "GET", "getDirectoryMembers").uri,
162-
).replace("/members", ""),
163-
});
182+
const allItems = [];
183+
const limit = 100;
184+
let start = 0;
185+
let totalItemCount = 0;
186+
do {
187+
const response = await this.fileSystemApi.getDirectoryMembers({
188+
sessionId: this.sessionId,
189+
directoryPath: this.trimComputePrefix(
190+
getLink(parentItem.links, "GET", "getDirectoryMembers").uri,
191+
).replace("/members", ""),
192+
limit,
193+
start,
194+
});
195+
totalItemCount = response.data.count;
164196

165-
// TODO (sas-server) We need to paginate and sort results
166-
return data.items.map((childItem: FileProperties, index) => ({
167-
...this.filePropertiesToContentItem(childItem),
168-
uid: `${parentItem.uid}/${index}`,
169-
}));
197+
allItems.push(
198+
...response.data.items.map((childItem: FileProperties, index) => ({
199+
...this.filePropertiesToContentItem(childItem),
200+
uid: `${parentItem.uid}/${index + start}`,
201+
})),
202+
);
203+
204+
start += limit;
205+
} while (start < totalItemCount);
206+
207+
return allItems.sort((a, b) => {
208+
const aIsDirectory = a.fileStat?.type === FileType.Directory;
209+
const bIsDirectory = b.fileStat?.type === FileType.Directory;
210+
if (aIsDirectory && !bIsDirectory) {
211+
return -1;
212+
} else if (!aIsDirectory && bIsDirectory) {
213+
return 1;
214+
} else {
215+
return a.name.localeCompare(b.name);
216+
}
217+
});
170218
}
171219

172220
public async getContentOfItem(item: ContentItem): Promise<string> {
@@ -204,14 +252,15 @@ class RestSASServerAdapter implements ContentAdapter {
204252
}
205253

206254
public async getItemOfUri(uri: Uri): Promise<ContentItem> {
207-
const resourceId = getResourceId(uri);
208-
209-
const { data } = await this.fileSystemApi.getFileorDirectoryProperties({
255+
const fileOrDirectoryPath = this.trimComputePrefix(getResourceId(uri));
256+
const response = await this.fileSystemApi.getFileorDirectoryProperties({
210257
sessionId: this.sessionId,
211-
fileOrDirectoryPath: this.trimComputePrefix(resourceId),
258+
fileOrDirectoryPath,
212259
});
213260

214-
return this.filePropertiesToContentItem(data);
261+
this.updateFileMetadata(fileOrDirectoryPath, response);
262+
263+
return this.filePropertiesToContentItem(response.data);
215264
}
216265

217266
public async getParentOfItem(
@@ -262,7 +311,25 @@ class RestSASServerAdapter implements ContentAdapter {
262311
item: ContentItem,
263312
targetParentFolderUri: string,
264313
): Promise<boolean> {
265-
throw new Error("Method not implemented.");
314+
const currentFilePath = this.trimComputePrefix(item.uri);
315+
const newFilePath = this.trimComputePrefix(targetParentFolderUri);
316+
const { etag } = await this.getFileInfo(currentFilePath);
317+
const params = {
318+
sessionId: this.sessionId,
319+
fileOrDirectoryPath: currentFilePath,
320+
ifMatch: etag,
321+
fileProperties: {
322+
name: item.name,
323+
path: newFilePath.split("~fs~").join("/"),
324+
},
325+
};
326+
327+
const response =
328+
await this.fileSystemApi.updateFileOrDirectoryOnSystem(params);
329+
delete this.fileMetadataMap[currentFilePath];
330+
this.updateFileMetadata(newFilePath, response);
331+
332+
return !!this.filePropertiesToContentItem(response.data);
266333
}
267334

268335
public async recycleItem(
@@ -285,7 +352,6 @@ class RestSASServerAdapter implements ContentAdapter {
285352
): Promise<ContentItem | undefined> {
286353
const filePath = this.trimComputePrefix(item.uri);
287354

288-
const isDirectory = item.fileStat?.type === FileType.Directory;
289355
const parsedFilePath = filePath.split("~fs~");
290356
parsedFilePath.pop();
291357
const path = parsedFilePath.join("/");
@@ -294,7 +360,7 @@ class RestSASServerAdapter implements ContentAdapter {
294360
sessionId: this.sessionId,
295361
fileOrDirectoryPath: filePath,
296362
ifMatch: "",
297-
fileProperties: { name: newName, path, isDirectory },
363+
fileProperties: { name: newName, path },
298364
});
299365

300366
this.updateFileMetadata(filePath, response);
@@ -308,7 +374,7 @@ class RestSASServerAdapter implements ContentAdapter {
308374

309375
public async updateContentOfItem(uri: Uri, content: string): Promise<void> {
310376
const filePath = this.trimComputePrefix(getResourceId(uri));
311-
const { etag } = this.getFileInfo(filePath);
377+
const { etag } = await this.getFileInfo(filePath);
312378

313379
const response = await this.fileSystemApi.updateFileContentOnSystem({
314380
sessionId: this.sessionId,
@@ -388,12 +454,26 @@ class RestSASServerAdapter implements ContentAdapter {
388454
this.fileMetadataMap[id] = {
389455
etag: headers.etag,
390456
};
457+
458+
return this.fileMetadataMap[id];
391459
}
392460

393-
private getFileInfo(resourceId: string) {
394-
if (resourceId in this.fileMetadataMap) {
395-
return this.fileMetadataMap[resourceId];
461+
private async getFileInfo(path: string) {
462+
if (path in this.fileMetadataMap) {
463+
return this.fileMetadataMap[path];
396464
}
465+
466+
// If we don't have file metadata stored, lets attempt to fetch it
467+
try {
468+
const response = await this.fileSystemApi.getFileorDirectoryProperties({
469+
sessionId: this.sessionId,
470+
fileOrDirectoryPath: path,
471+
});
472+
return this.updateFileMetadata(path, response);
473+
} catch (e) {
474+
// Intentionally blank
475+
}
476+
397477
return {
398478
etag: "",
399479
};

0 commit comments

Comments
 (0)