Skip to content

Commit 3a971ef

Browse files
committed
structured citations (development)
1 parent f2a58ea commit 3a971ef

29 files changed

+943
-3
lines changed

src/components/Form/FormGroup.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import FieldAffiliations from './fields/FieldAffiliations.vue';
5959
import FieldArchivingPn from './fields/FieldArchivingPn.vue';
6060
import FieldAutosuggestPreset from './fields/FieldAutosuggestPreset.vue';
6161
import FieldBaseAutosuggest from './fields/FieldBaseAutosuggest.vue';
62+
import FieldAuthors from './fields/FieldAuthors.vue';
6263
import FieldColor from './fields/FieldColor.vue';
6364
import FieldControlledVocab from './fields/FieldControlledVocab.vue';
6465
import FieldPubId from './fields/FieldPubId.vue';
@@ -91,6 +92,7 @@ export default {
9192
FieldArchivingPn,
9293
FieldAutosuggestPreset,
9394
FieldBaseAutosuggest,
95+
FieldAuthors,
9496
FieldColor,
9597
FieldControlledVocab,
9698
FieldPubId,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {Primary, Controls, Stories, Meta, ArgTypes} from '@storybook/blocks';
2+
3+
import * as FieldAuthorsStories from './FieldAuthors.stories.js';
4+
5+
<Meta of={FieldAuthorsStories}/>
6+
7+
# FieldAuthors
8+
9+
## Usage
10+
11+
A special component to maintain authors of a citation of publications.
12+
13+
The `value` is an array of objects `{ givenName, familyName, orcid }`.
14+
15+
<Primary/>
16+
<Controls/>
17+
<Stories/>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import FieldAuthors from './FieldAuthors.vue';
2+
import FieldAuthorsMock from '@/components/Form/mocks/field-authors.js';
3+
4+
const args = {...FieldAuthorsMock};
5+
6+
export default {
7+
title: 'Forms/FieldAuthors',
8+
component: FieldAuthors,
9+
args: {},
10+
parameters: {},
11+
render: (args) => ({
12+
components: {FieldAuthors},
13+
setup() {
14+
function change(name, prop, newValue, localeKey) {
15+
if (localeKey) {
16+
args[prop][localeKey] = newValue;
17+
} else {
18+
args[prop] = newValue;
19+
}
20+
}
21+
22+
return {args, change};
23+
},
24+
template: `
25+
<FieldAuthors v-bind="args" @change="change" />`,
26+
}),
27+
decorators: [
28+
() => ({
29+
template: '<div style="height: 600px"><story/></div>',
30+
}),
31+
],
32+
};
33+
34+
export const Base = {
35+
args: {...FieldAuthorsMock},
36+
};
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<template>
2+
<div
3+
:id="`${props.formId}-${props.name}`"
4+
class="pkpFormField pkpFormField--authors"
5+
>
6+
<div class="pkpFormField__heading">
7+
<label :id="labelId" class="pkpFormFieldLabel">
8+
{{ props.label }}
9+
</label>
10+
</div>
11+
<div :id="descriptionId" class="pkpFormField__description">
12+
{{ props.description }}
13+
</div>
14+
<PkpTable :labelled-by="labelId" :described-by="descriptionId">
15+
<TableHeader>
16+
<TableColumn id="">{{ t('user.givenName', []) }}</TableColumn>
17+
<TableColumn id="">{{ t('user.familyName', []) }}</TableColumn>
18+
<TableColumn id="">{{ t('user.orcid', []) }}</TableColumn>
19+
<TableColumn id="" class="w-[100px]">&nbsp;</TableColumn>
20+
</TableHeader>
21+
<TableBody>
22+
<TableRow v-for="(row, index) in currentValue" :key="index">
23+
<TableCell>
24+
<FieldText
25+
:name="'givenName'"
26+
:value="row.givenName"
27+
@change="
28+
(fieldName, _, fieldValue) => {
29+
updateRow(index, fieldName, fieldValue);
30+
}
31+
"
32+
:all-errors="{givenName: errors?.[index]?.givenName}"
33+
/>
34+
</TableCell>
35+
<TableCell>
36+
<FieldText
37+
:name="'familyName'"
38+
:value="row.familyName"
39+
@change="
40+
(fieldName, _, fieldValue) => {
41+
updateRow(index, fieldName, fieldValue);
42+
}
43+
"
44+
:all-errors="{familyName: errors?.[index]?.familyName}"
45+
/>
46+
</TableCell>
47+
<TableCell>
48+
<FieldText
49+
:name="'orcid'"
50+
:value="row.orcid"
51+
@change="
52+
(fieldName, _, fieldValue) => {
53+
updateRow(index, fieldName, fieldValue);
54+
}
55+
"
56+
:all-errors="{orcid: errors?.[index]?.orcid}"
57+
/>
58+
</TableCell>
59+
<TableCell>
60+
<PkpButton :is-link="true" @click="deleteRow(index)">
61+
{{ t('common.delete', []) }}
62+
</PkpButton>
63+
</TableCell>
64+
</TableRow>
65+
</TableBody>
66+
<template #bottom-controls>
67+
<PkpButton @click="addRow()">
68+
{{ addButtonLabel ? addButtonLabel : t('common.add') }}
69+
</PkpButton>
70+
</template>
71+
</PkpTable>
72+
</div>
73+
</template>
74+
75+
<script setup>
76+
import {computed, useId} from 'vue';
77+
import {useLocalize} from '@/composables/useLocalize';
78+
import PkpButton from '@/components/Button/Button.vue';
79+
import PkpTable from '@/components/Table/Table.vue';
80+
import TableCell from '@/components/Table/TableCell.vue';
81+
import TableRow from '@/components/Table/TableRow.vue';
82+
import TableColumn from '@/components/Table/TableColumn.vue';
83+
import TableHeader from '@/components/Table/TableHeader.vue';
84+
import TableBody from '@/components/Table/TableBody.vue';
85+
import FieldText from '@/components/Form/fields/FieldText.vue';
86+
87+
const {t} = useLocalize();
88+
const props = defineProps({
89+
/** Field key used for form submission */
90+
name: {
91+
type: String,
92+
default: null,
93+
},
94+
/** The ID of the form this field should appear in. This is passed down from the `Form`. */
95+
formId: {
96+
type: String,
97+
default: null,
98+
},
99+
/** The `<label>` for this field. May be used in a `<fieldset>` when appropriate. All form fields should have an accessible label. */
100+
label: {
101+
type: String,
102+
default: null,
103+
},
104+
/** Adds a description to the field. Can include HTML code. */
105+
description: {
106+
type: String,
107+
default: null,
108+
},
109+
/** Current value of the field */
110+
value: {
111+
type: Array,
112+
default: () => [],
113+
},
114+
/** Label for add button */
115+
addButtonLabel: {
116+
type: String,
117+
default: null,
118+
},
119+
/** Object containing all form errors */
120+
allErrors: {
121+
type: Object,
122+
default() {
123+
return {};
124+
},
125+
},
126+
});
127+
const labelId = useId();
128+
const descriptionId = useId();
129+
const emit = defineEmits(['change', 'set-errors']);
130+
const errors = computed(() => {
131+
if (!Object.keys(props.allErrors).includes(props.name)) {
132+
return [];
133+
}
134+
return props.allErrors[props.name];
135+
});
136+
const rowDataModel = () => {
137+
return {
138+
givenName: '',
139+
familyName: '',
140+
orcid: '',
141+
};
142+
};
143+
const currentValue = computed({
144+
get: () => props.value,
145+
set: (newVal) => emit('change', props.name, 'value', newVal),
146+
});
147+
148+
function deleteRow(index) {
149+
currentValue.value.splice(index, 1);
150+
}
151+
152+
function addRow() {
153+
currentValue.value.push(rowDataModel());
154+
}
155+
156+
function updateRow(rowIndex, fieldName, fieldValue) {
157+
currentValue.value = currentValue.value.map((row, index) => {
158+
if (index !== rowIndex) {
159+
return row;
160+
}
161+
return {
162+
...row,
163+
[fieldName]: fieldValue,
164+
};
165+
});
166+
}
167+
</script>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export default {
2+
name: 'author-authors',
3+
component: 'author-authors',
4+
label: 'Author Information',
5+
description: 'Author information description',
6+
value: [
7+
{
8+
givenName: 'Christian',
9+
familyName: 'Hauschke',
10+
orcid: 'https://orcid.org/0000-0003-2499-7741',
11+
},
12+
{
13+
givenName: 'Lambert',
14+
familyName: 'Heller',
15+
orcid: 'https://orcid.org/0000-0003-0232-7085',
16+
},
17+
{
18+
givenName: 'Bo-Christer',
19+
familyName: 'Björk',
20+
},
21+
{
22+
givenName: 'Cenyu',
23+
familyName: 'Shen',
24+
orcid: 'https://orcid.org/0000-0002-4411-9674',
25+
},
26+
{
27+
givenName: 'Mikael',
28+
familyName: 'Laakso',
29+
orcid: 'https://orcid.org/0000-0003-3951-7990',
30+
},
31+
],
32+
};

src/composables/useDataChanged.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// todo: @gaziyucel make relevant changes for structured citations
12
import {onUnmounted} from 'vue';
23
import {injectFromCurrentInstance} from '@/utils/defineComponentStore';
34

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {Primary, Controls, Stories, Meta, ArgTypes} from '@storybook/blocks';
2+
3+
import * as CitationManager from './CitationManager.stories.js';
4+
5+
<Meta of={CitationManager} />
6+
7+
# Citation manager
8+
9+
Listing of Citations.
10+
11+
## Props
12+
13+
<ArgTypes />
14+
15+
## Extension points for plugins
16+
17+
For more details and examples on how to use them, check out [Plugins guide](..?path=/docs/guide-plugins--docs)
18+
19+
The name of the Pinia store is `CitationManager`.
20+
21+
- `getTopItems`: Add/Change items in the top right, where the `Upload / Select` button is.
22+
- `getItemActions`: Add/Change the list of actions that are displayed after clicking the 3 dots button.
23+
- `getItemPrimaryActions`: Add/Change one individual Action which is displayed in the ACTIONS column.
24+
- `getCellStatusItems`: Add/Change what components are displayed in the Reviewer status.
25+
- `getColumns`: Add/Change the columns being displayed in the table.
26+
27+
<Primary />
28+
<Controls />
29+
<Stories />
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import CitationManager from './CitationManager.vue';
2+
3+
export default {
4+
title: 'Managers/CitationManager',
5+
component: CitationManager,
6+
render: (args) => ({
7+
components: {CitationManager},
8+
setup() {
9+
return {args};
10+
},
11+
template: `<CitationManager v-bind="args"/>`,
12+
}),
13+
};
14+
15+
export const Base = {
16+
args: {},
17+
};

0 commit comments

Comments
 (0)