From d948853f93cc4eaa5315e8a8ac44cb5b1f2c493b Mon Sep 17 00:00:00 2001 From: Jared Galanis Date: Mon, 27 May 2024 15:36:58 -0400 Subject: [PATCH] refactor: remove ember-data:deprecate-array-like deprecation --- app/components/found-manuscripts/index.js | 4 +- app/components/policy-card/index.js | 15 ++-- app/components/workflow-files/index.js | 51 +++++------ app/components/workflow-grants/index.js | 23 ++--- app/components/workflow-repositories/index.js | 33 ++++---- app/components/workflow-review/index.hbs | 7 +- app/controllers/grants/index.js | 2 +- app/controllers/submissions/detail.js | 5 +- app/controllers/submissions/new.js | 7 +- app/controllers/submissions/new/basics.js | 6 +- app/controllers/submissions/new/files.js | 31 +++++-- app/controllers/submissions/new/review.js | 4 +- app/deprecation-workflow.js | 5 +- app/models/repository.js | 1 - app/routes/grants/index.js | 2 +- app/routes/submissions/new.js | 2 +- app/routes/submissions/new/policies.js | 11 +-- app/services/metadata-schema.js | 2 +- app/services/submission-handler.js | 4 +- app/services/workflow.js | 6 +- app/styles/app.css | 8 ++ app/templates/submissions/detail.hbs | 7 +- app/templates/submissions/new/files.hbs | 5 +- .../found-manuscripts/component-test.js | 10 +-- .../components/policy-card-test.js | 28 ++++++- .../components/workflow-files-test.js | 28 ++++++- .../components/workflow-grants-test.js | 10 +-- .../components/workflow-repositories-test.js | 84 +++++++++++++------ .../controllers/submissions/new/files-test.js | 27 ++++-- 29 files changed, 274 insertions(+), 154 deletions(-) diff --git a/app/components/found-manuscripts/index.js b/app/components/found-manuscripts/index.js index 58f7467e..52915eb7 100644 --- a/app/components/found-manuscripts/index.js +++ b/app/components/found-manuscripts/index.js @@ -26,7 +26,7 @@ export default class FoundManuscriptsComponent extends Component { let prevFiles = this.args.previouslyUploadedFiles || []; let newFiles = this.args.newFiles || []; - const allFileNames = [...newFiles.toArray(), ...prevFiles.toArray()].map((file) => file.name); + const allFileNames = [...newFiles.slice(), ...prevFiles.slice()].map((file) => file.name); return this.foundManuscripts .filter((manuscript) => !allFileNames.includes(manuscript.name)) @@ -46,7 +46,7 @@ export default class FoundManuscriptsComponent extends Component { const foundOAMss = yield this.oaManuscriptService.lookup(doi); if (foundOAMss) { - this.foundManuscripts.pushObjects(foundOAMss); + this.foundManuscripts.push(foundOAMss); } }; } diff --git a/app/components/policy-card/index.js b/app/components/policy-card/index.js index 76b13242..780274b3 100644 --- a/app/components/policy-card/index.js +++ b/app/components/policy-card/index.js @@ -88,18 +88,21 @@ export default class PolicyCard extends Component { } } - _addEffectivePolicy(policy) { + async _addEffectivePolicy(policy) { + const effectivePolicies = await this.args.submission.effectivePolicies; // Only add the policy if it is not already in the list of effective policies if (!this._hasEffectivePolicy(policy.id)) { - this.args.submission.effectivePolicies.pushObject(policy); + this.args.submission.effectivePolicies = [...effectivePolicies, policy]; } } - _removeEffectivePolicy(policy) { - this.args.submission.effectivePolicies.removeObject(policy); + async _removeEffectivePolicy(policy) { + let effectivePolicies = await this.args.submission.effectivePolicies; + this.args.submission.effectivePolicies = effectivePolicies.filter((p) => p.id === policy.id); } - _hasEffectivePolicy(policyId) { - return this.args.submission.effectivePolicies && this.args.submission.effectivePolicies.isAny('id', policyId); + async _hasEffectivePolicy(policyId) { + const effectivePolicies = await this.args.submission.effectivePolicies; + return effectivePolicies && effectivePolicies.some((policy) => policy.id === policyId); } } diff --git a/app/components/workflow-files/index.js b/app/components/workflow-files/index.js index 51e58e95..9b9a28d7 100644 --- a/app/components/workflow-files/index.js +++ b/app/components/workflow-files/index.js @@ -1,9 +1,10 @@ /* eslint-disable ember/no-computed-properties-in-native-classes, ember/no-get, ember/require-computed-property-dependencies */ import Component from '@glimmer/component'; -import { action, get, set, computed } from '@ember/object'; +import { action, get } from '@ember/object'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency-decorators'; import ENV from 'pass-ui/config/environment'; +import { tracked } from '@glimmer/tracking'; export default class WorkflowFiles extends Component { @service store; @@ -12,42 +13,37 @@ export default class WorkflowFiles extends Component { @service currentUser; @service flashMessages; - @computed('manuscript') get hasManuscript() { - return !!get(this, 'manuscript'); + return !!this.manuscript; } - @computed('args.newFiles.[]', 'previouslyUploadedFiles.[]') get manuscript() { - const newFiles = get(this, 'args.newFiles') || []; - const prevFiles = get(this, 'args.previouslyUploadedFiles') || []; + const newFiles = this.args.newFiles || []; + const prevFiles = this.args.previouslyUploadedFiles || []; - return [...prevFiles.toArray(), ...newFiles.toArray()].find((file) => file.fileRole === 'manuscript'); + return [...prevFiles.slice(), ...newFiles.slice()].find((file) => file.fileRole === 'manuscript'); } /** * Any non-manuscript files */ - @computed('args.newFiles.[]', 'previouslyUploadedFiles.[]') get supplementalFiles() { - const newFiles = get(this, 'args.newFiles') || []; - const prevFiles = get(this, 'args.previouslyUploadedFiles') || []; + const newFiles = this.args.newFiles || []; + const prevFiles = this.args.previouslyUploadedFiles || []; - return [...prevFiles.toArray(), ...newFiles.toArray()].filter((file) => file.fileRole !== 'manuscript'); + return [...prevFiles.slice(), ...newFiles.slice()].filter((file) => file.fileRole !== 'manuscript'); } @task handleExternalMs = function* (file) { - const newFiles = get(this, 'args.newFiles'); - - file.set('submission', get(this, 'args.submission')); - if (!get(this, 'hasManuscript')) { - file.set('fileRole', 'manuscript'); + file.submission = this.args.submission; + if (!this.hasManuscript) { + file.fileRole = 'manuscript'; } else { - file.set('fileRole', 'supplemental'); + file.fileRole = 'supplemental'; } - newFiles.pushObject(file); + this.args.updateNewFiles(file); yield file.save(); }; @@ -67,15 +63,15 @@ export default class WorkflowFiles extends Component { const deleted = await this.deleteFile(file); if (deleted) { - const mFiles = get(this, 'args.previouslyUploadedFiles'); + const mFiles = this.args.previouslyUploadedFiles; // Remove the file from the model if (mFiles) { - mFiles.removeObject(file); + this.args.updatePreviouslyUploadedFiles(mFiles.filter((f) => f.id !== file.id)); } - const newFiles = get(this, 'args.newFiles'); + const newFiles = this.args.newFiles; if (newFiles) { - newFiles.removeObject(file); + this.args.updateNewFiles(newFiles.filter((f) => f.id !== file.id)); } document.querySelector('#file-multiple-input').value = null; } @@ -111,8 +107,10 @@ export default class WorkflowFiles extends Component { if (!this.hasManuscript) { newFile.fileRole = 'manuscript'; } - await newFile.save(); - this.args.newFiles.pushObject(newFile); + const savedFile = await newFile.save(); + + this.args.updateNewFiles([savedFile, ...this.args.newFiles]); + this.args.updateAllFiles([savedFile, ...this.args.newFiles, ...this.args.previouslyUploadedFiles]); } catch (error) { FileUpload.file.state = 'aborted'; console.error(error); @@ -134,7 +132,10 @@ export default class WorkflowFiles extends Component { return await file .destroyRecord() .then(() => { - files.removeObject(file); + const filteredFiles = files.filter((f) => f.id !== file.id); + + this.args.updateAllFiles(filteredFiles); + return true; }) .catch((error) => { diff --git a/app/components/workflow-grants/index.js b/app/components/workflow-grants/index.js index 62e3046e..3c2deccb 100644 --- a/app/components/workflow-grants/index.js +++ b/app/components/workflow-grants/index.js @@ -97,12 +97,13 @@ export default class WorkflowGrants extends Component { // Init selected grants to grants already attached to submission - this._selectedGrants.clear(); + this._selectedGrants = []; + let grants = yield this.args.submission.grants; if (this.preLoadedGrant) { - this.args.submission.grants.pushObject(this.preLoadedGrant); + grants = [this.preLoadedGrant, ...grants]; this.workflow.addGrant(this.preLoadedGrant); } - this._selectedGrants.addObjects(get(this, 'args.submission.grants')); + this._selectedGrants = [...grants]; }; updateGrants = task(async () => { @@ -174,18 +175,19 @@ export default class WorkflowGrants extends Component { * @param {Grant} grant */ @action - addGrant(grant) { + async addGrant(grant) { const workflow = this.workflow; const submission = this.args.submission; + let grants = await submission.grants; - if (!get(submission, 'grants').includes(grant)) { - get(submission, 'grants').pushObject(grant); + if (!grants.includes(grant)) { + this.args.submission.grants = [grant, ...grants]; } if (!workflow.getAddedGrants().includes(grant)) { workflow.addGrant(grant); } if (!this._selectedGrants.includes(grant)) { - this._selectedGrants.pushObject(grant); + this._selectedGrants = [grant, ...this._selectedGrants]; } this.setWorkflowStepHere(); @@ -200,7 +202,7 @@ export default class WorkflowGrants extends Component { * @param {Grant} grant */ @action - removeGrant(grant) { + async removeGrant(grant) { const workflow = this.workflow; // if grant is grant passed in from grant detail page remove query parms @@ -208,9 +210,10 @@ export default class WorkflowGrants extends Component { this.preLoadedGrant = null; } const submission = this.args.submission; - get(submission, 'grants').removeObject(grant); + const grants = await submission.grants; + this.args.submission.grants = grants.filter((g) => g !== grant); workflow.removeGrant(grant); - this._selectedGrants.removeObject(grant); + this._selectedGrants = this._selectedGrants.filter((g) => g !== grant); this.setWorkflowStepHere(); } diff --git a/app/components/workflow-repositories/index.js b/app/components/workflow-repositories/index.js index c1d1e2f4..0b9d42f7 100644 --- a/app/components/workflow-repositories/index.js +++ b/app/components/workflow-repositories/index.js @@ -45,7 +45,9 @@ export default class WorkflowRepositories extends Component { // Separate out repositories that PASS has no integration get requiredWeblinkRepos() { - return this.args.requiredRepositories.filter((repoInfo) => repoInfo.repository._isWebLink); + const webLinkRepos = this.args.requiredRepositories.filter((repoInfo) => repoInfo.repository._isWebLink); + + return webLinkRepos; } /** @@ -54,8 +56,8 @@ export default class WorkflowRepositories extends Component { */ @action setupRepos() { - set(this, 'addedRepos', this.getAddedRepositories()); - const currentRepos = get(this, 'submission.repositories'); + this.addedRepos = this.getAddedRepositories(); + const currentRepos = this.args.submission.repositories.slice(); const opt = this.args.optionalRepositories; const req = this.args.requiredRepositories; @@ -106,7 +108,9 @@ export default class WorkflowRepositories extends Component { * Use IDs instead of full Repository objects to try to avoid weird JS equality * nonsense. */ - currentRepos.filter((repo) => !validRepos.includes(repo.id)).forEach((repo) => currentRepos.removeObject(repo)); + currentRepos + .filter((repo) => !validRepos.includes(repo.id)) + .forEach((repo) => (this.args.submission.repositories = currentRepos.filter((r) => r.name === repo.name))); } else { /** * If no repositories have been saved to the submission yet, force add all required repositories @@ -117,13 +121,13 @@ export default class WorkflowRepositories extends Component { } if (opt) { opt - .filter((repoInfo) => get(repoInfo, 'repository._selected')) + .filter((repoInfo) => repoInfo.repository._selected) .forEach((repoInfo) => this.addRepository(repoInfo.repository, false)); } if (choice) { choice.forEach((group) => { group - .filter((repoInfo) => get(repoInfo, 'repository._selected')) + .filter((repoInfo) => repoInfo.repository._selected) .forEach((repoInfo) => this.addRepository(repoInfo.repository, false)); }); } @@ -145,16 +149,16 @@ export default class WorkflowRepositories extends Component { * * @param {Repository} repo the repository that may be modified */ - setSelected(repo) { + async setSelected(repo) { const id = repo.id; const addedRepos = this.addedRepos; - const currentRepos = get(this, 'args.submission.repositories'); + const currentRepos = await this.args.submission.repositories; - if (addedRepos.isAny('id', id)) { + if (addedRepos.some((r) => r.id === id)) { return; } - repo.set('_selected', currentRepos.isAny('id', id)); + repo._selected = currentRepos.some((r) => r.id === id); } /** @@ -203,10 +207,10 @@ export default class WorkflowRepositories extends Component { * @param {boolean} setMaxStep should we modify 'maxStep' in the workflow? */ addRepository(repository, setMaxStep) { - const subRepos = get(this, 'args.submission.repositories'); + const repos = this.args.submission.repositories.slice(); - if (!subRepos.includes(repository)) { - subRepos.pushObject(repository); + if (!repos.includes(repository)) { + this.args.submission.repositories = [repository, ...repos]; } if (setMaxStep) { this.workflow.setMaxStep(4); @@ -220,7 +224,8 @@ export default class WorkflowRepositories extends Component { * @param {boolean} setMaxStep should we modify 'maxStep' in the workflow? */ removeRepository(repository, setMaxStep) { - get(this, 'args.submission.repositories').removeObject(repository); + const repositories = this.args.submission.repositories.slice(); + this.args.submission.repositories = repositories.filter((r) => r.name !== repository.name); if (setMaxStep) { this.workflow.setMaxStep(4); } diff --git a/app/components/workflow-review/index.hbs b/app/components/workflow-review/index.hbs index 04590573..9e24529a 100644 --- a/app/components/workflow-review/index.hbs +++ b/app/components/workflow-review/index.hbs @@ -63,23 +63,20 @@ diff --git a/app/controllers/grants/index.js b/app/controllers/grants/index.js index b1a83151..afb8483e 100644 --- a/app/controllers/grants/index.js +++ b/app/controllers/grants/index.js @@ -201,7 +201,7 @@ export default class GrantsIndexController extends Controller { submission.grants.forEach((grant) => { let match = results.grantMap.find((res) => res.grant.id === grant.id); if (match) { - match.submissions.pushObject(submission); + match.submissions.push(submission); } }); }); diff --git a/app/controllers/submissions/detail.js b/app/controllers/submissions/detail.js index abd2beb9..fca93ec4 100644 --- a/app/controllers/submissions/detail.js +++ b/app/controllers/submissions/detail.js @@ -5,6 +5,7 @@ import { action, get, computed } from '@ember/object'; import ENV from 'pass-ui/config/environment'; import { inject as service } from '@ember/service'; import { later, scheduleOnce } from '@ember/runloop'; +import _ from 'lodash'; export default class SubmissionsDetail extends Controller { @service currentUser; @@ -285,9 +286,11 @@ export default class SubmissionsDetail extends Controller { // Validate manuscript files let manuscriptFiles = [] - .concat(this.filesTemp, get(this, 'model.files') && get(this, 'model.files').toArray()) + .concat(this.filesTemp, get(this, 'model.files') && get(this, 'model.files').slice()) .filter((file) => file && file.get('fileRole') === 'manuscript'); + manuscriptFiles = _.uniqBy(manuscriptFiles, 'id'); + if (manuscriptFiles.length == 0) { swal( 'Manuscript is missing', diff --git a/app/controllers/submissions/new.js b/app/controllers/submissions/new.js index 793c0ed6..94fa1b05 100644 --- a/app/controllers/submissions/new.js +++ b/app/controllers/submissions/new.js @@ -3,6 +3,7 @@ import Controller from '@ember/controller'; import { tracked } from '@glimmer/tracking'; import { action, get, set } from '@ember/object'; import { inject as service } from '@ember/service'; +import _ from 'lodash'; export default class SubmissionsNew extends Controller { queryParams = ['grant', 'submission', 'covid']; @@ -79,8 +80,10 @@ export default class SubmissionsNew extends Controller { @action async submit() { let manuscriptFiles = [] - .concat(this.filesTemp, get(this, 'model.files') && get(this, 'model.files').toArray()) - .filter((file) => file && get(file, 'fileRole') === 'manuscript'); + .concat(this.filesTemp, this.model.files && this.model.files.slice()) + .filter((file) => file && file.fileRole === 'manuscript'); + + manuscriptFiles = _.uniqBy(manuscriptFiles, 'id'); if (manuscriptFiles.length == 0 && this.userIsSubmitter) { swal('Manuscript Is Missing', 'At least one manuscript file is required. Please go back and add one', 'warning'); diff --git a/app/controllers/submissions/new/basics.js b/app/controllers/submissions/new/basics.js index a6107c0a..5c120473 100644 --- a/app/controllers/submissions/new/basics.js +++ b/app/controllers/submissions/new/basics.js @@ -26,9 +26,9 @@ export default class SubmissionsNewBasics extends Controller { get flaggedFields() { let fields = []; - if (this.titleError) fields.pushObject('title'); - if (this.journalError) fields.pushObject('journal'); - if (this.submitterEmailError) fields.pushObject('submitterEmail'); + if (this.titleError) fields.push('title'); + if (this.journalError) fields.push('journal'); + if (this.submitterEmailError) fields.push('submitterEmail'); return fields; } diff --git a/app/controllers/submissions/new/files.js b/app/controllers/submissions/new/files.js index b129f005..08b7f55d 100644 --- a/app/controllers/submissions/new/files.js +++ b/app/controllers/submissions/new/files.js @@ -19,6 +19,8 @@ export default class SubmissionsNewFiles extends Controller { @tracked loadingNext = false; @tracked filesTemp = this.workflow.filesTemp; + @tracked newFiles = []; + @tracked previouslyUploadedFiles = this.model.files; @computed('workflow.maxStep') get nextTabIsActive() { @@ -30,11 +32,6 @@ export default class SubmissionsNewFiles extends Controller { return this.nextTabIsActive || this.loadingNext; } - @computed('workflow.filesTemp') - get newFiles() { - return get(this, 'workflow').getFilesTemp(); - } - @action loadNext() { set(this, 'loadingNext', true); @@ -54,14 +51,32 @@ export default class SubmissionsNewFiles extends Controller { this.router.transitionTo(gotoRoute); } + @action + updateAllFiles(files) { + this.workflow.filesTemp = [...files, ...this.workflow.filesTemp]; + files.forEach((file) => { + file.submission = this.submission; + }); + } + + @action + updatePreviouslyUploadedFiles(files) { + this.previouslyUploadedFiles = [...files]; + } + + @action + updateNewFiles(files) { + this.newFiles = [...files]; + } + @action async validateAndLoadTab(gotoTab) { let needValidation = this.needValidation; if (needValidation) { let files = this.files; - let manuscriptFiles = [] - .concat(this.newFiles, files && files.toArray()) - .filter((file) => file && get(file, 'fileRole') === 'manuscript'); + let manuscriptFiles = [...this.newFiles, ...this.model.files.slice()].filter( + (file) => file && get(file, 'fileRole') === 'manuscript' + ); if (manuscriptFiles.length == 0 && !this.parent.userIsSubmitter) { let result = await swal({ diff --git a/app/controllers/submissions/new/review.js b/app/controllers/submissions/new/review.js index ccc1363d..2c225a89 100644 --- a/app/controllers/submissions/new/review.js +++ b/app/controllers/submissions/new/review.js @@ -7,12 +7,14 @@ import { inject as service } from '@ember/service'; export default class SubmissionsNewReview extends Controller { @service router; + @service workflow; @alias('model.newSubmission') submission; - @alias('model.files') files; @alias('model.publication') publication; @alias('model.submissionEvents') submissionEvents; + @tracked files = this.workflow.filesTemp; + @controller('submissions.new') parent; @computed('parent.waitingMessage') diff --git a/app/deprecation-workflow.js b/app/deprecation-workflow.js index 6844bf95..e666c2bb 100644 --- a/app/deprecation-workflow.js +++ b/app/deprecation-workflow.js @@ -1,8 +1,5 @@ import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow'; setupDeprecationWorkflow({ - workflow: [ - { handler: 'silence', matchId: 'ember-data:deprecate-promise-many-array-behaviors' }, - { handler: 'silence', matchId: 'ember-data:deprecate-array-like' }, - ], + workflow: [{ handler: 'silence', matchId: 'ember-data:deprecate-promise-many-array-behaviors' }], }); diff --git a/app/models/repository.js b/app/models/repository.js index 1cd92d06..fee8c560 100644 --- a/app/models/repository.js +++ b/app/models/repository.js @@ -13,7 +13,6 @@ export default class RepositoryModel extends Model { @attr('boolean') _selected; - @computed('integrationType') get _isWebLink() { return this.integrationType === 'web-link'; } diff --git a/app/routes/grants/index.js b/app/routes/grants/index.js index 01d002d2..fcd3296b 100644 --- a/app/routes/grants/index.js +++ b/app/routes/grants/index.js @@ -56,7 +56,7 @@ export default class IndexRoute extends CheckSessionRoute { submission.grants.forEach((grant) => { let match = results.grantMap.find((res) => res.grant.id === grant.id); if (match) { - match.submissions.pushObject(submission); + match.submissions.push(submission); } }); }); diff --git a/app/routes/submissions/new.js b/app/routes/submissions/new.js index f05a267d..5fc338cc 100644 --- a/app/routes/submissions/new.js +++ b/app/routes/submissions/new.js @@ -66,7 +66,7 @@ export default class NewRoute extends CheckSessionRoute { sort: '+performedDate', }); - files = this.store.query('file', fileForSubmissionQuery(newSubmission.id)).then((files) => [...files.toArray()]); + files = this.store.query('file', fileForSubmissionQuery(newSubmission.id)).then((files) => [...files.slice()]); // Also seed workflow.doiInfo with metadata from the Submission const metadata = newSubmission.get('metadata'); diff --git a/app/routes/submissions/new/policies.js b/app/routes/submissions/new/policies.js index e3e21aa0..aa8fc04c 100644 --- a/app/routes/submissions/new/policies.js +++ b/app/routes/submissions/new/policies.js @@ -30,15 +30,6 @@ export default class PoliciesRoute extends CheckSessionRoute { async model() { const parentModel = this.modelFor('submissions.new'); const submission = parentModel.newSubmission; - - // Weed out duplicates, while also resolving Policy objects - // let policies = Ember.A(); - // results.forEach(async (res) => { - // if (!policies.isAny('id', res.id)) { - // policies.push(res); - // } - // }); - /** * Remove current effectivePolicies from the submission because * it will be recalculated and added back in this step. @@ -57,7 +48,7 @@ export default class PoliciesRoute extends CheckSessionRoute { } clearEffectivePolicies(submission) { - submission.get('effectivePolicies').clear(); + submission.effectivePolicies = []; } @action diff --git a/app/services/metadata-schema.js b/app/services/metadata-schema.js index f5f9703f..8e6b04c0 100644 --- a/app/services/metadata-schema.js +++ b/app/services/metadata-schema.js @@ -415,7 +415,7 @@ export default class MetadataSchemaService extends Service { 'volume', ]; - const repos = await submission.repositories.toArray(); + const repos = await submission.repositories.slice(); const schemas = await this.getMetadataSchemas(repos); const titleMap = this.getFieldTitleMap(schemas); const metadata = JSON.parse(submission.metadata); diff --git a/app/services/submission-handler.js b/app/services/submission-handler.js index 258a115a..8734f927 100644 --- a/app/services/submission-handler.js +++ b/app/services/submission-handler.js @@ -29,10 +29,10 @@ export default class SubmissionHandlerService extends Service { const primaryRepos = grant.get('primaryFunder.policy.repositories'); if (isArray(directRepos)) { - result.pushObjects(directRepos.toArray()); + result.push(directRepos.slice()); } if (isArray(primaryRepos)) { - result.pushObjects(primaryRepos.toArray()); + result.push(primaryRepos.slice()); } }); diff --git a/app/services/workflow.js b/app/services/workflow.js index 10710f51..080fa04b 100644 --- a/app/services/workflow.js +++ b/app/services/workflow.js @@ -98,14 +98,14 @@ export default class Workflow extends Service { } addGrant(grant) { - this.addedGrants.pushObject(grant); + this.addedGrants = [grant, ...this.addedGrants]; } removeGrant(grant) { - this.addedGrants.removeObject(grant); + this.addedGrants = this.addedGrants.filter((g) => g.id !== grant.id); } clearAddedGrants() { - this.addedGrants.clear(); + this.addedGrants = []; } } diff --git a/app/styles/app.css b/app/styles/app.css index 18ff8b45..3c7c6b0d 100644 --- a/app/styles/app.css +++ b/app/styles/app.css @@ -794,3 +794,11 @@ footer { overflow: auto; background-color: var(--grey-light); } + +.grant-item { + padding: 10px 0; /* Add padding if needed */ +} + +.grant-item:not(:last-child) { + border-bottom: 1px solid #ccc; /* Add a bottom border except for the last item */ +} diff --git a/app/templates/submissions/detail.hbs b/app/templates/submissions/detail.hbs index e35ad358..d442ab0e 100644 --- a/app/templates/submissions/detail.hbs +++ b/app/templates/submissions/detail.hbs @@ -94,23 +94,20 @@ diff --git a/app/templates/submissions/new/files.hbs b/app/templates/submissions/new/files.hbs index 6ae67310..c3415f60 100644 --- a/app/templates/submissions/new/files.hbs +++ b/app/templates/submissions/new/files.hbs @@ -9,7 +9,10 @@ > { const mockMsService = Service.extend({ lookup(doi) { assert.ok(doi, 'DOI needs to be present'); - return Promise.resolve([ - { - name: 'This is a moo', - url: 'http://moo.example.com', - }, - ]); + return Promise.resolve({ + name: 'This is a moo', + url: 'http://moo.example.com', + }); }, }); diff --git a/tests/integration/components/policy-card-test.js b/tests/integration/components/policy-card-test.js index c0ae37e9..b858008e 100644 --- a/tests/integration/components/policy-card-test.js +++ b/tests/integration/components/policy-card-test.js @@ -67,6 +67,28 @@ module('Integration | Component | policy card', (hooks) => { }); test('PMC journal displays user input', async function (assert) { + const repositoryFactory = this.server.create('repository'); + const policyFactory = this.server.create('policy', { + repositories: [repositoryFactory], + }); + const journalFactory = this.server.create('journal', { pmcParticipation: 'B' }); + + const repository = this.store.createRecord('repository', repositoryFactory.attrs); + const policy = this.store.createRecord('policy', { + ...policyFactory.attrs, + description: 'This is a moo-scription', + title: 'Moo title', + repositories: [repository], + }); + const journal = this.store.createRecord('journal', journalFactory.attrs); + const submissionAttrs = this.server.create('submission').attrs; + const submission = this.store.createRecord('submission', { effectivePolicies: [policy], ...submissionAttrs }); + + this.set('submission', submission); + this.set('policy', policy); + this.set('journal', journal); + this.set('repository', repository); + await render( hbs`` ); @@ -74,10 +96,10 @@ module('Integration | Component | policy card', (hooks) => { assert.dom('[data-test-workflow-policies-radio-no-direct-deposit]').exists(); assert.dom('[data-test-workflow-policies-radio-direct-deposit]').exists(); - const effectivePolicies = this.submission.effectivePolicies; + const effectivePolicies = this.submission.effectivePolicies.slice(); assert.strictEqual(effectivePolicies.length, 1, 'Should be ONE effective policy on submission'); - assert.ok(effectivePolicies.isAny('title', 'Moo title')); + assert.ok(effectivePolicies.some((p) => p.title === 'Moo title')); }); test('PMC non-type A can be removed', async function (assert) { @@ -91,7 +113,7 @@ module('Integration | Component | policy card', (hooks) => { // Select option to remove this policy await click('[data-test-workflow-policies-radio-direct-deposit]'); - const effectivePolicies = this.submission.effectivePolicies; + const effectivePolicies = await this.submission.effectivePolicies; assert.strictEqual(effectivePolicies.length, 0, 'Should be ZERO effective policies'); }); diff --git a/tests/integration/components/workflow-files-test.js b/tests/integration/components/workflow-files-test.js index cdf22cdb..32ec231c 100644 --- a/tests/integration/components/workflow-files-test.js +++ b/tests/integration/components/workflow-files-test.js @@ -1,6 +1,6 @@ /* eslint-disable ember/no-classic-classes */ import { selectFiles } from 'ember-file-upload/test-support'; -import EmberObject from '@ember/object'; +import EmberObject, { set } from '@ember/object'; import { setupRenderingTest } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; import { module, test } from 'qunit'; @@ -27,6 +27,20 @@ module('Integration | Component | workflow files', (hooks) => { // Bogus action so component actions don't complain this.fakeAction = sinon.fake(); + this.updateAllFiles = (files) => { + files.forEach((file) => { + file.submission = this.submission; + }); + }; + + this.updatePreviouslyUploadedFiles = (files) => { + this.previouslyUploadedFiles = [...files]; + }; + + this.updateNewFiles = (files) => { + set(this, 'newFiles', [...files]); + }; + const staticConfig = this.owner.lookup('service:app-static-config'); sinon.replace( staticConfig, @@ -81,6 +95,9 @@ module('Integration | Component | workflow files', (hooks) => { @submission={{this.submission}} @previouslyUploadedFiles={{this.previouslyUploadedFiles}} @newFiles={{this.newFiles}} + @updatePreviouslyUploadedFiles={{this.updatePreviouslyUploadedFiles}} + @updateNewFiles={{this.updateNewFiles}} + @updateAllFiles={{this.updateAllFiles}} @next={{action this.fakeAction}} @back={{action this.fakeAction}} @abort={{action this.fakeAction}} @@ -124,6 +141,9 @@ module('Integration | Component | workflow files', (hooks) => { @submission={{this.submission}} @previouslyUploadedFiles={{this.previouslyUploadedFiles}} @newFiles={{this.newFiles}} + @updatePreviouslyUploadedFiles={{this.updatePreviouslyUploadedFiles}} + @updateNewFiles={{this.updateNewFiles}} + @updateAllFiles={{this.updateAllFiles}} @next={{this.fakeAction}} @back={{this.fakeAction}} @abort={{this.fakeAction}} @@ -148,6 +168,9 @@ module('Integration | Component | workflow files', (hooks) => { @submission={{this.submission}} @previouslyUploadedFiles={{this.previouslyUploadedFiles}} @newFiles={{this.newFiles}} + @updatePreviouslyUploadedFiles={{this.updatePreviouslyUploadedFiles}} + @updateNewFiles={{this.updateNewFiles}} + @updateAllFiles={{this.updateAllFiles}} @next={{this.fakeAction}} @back={{this.fakeAction}} @abort={{this.fakeAction}} @@ -196,6 +219,9 @@ module('Integration | Component | workflow files', (hooks) => { @submission={{this.submission}} @previouslyUploadedFiles={{this.previouslyUploadedFiles}} @newFiles={{this.newFiles}} + @updatePreviouslyUploadedFiles={{this.updatePreviouslyUploadedFiles}} + @updateNewFiles={{this.updateNewFiles}} + @updateAllFiles={{this.updateAllFiles}} @next={{action this.fakeAction}} @back={{action this.fakeAction}} @abort={{action this.fakeAction}} diff --git a/tests/integration/components/workflow-grants-test.js b/tests/integration/components/workflow-grants-test.js index 691d7dc8..1f05da99 100644 --- a/tests/integration/components/workflow-grants-test.js +++ b/tests/integration/components/workflow-grants-test.js @@ -117,14 +117,14 @@ module('Integration | Component | workflow grants', (hooks) => { this.set('preLoadedGrant', undefined); - const list = A(); + let list = []; this.owner.register( 'service:workflow', Service.extend({ setMaxStep: (step) => {}, addGrant(grant) { assert.ok(grant); - list.pushObject(grant); + list = [grant, ...list]; }, getAddedGrants() { return list; @@ -167,7 +167,7 @@ module('Integration | Component | workflow grants', (hooks) => { test('Clicking on a selected grant will remove it', async function (assert) { assert.expect(6); - const list = A(); + let list = []; this.owner.register( 'service:workflow', Service.extend({ @@ -177,11 +177,11 @@ module('Integration | Component | workflow grants', (hooks) => { }, getAddedGrants: () => list, addGrant: (grant) => { - list.pushObject(grant); + list = [grant, ...list]; }, removeGrant(grant) { assert.ok(true); - list.removeObject(grant); + list = list.filter((g) => g.id !== grant.id); }, }) ); diff --git a/tests/integration/components/workflow-repositories-test.js b/tests/integration/components/workflow-repositories-test.js index f293d2e6..ee33f122 100644 --- a/tests/integration/components/workflow-repositories-test.js +++ b/tests/integration/components/workflow-repositories-test.js @@ -10,7 +10,8 @@ module('Integration | Component | workflow repositories', (hooks) => { setupRenderingTest(hooks); hooks.beforeEach(function () { - this.submission = { id: '0', repositories: [] }; + this.storeService = this.owner.lookup('service:store'); + this.submission = this.storeService.createRecord('submission', { repositories: [] }); this.requiredRepositories = []; this.optionalRepositories = []; this.choiceRepositories = []; @@ -33,7 +34,9 @@ module('Integration | Component | workflow repositories', (hooks) => { }); test('required repositories should display with no checkboxes', async function (assert) { - this.requiredRepositories = [{ repository: { name: 'Moo-pository 1' } }]; + this.requiredRepositories = [ + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 1' }) }, + ]; await render(hbs` { test('User cannot deselect all choice repos', async function (assert) { this.choiceRepositories = [ [ - { repository: EmberObject.create({ name: 'Moo-pository 1', _selected: true }) }, - { repository: EmberObject.create({ name: 'Moo-pository 2', _selected: false }) }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 1', _selected: true }) }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 2', _selected: false }) }, ], ]; @@ -111,12 +114,16 @@ module('Integration | Component | workflow repositories', (hooks) => { }); test('Selecting an optional repo adds it to submission', async function (assert) { - this.requiredRepositories = [{ repository: { name: 'Moo-pository XYZ' } }]; - this.optionalRepositories = [{ selected: false, repository: { name: 'Moo-pository 00' } }]; + this.requiredRepositories = [ + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository XYZ' }) }, + ]; + this.optionalRepositories = [ + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 00', selected: false }) }, + ]; this.choiceRepositories = [ [ - { repository: EmberObject.create({ name: 'Moo-pository 1', _selected: true }) }, - { repository: EmberObject.create({ name: 'Moo-pository 2', _selected: false }) }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 1', _selected: true }) }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 2', _selected: false }) }, ], ]; @@ -129,30 +136,35 @@ module('Integration | Component | workflow repositories', (hooks) => { /> `); - const repos = this.submission.repositories; - assert.strictEqual(repos.length, 2, 'unexpected number of repositories attached to the submission'); - assert.ok(repos.isAny('name', 'Moo-pository XYZ')); + let repos = this.submission.repositories.slice(); + assert.strictEqual(repos.length, 2, 'expected number of repositories attached to the submission'); + assert.ok(repos.some((repo) => repo.name === 'Moo-pository XYZ')); const checkboxes = this.element.querySelectorAll('input[type="checkbox"]'); - assert.strictEqual(checkboxes.length, 3, 'Unexpected number of checkboxes found'); + assert.strictEqual(checkboxes.length, 3, 'expected number of checkboxes found'); assert.dom(checkboxes[2]).isNotChecked(); await click(checkboxes[2]); - assert.strictEqual(repos.length, 3, 'unexpected number of repositories attached to submission'); - assert.ok(repos.isAny('name', 'Moo-pository 00')); + repos = this.submission.repositories.slice(); + assert.strictEqual(repos.length, 3, 'expected number of repositories attached to submission'); + assert.ok(repos.some((repo) => repo.name === 'Moo-pository 00')); assert.notOk(repos.includes(undefined), 'there should be no "undefined" entries'); assert.dom(checkboxes[2]).isChecked(); }); test('Unselecting optional repo removes it from submission', async function (assert) { - this.requiredRepositories = [{ repository: { name: 'Moo-pository XYZ' } }]; - this.optionalRepositories = [{ repository: { name: 'Moo-pository 00', _selected: true } }]; + this.requiredRepositories = [ + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository XYZ' }) }, + ]; + this.optionalRepositories = [ + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 00', _selected: true }) }, + ]; this.choiceRepositories = [ [ - { repository: { name: 'Moo-pository 1', _selected: true } }, - { repository: { name: 'Moo-pository 2', _selected: false } }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 1', _selected: true }) }, + { repository: this.storeService.createRecord('repository', { name: 'Moo-pository 2', _selected: false }) }, ], ]; @@ -165,20 +177,25 @@ module('Integration | Component | workflow repositories', (hooks) => { /> `); - const repos = this.submission.repositories; + let repos = this.submission.repositories.slice(); assert.strictEqual(repos.length, 3, 'unexpected number of repositories attached to submission'); assert.notOk(repos.includes(undefined), 'should be no undefined items'); - assert.ok(repos.isAny('name', 'Moo-pository 00'), 'The optional repo should be present'); + assert.ok( + repos.some((repo) => repo.name === 'Moo-pository 00'), + 'The optional repo should be present' + ); const checkboxes = this.element.querySelectorAll('input[type="checkbox"]'); - assert.strictEqual(checkboxes.length, 3, 'unexpected number of checkboxes found'); + assert.strictEqual(checkboxes.length, 3, 'expected number of checkboxes found'); assert.dom(checkboxes[2]).isChecked(); await click(checkboxes[2]); - assert.strictEqual(repos.length, 2, 'unexpected number of repositories attached to the submission'); - assert.notOk(repos.isAny('name', 'Moo-pository 00')); + repos = this.submission.repositories.slice(); + assert.strictEqual(repos.length, 2, 'expected number of repositories attached to the submission'); + + assert.notOk(repos.some((repo) => repo.name === 'Moo-pository 00')); assert.dom(checkboxes[2]).isNotChecked(); }); @@ -230,9 +247,24 @@ module('Integration | Component | workflow repositories', (hooks) => { test('Weblink repos are broken out into separate section', async function (assert) { this.requiredRepositories = [ - { repository: { id: 0, name: 'Required repo 1', type: 'full', _isWebLink: false } }, - { repository: { id: 1, name: 'Required repo 2', type: 'full', _isWebLink: false } }, - { repository: { id: 2, name: 'Required web-link repo 3', type: 'web-link', _isWebLink: true } }, + { + repository: this.storeService.createRecord('repository', { + name: 'Required repo 1', + integrationType: 'full', + }), + }, + { + repository: this.storeService.createRecord('repository', { + name: 'Required repo 2', + integrationType: 'full', + }), + }, + { + repository: this.storeService.createRecord('repository', { + name: 'Required web-link repo 3', + integrationType: 'web-link', + }), + }, ]; await render(hbs` diff --git a/tests/unit/controllers/submissions/new/files-test.js b/tests/unit/controllers/submissions/new/files-test.js index 0ed90391..c9984128 100644 --- a/tests/unit/controllers/submissions/new/files-test.js +++ b/tests/unit/controllers/submissions/new/files-test.js @@ -2,7 +2,6 @@ import EmberObject from '@ember/object'; import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { render, click } from '@ember/test-helpers'; module('Unit | Controller | submissions/new/files', (hooks) => { setupTest(hooks); @@ -36,7 +35,8 @@ module('Unit | Controller | submissions/new/files', (hooks) => { let model = { files: [] }; controller.set('model', model); controller.set('loadingNext', true); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { loadTabAccessed = true; }; assert.strictEqual(controller.get('workflow').getFilesTemp().length, 0); @@ -67,7 +67,8 @@ module('Unit | Controller | submissions/new/files', (hooks) => { ); let model = { files: [] }; controller.set('model', model); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { loadTabAccessed = true; }; assert.strictEqual(controller.get('workflow').getFilesTemp().length, 0); @@ -78,11 +79,24 @@ module('Unit | Controller | submissions/new/files', (hooks) => { }); test('Multiple manuscript files stops transition', function (assert) { + const storeService = this.owner.lookup('service:store'); + + const submission = storeService.createRecord('submission', { + save: () => { + return Promise.resolve(); + }, + }); let controller = this.owner.lookup('controller:submissions/new/files'); + let loadTabAccessed = false; - let file = EmberObject.create({ + + const file = storeService.createRecord('file', { fileRole: 'manuscript', + save: () => { + return Promise.resolve(); + }, }); + this.owner.register( 'controller:submissions.new', EmberObject.extend({ @@ -101,9 +115,10 @@ module('Unit | Controller | submissions/new/files', (hooks) => { }) ); let files = [file]; - let model = { files }; + let model = { files, newSubmission: submission }; controller.set('model', model); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { loadTabAccessed = true; }; assert.strictEqual(controller.get('workflow').getFilesTemp().length, 1);