Skip to content

Credit Roles #644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/components/Form/FormGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import FieldBaseAutosuggest from './fields/FieldBaseAutosuggest.vue';
import FieldAuthors from './fields/FieldAuthors.vue';
import FieldColor from './fields/FieldColor.vue';
import FieldControlledVocab from './fields/FieldControlledVocab.vue';
import FieldCreditRoles from './fields/FieldCreditRoles.vue';
import FieldPubId from './fields/FieldPubId.vue';
import FieldHtml from './fields/FieldHtml.vue';
import FieldMetadataSetting from './fields/FieldMetadataSetting.vue';
Expand Down Expand Up @@ -95,6 +96,7 @@ export default {
FieldAuthors,
FieldColor,
FieldControlledVocab,
FieldCreditRoles,
FieldPubId,
FieldHtml,
FieldMetadataSetting,
Expand Down
19 changes: 19 additions & 0 deletions src/components/Form/fields/FieldCreditRoles.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Primary, Controls, Stories, Meta, ArgTypes} from '@storybook/blocks';

import * as FieldCreditRolesStories from './FieldCreditRoles.stories.js';

<Meta of={FieldCreditRolesStories} />

# FieldCreditRole

## Usage

A special component to maintain Credit roles and degrees of authors (contributors).

The CreditRoles currently saved are shown in a tabular way as roles and degrees.

The `value` is an array of objects `{ role, degree }`.

<Primary />
<Controls />
<Stories />
29 changes: 29 additions & 0 deletions src/components/Form/fields/FieldCreditRoles.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import FieldCreditRoles from './FieldCreditRoles.vue';
import FieldCreditRolesMock from '@/components/Form/mocks/field-credit-roles';

export default {
title: 'Forms/FieldCreditRoles',
component: FieldCreditRoles,
render: (args) => ({
components: {FieldCreditRoles},
setup() {
function change(name, prop, newValue, localeKey) {
args[prop] = newValue;
}

return {args, change};
},
template: '<FieldCreditRoles v-bind="args" @change="change"/>',
}),
parameters: {
docs: {
story: {
height: '500px',
},
},
},
};

export const Base = {
args: {...FieldCreditRolesMock},
};
139 changes: 139 additions & 0 deletions src/components/Form/fields/FieldCreditRoles.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<template>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add it also to the storybook?

Have we had designs for it? Just wondering if there is reference for me to look at.

Copy link
Contributor

@bozana bozana Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it added to the storybook?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checkout FieldAffiliations.stories.js for example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. How do I test stories? I haven't done this before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jardakotesovec , I added the storybook

<!-- To be able to scroll to this field on error-->
<div
:id="`${props.formId}-${props.name}`"
class="pkpFormField pkpFormField--creditRoles"
>
<div class="pkpFormField__heading">
<label :id="labelId" class="pkpFormFieldLabel">
{{ t('submission.submit.creditRoles.title', {}) }}
</label>
</div>
<div :id="descriptionId" class="pkpFormField__description">
{{ t('submission.submit.creditRoles.description', {}) }}
</div>
<div class="pkpFormField__control pkpFormField--creditRoles__control">
<PkpTable :labelled-by="labelId" :described-by="descriptionId">
<TableHeader>
<TableColumn id="" class="w-[45%]">
{{ t('submission.submit.creditRoles.role', {}) }}
</TableColumn>
<TableColumn id="">
{{ t('submission.submit.creditRoles.degree', {}) }}
</TableColumn>
<TableColumn id="" class="w-[100px]">&nbsp;</TableColumn>
</TableHeader>
<TableBody>
<TableRow
v-for="({role, degree}, creditRoleIndex) in currentValue"
:key="creditRoleIndex"
>
<TableCell>
<FieldSelect
name="role"
:label="t('submission.submit.creditRoles.selectRole')"
:is-required="true"
:value="role"
:options="props.options.roles"
class="creditRole__roleSelect"
@change="
(fieldName, propName, newValue, localeKey) =>
updateCreditRole(creditRoleIndex, fieldName, newValue)
"
/>
</TableCell>
<TableCell>
<FieldSelect
name="degree"
:label="t('submission.submit.creditRoles.selectDegree')"
:value="degree"
:options="props.options.degrees"
class="creditRole__roleSelect"
@change="
(fieldName, propName, newValue, localeKey) =>
updateCreditRole(creditRoleIndex, fieldName, newValue)
"
/>
</TableCell>
<TableCell>
<PkpButton
:is-warnable="true"
@click="removeCreditRole(creditRoleIndex)"
>
{{ t('submission.submit.creditRoles.button.remove') }}
</PkpButton>
</TableCell>
</TableRow>
</TableBody>
<template #bottom-controls>
<PkpButton @click="addCreditRole()">
{{ t('submission.submit.creditRoles.button.add') }}
</PkpButton>
</template>
</PkpTable>
</div>
</div>
</template>

<script setup>
import {computed, useId} from 'vue';
import {t} from '@/utils/i18n';
import PkpButton from '@/components/Button/Button.vue';
import PkpTable from '@/components/Table/Table.vue';
import TableHeader from '@/components/Table/TableHeader.vue';
import TableBody from '@/components/Table/TableBody.vue';
import TableRow from '@/components/Table/TableRow.vue';
import TableColumn from '@/components/Table/TableColumn.vue';
import TableCell from '@/components/Table/TableCell.vue';
import FieldSelect from './FieldSelect.vue';

const props = defineProps({
/** Field key used for form submission */
name: {
type: String,
default: null,
},
/** The ID of the form this field should appear in. This is passed down from the `Form`. */
formId: {
type: String,
default: null,
},
/** Current value of the field */
value: {
type: Array,
default: () => [],
},
options: {
type: Object,
required: true,
},
});

/**
* Accessibility
*/
const labelId = useId();
const descriptionId = useId();

const emit = defineEmits(['change']);

const currentValue = computed({
get: () => props.value,
set: (newVal) => emit('change', props.name, 'value', newVal),
});

function addCreditRole() {
currentValue.value.push({
role: props.options.roles[0].value,
degree: props.options.degrees[0].value,
});
}

function removeCreditRole(index) {
currentValue.value.splice(index, 1);
}

function updateCreditRole(index, fieldName, newValue) {
currentValue.value[index][fieldName] = newValue;
}
</script>
36 changes: 36 additions & 0 deletions src/components/Form/mocks/field-credit-roles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export default {
name: 'contributor-credit-roles',
component: 'contributor-credit-roles',
value: [
{
role: 'https://credit.niso.org/contributor-roles/data-curation/',
degree: null,
},
],
options: {
roles: [
{
label: 'Conceptualization',
value: 'https://credit.niso.org/contributor-roles/conceptualization/',
},
{
label: 'Data Curation',
value: 'https://credit.niso.org/contributor-roles/data-curation/',
},
{
label: 'Formal Analysis',
value: 'https://credit.niso.org/contributor-roles/formal-analysis/',
},
],
degrees: [
{
label: '',
value: null,
},
{
label: 'LEAD',
value: 'LEAD',
},
],
},
};