From 49a5339089ad2d2547d07765453676dd29b48643 Mon Sep 17 00:00:00 2001 From: Erik Hanson Date: Tue, 10 Oct 2023 07:14:35 -0700 Subject: [PATCH] pkp/pkp-lib#9771 Move ORCID functionality into core application --- public/globals.js | 7 + src/components/Form/Form.vue | 2 +- src/components/Form/FormGroup.vue | 2 + src/components/Form/fields/FieldBase.vue | 7 + src/components/Form/fields/FieldOrcid.mdx | 15 ++ .../Form/fields/FieldOrcid.stories.js | 65 +++++ src/components/Form/fields/FieldOrcid.vue | 251 ++++++++++++++++++ src/components/Form/mocks/field-orcid.js | 9 + .../contributors/ContributorsListPanel.vue | 9 +- src/styles/_global.less | 4 +- 10 files changed, 365 insertions(+), 6 deletions(-) create mode 100644 src/components/Form/fields/FieldOrcid.mdx create mode 100644 src/components/Form/fields/FieldOrcid.stories.js create mode 100644 src/components/Form/fields/FieldOrcid.vue create mode 100644 src/components/Form/mocks/field-orcid.js diff --git a/public/globals.js b/public/globals.js index 0b1c9cd61..4b31c4587 100644 --- a/public/globals.js +++ b/public/globals.js @@ -433,6 +433,13 @@ window.pkp = { 'metadata.property.displayName.doi': 'DOI', 'navigation.backTo': '\u27f5 Back to {$page}', 'publication.contributors': 'Contributors', + 'orcid.field.verification.request': 'Request verification', + 'orcid.field.verification.requested': 'Verification requested!', + 'orcid.field.authorEmailModal.title': 'Request ORCID verification', + 'orcid.field.authorEmailModal.message': 'Would you like to send an email to this author requesting they verify their ORCID?', + 'orcid.field.deleteOrcidModal.title': 'Delete ORCID', + 'orcid.field.deleteOrcidModal.message': 'Are you sure you want to remove this ORCID?', + 'orcid.field.unverified.shouldRequest': 'This ORCID has not been verified. Please remove this unverified ORCID and request verification from the user/author directly.', 'publication.jats.autoCreatedMessage': 'This JATS file is generated automatically by the submission metadata', 'publication.jats.confirmDeleteFileButton': 'Delete JATS File', diff --git a/src/components/Form/Form.vue b/src/components/Form/Form.vue index 5e711a144..a5d218c69 100644 --- a/src/components/Form/Form.vue +++ b/src/components/Form/Form.vue @@ -211,7 +211,7 @@ export default { submitValues() { let values = {}; this.fields.forEach((field) => { - if (field.component === 'field-html') { + if (field.isInert) { return; } if (!field.isMultilingual) { diff --git a/src/components/Form/FormGroup.vue b/src/components/Form/FormGroup.vue index 5e3b31974..ce7b6087c 100644 --- a/src/components/Form/FormGroup.vue +++ b/src/components/Form/FormGroup.vue @@ -62,6 +62,7 @@ import FieldPubId from './fields/FieldPubId.vue'; import FieldHtml from './fields/FieldHtml.vue'; import FieldMetadataSetting from './fields/FieldMetadataSetting.vue'; import FieldOptions from './fields/FieldOptions.vue'; +import FieldOrcid from './fields/FieldOrcid.vue'; import FieldPreparedContent from './fields/FieldPreparedContent.vue'; import FieldRadioInput from './fields/FieldRadioInput.vue'; import FieldRichTextarea from './fields/FieldRichTextarea.vue'; @@ -92,6 +93,7 @@ export default { FieldHtml, FieldMetadataSetting, FieldOptions, + FieldOrcid, FieldPreparedContent, FieldRadioInput, FieldRichTextarea, diff --git a/src/components/Form/fields/FieldBase.vue b/src/components/Form/fields/FieldBase.vue index e7714ea37..82529f34d 100644 --- a/src/components/Form/fields/FieldBase.vue +++ b/src/components/Form/fields/FieldBase.vue @@ -33,6 +33,13 @@ export default { groupId: String, /** The ID of the form this field should appear in. This is passed down from the `Form`. */ formId: String, + /** Whether the field should be ignored when a form is submitted (e.g. purely informational field). */ + isInert: { + type: Boolean, + default() { + return false; + }, + }, /** Whether or not this field should be presented for each supported language. */ isMultilingual: Boolean, /** Whether or not a value for this field should be required. */ diff --git a/src/components/Form/fields/FieldOrcid.mdx b/src/components/Form/fields/FieldOrcid.mdx new file mode 100644 index 000000000..56c39e316 --- /dev/null +++ b/src/components/Form/fields/FieldOrcid.mdx @@ -0,0 +1,15 @@ +import {Primary, Controls, Meta, Stories} from '@storybook/blocks'; + +import * as FieldOrcidStories from './FieldOrcid.stories.js'; + +{' '} + +# FieldOrcid + +## Usage + +Field used for managing a linked user/author's ORCID + + + + diff --git a/src/components/Form/fields/FieldOrcid.stories.js b/src/components/Form/fields/FieldOrcid.stories.js new file mode 100644 index 000000000..2bca8bd31 --- /dev/null +++ b/src/components/Form/fields/FieldOrcid.stories.js @@ -0,0 +1,65 @@ +import FieldOrcid from '@/components/Form/fields/FieldOrcid.vue'; +import FieldBaseMock from '../mocks/field-base'; +import FieldOrcidMock from '../mocks/field-orcid'; +import {http, HttpResponse} from 'msw'; + +export default { + title: 'Forms/FieldOrcid', + component: FieldOrcid, + render: (args) => ({ + components: {FieldOrcid}, + setup() { + function change(name, prop, newValue, localeKey) { + if (localeKey) { + args[prop][localeKey] = newValue; + } else { + args[prop] = newValue; + } + } + + return {args, change}; + }, + template: ` + + `, + }), + parameters: { + msw: { + handlers: [ + http.post( + 'https://mock/index.php/publicknowledge/api/v1/orcid/requestAuthorVerification/1', + async () => { + return HttpResponse.json(); + }, + ), + http.post( + 'https://mock/index.php/publicknowledge/api/v1/orcid/deleteForAuthor/1', + async () => { + return HttpResponse.json(); + }, + ), + ], + }, + }, +}; + +export const Base = { + args: {...FieldBaseMock, ...FieldOrcidMock}, +}; + +export const WithOrcid = { + args: { + ...FieldBaseMock, + ...FieldOrcidMock, + orcid: 'https://sandbox.orcid.org/0009-0009-3222-5777', + isVerified: true, + }, +}; + +export const WithUnverifiedOrcid = { + args: { + ...FieldBaseMock, + ...FieldOrcidMock, + orcid: 'https://sandbox.orcid.org/0009-0009-3222-5777', + }, +}; diff --git a/src/components/Form/fields/FieldOrcid.vue b/src/components/Form/fields/FieldOrcid.vue new file mode 100644 index 000000000..73c0f7eaa --- /dev/null +++ b/src/components/Form/fields/FieldOrcid.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/src/components/Form/mocks/field-orcid.js b/src/components/Form/mocks/field-orcid.js new file mode 100644 index 000000000..a08ab562b --- /dev/null +++ b/src/components/Form/mocks/field-orcid.js @@ -0,0 +1,9 @@ +export default { + name: 'orcid', + component: 'field-orcid', + label: 'ORCID', + orcid: '', + authorId: 1, + tooltip: + 'ORCID is an independent non-profit organization that provides a persistent identifier – an ORCID iD – that distinguishes you from other researchers and a mechanism for linking your research outputs and activities to your iD. ORCID is integrated into many systems used by publishers, funders, institutions, and other research-related services. Learn more at https://orcid.org.', +}; diff --git a/src/components/ListPanel/contributors/ContributorsListPanel.vue b/src/components/ListPanel/contributors/ContributorsListPanel.vue index 32cbe1ab2..782c8159b 100644 --- a/src/components/ListPanel/contributors/ContributorsListPanel.vue +++ b/src/components/ListPanel/contributors/ContributorsListPanel.vue @@ -436,7 +436,7 @@ export default { }, ); this.$emit('updated:contributors', newContributors); - + this.getAndUpdatePublication(); }, complete(r) { @@ -475,7 +475,11 @@ export default { activeForm.action = apiUrl; activeForm.method = 'PUT'; activeForm.fields = activeForm.fields.map((field) => { - if (Object.keys(author).includes(field.name)) { + if (field.name === 'orcid') { + field.orcid = author['orcid'] ?? ''; + field.authorId = author['id']; + field.isVerified = author['orcidIsVerified'] ?? false; + } else if (Object.keys(author).includes(field.name)) { field.value = author[field.name]; } return field; @@ -654,7 +658,6 @@ export default { }, }); }, - }, }; diff --git a/src/styles/_global.less b/src/styles/_global.less index abf2cb657..cb3cbf18a 100644 --- a/src/styles/_global.less +++ b/src/styles/_global.less @@ -2,8 +2,8 @@ @tailwind base; -/* - Apply some styles for backward-compatibility as tailwind by +/* + Apply some styles for backward-compatibility as tailwind by default resets styling of headers This is just temporary until styling is migrated to taildwind classes */