Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENG-6346] Update logic to set initial folder id in file manager #2356

13 changes: 10 additions & 3 deletions app/models/addon-operation-invocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,27 @@
as |fileManager|
>
<div local-class='current-path'>
{{#each fileManager.currentPath as |pathItem index|}}
<span>
<Button
data-test-folder-path-option='{{pathItem.itemName}}'
data-analytics-name='Go to ancestor folder'
@layout='fake-link'
aria-label={{t 'addons.configure.go-to-folder' folderName=pathItem.itemName}}
{{on 'click' (fn fileManager.goToFolder pathItem)}}
>
{{#if (eq index 0)}}
<FaIcon @icon='home' />
{{else}}
<FaIcon @icon='chevron-right' />
{{/if}}
{{pathItem.itemName}}
</Button>
</span>
<Button
data-test-go-to-root
data-analytics-name='Go to root folder'
@layout='fake-link'
aria-label={{t 'addons.configure.go-to-root'}}
{{on 'click' fileManager.goToRoot}}
>
<FaIcon @icon='home' />
{{t 'general.home'}}
</Button>
{{#each fileManager.currentPath as |pathItem|}}
<Button
data-test-folder-path-option='{{pathItem.itemName}}'
data-analytics-name='Go to ancestor folder'
@layout='fake-link'
aria-label={{t 'addons.configure.go-to-folder' folderName=pathItem.itemName}}
{{on 'click' (fn fileManager.goToFolder pathItem)}}
>
<FaIcon @icon='chevron-right' />
{{pathItem.itemName}}
</Button>
{{/each}}
</div>
<table local-class='file-tree-table'>
Expand All @@ -54,43 +58,59 @@
</tr>
</thead>
<tbody local-class='table-body'>
{{#each fileManager.currentItems as |folder|}}
<tr>
<td>
<Button
data-test-folder-link='{{folder.itemName}}'
data-analytics-name='Go to folder'
@layout='fake-link'
aria-label={{t 'addons.configure.go-to-folder' folderName=folder.itemName}}
{{on 'click' (fn fileManager.goToFolder folder)}}
>
<FaIcon @icon='folder' />
{{folder.itemName}}
</Button>
</td>
<td>
<input
data-test-root-folder-option='{{folder.itemName}}'
data-analytics-name='Select folder'
type='radio'
name='folder'
value={{folder.itemName}}
aria-label={{t 'addons.configure.select-folder' folderName=folder.itemName}}
{{on 'change'(fn this.selectFolder folder)}}
>
</td>
</tr>
{{else if fileManager.isLoading}}
{{#if fileManager.isLoading}}
<LoadingIndicator @dark={{true}} />
{{else if fileManager.isError}}
<tr>
<td colspan='2'>{{t 'addons.configure.error-loading-items'}}</td>
</tr>
{{else}}
<tr>
<td colspan='2'>{{t 'addons.configure.no-folders'}}</td>
</tr>
{{/each}}
{{#each fileManager.currentItems as |folder|}}
<tr>
<td>
<Button
data-test-folder-link='{{folder.itemName}}'
data-analytics-name='Go to folder'
@layout='fake-link'
aria-label={{t 'addons.configure.go-to-folder' folderName=folder.itemName}}
{{on 'click' (fn fileManager.goToFolder folder)}}
>
<FaIcon @icon='folder' />
{{folder.itemName}}
</Button>
</td>
<td>
<input
data-test-root-folder-option='{{folder.itemName}}'
data-analytics-name='Select folder'
type='radio'
name='folder'
value={{folder.itemName}}
aria-label={{t 'addons.configure.select-folder' folderName=folder.itemName}}
{{on 'change'(fn this.selectFolder folder)}}
>
</td>
</tr>
{{else}}
<tr>
<td colspan='2'>{{t 'addons.configure.no-folders'}}</td>
</tr>
{{/each}}
{{#if fileManager.hasMore}}
<tr>
<td colspan='2'>
<Button
data-test-load-more-folders
data-analytics-name='Load more folders'
@layout='fake-link'
{{on 'click' fileManager.getMore}}
>
{{t 'general.load_more'}}
</Button>
</td>
</tr>
{{/if}}
{{/if}}
</tbody>
</table>
<div local-class='footer-buttons-wrapper'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -24,9 +24,9 @@ export default class FileManager extends Component<Args> {

@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;
Expand All @@ -43,22 +43,27 @@ export default class FileManager extends Component<Args> {

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);
Expand All @@ -71,7 +76,7 @@ export default class FileManager extends Component<Args> {

@action
getMore() {
this.cursor = this.lastInvocation?.operationResult.cursor;
this.cursor = this.lastInvocation?.operationResult.nextSampleCursor;
taskFor(this.getItems).perform();
}

Expand All @@ -81,8 +86,12 @@ export default class FileManager extends Component<Args> {
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');
Expand All @@ -98,16 +107,15 @@ export default class FileManager extends Component<Args> {
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');
Expand Down
15 changes: 9 additions & 6 deletions mirage/views/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,20 +260,23 @@ export function createAddonOperationInvocation(this: HandlerContext, schema: Sch
const invocation = schema.addonOperationInvocations.create(attrs) as ModelInstance<MirageAddonOperationInvocation>;
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,
})),
};
}
Expand Down
3 changes: 2 additions & 1 deletion tests/acceptance/guid-node/addons-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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');
Expand Down
2 changes: 2 additions & 0 deletions translations/en-us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
Loading