diff --git a/app/models/addon-operation-invocation.ts b/app/models/addon-operation-invocation.ts
index 8e90627ef8..c6369d8f75 100644
--- a/app/models/addon-operation-invocation.ts
+++ b/app/models/addon-operation-invocation.ts
@@ -16,15 +16,22 @@ export enum ItemType {
File = 'FILE',
}
-export interface OperationResult{
+export type OperationResult = ListItemsResult | Item;
+
+export interface ListItemsResult {
items: Item[];
- cursor?: string; // TODO: name??
+ thisSampleCursor?: string;
+ nextSampleCursor?: string;
+ prevSampleCursor?: string;
+ firstSampleCursor?: string;
+ totalCount?: number;
}
+
export interface Item {
itemId: string;
itemName: string;
itemType: ItemType;
- itemPath: string;
+ itemPath?: Item[];
}
export default class AddonOperationInvocationModel extends Model {
diff --git a/lib/osf-components/addon/components/addons-service/configured-addon-edit/template.hbs b/lib/osf-components/addon/components/addons-service/configured-addon-edit/template.hbs
index 754df62aeb..994b78c29f 100644
--- a/lib/osf-components/addon/components/addons-service/configured-addon-edit/template.hbs
+++ b/lib/osf-components/addon/components/addons-service/configured-addon-edit/template.hbs
@@ -27,23 +27,27 @@
as |fileManager|
>
- {{#each fileManager.currentPath as |pathItem index|}}
-
-
-
+
+ {{#each fileManager.currentPath as |pathItem|}}
+
{{/each}}
diff --git a/lib/osf-components/addon/components/addons-service/file-manager/component.ts b/lib/osf-components/addon/components/addons-service/file-manager/component.ts
index b00b283da4..28bafde02d 100644
--- a/lib/osf-components/addon/components/addons-service/file-manager/component.ts
+++ b/lib/osf-components/addon/components/addons-service/file-manager/component.ts
@@ -8,7 +8,7 @@ import { taskFor } from 'ember-concurrency-ts';
import IntlService from 'ember-intl/services/intl';
import Toast from 'ember-toastr/services/toast';
-import { Item } from 'ember-osf-web/models/addon-operation-invocation';
+import { Item, ListItemsResult } from 'ember-osf-web/models/addon-operation-invocation';
import ConfiguredStorageAddonModel, { OperationKwargs } from 'ember-osf-web/models/configured-storage-addon';
import captureException, { getApiErrorMessage } from 'ember-osf-web/utils/capture-exception';
@@ -24,9 +24,9 @@ export default class FileManager extends Component
{
@tracked currentPath: Item[] = [];
@tracked currentItems: Item[] = [];
- @tracked currentFolderId = this.args.startingFolderId;
+ @tracked currentFolderId?: string;
- @tracked cursor = '';
+ @tracked cursor?: string;
@tracked hasMore = false;
private lastInvocation: any = null;
@@ -43,22 +43,27 @@ export default class FileManager extends Component {
constructor(owner: unknown, args: Args) {
super(owner, args);
- taskFor(this.getStartingFolder).perform();
- taskFor(this.getItems).perform();
+ taskFor(this.initialize).perform();
}
+ @task
+ @waitFor
+ async initialize() {
+ await taskFor(this.getStartingFolder).perform();
+ await taskFor(this.getItems).perform();
+ }
@action
goToRoot() {
- this.cursor = '';
- this.currentPath = this.currentPath.slice(0, 1);
- this.currentFolderId = this.args.startingFolderId;
+ this.cursor = undefined;
+ this.currentPath = this.currentPath = [];
+ this.currentFolderId = undefined;
taskFor(this.getItems).perform();
}
@action
goToFolder(folder: Item) {
- this.cursor = '';
+ this.cursor = undefined;
this.currentItems = [];
if (this.currentPath.includes(folder)) {
this.currentPath = this.currentPath.slice(0, this.currentPath.indexOf(folder) + 1);
@@ -71,7 +76,7 @@ export default class FileManager extends Component {
@action
getMore() {
- this.cursor = this.lastInvocation?.operationResult.cursor;
+ this.cursor = this.lastInvocation?.operationResult.nextSampleCursor;
taskFor(this.getItems).perform();
}
@@ -81,8 +86,12 @@ export default class FileManager extends Component {
async getStartingFolder() {
const { startingFolderId, configuredStorageAddon } = this.args;
try {
- const invocation = await taskFor(configuredStorageAddon.getItemInfo).perform(startingFolderId);
- this.currentPath = [invocation.operationResult];
+ if (startingFolderId) {
+ const invocation = await taskFor(configuredStorageAddon.getItemInfo).perform(startingFolderId);
+ const result = invocation.operationResult as Item;
+ this.currentFolderId = result.itemId;
+ this.currentPath = result.itemPath ? [...result.itemPath] : [];
+ }
} catch (e) {
captureException(e);
const errorMessage = this.intl.t('osf-components.addons-service.file-manager.get-item-error');
@@ -98,16 +107,15 @@ export default class FileManager extends Component {
kwargs.itemId = this.currentFolderId;
kwargs.pageCursor = this.cursor;
try {
- let invocation;
+ const getFolderArgs = !this.currentFolderId ? {} : kwargs;
+ const invocation = await taskFor(this.args.configuredStorageAddon.getFolderItems).perform(getFolderArgs);
+ this.lastInvocation = invocation;
+ const operationResult = invocation.operationResult as ListItemsResult;
if (!this.currentFolderId) {
- invocation = await taskFor(this.args.configuredStorageAddon.getFolderItems).perform();
- } else {
- invocation = await taskFor(this.args.configuredStorageAddon.getFolderItems).perform(kwargs);
+ this.currentFolderId = operationResult.items[0].itemId;
}
- this.lastInvocation = invocation;
- const { operationResult } = invocation;
this.currentItems = this.cursor ? [...this.currentItems, ...operationResult.items] : operationResult.items;
- this.hasMore = Boolean(invocation.operationResult.cursor);
+ this.hasMore = Boolean(operationResult.nextSampleCursor);
} catch (e) {
captureException(e);
const errorMessage = this.intl.t('osf-components.addons-service.file-manager.get-items-error');
diff --git a/mirage/views/addons.ts b/mirage/views/addons.ts
index bc087aca79..5a1e2019f1 100644
--- a/mirage/views/addons.ts
+++ b/mirage/views/addons.ts
@@ -260,20 +260,23 @@ export function createAddonOperationInvocation(this: HandlerContext, schema: Sch
const invocation = schema.addonOperationInvocations.create(attrs) as ModelInstance;
let result: any = null;
const folderId = kwargs.item_id || 'root';
+ const item_type = kwargs.item_type || ItemType.Folder;
+ const fakePath = folderId.split('-')
+ .map((folder: string) => ({ item_id: folder, item_name: folder, item_type: ItemType.Folder }));
if (attrs.operationName === ConnectedOperationNames.GetItemInfo) {
result = {
item_id: folderId,
- item_name: `Item with ID ${folderId}`,
- item_type: kwargs.item_type || ItemType.Folder,
- item_path: folderId,
+ item_name: `Folder with ID ${folderId}`,
+ item_type,
+ item_path: folderId === 'root' ? undefined : fakePath,
};
} else {
result = {
items: '12345'.split('').map(i => ({
item_id: `${folderId}-${i}`,
- item_name: `${kwargs.item_type}${i} in ${folderId}`,
- item_type: kwargs.item_type,
- item_path: folderId,
+ item_name: `${item_type}${i} in ${folderId}`,
+ item_type,
+ item_path: folderId === 'root' ? undefined : fakePath,
})),
};
}
diff --git a/tests/acceptance/guid-node/addons-test.ts b/tests/acceptance/guid-node/addons-test.ts
index 40a5130fd7..cab1372d25 100644
--- a/tests/acceptance/guid-node/addons-test.ts
+++ b/tests/acceptance/guid-node/addons-test.ts
@@ -192,6 +192,7 @@ module('Acceptance | guid-node/addons', hooks => {
assert.dom('[data-test-display-name-input]').exists('Name input is present');
assert.dom('[data-test-display-name-input]')
.hasValue(s3AccountsDisplayNamesAndRootFolders[0].displayName, 'Name input has correct value');
+ assert.dom('[data-test-go-to-root]').exists('Go to root button is present');
assert.dom('[data-test-folder-path-option]').exists({ count: 1 }, 'Folder path shown');
assert.dom('[data-test-root-folder-save]').isEnabled('Save button is enabled when name is present');
assert.dom('[data-test-root-folder-cancel]').exists('Cancel button is present');
@@ -223,7 +224,7 @@ module('Acceptance | guid-node/addons', hooks => {
const firstRootFolder = document.querySelectorAll('[data-test-configured-addon-root-folder]')[0];
assert.dom(firstDisplayName)
.containsText('New S3 Account Display Name', 'Display name change is saved');
- assert.dom(firstRootFolder).containsText('s3root-1-1', 'Root folder change is saved');
+ assert.dom(firstRootFolder).containsText('root-1-1', 'Root folder change is saved');
// Remove other account
await click('[data-test-remove-connected-location]:last-child');
diff --git a/translations/en-us.yml b/translations/en-us.yml
index 38ed2c0fd5..3240b3719f 100644
--- a/translations/en-us.yml
+++ b/translations/en-us.yml
@@ -64,6 +64,7 @@ general:
hosted_on_the_osf: 'Hosted on OSF'
last_modified: 'Last modified'
loading: Loading...
+ load_more: 'Load more'
md5: MD5
modified: Modified
more: more
@@ -351,6 +352,7 @@ addons:
configure:
heading: 'Configure {providerName}'
display-name: 'Display name'
+ go-to-root: 'Go to home folder'
go-to-folder: 'Go to folder {folderName}'
select-folder: 'Select {folderName} as root folder'
table-headings: