From cd6fee3e977a361e92548d816b470942cf0b67ee Mon Sep 17 00:00:00 2001
From: GaziYucel <84437883+GaziYucel@users.noreply.github.com>
Date: Thu, 28 Aug 2025 11:24:21 +0200
Subject: [PATCH 01/15] structured citations (development)
---
src/components/Form/FormGroup.vue | 2 +
src/components/Form/fields/FieldAuthors.mdx | 23 ++
.../Form/fields/FieldAuthors.stories.js | 36 ++
src/components/Form/fields/FieldAuthors.vue | 167 +++++++++
src/components/Form/mocks/field-authors.js | 32 ++
.../CitationManager/CitationManager.mdx | 34 ++
.../CitationManager.stories.js | 17 +
.../CitationManager/CitationManager.vue | 104 ++++++
.../CitationManagerAddRawCitations.vue | 69 ++++
.../CitationManagerCellActions.vue | 34 ++
.../CitationManagerCellCitation.vue | 103 ++++++
.../CitationManagerCellToggle.vue | 43 +++
.../CitationManagerMetadataLookup.vue | 34 ++
.../CitationManagerSearchField.vue | 16 +
.../CitationManagerStatusProcessed.vue | 48 +++
.../CitationManagerToggleAll.vue | 18 +
.../CitationManager/citationManagerStore.js | 330 ++++++++++++++++++
.../modals/CitationEditModal.mdx | 16 +
.../modals/CitationEditModal.stories.js | 46 +++
.../modals/CitationEditModal.vue | 61 ++++
.../useCitationManagerActions.js | 9 +
.../useCitationManagerConfig.js | 75 ++++
src/pages/workflow/WorkflowPageOJS.vue | 2 +
.../workflowConfigEditorialOJS.js | 7 +-
24 files changed, 1323 insertions(+), 3 deletions(-)
create mode 100644 src/components/Form/fields/FieldAuthors.mdx
create mode 100644 src/components/Form/fields/FieldAuthors.stories.js
create mode 100644 src/components/Form/fields/FieldAuthors.vue
create mode 100644 src/components/Form/mocks/field-authors.js
create mode 100644 src/managers/CitationManager/CitationManager.mdx
create mode 100644 src/managers/CitationManager/CitationManager.stories.js
create mode 100644 src/managers/CitationManager/CitationManager.vue
create mode 100644 src/managers/CitationManager/CitationManagerAddRawCitations.vue
create mode 100644 src/managers/CitationManager/CitationManagerCellActions.vue
create mode 100644 src/managers/CitationManager/CitationManagerCellCitation.vue
create mode 100644 src/managers/CitationManager/CitationManagerCellToggle.vue
create mode 100644 src/managers/CitationManager/CitationManagerMetadataLookup.vue
create mode 100644 src/managers/CitationManager/CitationManagerSearchField.vue
create mode 100644 src/managers/CitationManager/CitationManagerStatusProcessed.vue
create mode 100644 src/managers/CitationManager/CitationManagerToggleAll.vue
create mode 100644 src/managers/CitationManager/citationManagerStore.js
create mode 100644 src/managers/CitationManager/modals/CitationEditModal.mdx
create mode 100644 src/managers/CitationManager/modals/CitationEditModal.stories.js
create mode 100644 src/managers/CitationManager/modals/CitationEditModal.vue
create mode 100644 src/managers/CitationManager/useCitationManagerActions.js
create mode 100644 src/managers/CitationManager/useCitationManagerConfig.js
diff --git a/src/components/Form/FormGroup.vue b/src/components/Form/FormGroup.vue
index fbc8b0cfe..5d2130ba3 100644
--- a/src/components/Form/FormGroup.vue
+++ b/src/components/Form/FormGroup.vue
@@ -59,6 +59,7 @@ import FieldAffiliations from './fields/FieldAffiliations.vue';
import FieldArchivingPn from './fields/FieldArchivingPn.vue';
import FieldAutosuggestPreset from './fields/FieldAutosuggestPreset.vue';
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 FieldPubId from './fields/FieldPubId.vue';
@@ -91,6 +92,7 @@ export default {
FieldArchivingPn,
FieldAutosuggestPreset,
FieldBaseAutosuggest,
+ FieldAuthors,
FieldColor,
FieldControlledVocab,
FieldPubId,
diff --git a/src/components/Form/fields/FieldAuthors.mdx b/src/components/Form/fields/FieldAuthors.mdx
new file mode 100644
index 000000000..ff9e1641a
--- /dev/null
+++ b/src/components/Form/fields/FieldAuthors.mdx
@@ -0,0 +1,23 @@
+import {
+ Primary,
+ Controls,
+ Stories,
+ Meta,
+ ArgTypes,
+} from '@storybook/addon-docs/blocks';
+
+import * as FieldAuthorsStories from './FieldAuthors.stories.js';
+
+
+
+# FieldAuthors
+
+## Usage
+
+A special component to maintain authors of a citation of publications.
+
+The `value` is an array of objects `{ givenName, familyName, orcid }`.
+
+
+
+
diff --git a/src/components/Form/fields/FieldAuthors.stories.js b/src/components/Form/fields/FieldAuthors.stories.js
new file mode 100644
index 000000000..b09d3801a
--- /dev/null
+++ b/src/components/Form/fields/FieldAuthors.stories.js
@@ -0,0 +1,36 @@
+import FieldAuthors from './FieldAuthors.vue';
+import FieldAuthorsMock from '@/components/Form/mocks/field-authors.js';
+
+const args = {...FieldAuthorsMock};
+
+export default {
+ title: 'Forms/FieldAuthors',
+ component: FieldAuthors,
+ args: {},
+ parameters: {},
+ render: (args) => ({
+ components: {FieldAuthors},
+ setup() {
+ function change(name, prop, newValue, localeKey) {
+ if (localeKey) {
+ args[prop][localeKey] = newValue;
+ } else {
+ args[prop] = newValue;
+ }
+ }
+
+ return {args, change};
+ },
+ template: `
+ `,
+ }),
+ decorators: [
+ () => ({
+ template: '
',
+ }),
+ ],
+};
+
+export const Base = {
+ args: {...FieldAuthorsMock},
+};
diff --git a/src/components/Form/fields/FieldAuthors.vue b/src/components/Form/fields/FieldAuthors.vue
new file mode 100644
index 000000000..9a5ce6ff4
--- /dev/null
+++ b/src/components/Form/fields/FieldAuthors.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
diff --git a/src/components/Form/mocks/field-authors.js b/src/components/Form/mocks/field-authors.js
new file mode 100644
index 000000000..c11d569b8
--- /dev/null
+++ b/src/components/Form/mocks/field-authors.js
@@ -0,0 +1,32 @@
+export default {
+ name: 'author-authors',
+ component: 'author-authors',
+ label: 'Author Information',
+ description: 'Author information description',
+ value: [
+ {
+ givenName: 'Christian',
+ familyName: 'Hauschke',
+ orcid: 'https://orcid.org/0000-0003-2499-7741',
+ },
+ {
+ givenName: 'Lambert',
+ familyName: 'Heller',
+ orcid: 'https://orcid.org/0000-0003-0232-7085',
+ },
+ {
+ givenName: 'Bo-Christer',
+ familyName: 'Björk',
+ },
+ {
+ givenName: 'Cenyu',
+ familyName: 'Shen',
+ orcid: 'https://orcid.org/0000-0002-4411-9674',
+ },
+ {
+ givenName: 'Mikael',
+ familyName: 'Laakso',
+ orcid: 'https://orcid.org/0000-0003-3951-7990',
+ },
+ ],
+};
diff --git a/src/managers/CitationManager/CitationManager.mdx b/src/managers/CitationManager/CitationManager.mdx
new file mode 100644
index 000000000..98bbbf1e7
--- /dev/null
+++ b/src/managers/CitationManager/CitationManager.mdx
@@ -0,0 +1,34 @@
+import {
+ Primary,
+ Controls,
+ Stories,
+ Meta,
+ ArgTypes
+} from '@storybook/addon-docs/blocks';
+import * as CitationManager from './CitationManager.stories.js';
+
+
+
+# Citation manager
+
+Listing of Citations.
+
+## Props
+
+
+
+## Extension points for plugins
+
+For more details and examples on how to use them, check out [Plugins guide](..?path=/docs/guide-plugins--docs)
+
+The name of the Pinia store is `CitationManager`.
+
+- `getTopItems`: Add/Change items in the top right, where the `Upload / Select` button is.
+- `getItemActions`: Add/Change the list of actions that are displayed after clicking the 3 dots button.
+- `getItemPrimaryActions`: Add/Change one individual Action which is displayed in the ACTIONS column.
+- `getColumns`: Add/Change the columns being displayed in the table.
+- ...
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManager.stories.js b/src/managers/CitationManager/CitationManager.stories.js
new file mode 100644
index 000000000..8977ee5bd
--- /dev/null
+++ b/src/managers/CitationManager/CitationManager.stories.js
@@ -0,0 +1,17 @@
+import CitationManager from './CitationManager.vue';
+
+export default {
+ title: 'Managers/CitationManager',
+ component: CitationManager,
+ render: (args) => ({
+ components: {CitationManager},
+ setup() {
+ return {args};
+ },
+ template: ``,
+ }),
+};
+
+export const Base = {
+ args: {},
+};
diff --git a/src/managers/CitationManager/CitationManager.vue b/src/managers/CitationManager/CitationManager.vue
new file mode 100644
index 000000000..de28233dc
--- /dev/null
+++ b/src/managers/CitationManager/CitationManager.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+ {{ t('submission.citations.structured') }}
+
+
+ {{ t('submission.citations.structured.descriptionTable') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ column.header }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerAddRawCitations.vue b/src/managers/CitationManager/CitationManagerAddRawCitations.vue
new file mode 100644
index 000000000..5c8ac7f7f
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerAddRawCitations.vue
@@ -0,0 +1,69 @@
+
+
+
+ {{ t('submission.citations') }}
+
+
+ {{ t('submission.citations.description') }}
+
+
+
+
+
+
+ {{ t('common.add', {}) }}
+
+
+
+
+
+ {{ t('submission.citations.structured.addRaw.success') }}
+
+
+
+
+
+
+
+ {{ t('submission.citations.structured.addRaw.partialSuccess') }}
+
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerCellActions.vue b/src/managers/CitationManager/CitationManagerCellActions.vue
new file mode 100644
index 000000000..1f9c19840
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerCellActions.vue
@@ -0,0 +1,34 @@
+
+
+ handleAction(actionName, citation)"
+ />
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerCellCitation.vue b/src/managers/CitationManager/CitationManagerCellCitation.vue
new file mode 100644
index 000000000..83522bf1a
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerCellCitation.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
{{ citation.title }}
+
+
+
+
+
+
+ {{ author.familyName }} {{ author.givenName }}
+
+
+
+
+
+
+ {{ citation.sourceName }}
+
+
+ Date: {{ citation.date }}
+ Volume: {{ citation.volume }}
+ Issue number: {{ citation.issue }}
+
+ Pages: {{ citation.firstPage }} - {{ citation.lastPage }}
+
+ Total pages: {{ citation.pages }}
+
+
+
+ {{ citation.rawCitation }}
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerCellToggle.vue b/src/managers/CitationManager/CitationManagerCellToggle.vue
new file mode 100644
index 000000000..9710d4ac1
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerCellToggle.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerMetadataLookup.vue b/src/managers/CitationManager/CitationManagerMetadataLookup.vue
new file mode 100644
index 000000000..2eabd6e76
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerMetadataLookup.vue
@@ -0,0 +1,34 @@
+
+
+
+ {{ t('submission.citations.structured') }}
+
+
+ {{ t('submission.citations.structured.description') }}
+
+
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerSearchField.vue b/src/managers/CitationManager/CitationManagerSearchField.vue
new file mode 100644
index 000000000..bd7c415a0
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerSearchField.vue
@@ -0,0 +1,16 @@
+
+ citationStore.setSearchPhrase(...args)"
+ />
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerStatusProcessed.vue b/src/managers/CitationManager/CitationManagerStatusProcessed.vue
new file mode 100644
index 000000000..e7287273d
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerStatusProcessed.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ {{
+ processed === total
+ ? t('submission.citations.structured.processed.title', {
+ total: total,
+ })
+ : t('submission.citations.structured.processing.title', {
+ processed: processed,
+ total: total,
+ })
+ }}
+
+
+
+ {{
+ processed === total
+ ? t('submission.citations.structured.processed.description')
+ : t('submission.citations.structured.processing.description')
+ }}
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/CitationManagerToggleAll.vue b/src/managers/CitationManager/CitationManagerToggleAll.vue
new file mode 100644
index 000000000..cb576e3c5
--- /dev/null
+++ b/src/managers/CitationManager/CitationManagerToggleAll.vue
@@ -0,0 +1,18 @@
+
+
+ {{
+ citationStore.allRowsExpanded
+ ? t('submission.citations.structured.collapseAll')
+ : t('submission.citations.structured.expandAll')
+ }}
+
+
+
+
diff --git a/src/managers/CitationManager/citationManagerStore.js b/src/managers/CitationManager/citationManagerStore.js
new file mode 100644
index 000000000..f961f239a
--- /dev/null
+++ b/src/managers/CitationManager/citationManagerStore.js
@@ -0,0 +1,330 @@
+import {computed, onMounted, reactive, ref, toRefs} from 'vue';
+import {defineComponentStore} from '@/utils/defineComponentStore';
+import {useSubmission} from '@/composables/useSubmission';
+import {useDataChanged} from '@/composables/useDataChanged';
+import {useExtender} from '@/composables/useExtender';
+import {useCitationManagerConfig} from '@/managers/CitationManager/useCitationManagerConfig';
+import {useLocalize} from '@/composables/useLocalize';
+import {useUrl} from '@/composables/useUrl';
+import {useModal} from '@/composables/useModal';
+import {useForm} from '@/composables/useForm';
+import {useFetch} from '@/composables/useFetch';
+import CitationEditModal from '@/managers/CitationManager/modals/CitationEditModal.vue';
+
+export const useCitationManagerStore = defineComponentStore(
+ 'citationManager',
+ (props) => {
+ const {openDialog, openSideModal} = useModal();
+ const {t} = useLocalize();
+ const extender = useExtender();
+ const {triggerDataChange} = useDataChanged();
+ function dataUpdateCallback() {
+ triggerDataChange();
+ }
+ const citationManagerConfig = extender.addFns(useCitationManagerConfig());
+ const columns = computed(() => citationManagerConfig.getColumns());
+ const topItems = computed(() => citationManagerConfig.getTopItems());
+ function getItemPrimaryActions(args) {
+ return citationManagerConfig.getItemPrimaryActions(args);
+ }
+ function getItemActions(args) {
+ return citationManagerConfig.getItemActions(args);
+ }
+
+ const {submission, publication} = toRefs(props);
+ const {apiUrl: apiUrlCitations} = useUrl(`citations`);
+ const {apiUrl: apiUrlSubmissions} = useUrl(
+ `submissions/${submission.value.id}/publications/${publication.value.id}/citations`,
+ );
+
+ /**
+ * citations metadata lookup
+ * // todo: this value should come from the metadata setting of journal
+ */
+ const defaultCitationsMetadataLookup = true;
+ const currentCitationsMetadataLookup = ref(false);
+ onMounted(() => {
+ if (publication.value.citationsMetadataLookup !== null) {
+ currentCitationsMetadataLookup.value =
+ publication.value.citationsMetadataLookup;
+ } else {
+ currentCitationsMetadataLookup.value = defaultCitationsMetadataLookup;
+ }
+ });
+ function citationsMetadataLookupChanged() {
+ let title = t('submission.citations.structured.disableModal.title');
+ let message = t('submission.citations.structured.disableModal.confirm');
+ if (currentCitationsMetadataLookup.value) {
+ title = t('submission.citations.structured.enableModal.title');
+ message = t('submission.citations.structured.enableModal.confirm');
+ }
+
+ const {openDialog} = useModal();
+ openDialog({
+ name: 'disableCitationsMetadataLookup',
+ title: title,
+ message: message,
+ actions: [
+ {
+ label: t('common.yes', {}),
+ isWarnable: true,
+ callback: async (close) => {
+ const {fetch} = useFetch(
+ `${apiUrlSubmissions.value}/metadataLookup`,
+ {
+ method: 'PUT',
+ body: {
+ citationsMetadataLookup:
+ currentCitationsMetadataLookup.value,
+ },
+ },
+ );
+ await fetch();
+ dataUpdateCallback();
+ close();
+ },
+ },
+ {
+ label: t('common.no', {}),
+ isPrimary: true,
+ callback: (close) => {
+ currentCitationsMetadataLookup.value =
+ !currentCitationsMetadataLookup.value;
+ close();
+ },
+ },
+ ],
+ close: () => {},
+ });
+ }
+
+ /**
+ * add new raw citations
+ */
+ const citationsRawToBeAdded = ref('');
+ const citationsRawShowMessage = ref('');
+ async function handleAddCitationsRawToList() {
+ const {fetch, data} = useFetch(
+ `${apiUrlSubmissions.value}/importAdditionalCitations`,
+ {
+ method: 'POST',
+ body: {rawCitations: citationsRawToBeAdded},
+ },
+ );
+ await fetch();
+ citationsRawToBeAdded.value = data.value.trim();
+ if (citationsRawToBeAdded.value) {
+ citationsRawShowMessage.value = 'partial';
+ } else {
+ citationsRawShowMessage.value = 'success';
+ }
+ dataUpdateCallback();
+ setTimeout(() => {
+ citationsRawShowMessage.value = '';
+ }, 10000);
+ }
+
+ /**
+ * status processed citations
+ */
+ const totalCitations = computed(() => {
+ return publication.value.citations
+ ? publication.value.citations.length
+ : 0;
+ });
+ const processedCitations = computed(() => {
+ return Object.entries(publication.value.citations)
+ .filter(([key, value]) => value['isProcessed'] === true)
+ .map(([key, value]) => ({item: key, c: value})).length;
+ });
+
+ /**
+ * delete all citations
+ */
+ function citationDeleteAllCitations() {
+ openDialog({
+ name: 'deleteCitation',
+ title: t('submission.citations.structured.deleteAllDialog.title'),
+ message: t(
+ 'submission.citations.structured.deleteAllDialog.confirm',
+ {},
+ ),
+ actions: [
+ {
+ label: t('common.yes'),
+ isPrimary: true,
+ callback: async (close) => {
+ const {fetch} = useFetch(
+ `${apiUrlSubmissions.value}/deleteCitationsByPublicationId`,
+ {method: 'DELETE'},
+ );
+ await fetch();
+ await dataUpdateCallback();
+ close();
+ },
+ },
+ {
+ label: t('common.no'),
+ isWarnable: true,
+ callback: (close) => {
+ close();
+ },
+ },
+ ],
+ });
+ }
+
+ /**
+ * Toggle all / toggle status
+ */
+ const allRowsExpanded = ref(false);
+ let toggleStatusRows = reactive({});
+ function toggleStatusRowChanged(citationId) {
+ if (typeof toggleStatusRows[citationId] === 'undefined') {
+ toggleStatusRows[citationId] = false;
+ }
+ toggleStatusRows[citationId] = !toggleStatusRows[citationId];
+ }
+ function allRowsExpandedChanged() {
+ allRowsExpanded.value = !allRowsExpanded.value;
+ publication.value.citations.forEach((citation) => {
+ toggleStatusRows[citation.id] = allRowsExpanded.value;
+ });
+ }
+
+ /**
+ * Filtered citations and search phrase
+ */
+ const citationsFiltered = computed(() => {
+ if (searchPhrase.value) {
+ return filterArrayByPhrase(
+ props?.publication?.citations,
+ searchPhrase.value,
+ );
+ } else {
+ return props?.publication?.citations;
+ }
+ });
+ const searchPhrase = ref('');
+ function setSearchPhrase(value) {
+ searchPhrase.value = value;
+ }
+ function containsSearchPhrase(obj, phrase) {
+ function deepSearch(value) {
+ if (value === null || value === undefined) return false;
+
+ if (typeof value === 'string') {
+ return value.toLowerCase().includes(phrase.toLowerCase());
+ }
+
+ if (Array.isArray(value)) {
+ return value.some(deepSearch);
+ }
+
+ if (typeof value === 'object') {
+ return Object.values(value).some(deepSearch);
+ }
+
+ return false;
+ }
+
+ return deepSearch(obj);
+ }
+ function filterArrayByPhrase(data, phrase) {
+ return data.filter((item) => containsSearchPhrase(item, phrase));
+ }
+
+ /**
+ * Edit citation
+ */
+ function citationEditCitation({citation}) {
+ let formName = 'citationRawEditForm';
+ if (props.publication.citationsMetadataLookup) {
+ formName = 'citationStructuredEditForm';
+ }
+ const {form, set, setValues, setAction} = useForm(props[formName]);
+ setValues(citation);
+ setAction(`${apiUrlCitations.value}/${citation.id}`);
+ openSideModal(CitationEditModal, {
+ title: t('submission.citations.structured.editModal.title'),
+ form: form,
+ onSet: set,
+ citation: citation,
+ onSuccess: () => {
+ dataUpdateCallback();
+ },
+ });
+ }
+
+ /**
+ * Delete citation
+ */
+ function citationDeleteCitation({citation}) {
+ openDialog({
+ name: 'deleteCitation',
+ title: t('submission.citations.structured.deleteDialog.title'),
+ message: t('submission.citations.structured.deleteDialog.confirm', {}),
+ actions: [
+ {
+ label: t('common.yes'),
+ isPrimary: true,
+ callback: async (close) => {
+ const {apiUrl} = useUrl(`citations`);
+ const {fetch} = useFetch(`${apiUrl.value}/${citation.id}`, {
+ method: 'DELETE',
+ });
+ await fetch();
+ await dataUpdateCallback();
+ close();
+ },
+ },
+ {
+ label: t('common.no'),
+ isWarnable: true,
+ callback: (close) => {
+ close();
+ },
+ },
+ ],
+ });
+ }
+
+ return {
+ columns,
+ topItems,
+ getItemPrimaryActions,
+ getItemActions,
+
+ submission,
+ publication,
+
+ apiUrlCitations,
+ apiUrlSubmissions,
+
+ defaultCitationsMetadataLookup,
+ currentCitationsMetadataLookup,
+ citationsMetadataLookupChanged,
+
+ citationsRawToBeAdded,
+ citationsRawShowMessage,
+ handleAddCitationsRawToList,
+
+ totalCitations,
+ processedCitations,
+
+ citationDeleteAllCitations,
+
+ allRowsExpanded,
+ allRowsExpandedChanged,
+ toggleStatusRows,
+ toggleStatusRowChanged,
+
+ citationsFiltered,
+ searchPhrase,
+ setSearchPhrase,
+
+ citationEditCitation,
+ citationDeleteCitation,
+ };
+ },
+);
diff --git a/src/managers/CitationManager/modals/CitationEditModal.mdx b/src/managers/CitationManager/modals/CitationEditModal.mdx
new file mode 100644
index 000000000..5adecd849
--- /dev/null
+++ b/src/managers/CitationManager/modals/CitationEditModal.mdx
@@ -0,0 +1,16 @@
+import {
+ Primary,
+ Controls,
+ Stories,
+ Meta,
+ ArgTypes,
+} from '@storybook/addon-docs/blocks';
+import * as CitationEditModalStories from './CitationEditModal.stories';
+
+
+
+# Citation Edit Modal
+
+A vue modal containing a form for editing a citation.
+
+
diff --git a/src/managers/CitationManager/modals/CitationEditModal.stories.js b/src/managers/CitationManager/modals/CitationEditModal.stories.js
new file mode 100644
index 000000000..7d9020931
--- /dev/null
+++ b/src/managers/CitationManager/modals/CitationEditModal.stories.js
@@ -0,0 +1,46 @@
+import CitationEditModal from './CitationEditModal.vue';
+import PkpButton from '@/components/Button/Button.vue';
+import {useModal} from '@/composables/useModal';
+
+export default {
+ title: 'Managers/CitationManager/modals/CitationEditModal',
+ component: CitationEditModal,
+};
+
+export const Base = {
+ render: (args) => ({
+ components: {
+ CitationEditModal,
+ PkpButton,
+ },
+ setup() {
+ const {openSideModal} = useModal();
+
+ function openEditStructuredModal() {
+ openSideModal(CitationEditModal, args.modalProps);
+ }
+
+ function openEditRawModal() {
+ openSideModal(CitationEditModal, args.modalProps);
+ }
+ return {
+ openEditStructuredModal,
+ openEditRawModal,
+ };
+ },
+ template: `Structured Raw`,
+ }),
+ args: {
+ modalProps: {
+ title: 'Edit citation',
+ form: {},
+ citation: {},
+ },
+ },
+ play: async ({canvasElement}) => {},
+ decorators: [
+ () => ({
+ template: '
',
+ }),
+ ],
+};
diff --git a/src/managers/CitationManager/modals/CitationEditModal.vue b/src/managers/CitationManager/modals/CitationEditModal.vue
new file mode 100644
index 000000000..d62c991e6
--- /dev/null
+++ b/src/managers/CitationManager/modals/CitationEditModal.vue
@@ -0,0 +1,61 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+ {{ t('submission.citations.structured.label.citation') }}
+
+
+
+ {{ citation['rawCitation'] }}
+
+
+
emit('set', ...args)"
+ @success="
+ (...args) => {
+ closeModal();
+ emit('success', ...args);
+ }
+ "
+ >
+
+
+
+
+
+
+
+
diff --git a/src/managers/CitationManager/useCitationManagerActions.js b/src/managers/CitationManager/useCitationManagerActions.js
new file mode 100644
index 000000000..bc1ab81e2
--- /dev/null
+++ b/src/managers/CitationManager/useCitationManagerActions.js
@@ -0,0 +1,9 @@
+export const Actions = {
+ CITATION_TOGGLE_ALL_CITATION: 'citationToggleAll',
+ CITATION_EDIT_CITATION: 'citationEditCitation',
+ CITATION_DELETE_CITATION: 'citationDeleteCitation',
+};
+
+export function useCitationManagerActions() {
+ return {};
+}
diff --git a/src/managers/CitationManager/useCitationManagerConfig.js b/src/managers/CitationManager/useCitationManagerConfig.js
new file mode 100644
index 000000000..b3d6d16fe
--- /dev/null
+++ b/src/managers/CitationManager/useCitationManagerConfig.js
@@ -0,0 +1,75 @@
+import {useLocalize} from '@/composables/useLocalize';
+import {Actions} from './useCitationManagerActions';
+
+export function useCitationManagerConfig() {
+ const {t} = useLocalize();
+
+ function getColumns() {
+ const columns = [];
+
+ columns.push({
+ header: t('submission.citations.structured'),
+ component: 'CitationManagerCellCitation',
+ props: {},
+ });
+
+ columns.push({
+ header: 'CitationManagerToggleAll',
+ component: 'CitationManagerCellToggle',
+ props: {},
+ isHeaderComponent: true,
+ });
+
+ columns.push({
+ header: '',
+ component: 'CitationManagerCellActions',
+ props: {},
+ });
+
+ return columns;
+ }
+
+ function getTopItems() {
+ const items = [];
+
+ items.push({
+ component: 'CitationManagerSearchField',
+ props: {
+ label: t('submission.citations.structured.expandAll'),
+ action: '',
+ },
+ });
+
+ return items;
+ }
+
+ function getItemPrimaryActions() {
+ const items = [];
+ return items;
+ }
+
+ function getItemActions() {
+ const actions = [];
+
+ actions.push({
+ label: t('common.edit'),
+ name: Actions.CITATION_EDIT_CITATION,
+ icon: 'Edit',
+ });
+
+ actions.push({
+ label: t('common.delete'),
+ name: Actions.CITATION_DELETE_CITATION,
+ icon: 'Cancel',
+ });
+
+ return actions;
+ }
+
+ return {
+ getColumns,
+ getTopItems,
+ getItemPrimaryActions,
+ getItemActions,
+ };
+}
diff --git a/src/pages/workflow/WorkflowPageOJS.vue b/src/pages/workflow/WorkflowPageOJS.vue
index 9d854e7c6..bd874c805 100644
--- a/src/pages/workflow/WorkflowPageOJS.vue
+++ b/src/pages/workflow/WorkflowPageOJS.vue
@@ -12,6 +12,7 @@ import FileManager from '@/managers/FileManager/FileManager.vue';
import ReviewerManager from '@/managers/ReviewerManager/ReviewerManager.vue';
import DiscussionManager from '@/managers/DiscussionManager/DiscussionManager.vue';
import ContributorManager from '@/managers/ContributorManager/ContributorManager.vue';
+import CitationManager from '@/managers/CitationManager/CitationManager.vue';
import ParticipantManager from '@/managers/ParticipantManager/ParticipantManager.vue';
import ReviewerSuggestionManager from '@/managers/ReviewerSuggestionManager/ReviewerSuggestionManager.vue';
import GalleyManager from '@/managers/GalleyManager/GalleyManager.vue';
@@ -49,6 +50,7 @@ const Components = markRaw({
ReviewerManager,
DiscussionManager,
ContributorManager,
+ CitationManager,
ParticipantManager,
ReviewerSuggestionManager,
GalleyManager,
diff --git a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js
index 15348ba40..8183727ab 100644
--- a/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js
+++ b/src/pages/workflow/composables/useWorkflowConfig/workflowConfigEditorialOJS.js
@@ -911,12 +911,13 @@ export const PublicationConfig = {
}) => {
return [
{
- component: 'WorkflowPublicationForm',
+ component: 'CitationManager',
props: {
- formName: 'reference',
- submission,
+ submission: submission,
publication: selectedPublication,
canEdit: permissions.canEditPublication,
+ citationStructuredEditForm: pageInitConfig.componentForms.citationStructuredEditForm,
+ citationRawEditForm: pageInitConfig.componentForms.citationRawEditForm,
},
},
];
From a2297c8c570714a18f1b42cdb528394e5ec2c1f5 Mon Sep 17 00:00:00 2001
From: GaziYucel <84437883+GaziYucel@users.noreply.github.com>
Date: Mon, 1 Sep 2025 12:24:13 +0200
Subject: [PATCH 02/15] structured citations (development)
---
src/managers/CitationManager/CitationManagerAddRawCitations.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/managers/CitationManager/CitationManagerAddRawCitations.vue b/src/managers/CitationManager/CitationManagerAddRawCitations.vue
index 5c8ac7f7f..4dd63ef2d 100644
--- a/src/managers/CitationManager/CitationManagerAddRawCitations.vue
+++ b/src/managers/CitationManager/CitationManagerAddRawCitations.vue
@@ -4,7 +4,7 @@
{{ t('submission.citations') }}
- {{ t('submission.citations.description') }}
+ {{ t('submission.citations.structured.description') }}
+
+
+ {{ t('submission.citations.structured.noStructuredInformationFound') }}
+
+