Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import config from 'ember-get-config';
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import Intl from 'ember-intl/services/intl';
import { SafeString } from '@ember/template/-private/handlebars';
import Toast from 'ember-toastr/services/toast';

const { OSF: { apiUrl } } = config;

interface Args {
providerId: string;
}

interface ErrorMessage {
cell: string;
title: string;
detail: string | SafeString;
}
interface ApiErrorDetail {
header: string;
column_index: string;
row_index: string;
type: string;
}
export default class UploadCsvComponent extends Component<Args> {
dropzoneOptions = {
createImageThumbnails: false,
method: 'PUT',
withCredentials: true,
preventMultipleFiles: true,
acceptDirectories: false,
};

@service intl!: Intl;
@service toast!: Toast;

@tracked errorMessages: ErrorMessage[] = [];
@tracked shouldShowErrorModal = false;
@tracked dropping = false;
@tracked uploading: any[] = [];

@action
buildUrl(files: any) {
return `${apiUrl}/_/registries/${this.args.providerId}/bulk_create/${files[0].name}/`;
}

@action
addedFile(_: any, __: any, file: any) {
this.uploading.push(file);
}

@action
uploadProgress(_: any, __: any, file: any, progress: number) {
$(`#uploading-${file.size}`).css('width', `${progress}%`);
}

@action
error(_: any, __: any, file: any, { errors }: { errors: ApiErrorDetail[]}) {
this.uploading.removeObject(file);
this.shouldShowErrorModal = true;
for (const error of errors) {
this.errorMessages.push(
{
cell: error.column_index + error.row_index,
title: this.intl.t(`registries.moderation.settings.${error.type}.title`),
detail: this.intl.t(`registries.moderation.settings.${error.type}.detail`, { htmlSafe: true }),
},
);
}
}

@action
success(_: any, __: any, file: any, ___: any) {
this.uploading.removeObject(file);
this.toast.success(this.intl.t('registries.moderation.settings.uploadSuccess'));
}

@action
closeErrorModal() {
this.shouldShowErrorModal = false;
this.errorMessages = [];
}

@action
async copyToClipboard(elementId: string) {
const mainElement = document.getElementById(elementId);
await navigator.clipboard.writeText(mainElement!.textContent!);
this.toast.success(this.intl.t('registries.moderation.settings.copyToClipboardSuccess'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.upload-zone-content {
text-align: center;
}

.upload-zone {
padding: 50px;
background: #f5f5f5;
border: 5px dashed #c7c7c7;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{{#let (unique-id 'upload-csv-dropzone') as |id|}}
<DropzoneWidget
@buildUrl={{action this.buildUrl}}
@options={{this.dropzoneOptions}}
@dropzone={{false}}
@addedfile={{action this.addedFile}}
@uploadprogress={{action this.uploadProgress}}
@success={{action this.success}}
@error={{action this.error}}
@dragenter={{action (mut this.dropping) true}}
@dragover={{action (mut this.dropping) true}}
@drop={{action (mut this.dropping) false}}
@dragleave={{action (mut this.dropping) false}}
@enable={{true}}
@id={{id}}
@clickable={{array
(concat '.' (local-class 'upload-zone'))
}}
>
<div local-class='upload-zone'>
<div local-class='upload-zone-content'>
<FaIcon @icon='upload' @size='5x' />
<div
local-class='file-placeholder-text'
>
{{t 'registries.moderation.settings.dropCsvHere'}}
</div>
</div>
</div>
</DropzoneWidget>
{{/let}}

{{#let (unique-id 'main-content') as |id|}}
<OsfDialog
@isOpen={{this.shouldShowErrorModal}}
@onClose={{this.closeErrorModal}}
as |dialog|
>
<dialog.heading>
{{t 'registries.moderation.settings.uploadError'}}
</dialog.heading>
<dialog.main id={{id}}>
<div>
<p>{{t 'registries.moderation.settings.generalErrorMessage' htmlSafe=true}}</p>
</div>

<dl>
{{#each this.errorMessages as |msg|}}
<p>
{{#if msg.cell}}
<dt>{{t 'registries.moderation.settings.cell'}} {{msg.cell}}</dt>
{{/if}}
<dt>{{msg.title}}</dt>
<dd>{{msg.detail}}</dd>
</p>
{{/each}}
</dl>
</dialog.main>
<dialog.footer>
<BsButton
@type='primary'
{{on 'click' (fn this.copyToClipboard id)}}
>
{{t 'registries.moderation.settings.copyToClipboard'}}
</BsButton>
</dialog.footer>
</OsfDialog>
{{/let}}
17 changes: 0 additions & 17 deletions lib/registries/addon/branded/moderation/notifications/template.hbs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { alias } from '@ember/object/computed';
import config from 'ember-get-config';
import pathJoin from 'ember-osf-web/utils/path-join';

export default class BrandedModerationNotificationsController extends Controller {
export default class BrandedModerationSettingsController extends Controller {
userSettingsLink = pathJoin(config.OSF.url, 'settings', 'notifications');
@alias('model.id') providerId?: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { inject as service } from '@ember/service';

import Analytics from 'ember-osf-web/services/analytics';

export default class BrandedModerationNotificationsRoute extends Route {
export default class BrandedModerationSettingsRoute extends Route {
@service analytics!: Analytics;

@action
Expand Down
25 changes: 25 additions & 0 deletions lib/registries/addon/branded/moderation/settings/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{{page-title (t 'registries.moderation.settings.title') prepend=false}}

<h2>
{{t 'registries.moderation.settings.heading'}}
</h2>
<p>
{{t 'registries.moderation.settings.paragraph' link=this.userSettingsLink htmlSafe=true}}
</p>

<Subscriptions::Manager
@subscriptionIds={{this.subscriptionIds}}
as |manager|
>
<Subscriptions::List
@manager={{manager}}
/>
</Subscriptions::Manager>

<h2>
{{t 'registries.moderation.settings.bulkUpload'}}
</h2>
<p>
{{t 'registries.moderation.settings.bulkUploadHelpText'}}
</p>
<Branded::Moderation::-Components::UploadCsv @providerId={{this.model.id}} />
8 changes: 4 additions & 4 deletions lib/registries/addon/branded/moderation/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
</OsfLink>
</nav.item>
{{/let}}
{{#let 'registries.branded.moderation.notifications' as |notificationsRoute|}}
<nav.item @active={{eq this.target.currentRouteName notificationsRoute}}>
{{#let 'registries.branded.moderation.settings' as |settingsRoute|}}
<nav.item @active={{eq this.target.currentRouteName settingsRoute}}>
<OsfLink
@route={{notificationsRoute}}
@route={{settingsRoute}}
@models={{array this.model.id}}
>
{{t 'registries.moderation.notifications.title'}}
{{t 'registries.moderation.settings.title'}}
</OsfLink>
</nav.item>
{{/let}}
Expand Down
2 changes: 1 addition & 1 deletion lib/registries/addon/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default buildRoutes(function() {
this.route('moderation', function() {
this.route('submissions');
this.route('moderators');
this.route('notifications');
this.route('settings');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SubscriptionFrequency } from 'ember-osf-web/models/subscription';
import { visit } from 'ember-osf-web/tests/helpers';
import { setupEngineApplicationTest } from 'ember-osf-web/tests/helpers/engines';

module('Registries | Acceptance | branded.moderation | notifications', hooks => {
module('Registries | Acceptance | branded.moderation | settings', hooks => {
setupEngineApplicationTest(hooks, 'registries');
setupMirage(hooks);

Expand All @@ -31,13 +31,13 @@ module('Registries | Acceptance | branded.moderation | notifications', hooks =>
});

test('logged out users are rerouted', async assert => {
await visit('/registries/mdr8n/moderation/notifications');
await visit('/registries/mdr8n/moderation/settings');
assert.equal(currentRouteName(), 'registries.page-not-found', 'Non-moderators are rerouted');
});

test('logged in, non-moderators are rerouted', async assert => {
server.create('user', 'loggedIn');
await visit('/registries/mdr8n/moderation/notifications');
await visit('/registries/mdr8n/moderation/settings');
assert.equal(currentRouteName(), 'registries.page-not-found', 'Non-moderators are rerouted');
});

Expand All @@ -46,10 +46,10 @@ module('Registries | Acceptance | branded.moderation | notifications', hooks =>
const currentUser = server.create('user', 'loggedIn');
server.create('moderator', { id: currentUser.id, user: currentUser, provider: regProvider }, 'asModerator');
regProvider.update({ permissions: ['view_submissions'] });
await visit('/registries/mdr8n/moderation/notifications');
await percySnapshot('moderation notifications page');
assert.equal(currentRouteName(), 'registries.branded.moderation.notifications',
'On the notifications page of registries reviews');
await visit('/registries/mdr8n/moderation/settings');
await percySnapshot('moderation settings page');
assert.equal(currentRouteName(), 'registries.branded.moderation.settings',
'On the settings page of registries reviews');
assert.dom('[data-test-subscription-list]').exists('Subscription list shown');
assert.dom('[data-test-subscription-list-row="mdr8n_new_pending_submissions"]')
.exists('Pending submissions notification shown');
Expand Down
49 changes: 47 additions & 2 deletions translations/en-us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1022,10 +1022,55 @@ registries:
removedModeratorError: 'Error removing {permission}'
updatedModeratorPermissionSuccess: 'Successfully updated {userName} to {permission}'
updatedModeratorPermissionError: 'Error updating permission to {permission}'
notifications:
title: 'Notifications'
settings:
title: 'Settings'
heading: 'Configure reviews notification preferences'
paragraph: 'To configure other notification preferences visit your <a href={link}>user settings</a>.'
bulkUpload: 'Bulk upload'
bulkUploadHelpText: 'Drag and drop the csv file that has the registration information to upload.'
dropCsvHere: 'Drop csv file here to upload'
uploadError: 'Upload error'
copyToClipboard: 'Copy to clipboard'
cell: 'Cell'
copyToClipboardSuccess: 'Successfully copied to clipboard.'
generalErrorMessage: 'Your file was not uploaded due to the errors listed below. Please correct the errors and try again. If you have any questions, please contact the help desk at <a href="mailto:support@osf.io">support@osf.io</a>.'
invalidSchemaId:
title: 'Invalid schema ID'
detail: 'The schema ID in this cell does not match with a registration template in our system. It’s likely this ID was manually edited after it was downloaded or the registration template is outdated. Download a new csv template to get the most updated version and try to upload again.'
invalidColumnId:
title: 'Invalid column ID'
detail: 'This Column ID does not match with the ones used by this registration template. It’s likely it was manually edited after it was downloaded or the registration template is outdated. Download a new csv template to get the most updated version and try to upload again.'
invalidProjectId:
title: 'Invalid project ID'
detail: 'This Project GUID does not exist. Check that each project’s GUID is accurate. Registrations that do not have a project should have a blank cell.'
invalidInstitutionName:
title: 'Invalid institution name'
detail: 'This affiliated institution name does not match our system. Check that the institution’s name is spelled correctly. <a href="https://osf.io/institutions?view_only=">Click here</a> to view a list of currently active affiliated institutions.'
invalidLicenseName:
title: 'Invalid license name'
detail: 'This license does not match our system. It’s likely that the license is either spelled incorrectly, is not an option in our system, or formatted incorrectly. <a href="https://help.osf.io/hc/en-us/articles/360019739014-Licensing">Click here</a> to view a list of available licenses. See section “CSV Templates” in our Moderator’s Guide for more information on formatting specific licenses.'
invalidSubjectName:
title: 'Invalid subject name'
detail: 'This subject does not match our system. It’s likely it is spelled incorrectly. OSF uses the <a href="https://www.bepress.com/wp-content/uploads/2016/12/Disciplines_taxonomy_2018-01.pdf">bepress taxonomy</a>. Only the word or phase after the last colon needs to be entered.'
invalidCategoryName:
title: 'Invalid category name'
detail: 'TThis category does not match our system. It’s likely that the category either spelled incorrectly or is not an option in our system. See section “CSV Templates” in our Moderator’s Guide for more information.'
invalidResponse:
title: 'Invalid response'
detail: 'This response is not acceptable by the system. It’s likely that this is due to misspelling or having multiple answers for a single response question. See section “CSV Templates”.'
invalidContributors:
title: 'Invalid format for contributors'
detail: 'This contributors list does not match the system’s formatting requirements. Review the required formatting in the Moderator’s Manual. Contact the help desk at <a href="mailto:support@osf.io">support@osf.io</a> this is not the issue.'
sizeExceedsLimit:
title: 'File size exceeds limit'
detail: 'The csv file exceeds the 1MB limit. Break the file into multiple files and reupload them. Contact the Help Desk at <a href="mailto:support@osf.io">support@osf.io</a> if you have any questions.'
bulkUploadJobExists:
title: 'Bulk upload job already exists'
detail: 'This csv file was already uploaded into the system and cannot be re-uploaded.'
invalidFileType:
title: 'Invalid file type'
detail: 'Only csv files can be uploaded in the system. Convert the file into the csv format and reupload the document. Contact the Help Desk at <a href="mailto:support@osf.io">support@osf.io</a> if you have any questions.'
uploadSuccess: 'Successfully uploaded csv file.'
overview:
title: 'Moderated Overview'
new:
Expand Down
Loading