From 5219b46d6ce06a5d8c62cda12e6d8edd56183611 Mon Sep 17 00:00:00 2001 From: Jared Galanis Date: Fri, 28 Jun 2024 10:31:22 -0400 Subject: [PATCH] refactor: remove remaining Ember 5 deprecation warnings (#1275) * refactor: remove routing.transition-methods deprecation * refactor: remove deprecation ember-data:no-a-with-array-like * refactor: remove ember-data:deprecate-array-like deprecation * refactor: remove ember-data:deprecate-promise-many-array-behaviors deprecation * tests passing * fix: missing loading of async false relationships in grants/submissions detail/index * fix: remove auto locationType deprecation warning * fix: include publication and journal in submission fetch on revisit sub workflow with sub id as query param * fix: include submitter with submission in submission index --- app/components/found-manuscripts/index.js | 13 +- app/components/policy-card/index.js | 18 +- .../submissions-repoid-cell/index.js | 11 +- app/components/workflow-basics/index.js | 9 +- app/components/workflow-files/index.js | 52 ++-- app/components/workflow-grants/index.js | 35 +-- app/components/workflow-metadata/index.js | 5 +- app/components/workflow-repositories/index.js | 50 ++-- app/components/workflow-review/index.hbs | 7 +- app/components/workflow-review/index.js | 74 +++--- app/controllers/grants/index.js | 5 +- app/controllers/submissions/detail.js | 13 +- app/controllers/submissions/new.js | 30 ++- app/controllers/submissions/new/basics.js | 12 +- app/controllers/submissions/new/files.js | 39 ++- app/controllers/submissions/new/grants.js | 5 +- app/controllers/submissions/new/metadata.js | 5 +- app/controllers/submissions/new/policies.js | 5 +- .../submissions/new/repositories.js | 66 +---- app/controllers/submissions/new/review.js | 11 +- app/deprecation-workflow.js | 7 +- app/models/repository.js | 1 - app/models/submission.js | 6 +- app/routes/application.js | 3 +- app/routes/grants/detail.js | 2 +- app/routes/grants/index.js | 5 +- app/routes/submissions/detail.js | 4 +- app/routes/submissions/new.js | 7 +- app/routes/submissions/new/index.js | 6 +- app/routes/submissions/new/policies.js | 11 +- app/routes/submissions/new/repositories.js | 84 +++++- app/services/metadata-schema.js | 2 +- app/services/submission-handler.js | 16 +- app/services/workflow.js | 9 +- app/styles/app.css | 8 + app/templates/submissions/detail.hbs | 7 +- app/templates/submissions/new/files.hbs | 5 +- .../submissions/new/repositories.hbs | 6 +- app/util/paginated-query.js | 3 +- config/environment.js | 2 +- package.json | 8 +- .../found-manuscripts/component-test.js | 10 +- .../components/policy-card-test.js | 28 +- .../submissions-repoid-cell-test.js | 12 +- .../components/workflow-files-test.js | 28 +- .../components/workflow-grants-test.js | 10 +- .../components/workflow-repositories-test.js | 84 ++++-- .../controllers/submissions/detail-test.js | 6 +- .../unit/controllers/submissions/new-test.js | 28 +- .../submissions/new/basics-test.js | 8 +- .../controllers/submissions/new/files-test.js | 38 ++- .../submissions/new/grants-test.js | 9 +- .../submissions/new/metadata-test.js | 7 +- .../submissions/new/policies-test.js | 13 +- .../submissions/new/repositories-test.js | 13 +- .../submissions/new/review-test.js | 3 +- yarn.lock | 247 +++++++++++++++--- 57 files changed, 783 insertions(+), 428 deletions(-) diff --git a/app/components/found-manuscripts/index.js b/app/components/found-manuscripts/index.js index 47537613..52915eb7 100644 --- a/app/components/found-manuscripts/index.js +++ b/app/components/found-manuscripts/index.js @@ -1,7 +1,6 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { inject as service } from '@ember/service'; -import { A } from '@ember/array'; import { task } from 'ember-concurrency-decorators'; import { action, get, set } from '@ember/object'; @@ -11,8 +10,8 @@ export default class FoundManuscriptsComponent extends Component { @service store; @service appStaticConfig; - @tracked foundManuscripts = A([]); - @tracked manuscriptsWithErrors = A([]); + @tracked foundManuscripts = []; + @tracked manuscriptsWithErrors = []; @tracked selectedManuscript = null; @tracked contactUrl; @@ -24,10 +23,10 @@ export default class FoundManuscriptsComponent extends Component { } get foundManuscriptsToDisplay() { - let prevFiles = this.args.previouslyUploadedFiles || A([]); - let newFiles = this.args.newFiles || A([]); + 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)) @@ -47,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..eee89c39 100644 --- a/app/components/policy-card/index.js +++ b/app/components/policy-card/index.js @@ -88,18 +88,22 @@ 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); + const hasEffectivePolicy = await this._hasEffectivePolicy(policy.id); + if (!hasEffectivePolicy) { + 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/submissions-repoid-cell/index.js b/app/components/submissions-repoid-cell/index.js index 4d22189b..649f04b8 100644 --- a/app/components/submissions-repoid-cell/index.js +++ b/app/components/submissions-repoid-cell/index.js @@ -3,7 +3,6 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action, get, set } from '@ember/object'; import { inject as service } from '@ember/service'; -import { A } from '@ember/array'; export default class SubmissionsRepoidCell extends Component { @service store; @@ -13,18 +12,18 @@ export default class SubmissionsRepoidCell extends Component { jscholarshipCheckString = '/handle/'; @action - setUpRepoidCell() { - const publicationId = get(this, 'args.record.publication.id'); - if (!publicationId) { + async setUpRepoidCell() { + const publication = await this.args.record.publication; + if (!publication?.id) { if (!(get(this, 'isDestroyed') || get(this, 'isDestroying'))) { - set(this, 'repoCopies', A()); + this.repoCopies = []; return; } } const query = { filter: { - repositoryCopy: `publication.id==${publicationId}`, + repositoryCopy: `publication.id==${publication.id}`, }, }; diff --git a/app/components/workflow-basics/index.js b/app/components/workflow-basics/index.js index be05b574..ecc64821 100644 --- a/app/components/workflow-basics/index.js +++ b/app/components/workflow-basics/index.js @@ -4,7 +4,6 @@ import { tracked } from '@glimmer/tracking'; import { action, get, set } from '@ember/object'; import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; -import { A } from '@ember/array'; import { task, timeout } from 'ember-concurrency'; import { scheduleOnce } from '@ember/runloop'; import { dropTask } from 'ember-concurrency-decorators'; @@ -207,7 +206,7 @@ export default class WorkflowBasics extends Component { }); if (result.value) { - set(this, 'submission.grants', A()); + set(this, 'submission.grants', []); this.updateSubmitterModel(isProxySubmission, submitter); this.flashMessages.info('Submitter and related grants removed from submission.'); @@ -224,10 +223,10 @@ export default class WorkflowBasics extends Component { this.submission.submitterName = ''; if (isProxySubmission) { this.submission.submitter = submitter; - this.submission.preparers = A([get(this, 'currentUser.user')]); + this.submission.preparers = [this.currentUser.user]; } else { - this.submission.submitter = get(this, 'currentUser.user'); - this.submission.preparers = A(); + this.submission.submitter = this.currentUser.user; + this.submission.preparers = []; } } diff --git a/app/components/workflow-files/index.js b/app/components/workflow-files/index.js index 805ae49f..c7fd2062 100644 --- a/app/components/workflow-files/index.js +++ b/app/components/workflow-files/index.js @@ -1,10 +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 { A } from '@ember/array'; 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; @@ -13,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') || A([]); - const prevFiles = get(this, 'args.previouslyUploadedFiles') || A([]); + 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') || A([]); - const prevFiles = get(this, 'args.previouslyUploadedFiles') || A([]); + 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(); }; @@ -68,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; } @@ -117,8 +112,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); @@ -140,7 +137,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 7972fb23..287395c7 100644 --- a/app/components/workflow-grants/index.js +++ b/app/components/workflow-grants/index.js @@ -2,7 +2,6 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action, get, set } from '@ember/object'; -import { A } from '@ember/array'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; @@ -28,7 +27,7 @@ export default class WorkflowGrants extends Component { @tracked submitterGrants = null; @tracked totalGrants = 0; /** Grants already attached to the submission on component init */ - @tracked _selectedGrants = A(); + @tracked _selectedGrants = []; @tracked preLoadedGrant = this.args.preLoadedGrant; @tracked grantColumns = [ { @@ -92,24 +91,26 @@ export default class WorkflowGrants extends Component { setup = function* () { this.contactUrl = this.appStaticConfig?.config?.branding?.pages?.contactUrl; - if (get(this, 'args.submission.submitter.id')) { + const submitter = yield this.args.submission.submitter; + if (submitter?.id) { yield this.updateGrants.perform(); } // 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 () => { let info = {}; - const userId = get(this, 'args.submission.submitter.id'); + const userId = await this.args.submission.submitter.id; // TODO: Ignore date filter for now ( >= 2011-01-01 ) const grantQuery = { filter: { @@ -125,8 +126,8 @@ export default class WorkflowGrants extends Component { this.submitterGrants = results; // TODO: How do we get pagination to work with store.query like this? - set(this, 'totalGrants', info.total); - set(this, 'pageCount', Math.ceil(info.total / this.pageSize)); + this.totalGrants = info.total; + this.pageCount = Math.ceil(info.total / this.pageSize); }); /** @@ -175,18 +176,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(); @@ -201,7 +203,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 @@ -209,9 +211,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-metadata/index.js b/app/components/workflow-metadata/index.js index ef475c24..cbebc22c 100644 --- a/app/components/workflow-metadata/index.js +++ b/app/components/workflow-metadata/index.js @@ -78,11 +78,12 @@ export default class WorkflowMetadata extends Component { // 10.4137/CMC.S38446 // 10.1039/c7an01256j if (!this.schemas) { - const repos = this.args.submission.repositories.map((repo) => repo.id); + const repositories = yield this.args.submission.repositories; + const repoIds = repositories.map((repo) => repo.id); // Load schemas by calling the Schema service try { - const schemas = yield this.metadataSchema.getMetadataSchemas(repos); + const schemas = yield this.metadataSchema.getMetadataSchemas(repoIds); const requiresJournal = schemas.findIndex((schema) => 'required' in schema && schema.required.includes('journal-title')) != -1; diff --git a/app/components/workflow-repositories/index.js b/app/components/workflow-repositories/index.js index 757e0751..bbfb651d 100644 --- a/app/components/workflow-repositories/index.js +++ b/app/components/workflow-repositories/index.js @@ -1,8 +1,7 @@ /* eslint-disable ember/no-get */ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; -import { action, get, set } from '@ember/object'; -import { A } from '@ember/array'; +import { action } from '@ember/object'; import { inject as service } from '@ember/service'; /** @@ -37,7 +36,7 @@ export default class WorkflowRepositories extends Component { @service submissionHandler; @service workflow; - @tracked addedRepos = A([]); + @tracked addedRepos = []; // Separate out repositories that PASS has some level of integration get requiredIntegratedRepos() { @@ -46,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,13 +55,13 @@ export default class WorkflowRepositories extends Component { * are valid */ @action - setupRepos() { - set(this, 'addedRepos', this.getAddedRepositories()); - const currentRepos = get(this, 'submission.repositories'); + async setupRepos() { + this.addedRepos = this.getAddedRepositories(); + const currentRepos = await this.args.submission.repositories; - const opt = this.args.optionalRepositories; - const req = this.args.requiredRepositories; - const choice = this.args.choiceRepositories; + const opt = await this.args.optionalRepositories; + const req = await this.args.requiredRepositories; + const choice = await this.args.choiceRepositories; if (currentRepos && currentRepos.length > 0) { /** @@ -107,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 @@ -118,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)); }); } @@ -146,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,11 +206,11 @@ export default class WorkflowRepositories extends Component { * @param {Repository} repository * @param {boolean} setMaxStep should we modify 'maxStep' in the workflow? */ - addRepository(repository, setMaxStep) { - const subRepos = get(this, 'args.submission.repositories'); + async addRepository(repository, setMaxStep) { + const repos = await this.args.submission.repositories; - if (!subRepos.includes(repository)) { - subRepos.pushObject(repository); + if (!repos.includes(repository)) { + this.args.submission.repositories = [repository, ...repos]; } if (setMaxStep) { this.workflow.setMaxStep(4); @@ -220,8 +223,9 @@ export default class WorkflowRepositories extends Component { * @param {Repository} repository * @param {boolean} setMaxStep should we modify 'maxStep' in the workflow? */ - removeRepository(repository, setMaxStep) { - get(this, 'args.submission.repositories').removeObject(repository); + async removeRepository(repository, setMaxStep) { + const repositories = await this.args.submission.repositories; + 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/components/workflow-review/index.js b/app/components/workflow-review/index.js index 474e91f1..e244c91a 100644 --- a/app/components/workflow-review/index.js +++ b/app/components/workflow-review/index.js @@ -2,7 +2,6 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action, get, set } from '@ember/object'; -import { A } from '@ember/array'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency-decorators'; import { later } from '@ember/runloop'; @@ -23,12 +22,13 @@ export default class WorkflowReview extends Component { @service currentUser; @service flashMessages; - @tracked isValidated = A(); + @tracked isValidated = []; @tracked filesTemp = this.workflow.filesTemp; @tracked hasVisitedWeblink = false; + @tracked repositories = this.args.submission.repositories; get parsedFiles() { - let newArr = A(); + let newArr = []; if (this.filesTemp) { newArr.addObjects(this.filesTemp); } @@ -39,12 +39,14 @@ export default class WorkflowReview extends Component { } get weblinkRepos() { - const repos = get(this, 'args.submission.repositories').filter((repo) => repo.get('_isWebLink')); - return repos; + const webLinkRepos = this.repositories.filter((repo) => repo._isWebLink); + + return webLinkRepos; } get mustVisitWeblink() { - const weblinkExists = get(this, 'weblinkRepos.length') > 0; + const weblinkExists = this.weblinkRepos.length > 0; + const isSubmitter = get(this, 'currentUser.user.id') === get(this, 'args.submission.submitter.id'); return weblinkExists && isSubmitter; } @@ -102,24 +104,25 @@ export default class WorkflowReview extends Component { } // User is submitting on own behalf. Must get repository agreements. - let reposWithAgreementText = get(this, 'args.submission.repositories') - .filter((repo) => !repo.get('_isWebLink') && repo.get('agreementText')) + const repos = yield this.args.submission.repositories; + let reposWithAgreementText = repos + .filter((repo) => !repo._isWebLink && repo.agreementText) .map((repo) => ({ - id: repo.get('name'), - title: `Deposit requirements for ${repo.get('name')}`, - html: `
${repo.get('agreementText')}
`, + id: repo.name, + title: `Deposit requirements for ${repo.name}`, + html: `
${repo.agreementText}
`, })); - let reposWithoutAgreementText = get(this, 'args.submission.repositories') - .filter((repo) => !repo.get('_isWebLink') && !repo.get('agreementText')) + let reposWithoutAgreementText = repos + .filter((repo) => !repo._isWebLink && !repo.agreementText) .map((repo) => ({ - id: repo.get('name'), + id: repo.name, })); - let reposWithWebLink = get(this, 'args.submission.repositories') - .filter((repo) => repo.get('_isWebLink')) + let reposWithWebLink = repos + .filter((repo) => repo._isWebLink) .map((repo) => ({ - id: repo.get('name'), + id: repo.name, })); const result = yield swal @@ -182,22 +185,23 @@ export default class WorkflowReview extends Component { * It is assumed that the user has done the necessary steps for each web-link repository, * so those are also kept in the list */ - set( - this, - 'args.submission.repositories', - get(this, 'args.submission.repositories').filter((repo) => { - if (repo.get('_isWebLink')) { - return true; - } - let temp = reposWithAgreementText.map((x) => x.id).includes(repo.get('name')); - if (!temp) { - return true; - } else if (reposThatUserAgreedToDeposit.map((r) => r.id).includes(repo.get('name'))) { - return true; - } - return false; - }) - ); + + const repos = yield this.args.submission.repositories; + + const filteredRepos = repos.filter((repo) => { + if (repo._isWebLink) { + return true; + } + let temp = reposWithAgreementText.map((x) => x.id).includes(repo.name); + if (!temp) { + return true; + } else if (reposThatUserAgreedToDeposit.map((r) => r.id).includes(repo.name)) { + return true; + } + return false; + }); + + this.args.submission.repositories = filteredRepos; this.args.submit(); } else { @@ -272,14 +276,14 @@ export default class WorkflowReview extends Component { return; } // Go to the weblink repo - this.externalRepoMap[repo.get('id')] = true; + this.externalRepoMap[repo.id] = true; const allLinksVisited = Object.values(this.externalRepoMap).every((val) => val === true); if (allLinksVisited) { this.hasVisitedWeblink = true; } $('#externalSubmission').modal('hide'); - var win = window.open(repo.get('url'), '_blank'); + var win = window.open(repo.url, '_blank'); if (win) { win.focus(); diff --git a/app/controllers/grants/index.js b/app/controllers/grants/index.js index 101b3931..a8835efd 100644 --- a/app/controllers/grants/index.js +++ b/app/controllers/grants/index.js @@ -1,5 +1,4 @@ /* eslint-disable ember/classic-decorator-no-classic-methods */ -import { A } from '@ember/array'; import Controller from '@ember/controller'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking'; @@ -185,7 +184,7 @@ export default class GrantsIndexController extends Controller { const meta = data.meta; let results = data.map((grant) => ({ grant, - submissions: A(), + submissions: [], })); return { @@ -202,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 7220c22c..61dec412 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; @@ -12,6 +13,7 @@ export default class SubmissionsDetail extends Controller { @service submissionHandler; @service searchHelper; @service flashMessages; + @service router; constructor() { super(...arguments); @@ -88,10 +90,11 @@ export default class SubmissionsDetail extends Controller { /** * Get enough information about 'web-link' repositories to display to a user. */ - get externalSubmissionsMetadata() { + async externalSubmissionsMetadata() { let result = []; - this.repositories + const repos = await this.model.sub.repositories; + repos .filter((repo) => repo._isWebLink) .forEach((repo) => { result.push({ @@ -284,9 +287,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', @@ -479,7 +484,7 @@ export default class SubmissionsDetail extends Controller { ignoreList.clearIgnore(); ignoreList.ignore(submission.get('id')); - this.transitionToRoute('submissions'); + this.router.transitionTo('submissions'); } catch (e) { this.flashMessages.danger( 'We encountered an error deleting this draft submission. Please try again later or contact your administrator' diff --git a/app/controllers/submissions/new.js b/app/controllers/submissions/new.js index 81a4b617..7647000d 100644 --- a/app/controllers/submissions/new.js +++ b/app/controllers/submissions/new.js @@ -1,9 +1,9 @@ /* eslint-disable ember/no-get, ember/classic-decorator-no-classic-methods */ import Controller from '@ember/controller'; import { tracked } from '@glimmer/tracking'; -import { A } from '@ember/array'; 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']; @@ -20,10 +20,11 @@ export default class SubmissionsNew extends Controller { @tracked user = this.currentUser.user; @tracked submitter = this.model.newSubmission.submitter; @tracked covid = null; - @tracked filesTemp = get(this, 'workflow.filesTemp'); + @tracked filesTemp = this.workflow.filesTemp; - get userIsSubmitter() { - return get(this, 'model.newSubmission.submitter.id') === this.user.id; + async userIsSubmitter() { + const submitter = await this.model.newSubmission.submitter; + return submitter?.id === this.user.id; } /** @@ -80,8 +81,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'); @@ -92,25 +95,26 @@ export default class SubmissionsNew extends Controller { 'warning' ); } else { - let sub = get(this, 'model.newSubmission'); - let pub = get(this, 'model.publication'); + let sub = this.model.newSubmission; + let pub = this.model.publication; let files = this.filesTemp; let comment = this.comment; this.set('uploading', true); this.set('waitingMessage', 'Saving your submission'); - await get(this, 'submissionHandler.submit') + await this.submissionHandler.submit .perform(sub, pub, files, comment) .then(() => { set(this, 'uploading', false); set(this, 'comment', ''); - set(this, 'workflow.filesTemp', A()); - this.transitionToRoute('thanks', { queryParams: { submission: get(sub, 'id') } }); + set(this, 'workflow.filesTemp', []); + this.router.transitionTo('thanks', { queryParams: { submission: sub.id } }); }) .catch((error) => { this.set('uploading', false); + console.error(error.stack); this.flashMessages.danger(`Submission failed: ${error.message}`); const elements = document.querySelectorAll('.block-user-input'); @@ -123,7 +127,7 @@ export default class SubmissionsNew extends Controller { @action async abort() { - const submission = get(this, 'model.newSubmission'); + const submission = this.model.newSubmission; const ignoreList = this.searchHelper; let result = await swal({ @@ -138,7 +142,7 @@ export default class SubmissionsNew extends Controller { ignoreList.clearIgnore(); if (submission.id) { await this.submissionHandler.deleteSubmission(submission); - ignoreList.ignore(get(submission, 'id')); + ignoreList.ignore(submission.id); } this.router.transitionTo('submissions'); } diff --git a/app/controllers/submissions/new/basics.js b/app/controllers/submissions/new/basics.js index 57f3a648..5c120473 100644 --- a/app/controllers/submissions/new/basics.js +++ b/app/controllers/submissions/new/basics.js @@ -2,7 +2,6 @@ import Controller, { inject as controller } from '@ember/controller'; import { tracked } from '@glimmer/tracking'; import { action, computed, get, set } from '@ember/object'; -import { A } from '@ember/array'; import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency-decorators'; @@ -10,6 +9,7 @@ import { task } from 'ember-concurrency-decorators'; export default class SubmissionsNewBasics extends Controller { @service workflow; @service flashMessages; + @service router; @alias('model.newSubmission') submission; @alias('model.publication') publication; @@ -25,10 +25,10 @@ export default class SubmissionsNewBasics extends Controller { @tracked submitterEmailError = false; get flaggedFields() { - let fields = A(); - if (this.titleError) fields.pushObject('title'); - if (this.journalError) fields.pushObject('journal'); - if (this.submitterEmailError) fields.pushObject('submitterEmail'); + let fields = []; + if (this.titleError) fields.push('title'); + if (this.journalError) fields.push('journal'); + if (this.submitterEmailError) fields.push('submitterEmail'); return fields; } @@ -64,7 +64,7 @@ export default class SubmissionsNewBasics extends Controller { this.doiInfo.title = this.publication.title; await this.submission.save(); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); } @action diff --git a/app/controllers/submissions/new/files.js b/app/controllers/submissions/new/files.js index 7cb266c4..eedf43d9 100644 --- a/app/controllers/submissions/new/files.js +++ b/app/controllers/submissions/new/files.js @@ -8,6 +8,7 @@ import { inject as service } from '@ember/service'; export default class SubmissionsNewFiles extends Controller { @service workflow; @service flashMessages; + @service router; @alias('model.newSubmission') submission; @alias('model.files') files; @@ -18,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() { @@ -29,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); @@ -50,19 +48,38 @@ export default class SubmissionsNewFiles extends Controller { this.updateRelatedData(); await this.submission.save(); set(this, 'loadingNext', false); // reset for next time - this.transitionToRoute(gotoRoute); + 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' + ); + + const submitter = await this.parent.userIsSubmitter(); - if (manuscriptFiles.length == 0 && !this.parent.userIsSubmitter) { + if (manuscriptFiles.length == 0 && !submitter) { let result = await swal({ title: 'No manuscript present', text: 'If no manuscript is attached, the designated submitter will need to add one before final submission', diff --git a/app/controllers/submissions/new/grants.js b/app/controllers/submissions/new/grants.js index bdd01a48..1e90aad7 100644 --- a/app/controllers/submissions/new/grants.js +++ b/app/controllers/submissions/new/grants.js @@ -2,8 +2,11 @@ import Controller, { inject as controller } from '@ember/controller'; import { action } from '@ember/object'; import { alias } from '@ember/object/computed'; +import { inject as service } from '@ember/service'; export default class SubmissionsNewGrants extends Controller { + @service router; + @alias('model.newSubmission') submission; @alias('model.publication') publication; @alias('model.submissionEvents') submissionEvents; @@ -24,7 +27,7 @@ export default class SubmissionsNewGrants extends Controller { async loadTab(gotoRoute) { // add validation, processing await this.submission.save(); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); } @action diff --git a/app/controllers/submissions/new/metadata.js b/app/controllers/submissions/new/metadata.js index e3d63aa9..fa7fb989 100644 --- a/app/controllers/submissions/new/metadata.js +++ b/app/controllers/submissions/new/metadata.js @@ -2,8 +2,11 @@ import Controller, { inject as controller } from '@ember/controller'; import { action } from '@ember/object'; import { alias } from '@ember/object/computed'; +import { inject as service } from '@ember/service'; export default class SubmissionsNewMetadata extends Controller { + @service router; + @alias('model.newSubmission') submission; @alias('model.repositories') repositories; @alias('model.publication') publication; @@ -25,7 +28,7 @@ export default class SubmissionsNewMetadata extends Controller { async loadTab(gotoRoute) { // add validation, processing await this.submission.save(); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); } @action diff --git a/app/controllers/submissions/new/policies.js b/app/controllers/submissions/new/policies.js index ff3ef5a7..be7b752f 100644 --- a/app/controllers/submissions/new/policies.js +++ b/app/controllers/submissions/new/policies.js @@ -2,8 +2,11 @@ import Controller, { inject as controller } from '@ember/controller'; import { action } from '@ember/object'; import { alias } from '@ember/object/computed'; +import { inject as service } from '@ember/service'; export default class SubmissionsNewPolicies extends Controller { + @service router; + @alias('model.newSubmission') submission; @alias('model.policies') policies; @alias('model.publication') publication; @@ -25,7 +28,7 @@ export default class SubmissionsNewPolicies extends Controller { async loadTab(gotoRoute) { // add validation, processing await this.submission.save(); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); } @action diff --git a/app/controllers/submissions/new/repositories.js b/app/controllers/submissions/new/repositories.js index abf44263..45a8dab6 100644 --- a/app/controllers/submissions/new/repositories.js +++ b/app/controllers/submissions/new/repositories.js @@ -1,12 +1,13 @@ /* eslint-disable ember/no-computed-properties-in-native-classes, ember/no-get, ember/require-computed-property-dependencies */ import Controller, { inject as controller } from '@ember/controller'; import { tracked } from '@glimmer/tracking'; -import { action, computed, get, set } from '@ember/object'; +import { action, get, set } from '@ember/object'; import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; export default class SubmissionsNewRepositories extends Controller { @service workflow; + @service router; @alias('model.newSubmission') submission; @alias('model.repositories') repositories; @@ -18,56 +19,14 @@ export default class SubmissionsNewRepositories extends Controller { @tracked maxStep = this.workflow.maxStep; @tracked loadingNext = false; - @computed('workflow.maxStep') get nextTabIsActive() { return get(this, 'workflow').getMaxStep() > 6; } - @computed('nextTabIsActive', 'loadingNext') get needValidation() { return this.nextTabIsActive || this.loadingNext; } - /* - * Do some light processing on the repository containers, such as adding the names of funders - * that both are associated with the submission AND associated with each repository. - */ - @computed('model.requiredRepositories') - get requiredRepositories() { - let req = get(this, 'model.requiredRepositories'); - const submission = this.submission; - - return req.map((repo) => ({ - repository: repo, - funders: this._getFunderNamesForRepo(repo, submission), - })); - } - - @computed('model.optionalRepositories') - get optionalRepositories() { - const submission = this.submission; - let optionals = get(this, 'model.optionalRepositories'); - - return optionals.map((repo) => ({ - repository: repo, - funders: this._getFunderNamesForRepo(repo, submission), - })); - } - - @computed('model.choiceRepositories') - get choiceRespositories() { - const submission = this.submission; - let choices = get(this, 'model.choiceRepositories'); - - choices.forEach((group) => { - group.map((repo) => ({ - repository: repo, - funders: this._getFunderNamesForRepo(repo, submission), - })); - }); - return choices; - } - @action loadNext() { set(this, 'loadingNext', true); @@ -82,7 +41,7 @@ export default class SubmissionsNewRepositories extends Controller { @action async loadTab(gotoRoute) { await this.submission.save(); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); set(this, 'loadingNext', false); // reset for next time } @@ -102,7 +61,7 @@ export default class SubmissionsNewRepositories extends Controller { }); if (value.dismiss) { - this.transitionToRoute('dashboard'); + this.router.transitionTo('dashboard'); } // do nothing } else { @@ -119,21 +78,4 @@ export default class SubmissionsNewRepositories extends Controller { updateCovidSubmission() { this.parent.updateCovidSubmission(); } - - _getFunderNamesForRepo(repo, submission) { - const funders = get(submission, 'grants').map((grant) => get(grant, 'primaryFunder')); - const fundersWithRepos = funders.filter((funder) => get(funder, 'policy.repositories')); - // List of funders that include this repository - const fundersWithOurRepo = fundersWithRepos.filter( - (funder) => get(funder, 'policy') && funder.get('policy.repositories').includes(repo) - ); - - if (fundersWithRepos && fundersWithOurRepo.length > 0) { - return fundersWithOurRepo - .map((funder) => get(funder, 'name')) - .filter((item, index, arr) => arr.indexOf(item) == index) - .join(', '); - } - return ''; - } } diff --git a/app/controllers/submissions/new/review.js b/app/controllers/submissions/new/review.js index 2ac3fe94..2c225a89 100644 --- a/app/controllers/submissions/new/review.js +++ b/app/controllers/submissions/new/review.js @@ -3,13 +3,18 @@ import Controller, { inject as controller } from '@ember/controller'; import { action, computed, get } from '@ember/object'; import { alias } from '@ember/object/computed'; import { tracked } from '@glimmer/tracking'; +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') @@ -31,9 +36,7 @@ export default class SubmissionsNewReview extends Controller { @action loadTab(gotoRoute) { - // add validation, processing - // this.submission.save().then(() => this.transitionToRoute(gotoRoute)); - this.transitionToRoute(gotoRoute); + this.router.transitionTo(gotoRoute); } @action diff --git a/app/deprecation-workflow.js b/app/deprecation-workflow.js index 2d48a9c0..a0f1a874 100644 --- a/app/deprecation-workflow.js +++ b/app/deprecation-workflow.js @@ -1,10 +1,5 @@ import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow'; setupDeprecationWorkflow({ - workflow: [ - { handler: 'silence', matchId: 'routing.transition-methods' }, - { handler: 'silence', matchId: 'ember-data:deprecate-promise-many-array-behaviors' }, - { handler: 'silence', matchId: 'ember-data:deprecate-array-like' }, - { handler: 'silence', matchId: 'ember-data:no-a-with-array-like' }, - ], + workflow: [{ handler: 'throw', 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/models/submission.js b/app/models/submission.js index fd6c4a7c..a9cfaedc 100644 --- a/app/models/submission.js +++ b/app/models/submission.js @@ -21,11 +21,11 @@ export default class SubmissionModel extends Model { @attr('number') version; @belongsTo('user', { async: false, inverse: null }) submitter; - @belongsTo('publication', { async: false, inverse: null }) publication; + @belongsTo('publication', { async: true, inverse: null }) publication; @hasMany('user', { async: false, inverse: null }) preparers; - @hasMany('repository', { async: true, inverse: null }) repositories; - @hasMany('policy', { async: false, inverse: null }) effectivePolicies; + @hasMany('repository', { async: false, inverse: null }) repositories; + @hasMany('policy', { async: true, inverse: null }) effectivePolicies; // not on this model on API @hasMany('submissionEvent', { async: true, diff --git a/app/routes/application.js b/app/routes/application.js index 44981bbf..22a6282c 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -5,6 +5,7 @@ import { action } from '@ember/object'; export default class ApplicationRoute extends CheckSessionRoute { @service('app-static-config') staticConfig; + @service router; queryParams = ['userToken']; @@ -16,7 +17,7 @@ export default class ApplicationRoute extends CheckSessionRoute { @action transitionTo(route, model) { - this.transitionTo(route, model); + this.router.transitionTo(route, model); } /** diff --git a/app/routes/grants/detail.js b/app/routes/grants/detail.js index 63af7eb7..a64663a5 100644 --- a/app/routes/grants/detail.js +++ b/app/routes/grants/detail.js @@ -28,7 +28,7 @@ export default class DetailRoute extends CheckSessionRoute { return; } - const grant = this.store.findRecord('grant', params.grant_id); + const grant = this.store.findRecord('grant', params.grant_id, { include: 'pi,coPis' }); const submissionQuery = grantDetailsQuery(params, params.grant_id, this.currentUser.user); const submissions = this.store.query('submission', submissionQuery).then((data) => ({ data, meta: data.meta })); diff --git a/app/routes/grants/index.js b/app/routes/grants/index.js index 3e96efb6..fcd3296b 100644 --- a/app/routes/grants/index.js +++ b/app/routes/grants/index.js @@ -1,5 +1,4 @@ import { service } from '@ember/service'; -import { A } from '@ember/array'; import CheckSessionRoute from '../check-session-route'; import { grantsIndexGrantQuery, grantsIndexSubmissionQuery } from '../../util/paginated-query'; @@ -44,7 +43,7 @@ export default class IndexRoute extends CheckSessionRoute { grants.forEach((grant) => { results.grantMap.push({ grant, - submissions: A(), + submissions: [], }); }); @@ -57,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/detail.js b/app/routes/submissions/detail.js index 2452f179..b3c93f44 100644 --- a/app/routes/submissions/detail.js +++ b/app/routes/submissions/detail.js @@ -25,7 +25,9 @@ export default class DetailRoute extends CheckSessionRoute { // sort: '+performedDate', }); - const sub = await this.store.findRecord('submission', params.submission_id); + const sub = await this.store.findRecord('submission', params.submission_id, { + include: 'publication.journal,repositories', + }); const publication = await sub.get('publication'); const repoCopies = await this.store.query('repositoryCopy', { filter: { repositoryCopy: `publication.id==${publication.id}` }, diff --git a/app/routes/submissions/new.js b/app/routes/submissions/new.js index b4908bff..5b6c48df 100644 --- a/app/routes/submissions/new.js +++ b/app/routes/submissions/new.js @@ -8,13 +8,14 @@ export default class NewRoute extends CheckSessionRoute { @service('workflow') workflow; @service store; + @service router; @service('current-user') currentUser; beforeModel() { if (this.workflow.getCurrentStep() === 0) { - this.transitionTo('submissions.new'); + this.router.transitionTo('submissions.new'); } } @@ -54,7 +55,7 @@ export default class NewRoute extends CheckSessionRoute { if (params.submission) { // Operating on existing submission - newSubmission = await this.store.findRecord('submission', params.submission); + newSubmission = await this.store.findRecord('submission', params.submission, { include: 'publication.journal' }); publication = await newSubmission.get('publication'); journal = publication.get('journal'); @@ -65,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/index.js b/app/routes/submissions/new/index.js index f90f1791..7b2c5df1 100644 --- a/app/routes/submissions/new/index.js +++ b/app/routes/submissions/new/index.js @@ -2,11 +2,11 @@ import { inject as service } from '@ember/service'; import CheckSessionRoute from './../../check-session-route'; export default class IndexRoute extends CheckSessionRoute { - @service('workflow') - workflow; + @service workflow; + @service router; beforeModel() { this.workflow.resetWorkflow(); - this.replaceWith('submissions.new.basics'); + this.router.replaceWith('submissions.new.basics'); } } 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/routes/submissions/new/repositories.js b/app/routes/submissions/new/repositories.js index 86acd326..9310f52f 100644 --- a/app/routes/submissions/new/repositories.js +++ b/app/routes/submissions/new/repositories.js @@ -5,27 +5,89 @@ import { hash } from 'rsvp'; import CheckSessionRoute from '../../check-session-route'; export default class RepositoriesRoute extends CheckSessionRoute { - @service('workflow') - workflow; - - @service('policies') - policyService; + @service workflow; + @service policies; async model() { const parentModel = this.modelFor('submissions.new'); - const submission = parentModel.newSubmission; + this.submission = parentModel.newSubmission; - const repoPromise = await get(this, 'policyService.getRepositories').perform(submission); + this.repositories = await this.policies.getRepositories.perform(this.submission); return hash({ - newSubmission: submission, + newSubmission: this.submission, preLoadedGrant: parentModel.preLoadedGrant, - requiredRepositories: repoPromise.required, - optionalRepositories: repoPromise.optional, - choiceRepositories: repoPromise['one-of'], + requiredRepositories: this.requiredRepositories(), + optionalRepositories: this.optionalRepositories(), + choiceRepositories: this.choiceRepositories(), }); } + async _getFunderNamesForRepo(repo, submission) { + const grants = await submission.grants; + + const funders = grants.map((grant) => get(grant, 'primaryFunder')); + const fundersWithRepos = funders.filter((funder) => get(funder, 'policy.repositories')); + // List of funders that include this repository + const fundersWithOurRepo = fundersWithRepos.filter( + (funder) => get(funder, 'policy') && funder.get('policy.repositories').includes(repo) + ); + + if (fundersWithRepos && fundersWithOurRepo.length > 0) { + return fundersWithOurRepo + .map((funder) => funder.get('name')) + .filter((item, index, arr) => arr.indexOf(item) == index) + .join(', '); + } + return ''; + } + + async requiredRepositories() { + return Promise.all( + this.repositories?.required.map(async (repo) => { + const funders = await this._getFunderNamesForRepo(repo, this.submission); + return { + repository: repo, + funders, + }; + }) + ); + } + + async optionalRepositories() { + return Promise.all( + this.repositories?.optional.map(async (repo) => { + const funders = await this._getFunderNamesForRepo(repo, this.submission); + + return { + repository: repo, + funders, + }; + }) + ); + } + + async choiceRepositories() { + let formattedChoices = []; + const choices = this.repositories['one-of'] ?? []; + + for (const group of choices) { + const formattedGroup = []; + for (const repo of group) { + const funders = await this._getFunderNamesForRepo(repo, this.submission); + + formattedGroup.push({ + repository: repo, + funders, + }); + } + + formattedChoices.push(formattedGroup); + } + + return formattedChoices; + } + @action didTransition() { this.workflow.setCurrentStep(4); diff --git a/app/services/metadata-schema.js b/app/services/metadata-schema.js index f5f9703f..d01a4d89 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; 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 5d538a79..423c3422 100644 --- a/app/services/submission-handler.js +++ b/app/services/submission-handler.js @@ -1,10 +1,9 @@ /* eslint-disable ember/no-get */ -import { A, isArray } from '@ember/array'; +import { isArray } from '@ember/array'; import Service, { inject as service } from '@ember/service'; import ENV from 'pass-ui/config/environment'; import { task } from 'ember-concurrency-decorators'; import { get } from '@ember/object'; -import SubmissionModel from '../models/submission'; import { fileForSubmissionQuery, submissionsWithPublicationQuery } from '../util/paginated-query'; /** @@ -22,17 +21,17 @@ export default class SubmissionHandlerService extends Service { * @returns EmberArray with repositories */ getRepositoriesFromGrants(grants) { - let result = A(); + let result = []; grants.forEach((grant) => { const directRepos = grant.get('directFunder.policy.repositories'); 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()); } }); @@ -77,8 +76,9 @@ export default class SubmissionHandlerService extends Service { submission.set('submissionStatus', 'submitted'); submission.set('submittedDate', new Date()); + const repos = yield submission.repositories; // Add agreements metadata - const agreemd = get(this, 'schemaService').getAgreementsBlob(submission.get('repositories')); + const agreemd = get(this, 'schemaService').getAgreementsBlob(repos); if (agreemd) { let md = JSON.parse(submission.get('metadata')); @@ -135,9 +135,7 @@ export default class SubmissionHandlerService extends Service { yield get(this, '_finishSubmission') .perform(s, comment) .catch((e) => { - if (!didCancel(e)) { - throw e; - } + throw e; }); }; diff --git a/app/services/workflow.js b/app/services/workflow.js index 35f8fbf2..080fa04b 100644 --- a/app/services/workflow.js +++ b/app/services/workflow.js @@ -1,5 +1,4 @@ /* eslint-disable ember/classic-decorator-no-classic-methods */ -import { A } from '@ember/array'; import Service from '@ember/service'; import { tracked } from '@glimmer/tracking'; @@ -20,7 +19,7 @@ export default class Workflow extends Service { @tracked filesTemp = []; @tracked defaultRepoLoaded = false; // you only want to load the default setting on first access, after that is should respect he user's choice. - @tracked addedGrants = A([]); + @tracked addedGrants = []; resetWorkflow() { this.setCurrentStep(0); @@ -99,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..6b2ee44a 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 = await this.submission.effectivePolicies; 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/submissions-repoid-cell-test.js b/tests/integration/components/submissions-repoid-cell-test.js index 535beaee..805def72 100644 --- a/tests/integration/components/submissions-repoid-cell-test.js +++ b/tests/integration/components/submissions-repoid-cell-test.js @@ -24,6 +24,12 @@ module('Integration | Component | submissions repoid cell', (hooks) => { }); test('it renders', async function (assert) { + const record = EmberObject.create({ + publication: EmberObject.create({ id: '1' }), + }); + + this.record = record; + await render(hbs` @@ -31,7 +37,7 @@ module('Integration | Component | submissions repoid cell', (hooks) => { - + `); assert.ok(true); @@ -54,7 +60,7 @@ module('Integration | Component | submissions repoid cell', (hooks) => { const record = EmberObject.create({ publication: EmberObject.create({}), }); - this.set('record', record); + this.record = record; await render(hbs` @@ -63,7 +69,7 @@ module('Integration | Component | submissions repoid cell', (hooks) => { - + `); assert.ok(true); }); 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..b85ae0ad 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 = await this.submission.repositories; + 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 = await this.submission.repositories; + 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 = await this.submission.repositories; 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 = await this.submission.repositories; + 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/detail-test.js b/tests/unit/controllers/submissions/detail-test.js index 0c48a753..b72d728b 100644 --- a/tests/unit/controllers/submissions/detail-test.js +++ b/tests/unit/controllers/submissions/detail-test.js @@ -13,7 +13,7 @@ module('Unit | Controller | submissions/detail', (hooks) => { }); test('delete action should call the submission handler', function (assert) { - assert.expect(3); + assert.expect(2); // Mock the global SweetAlert object to always return immediately swal = () => @@ -35,7 +35,6 @@ module('Unit | Controller | submissions/detail', (hooks) => { }, }) ); - controller.set('transitionToRoute', () => assert.ok(true)); controller.send('deleteSubmission', submission); }); @@ -47,7 +46,8 @@ module('Unit | Controller | submissions/detail', (hooks) => { swal = Sinon.fake.resolves({ value: true }); const controller = this.owner.lookup('controller:submissions/detail'); - const transitionFake = Sinon.replace(controller, 'transitionToRoute', Sinon.fake()); + const routerService = this.owner.lookup('service:router'); + const transitionFake = Sinon.replace(routerService, 'transitionTo', Sinon.fake()); controller.submissionHandler = this.owner.lookup('service:submission-handler'); const deleteFake = Sinon.replace(controller.submissionHandler, 'deleteSubmission', Sinon.fake.rejects()); diff --git a/tests/unit/controllers/submissions/new-test.js b/tests/unit/controllers/submissions/new-test.js index 14df52a1..57b253e4 100644 --- a/tests/unit/controllers/submissions/new-test.js +++ b/tests/unit/controllers/submissions/new-test.js @@ -94,7 +94,9 @@ module('Unit | Controller | submissions/new', (hooks) => { // After the route transition to thanks, all promises should be resolved handler // and tests can be run. - controller.set('transitionToRoute', (name) => { + + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { assert.strictEqual(name, 'thanks'); assert.true(publicationSaved); @@ -120,7 +122,7 @@ module('Unit | Controller | submissions/new', (hooks) => { assert.deepEqual(md.agreements[0], { moo: 'Milk cows', }); - }); + }; controller.set('model', model); controller.set('comment', comment); @@ -182,18 +184,24 @@ module('Unit | Controller | submissions/new', (hooks) => { }, }); + let file = EmberObject.create({ + fileRole: 'manuscript', + }); + let comment = 'moo'; let model = EmberObject.create({ newSubmission: submission, publication, + files: [file], }); assert.expect(11); // After the route transition to thanks, all promises should be resolved handler // and tests can be run. - controller.set('transitionToRoute', (name) => { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { assert.strictEqual(name, 'thanks'); assert.true(publicationSaved); @@ -207,7 +215,7 @@ module('Unit | Controller | submissions/new', (hooks) => { assert.strictEqual(submissionEvent.performerRole, 'preparer'); assert.strictEqual(submissionEvent.eventType, 'approval-requested'); assert.strictEqual(submissionEvent.comment, comment); - }); + }; controller.set('model', model); controller.set('comment', comment); @@ -268,18 +276,24 @@ module('Unit | Controller | submissions/new', (hooks) => { }, }); + let file = EmberObject.create({ + fileRole: 'manuscript', + }); + let comment = 'moo'; let model = EmberObject.create({ newSubmission: submission, publication, + files: [file], }); assert.expect(13); // After the route transition to thanks, all promises should be resolved handler // and tests can be run. - controller.set('transitionToRoute', (name) => { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = (name) => { assert.strictEqual(name, 'thanks'); assert.true(publicationSaved); @@ -295,7 +309,7 @@ module('Unit | Controller | submissions/new', (hooks) => { assert.strictEqual(submissionEvent.performerRole, 'preparer'); assert.strictEqual(submissionEvent.eventType, 'approval-requested-newuser'); assert.strictEqual(submissionEvent.comment, comment); - }); + }; controller.set('model', model); controller.set('comment', comment); @@ -310,7 +324,7 @@ module('Unit | Controller | submissions/new', (hooks) => { * to the expected route. * * This action should first create a SweetAlert (swal), then call 'deleteSubmission' in the - * submission handler, finally call 'transitionToRoute' to transition to the 'submissions' + * submission handler, finally call 'transitionTo' to transition to the 'submissions' * route. */ test('abort should delete submission and transition', async function (assert) { diff --git a/tests/unit/controllers/submissions/new/basics-test.js b/tests/unit/controllers/submissions/new/basics-test.js index 138c127a..821c82b4 100644 --- a/tests/unit/controllers/submissions/new/basics-test.js +++ b/tests/unit/controllers/submissions/new/basics-test.js @@ -139,7 +139,8 @@ module('Unit | Controller | submissions/new/basics', (hooks) => { publication, }; controller.set('model', model); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = () => { assert.ok(true); loadTabAccessed = true; }; @@ -192,7 +193,8 @@ module('Unit | Controller | submissions/new/basics', (hooks) => { }; controller.set('model', model); - controller.set('transitionToRoute', (route) => { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = () => { // no errors and loadTab accessed assert.false(controller.get('submitterIsInvalid')); assert.false(controller.get('titleError')); @@ -203,7 +205,7 @@ module('Unit | Controller | submissions/new/basics', (hooks) => { assert.strictEqual(controller.get('flaggedFields').indexOf('submitterEmail'), -1); assert.ok(subSaved, 'submission was not saved'); - }); + }; assert.true(controller.get('model.newSubmission.isProxySubmission')); controller.send('validateAndLoadTab', 'submissions.new.basics'); diff --git a/tests/unit/controllers/submissions/new/files-test.js b/tests/unit/controllers/submissions/new/files-test.js index 8f8f75b1..7929845e 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); @@ -19,7 +18,7 @@ module('Unit | Controller | submissions/new/files', (hooks) => { this.owner.register( 'controller:submissions.new', EmberObject.extend({ - userIsSubmitter: true, + userIsSubmitter: () => true, }) ); this.owner.register( @@ -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); @@ -51,7 +51,7 @@ module('Unit | Controller | submissions/new/files', (hooks) => { this.owner.register( 'controller:submissions.new', EmberObject.extend({ - userIsSubmitter: false, + userIsSubmitter: () => false, }) ); this.owner.register( @@ -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,15 +79,28 @@ 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({ - userIsSubmitter: false, + userIsSubmitter: () => false, }) ); this.owner.register( @@ -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); @@ -118,7 +133,7 @@ module('Unit | Controller | submissions/new/files', (hooks) => { this.owner.register( 'controller:submissions.new', EmberObject.extend({ - userIsSubmitter: false, + userIsSubmitter: () => false, }) ); this.owner.register( @@ -152,7 +167,8 @@ module('Unit | Controller | submissions/new/files', (hooks) => { }), }; controller.set('model', model); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = () => { assert.ok(subSaved, 'Submission was not saved'); assert.strictEqual(controller.get('workflow').getFilesTemp().length, 0); assert.strictEqual(controller.get('model.files').length, 1); diff --git a/tests/unit/controllers/submissions/new/grants-test.js b/tests/unit/controllers/submissions/new/grants-test.js index e070318f..31afb1a8 100644 --- a/tests/unit/controllers/submissions/new/grants-test.js +++ b/tests/unit/controllers/submissions/new/grants-test.js @@ -23,7 +23,8 @@ module('Unit | Controller | submissions/new/grants', (hooks) => { controller.set('model', model); - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.strictEqual(route, 'submissions.new.basics'); }; controller.send('loadPrevious'); @@ -41,7 +42,8 @@ module('Unit | Controller | submissions/new/grants', (hooks) => { controller.set('model', model); - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.strictEqual(route, 'submissions.new.policies'); }; controller.send('loadNext'); @@ -62,7 +64,8 @@ module('Unit | Controller | submissions/new/grants', (hooks) => { }); controller.set('model', model); - controller.set('transitionToRoute', () => {}); + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = () => {}; controller.send('loadNext'); controller.send('loadPrevious'); diff --git a/tests/unit/controllers/submissions/new/metadata-test.js b/tests/unit/controllers/submissions/new/metadata-test.js index 6a45534c..c9cecf38 100644 --- a/tests/unit/controllers/submissions/new/metadata-test.js +++ b/tests/unit/controllers/submissions/new/metadata-test.js @@ -26,7 +26,8 @@ module('Unit | Controller | submissions/new/metadata', (hooks) => { }); controller.set('model', model); - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.ok(subSaved, 'submission was not saved'); assert.strictEqual(route, 'submissions.new.repositories'); }; @@ -47,7 +48,9 @@ module('Unit | Controller | submissions/new/metadata', (hooks) => { }); controller.set('model', model); - controller.transitionToRoute = function (route) { + + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.ok(subSaved, 'submission was not saved'); assert.strictEqual(route, 'submissions.new.files'); }; diff --git a/tests/unit/controllers/submissions/new/policies-test.js b/tests/unit/controllers/submissions/new/policies-test.js index 98100b71..9d476ef4 100644 --- a/tests/unit/controllers/submissions/new/policies-test.js +++ b/tests/unit/controllers/submissions/new/policies-test.js @@ -22,7 +22,8 @@ module('Unit | Controller | submissions/new/policies', (hooks) => { }); controller.set('model', model); - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.strictEqual(route, 'submissions.new.grants'); }; controller.send('loadPrevious'); @@ -39,7 +40,8 @@ module('Unit | Controller | submissions/new/policies', (hooks) => { }); controller.set('model', model); - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.strictEqual(route, 'submissions.new.repositories'); }; controller.send('loadNext'); @@ -56,9 +58,10 @@ module('Unit | Controller | submissions/new/policies', (hooks) => { }); controller.set('model', model); - controller.set('transitionToRoute', (route) => - assert.ok(route === 'submissions.new.repositories' || route === 'submissions.new.grants') - ); + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { + assert.ok(route === 'submissions.new.repositories' || route === 'submissions.new.grants'); + }; controller.send('loadNext'); controller.send('loadPrevious'); diff --git a/tests/unit/controllers/submissions/new/repositories-test.js b/tests/unit/controllers/submissions/new/repositories-test.js index c73774bf..7e625e3c 100644 --- a/tests/unit/controllers/submissions/new/repositories-test.js +++ b/tests/unit/controllers/submissions/new/repositories-test.js @@ -31,7 +31,8 @@ module('Unit | Controller | submissions/new/repositories', (hooks) => { }); controller.set('model', model); let loadTabAccessed = false; - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { loadTabAccessed = true; }; // override swal so it doesn't pop up @@ -65,7 +66,8 @@ module('Unit | Controller | submissions/new/repositories', (hooks) => { }); controller.set('model', model); - controller.transitionToRoute = function () { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { assert.ok(true); }; controller.send('validateAndLoadTab'); @@ -119,9 +121,10 @@ module('Unit | Controller | submissions/new/repositories', (hooks) => { }); controller.set('model', model); - controller.set('transitionToRoute', (route) => - assert.ok(['submissions.new.metadata', 'submissions.new.policies'].includes(route)) - ); + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { + assert.ok(['submissions.new.metadata', 'submissions.new.policies'].includes(route)); + }; controller.send('loadNext'); assert.ok(subSaved); diff --git a/tests/unit/controllers/submissions/new/review-test.js b/tests/unit/controllers/submissions/new/review-test.js index 7c8c0432..f25f27f9 100644 --- a/tests/unit/controllers/submissions/new/review-test.js +++ b/tests/unit/controllers/submissions/new/review-test.js @@ -24,7 +24,8 @@ module('Unit | Controller | submissions/new/review', (hooks) => { controller.set('model', model); let loadTabAccessed = false; - controller.transitionToRoute = function (route) { + const routerService = this.owner.lookup('service:router'); + routerService.transitionTo = function (route) { loadTabAccessed = true; assert.strictEqual(route, 'submissions.new.files'); }; diff --git a/yarn.lock b/yarn.lock index 1892858d..97f7f370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -46,6 +46,14 @@ "@babel/highlight" "^7.24.6" picocolors "^1.0.0" +"@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" @@ -61,6 +69,11 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.6.tgz#b3600217688cabb26e25f8e467019e66d71b7ae2" integrity sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ== +"@babel/compat-data@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" + integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== + "@babel/core@^7.0.0", "@babel/core@^7.12.0", "@babel/core@^7.13.10", "@babel/core@^7.16.10", "@babel/core@^7.16.7", "@babel/core@^7.18.13", "@babel/core@^7.19.6", "@babel/core@^7.21.3", "@babel/core@^7.3.4": version "7.21.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e" @@ -124,6 +137,27 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/core@^7.24.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" + integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helpers" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/eslint-parser@^7.21.3": version "7.21.3" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7" @@ -173,6 +207,16 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" +"@babel/generator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" + integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== + dependencies: + "@babel/types" "^7.24.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -242,6 +286,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" + integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== + dependencies: + "@babel/compat-data" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.5.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz#64f49ecb0020532f19b1d014b03bccaa1ab85fb9" @@ -341,6 +396,13 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz#ac7ad5517821641550f6698dd5468f8cef78620d" integrity sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g== +"@babel/helper-environment-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + "@babel/helper-explode-assignable-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" @@ -372,6 +434,14 @@ "@babel/template" "^7.24.6" "@babel/types" "^7.24.6" +"@babel/helper-function-name@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -393,6 +463,13 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-hoist-variables@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" + integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== + dependencies: + "@babel/types" "^7.24.7" + "@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" @@ -435,6 +512,14 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" @@ -471,6 +556,17 @@ "@babel/helper-split-export-declaration" "^7.24.6" "@babel/helper-validator-identifier" "^7.24.6" +"@babel/helper-module-transforms@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" + integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== + dependencies: + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" @@ -577,6 +673,14 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" @@ -619,6 +723,13 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-split-export-declaration@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + dependencies: + "@babel/types" "^7.24.7" + "@babel/helper-string-parser@^7.19.4": version "7.19.4" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" @@ -639,6 +750,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz#28583c28b15f2a3339cfafafeaad42f9a0e828df" integrity sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q== +"@babel/helper-string-parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" + integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -654,6 +770,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz#08bb6612b11bdec78f3feed3db196da682454a5e" integrity sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw== +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + "@babel/helper-validator-option@^7.18.6": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" @@ -669,6 +790,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz#59d8e81c40b7d9109ab7e74457393442177f460a" integrity sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ== +"@babel/helper-validator-option@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" + integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== + "@babel/helper-wrap-function@^7.18.9": version "7.20.5" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" @@ -714,6 +840,14 @@ "@babel/template" "^7.24.6" "@babel/types" "^7.24.6" +"@babel/helpers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" + integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -751,6 +885,16 @@ js-tokens "^4.0.0" picocolors "^1.0.0" +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.20.7", "@babel/parser@^7.21.3", "@babel/parser@^7.4.5", "@babel/parser@^7.7.0": version "7.21.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3" @@ -771,6 +915,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.6.tgz#5e030f440c3c6c78d195528c3b688b101a365328" integrity sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q== +"@babel/parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" + integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" @@ -2084,6 +2233,15 @@ "@babel/parser" "^7.24.6" "@babel/types" "^7.24.6" +"@babel/template@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" + integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.3", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" @@ -2132,6 +2290,22 @@ debug "^4.3.1" globals "^11.1.0" +"@babel/traverse@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" + integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.7" + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-function-name" "^7.24.7" + "@babel/helper-hoist-variables" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.12.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2": version "7.21.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05" @@ -2168,6 +2342,15 @@ "@babel/helper-validator-identifier" "^7.24.6" to-fast-properties "^2.0.0" +"@babel/types@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" + integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== + dependencies: + "@babel/helper-string-parser" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -2445,30 +2628,33 @@ common-ancestor-path "^1.0.1" semver "^7.3.8" -"@embroider/macros@1.9.0", "@embroider/macros@^0.50.0 || ^1.0.0", "@embroider/macros@^1.0.0", "@embroider/macros@^1.10.0", "@embroider/macros@^1.12.0", "@embroider/macros@^1.13.2", "@embroider/macros@^1.16.1", "@embroider/macros@^1.8.0", "@embroider/macros@^1.8.3", "@embroider/macros@^1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-1.9.0.tgz#0df2a56fdd93f11fddea450b6ca83cc2119b5008" - integrity sha512-12ElrRT+mX3aSixGHjHnfsnyoH1hw5nM+P+Ax0ITZdp6TaAvWZ8dENnVHltdnv4ssHiX0EsVEXmqbIIdMN4nLA== +"@embroider/macros@1.16.0", "@embroider/macros@^0.50.0 || ^1.0.0", "@embroider/macros@^1.0.0", "@embroider/macros@^1.10.0", "@embroider/macros@^1.12.0", "@embroider/macros@^1.13.2", "@embroider/macros@^1.16.1", "@embroider/macros@^1.8.0", "@embroider/macros@^1.8.3", "@embroider/macros@^1.9.0": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-1.16.0.tgz#4d7ffe3496f6052a6f7abe2d1235be44c5f10720" + integrity sha512-k36Zt+RPGZiMR6lFqrb/fJmMCCG7He0ww7O1w72eT/QVlvlJ2d7T1/0yvG+ZThHGpvX1FQMKQYJkREfG2DJF6w== dependencies: - "@embroider/shared-internals" "1.8.3" + "@babel/core" "^7.24.0" + "@embroider/shared-internals" "2.6.0" assert-never "^1.2.1" - babel-import-util "^1.1.0" - ember-cli-babel "^7.26.6" + babel-import-util "^2.0.0" + ember-cli-babel "^8.2.0" find-up "^5.0.0" lodash "^4.17.21" resolve "^1.20.0" semver "^7.3.2" -"@embroider/shared-internals@1.8.3": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-1.8.3.tgz#52d868dc80016e9fe983552c0e516f437bf9b9f9" - integrity sha512-N5Gho6Qk8z5u+mxLCcMYAoQMbN4MmH+z2jXwQHVs859bxuZTxwF6kKtsybDAASCtd2YGxEmzcc1Ja/wM28824w== +"@embroider/shared-internals@2.6.0", "@embroider/shared-internals@^2.5.1", "@embroider/shared-internals@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-2.6.0.tgz#851fd8d051fd4f7f93b2b7130e2ae5cdd537c5d6" + integrity sha512-A2BYQkhotdKOXuTaxvo9dqOIMbk+2LqFyqvfaaePkZcFJvtCkvTaD31/sSzqvRF6rdeBHjdMwU9Z2baPZ55fEQ== dependencies: - babel-import-util "^1.1.0" + babel-import-util "^2.0.0" + debug "^4.3.2" ember-rfc176-data "^0.3.17" fs-extra "^9.1.0" js-string-escape "^1.0.1" lodash "^4.17.21" + minimatch "^3.0.4" resolve-package-path "^4.0.1" semver "^7.3.5" typescript-memoize "^1.0.1" @@ -2487,22 +2673,6 @@ semver "^7.3.5" typescript-memoize "^1.0.1" -"@embroider/shared-internals@^2.5.1", "@embroider/shared-internals@^2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-2.6.0.tgz#851fd8d051fd4f7f93b2b7130e2ae5cdd537c5d6" - integrity sha512-A2BYQkhotdKOXuTaxvo9dqOIMbk+2LqFyqvfaaePkZcFJvtCkvTaD31/sSzqvRF6rdeBHjdMwU9Z2baPZ55fEQ== - dependencies: - babel-import-util "^2.0.0" - debug "^4.3.2" - ember-rfc176-data "^0.3.17" - fs-extra "^9.1.0" - js-string-escape "^1.0.1" - lodash "^4.17.21" - minimatch "^3.0.4" - resolve-package-path "^4.0.1" - semver "^7.3.5" - typescript-memoize "^1.0.1" - "@embroider/util@^0.39.1 || ^0.40.0 || ^0.41.0 || ^1.0.0", "@embroider/util@^1.0.0", "@embroider/util@^1.10.0", "@embroider/util@^1.9.0": version "1.10.0" resolved "https://registry.yarnpkg.com/@embroider/util/-/util-1.10.0.tgz#8320d73651e7f5d48dac1b71fb9e6d21cac7c803" @@ -2583,6 +2753,11 @@ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz#88da2b70d6ca18aaa6ed3687832e11f39e80624b" integrity sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ== +"@fortawesome/fontawesome-common-types@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz#eaf2f5699f73cef198454ebc0c414e3688898179" + integrity sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw== + "@fortawesome/fontawesome-svg-core@^6.2.0": version "6.4.0" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz#3727552eff9179506e9203d72feb5b1063c11a21" @@ -2590,6 +2765,13 @@ dependencies: "@fortawesome/fontawesome-common-types" "6.4.0" +"@fortawesome/fontawesome-svg-core@^6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz#4b42de71e196039b0d5ccf88559b8044e3296c21" + integrity sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw== + dependencies: + "@fortawesome/fontawesome-common-types" "6.5.2" + "@fortawesome/free-regular-svg-icons@^6.4.0": version "6.4.0" resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz#cacc53bd8d832d46feead412d9ea9ce80a55e13a" @@ -4551,7 +4733,7 @@ broccoli-persistent-filter@^3.0.0, broccoli-persistent-filter@^3.1.1, broccoli-p symlink-or-copy "^1.0.1" sync-disk-cache "^2.0.0" -broccoli-plugin@*, broccoli-plugin@^4.0.0, broccoli-plugin@^4.0.2, broccoli-plugin@^4.0.3, broccoli-plugin@^4.0.5, broccoli-plugin@^4.0.7: +broccoli-plugin@*, broccoli-plugin@^4.0.0, broccoli-plugin@^4.0.2, broccoli-plugin@^4.0.3, broccoli-plugin@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-4.0.7.tgz#dd176a85efe915ed557d913744b181abe05047db" integrity sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg== @@ -6040,15 +6222,12 @@ ember-cli-dependency-lint@^2.0.1: chalk "^2.3.0" semver "^5.5.0" -"ember-cli-deprecation-workflow@github:mixonic/ember-cli-deprecation-workflow#master": +"ember-cli-deprecation-workflow@github:ember-cli/ember-cli-deprecation-workflow#main": version "2.2.0" - resolved "https://codeload.github.com/mixonic/ember-cli-deprecation-workflow/tar.gz/0b4cbe79b3d450722f1053f145176fbf736fd764" + resolved "https://codeload.github.com/ember-cli/ember-cli-deprecation-workflow/tar.gz/798d0d0b99d9bdfdbc442e99371d0c2e08ed0d62" dependencies: "@babel/core" "^7.23.2" "@ember/string" "^3.0.0" - broccoli-funnel "^3.0.3" - broccoli-merge-trees "^4.2.0" - broccoli-plugin "^4.0.5" ember-cli-babel "^8.2.0" ember-cli-flash@^4.0.0: