forked from pkp/ui-library
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pkp/pkp-lib#9771 Move ORCID functionality into core application
- Loading branch information
Showing
12 changed files
with
352 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<script> | ||
import Form from '../Form.vue'; | ||
export default { | ||
name: 'OrcidSettingsForm', | ||
extends: Form, | ||
props: {}, | ||
methods: { | ||
/** | ||
* Update values when a field has changed | ||
* | ||
* @param {String} name Name of the field to modify | ||
* @param {String} prop Name of the prop to modify | ||
* @param {mixed} value The new value for the prop | ||
* @param {String} localeKey Optional locale key for multilingual props | ||
*/ | ||
fieldChanged: function (name, prop, value, localeKey) { | ||
// TODO: This isn't actually working as the fields are properly required. | ||
if (name === 'orcidEnabled') { | ||
this.removeError('orcidApiType', localeKey); | ||
this.removeError('orcidClientId', localeKey); | ||
this.removeError('orcidClientSecret', localeKey); | ||
} | ||
Form.methods.fieldChanged.apply(this, [name, prop, value, localeKey]); | ||
}, | ||
}, | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {Primary, Controls, Meta} from '@storybook/blocks'; | ||
|
||
import * as FieldOrcidStories from './FieldOrcid.stories.js'; | ||
|
||
<Meta of={FieldOrcidStories} />{' '} | ||
|
||
# FieldOrcid | ||
|
||
## Usage | ||
|
||
Field used for managing a linked user/author's ORCID | ||
|
||
<Primary /> | ||
<Controls /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
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: ` | ||
<FieldOrcid v-bind="args" @change="change" /> | ||
`, | ||
}), | ||
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}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
<template> | ||
<div class="pkpFormField pkpFormField--html"> | ||
<div class="pkpFormField__heading"> | ||
<span class="pkpFormFieldLabel"> | ||
{{ label }} | ||
</span> | ||
<tooltip v-if="tooltip" aria-hidden="true" :tooltip="tooltip" label="" /> | ||
<span v-if="tooltip" class="-screenReader" v-html="tooltip" /> | ||
<help-button | ||
v-if="helpTopic" | ||
:topic="helpTopic" | ||
:section="helpSection" | ||
:label="t('help.help')" | ||
/> | ||
</div> | ||
<!-- When ORCID is present --> | ||
<div | ||
v-if="hasOrcid" | ||
class="pkpFormField__control pkpFormField__control--html" | ||
v-html="orcidValue" | ||
/> | ||
<pkp-button | ||
v-if="hasOrcid" | ||
class="pkpFormField__control--html__button" | ||
:is-warnable="true" | ||
:is-disabled="isButtonDisabled" | ||
@click="openDeleteDialog" | ||
> | ||
{{ t('common.delete') }} | ||
</pkp-button> | ||
<!-- When ORCID is absent --> | ||
<pkp-button | ||
v-if="!hasOrcid" | ||
:disabled="verificationRequested || isButtonDisabled" | ||
:icon="verificationRequested ? 'Complete' : null" | ||
@click="openSendAuthorEmailDialog" | ||
> | ||
{{ | ||
verificationRequested | ||
? t('orcid.field.verification.requested') | ||
: t('orcid.field.verification.request') | ||
}} | ||
</pkp-button> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import FieldBase from '@/components/Form/fields/FieldBase.vue'; | ||
import {useApiUrl} from '@/composables/useApiUrl'; | ||
import {useFetch} from '@/composables/useFetch'; | ||
import {useModal} from '@/composables/useModal'; | ||
export default { | ||
name: 'FieldOrcid', | ||
extends: FieldBase, | ||
props: { | ||
/** ORCID URL that has been verified */ | ||
orcid: { | ||
type: String, | ||
required: true, | ||
default: '', | ||
}, | ||
/** Author ID used in ORCID related actions */ | ||
authorId: { | ||
type: Number, | ||
required: true, | ||
default: 0, | ||
}, | ||
}, | ||
data() { | ||
return { | ||
/** Internal value used for displaying ORCID in component. Takes initial value from `orcid` prop */ | ||
orcidValue: '', | ||
/** Whether an email requesting users verify their ORCID has been sent or not */ | ||
verificationRequested: false, | ||
/** Whether request verification/delete ORCID button should be disabled or not */ | ||
isButtonDisabled: false, | ||
}; | ||
}, | ||
computed: { | ||
/** | ||
* Helper to see if an ORCID value is present | ||
* @returns {boolean} | ||
*/ | ||
hasOrcid: function () { | ||
return this.orcidValue.length !== 0; | ||
}, | ||
}, | ||
created() { | ||
this.orcidValue = this.orcid; | ||
}, | ||
methods: { | ||
/** | ||
* Triggers author email request via API | ||
* | ||
* @returns {Promise<void>} | ||
*/ | ||
sendAuthorEmail: async function () { | ||
this.isButtonDisabled = true; | ||
const {apiUrl} = useApiUrl( | ||
`orcid/requestAuthorVerification/${this.authorId}`, | ||
); | ||
const {data, validationError, fetch} = useFetch(apiUrl, { | ||
method: 'POST', | ||
expectValidationError: true, | ||
}); | ||
await fetch(); | ||
if (validationError.value !== null) { | ||
this.verificationRequested = false; | ||
pkp.eventBus.$emit('notify', validationError.value['error'], 'warning'); | ||
} | ||
if (data.value !== null) { | ||
this.verificationRequested = true; | ||
} | ||
this.isButtonDisabled = false; | ||
}, | ||
/** | ||
* Open confirmation dialog for requesting author ORCID verification | ||
*/ | ||
openSendAuthorEmailDialog: function () { | ||
const {openDialog} = useModal(); | ||
openDialog({ | ||
name: 'sendAuthorEmail', | ||
title: this.t('orcid.field.authorEmailModal.title'), | ||
message: this.t('orcid.field.authorEmailModal.message'), | ||
actions: [ | ||
{ | ||
label: this.t('common.yes'), | ||
isPrimary: true, | ||
callback: async (close) => { | ||
await this.sendAuthorEmail(); | ||
close(); | ||
}, | ||
}, | ||
{ | ||
label: this.t('common.no'), | ||
isWarnable: true, | ||
callback: (close) => { | ||
close(); | ||
}, | ||
}, | ||
], | ||
close: () => {}, | ||
}); | ||
}, | ||
/** | ||
* Trigger API request to remove ORCID and access tokens from author/user | ||
* | ||
* @returns {Promise<void>} | ||
*/ | ||
deleteOrcid: async function () { | ||
this.isButtonDisabled = true; | ||
const {apiUrl} = useApiUrl(`orcid/deleteForAuthor/${this.authorId}`); | ||
const {data, validationError, fetch} = useFetch(apiUrl, { | ||
method: 'POST', | ||
expectValidationError: true, | ||
}); | ||
await fetch(); | ||
if (validationError.value !== null) { | ||
pkp.eventBus.$emit('notify', validationError.value['error'], 'warning'); | ||
} | ||
if (data.value !== null) { | ||
this.orcidValue = ''; | ||
} | ||
this.isButtonDisabled = false; | ||
}, | ||
/** | ||
* Opens dialog to confirm deletion of ORCID from author/user | ||
*/ | ||
openDeleteDialog: function () { | ||
const {openDialog} = useModal(); | ||
openDialog({ | ||
name: 'deleteOrcid', | ||
title: this.t('orcid.field.deleteOrcidModal.title'), | ||
message: this.t('orcid.field.deleteOrcidModal.message'), | ||
actions: [ | ||
{ | ||
label: this.t('common.yes'), | ||
isPrimary: true, | ||
callback: async (close) => { | ||
await this.deleteOrcid(); | ||
close(); | ||
}, | ||
}, | ||
{ | ||
label: this.t('common.no'), | ||
isWarnable: true, | ||
callback: (close) => { | ||
close(); | ||
}, | ||
}, | ||
], | ||
close: () => {}, | ||
}); | ||
}, | ||
}, | ||
}; | ||
</script> | ||
|
||
<style lang="less"> | ||
@import '../../../styles/_import'; | ||
.pkpFormField__control--html { | ||
font-size: @font-sml; | ||
line-height: 1.8em; | ||
display: inline-block; | ||
p:first-child { | ||
margin-top: 0; | ||
} | ||
p:last-child { | ||
margin-bottom: 0; | ||
} | ||
} | ||
.pkpFormField__control--html__button { | ||
margin-inline-start: 0.25rem; | ||
} | ||
</style> |
Oops, something went wrong.