Skip to content

Commit

Permalink
[WIP] first stab at Boa addon ux
Browse files Browse the repository at this point in the history
 * make boa modal findable
 * save WIP on dataset select
 * futa wisdom attained/accepted
 * add action; fetch parents properly
 * enabled addons enabled
 * cleanups; fix closemodal
  • Loading branch information
felliott committed Nov 1, 2023
1 parent 21c4f2c commit f5d1b93
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/guid-file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default class GuidFile extends Route {
};
this.set('headTags', this.metaTags.getHeadTags(metaTagsData));
this.headTagsService.collectHeadTags();
await taskFor(model.target.get('getEnabledAddons')).perform();
blocker.done();
}

Expand Down
7 changes: 6 additions & 1 deletion app/guid-file/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
({{t 'general.version'}}: {{this.viewedVersion}})
{{/if}}
</h2>
<FileActionsMenu @item={{this.model}} @onDelete={{this.onDelete}} @allowRename={{false}} />
<FileActionsMenu
@item={{this.model}}
@onDelete={{this.onDelete}}
@allowRename={{false}}
@addonsEnabled={{this.model.fileModel.target.addonsEnabled}}
/>
</div>
</:header>
<:body>
Expand Down
1 change: 1 addition & 0 deletions app/guid-node/files/provider/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class GuidNodeFilesProviderRoute extends Route.extend({}) {
@waitFor
async fileProviderTask(guidRouteModel: GuidRouteModel<NodeModel>, fileProviderId: string) {
const node = await guidRouteModel.taskInstance;
await taskFor(node.getEnabledAddons).perform();
try {
const fileProviders = await node.queryHasMany(
'files',
Expand Down
27 changes: 27 additions & 0 deletions app/models/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { htmlSafe } from '@ember/template';
import { buildValidations, validator } from 'ember-cp-validations';
import Intl from 'ember-intl/services/intl';

import fetch from 'fetch';
import config from 'ember-osf-web/config/environment';
import { task } from 'ember-concurrency';
import { waitFor } from '@ember/test-waiters';

import getRelatedHref from 'ember-osf-web/utils/get-related-href';

import AbstractNodeModel from 'ember-osf-web/models/abstract-node';
Expand All @@ -25,6 +30,13 @@ import RegistrationModel from './registration';
import SubjectModel from './subject';
import WikiModel from './wiki';

const {
OSF: {
apiUrl,
apiNamespace,
},
} = config;

const Validations = buildValidations({
title: [
validator('presence', true),
Expand Down Expand Up @@ -107,6 +119,7 @@ export default class NodeModel extends AbstractNodeModel.extend(Validations, Col
@attr('boolean') preprint!: boolean;
@attr('boolean') currentUserCanComment!: boolean;
@attr('boolean') wikiEnabled!: boolean;
@attr('fixstringarray') addonsEnabled!: string[];

@hasMany('contributor', { inverse: 'node' })
contributors!: AsyncHasMany<ContributorModel> & ContributorModel[];
Expand Down Expand Up @@ -311,6 +324,20 @@ export default class NodeModel extends AbstractNodeModel.extend(Validations, Col

this.set('nodeLicense', props);
}

@task
@waitFor
async getEnabledAddons() {
const endpoint = `${apiUrl}/${apiNamespace}/nodes/${this.id}/addons/`;
const response = await fetch(endpoint);
if (response.status === 200) {
const addons = await response.json();
const addonList = addons.data
.filter(addon => addon.attributes.node_has_auth)
.map(addon => addon.id);
this.set('addonsEnabled', addonList);
}
}
}

declare module 'ember-data/types/registries/model' {
Expand Down
8 changes: 8 additions & 0 deletions app/packages/files/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ export default abstract class File {
);
}

get isBoaFile() {
return this.fileModel.name.endsWith('.boa');
}

get providerIsOsfstorage() {
return this.fileModel.provider === 'osfstorage';
}

async createFolder(newFolderName: string) {
if (this.fileModel.isFolder) {
await this.fileModel.createFolder(newFolderName);
Expand Down
16 changes: 16 additions & 0 deletions lib/osf-components/addon/components/file-actions-menu/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface Args {
item: File;
onDelete: () => void;
manager?: StorageManager; // No manager for file-detail page
addonsEnabled? : string[];
}

export default class FileActionsMenu extends Component<Args> {
Expand All @@ -19,6 +20,7 @@ export default class FileActionsMenu extends Component<Args> {
@tracked moveModalOpen = false;
@tracked useCopyModal = false;
@tracked renameModalOpen = false;
@tracked isSubmitToBoaModalOpen = false;

@action
closeDeleteModal() {
Expand All @@ -34,4 +36,18 @@ export default class FileActionsMenu extends Component<Args> {
openRenameModal() {
this.renameModalOpen = true;
}

@action
closeSubmitToBoaModal() {
this.isSubmitToBoaModalOpen = false;
}

@action
openSubmitToBoaModal() {
this.isSubmitToBoaModalOpen = true;
}

get isBoaEnabled() {
return this.args.addonsEnabled.includes('boa');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { inject as service } from '@ember/service';
import { waitFor } from '@ember/test-waiters';
import Component from '@glimmer/component';
import { task } from 'ember-concurrency';
import IntlService from 'ember-intl/services/intl';
import File from 'ember-osf-web/packages/files/file';
import captureException, { getApiErrorMessage } from 'ember-osf-web/utils/capture-exception';
import config from 'ember-osf-web/config/environment';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

interface Args {
file: File;
isOpen: boolean;
closeModal: () => {};
}

export default class SubmitToBoaModal extends Component<Args> {
@service toast!: Toastr;
@service intl!: IntlService;
datasets?: string[];
@tracked selectedDataset?: string;

datasets = [
'2022 Jan/Java',
'2022 Feb/Python',
'2021 Method Chains',
'2021 Aug/Python',
'2021 Aug/Kotlin (small)',
'2021 Aug/Kotlin',
'2021 Jan/ML-Verse',
'2020 August/Python-DS',
'2019 October/GitHub (small)',
'2019 October/GitHub (medium)',
'2019 October/GitHub',
'2015 September/GitHub',
'2013 September/SF (small)',
'2013 September/SF (medium)',
'2013 September/SF',
'2013 May/SF',
'2013 February/SF',
'2012 July/SF',
];

@action
onDatasetChange(newDataset: string) {
this.selectedDataset = newDataset;
}

@task
@waitFor
async confirmSubmitToBoa() {
try {
const file = this.args.file;
const fileModel = file.fileModel;
const parentFolder = await fileModel.get('parentFolder');
const grandparentFolder = await parentFolder.get('parentFolder');
const endpoint = config.OSF.url + 'api/v1/project/' + fileModel.target.get('id') + '/boa/submit-job/';
const payload = {
data: {
nodeId: fileModel.target.get('id'),
name: file.name,
materialized: fileModel.materializedPath,
links: {
download: file.links.download,
upload: file.links.upload,
},
},
parent: {
links: {
upload: parentFolder.get('links').upload,
},
isAddonRoot: !grandparentFolder,
},
dataset: this.selectedDataset,
};
await this.args.file.currentUser.authenticatedAJAX({
url: endpoint,
type: 'POST',
data: JSON.stringify(payload),
xhrFields: { withCredentials: true },
headers: {
'Content-Type': 'application/json',
},
});

this.args.closeModal();
} catch (e) {
captureException(e);
this.toast.error(getApiErrorMessage(e),
this.intl.t('osf-components.file-browser.submit_to_boa_fail', { fileName: this.args.file.name }));
return;
}

this.toast.success(
this.intl.t('osf-components.file-browser.submit_to_boa_success', { fileName: this.args.file.name }),
);
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<OsfDialog @isOpen={{@isOpen}} @onClose={{@closeModal}} as |dialog|>
<dialog.heading>
{{t 'osf-components.file-browser.submit_to_boa'}}
</dialog.heading>
<dialog.main>

<p>{{t 'osf-components.file-browser.boa_dataset_spiel'}}</p>
<PowerSelect
@options={{this.datasets}}
@selected={{this.selectedDataset}}
@onChange={{this.onDatasetChange}}
as |dataset|
>
{{dataset}}
</PowerSelect>
<p>{{t 'osf-components.file-browser.confirm_submit_to_boa' fileName=@file.name}}</p>

</dialog.main>
<dialog.footer>
<Button
{{on 'click' (fn (mut @isOpen) false)}}
>
{{t 'general.cancel'}}
</Button>
<Button
@type='destroy'
disabled={{this.confirmSubmitToBoa.isRunning}}
{{on 'click' (perform this.confirmSubmitToBoa)}}
>
{{t 'osf-components.file-browser.confirm_submit_to_boa_yes'}}
</Button>
</dialog.footer>
</OsfDialog>
26 changes: 26 additions & 0 deletions lib/osf-components/addon/components/file-actions-menu/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,35 @@
</Button>
{{/if}}
{{/if}}
{{#if @item.currentUserCanDelete}}
{{#if @item.providerIsOsfstorage}}
{{#if @item.isBoaFile}}
{{#if this.isBoaEnabled}}
<Button
@layout='fake-link'
data-test-submit-to-boa
data-analytics-name='Submit to Boa'
local-class='DropdownItem'
{{on 'click' (queue
dropdown.close
this.openSubmitToBoaModal
)}}
>
<FaIcon @icon='upload' />
{{t 'file_actions_menu.submit_to_boa'}}
</Button>
{{/if}}
{{/if}}
{{/if}}
{{/if}}
</dropdown.content>
</ResponsiveDropdown>
<FileActionsMenu::DeleteModal @file={{@item}} @isOpen={{this.isDeleteModalOpen}} @closeModal={{this.closeDeleteModal}} @onDelete={{@onDelete}} />
<FileActionsMenu::SubmitToBoaModal
@file={{@item}}
@isOpen={{this.isSubmitToBoaModalOpen}}
@closeModal={{this.closeSubmitToBoaModal}}
/>
{{#if @manager}}
<MoveFileModal
@isOpen={{this.moveModalOpen}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,13 @@
local-class='FileList__item__options'
>
{{#unless @manager.selectedFiles}}
<FileActionsMenu @item={{@item}} @onDelete={{@manager.reload}} @manager={{@manager}} @allowRename={{true}} />
<FileActionsMenu
@item={{@item}}
@onDelete={{@manager.reload}}
@manager={{@manager}}
@allowRename={{true}}
@addonsEnabled={{@manager.targetNode.addonsEnabled}}
/>
{{/unless}}
</div>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'osf-components/components/file-actions-menu/submit-to-boa-modal/component';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'osf-components/components/file-actions-menu/submit-to-boa-modal/template';
7 changes: 7 additions & 0 deletions translations/en-us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ file_actions_menu:
error_message: 'Could not copy to clipboard'
rename: 'Rename'
rename_aria: 'Open rename link'
submit_to_boa: 'Submit to Boa'
node_categories:
analysis: Analysis
communication: Communication
Expand Down Expand Up @@ -2222,6 +2223,12 @@ osf-components:
delete_success: '{itemCount, plural, one {# item} other {# items}} deleted successfully'
deleting: 'Deleting {itemCount, plural, one {# item} other {# items}}'
retry: 'retry delete'
submit_to_boa: 'Submit file to Boa?'
confirm_submit_to_boa: 'Are you sure you want to submit "{fileName}" to Boa?'
confirm_submit_to_boa_yes: 'Submit'
submit_to_boa_fail: 'Failed to submit "{fileName}" to Boa'
submit_to_boa_success: 'Successfully submitted "{fileName}" to Boa'
boa_dataset_spiel: 'Please select a dataset to run the query against:'
help_modal:
heading: 'Using the OSF Files Browser'
providers: 'See All Files in a Provider'
Expand Down

0 comments on commit f5d1b93

Please sign in to comment.