From e22e8b862a9b54d811807ee3e040caca89526505 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Thu, 21 Dec 2023 10:44:52 +0100 Subject: [PATCH 01/11] pkp/pkp-lib#9666 COUNTER R5 TSV reports --- .../Container/CounterReportsPage.vue | 12 + .../Form/counter/CounterReportForm.vue | 137 ++++++++++++ .../counter/CounterReportsListPanel.vue | 208 ++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 src/components/Container/CounterReportsPage.vue create mode 100644 src/components/Form/counter/CounterReportForm.vue create mode 100644 src/components/ListPanel/counter/CounterReportsListPanel.vue diff --git a/src/components/Container/CounterReportsPage.vue b/src/components/Container/CounterReportsPage.vue new file mode 100644 index 000000000..396625750 --- /dev/null +++ b/src/components/Container/CounterReportsPage.vue @@ -0,0 +1,12 @@ + diff --git a/src/components/Form/counter/CounterReportForm.vue b/src/components/Form/counter/CounterReportForm.vue new file mode 100644 index 000000000..492b9f274 --- /dev/null +++ b/src/components/Form/counter/CounterReportForm.vue @@ -0,0 +1,137 @@ + diff --git a/src/components/ListPanel/counter/CounterReportsListPanel.vue b/src/components/ListPanel/counter/CounterReportsListPanel.vue new file mode 100644 index 000000000..13437d5ed --- /dev/null +++ b/src/components/ListPanel/counter/CounterReportsListPanel.vue @@ -0,0 +1,208 @@ + + + + + From ee3ff76b42495f70add9418a5e8b3ec8d987c466 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Wed, 17 Jul 2024 15:31:36 +0200 Subject: [PATCH 02/11] fix counter list panel --- .../counter/CounterReportsEditModal.vue | 26 ++++ .../counter/CounterReportsListPanel.vue | 118 ++++++++---------- 2 files changed, 78 insertions(+), 66 deletions(-) create mode 100644 src/components/ListPanel/counter/CounterReportsEditModal.vue diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue new file mode 100644 index 000000000..3da3bb12b --- /dev/null +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/ListPanel/counter/CounterReportsListPanel.vue b/src/components/ListPanel/counter/CounterReportsListPanel.vue index 13437d5ed..e3740fbdf 100644 --- a/src/components/ListPanel/counter/CounterReportsListPanel.vue +++ b/src/components/ListPanel/counter/CounterReportsListPanel.vue @@ -1,85 +1,80 @@ diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue index 3da3bb12b..8f73b9ae0 100644 --- a/src/components/ListPanel/counter/CounterReportsEditModal.vue +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -4,10 +4,10 @@ {{ title }} - @@ -16,11 +16,108 @@ diff --git a/src/components/ListPanel/counter/CounterReportsListPanel.vue b/src/components/ListPanel/counter/CounterReportsListPanel.vue index e3740fbdf..b4f8cc7a6 100644 --- a/src/components/ListPanel/counter/CounterReportsListPanel.vue +++ b/src/components/ListPanel/counter/CounterReportsListPanel.vue @@ -135,8 +135,6 @@ export default { } let activeForm = cloneDeep(this.form); - activeForm.reportId = id; - activeForm.action = this.apiUrl + '/' + report.Path; activeForm.method = 'GET'; activeForm.fields = activeForm.reportFields[id]; this.activeForm = activeForm; @@ -146,6 +144,7 @@ export default { openSideModal(CounterReportsEditModal, { title: this.editCounterReportLabel, + submitAction: this.apiUrl + '/' + report.Path, activeForm, onUpdateForm: this.updateForm, onFormSuccess: this.formSuccess, From 5e20892fa777e7b7ac6b5f42302974c2eda2b4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?= Date: Thu, 22 Aug 2024 14:10:57 +0200 Subject: [PATCH 04/11] Form customSubmit with useFetch --- src/components/Form/Form.vue | 28 ++++++-- .../counter/CounterReportsEditModal.vue | 71 +++++-------------- src/composables/useForm.js | 6 +- 3 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/components/Form/Form.vue b/src/components/Form/Form.vue index 8946a24f2..31eca16b3 100644 --- a/src/components/Form/Form.vue +++ b/src/components/Form/Form.vue @@ -17,7 +17,7 @@ :primary-locale-key="primaryLocale" :locales="availableLocales" :visible="visibleLocales" - @updateLocales="setVisibleLocales" + @update-locales="setVisibleLocales" />
    @@ -59,10 +59,10 @@ :available-locales="availableLocales" :is-saving="isSaving" @change="fieldChanged" - @pageSubmitted="nextPage" - @previousPage="setCurrentPage(false)" - @showField="showField" - @showLocale="showLocale" + @page-submitted="nextPage" + @previous-page="setCurrentPage(false)" + @show-field="showField" + @show-locale="showLocale" @cancel="cancel" @set-errors="setErrors" /> @@ -128,6 +128,10 @@ export default { visibleLocales: Array, /** The locale(s) supported by this form. If a form has multilingual fields, it will display a separate input control for each of these locales. */ supportedFormLocales: Array, + /** For custom AJAX call, while still keep the error handling within Form + * Async function, receiving data from form and returning {validationError, data} from useFetch + */ + customSubmit: Function, }, emits: [ /** When the form props need to be updated. The payload is an object with any keys that need to be modified. */ @@ -285,7 +289,7 @@ export default { /** * Submit the form */ - submit() { + async submit() { if (!this.canSubmit) { return false; } @@ -304,7 +308,17 @@ export default { return; } - if (this.action === 'emit') { + if (this.customSubmit) { + const {data, validationError} = await this.customSubmit( + this.submitValues, + ); + if (validationError) { + this.error({status: 400, responseJSON: validationError}); + } else { + this.success(data); + } + this.complete(); + } else if (this.action === 'emit') { this.$emit('success', this.submitValues); } else { $.ajax({ diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue index 8f73b9ae0..6ff99f9fc 100644 --- a/src/components/ListPanel/counter/CounterReportsEditModal.vue +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -4,11 +4,7 @@ {{ title }} - + @@ -18,13 +14,13 @@ import SideModalBody from '@/components/Modal/SideModalBody.vue'; import SideModalLayoutBasic from '@/components/Modal/SideModalLayoutBasic.vue'; import PkpForm from '@/components/Form/Form.vue'; import {useForm} from '@/composables/useForm'; +import {useFetch} from '@/composables/useFetch'; const props = defineProps({ title: {type: String, required: true}, submitAction: {type: String, required: true}, activeForm: {type: Object, required: true}, }); -const emit = defineEmits(['updateForm', 'formSuccess']); /** * Get the report parameters @@ -66,58 +62,25 @@ function getReportParams(formSubmitValues) { return params; } -/** - * Submit the form - * - * @param {Object} - */ -function counterFormSubmit(submittedValues) { - const {form: form} = useForm(props.activeForm); +const {form, set} = useForm(props.activeForm, { + customSubmit: async (submittedValues) => { + const {validationError, data, fetch} = useFetch(props.submitAction, { + expectValidationError: true, + headers: {Accept: 'text/tab-separated-values; charset=utf-8'}, + query: getReportParams(submittedValues), + }); - form.isSaving = true; + await fetch(); - $.ajax({ - context: form, - method: form.method, - url: props.submitAction, - headers: { - Accept: 'text/tab-separated-values; charset=utf-8', - }, - data: getReportParams(submittedValues), - error(r) { - form.isSaving = false; - if (r.status && r.status === 400) { - if (Object.prototype.hasOwnProperty.call(r.responseJSON, 'Code')) { - // COUNTER speific errors should actually not occur - // because of the form/user input validation - // but consider them for any case as well. - pkp.eventBus.$emit( - 'notify', - r.responseJSON.Code + - ':' + - r.responseJSON.Message + - '(' + - r.responseJSON.Data + - ')', - 'warning', - ); - } else { - // Field validation errors - emit('updateForm', form.id, {errors: r.responseJSON}); - } - } else { - form.error(r); - } - }, - success(r) { - var blob = new Blob([r]); + if (data.value) { + var blob = new Blob([data.value]); var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = 'counterReport.tsv'; link.click(); - form.isSaving = false; - emit('formSuccess', this.id, r); - }, - }); -} + } + + return {data: data.value, validationError: validationError.value}; + }, +}); diff --git a/src/composables/useForm.js b/src/composables/useForm.js index 0656d0760..f0d2ef049 100644 --- a/src/composables/useForm.js +++ b/src/composables/useForm.js @@ -30,9 +30,13 @@ function mapFromSelectedToValue(selected) { return selected.map((iv) => iv.value); } -export function useForm(_form) { +export function useForm(_form, {customSubmit}) { const form = ref(_form); + if (customSubmit) { + form.value.customSubmit = customSubmit; + } + function connectWithPayload(payload) { watch( payload, From e5a5a001bbf9fc68cf68d0e23c2c3277e2906f61 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Mon, 26 Aug 2024 15:34:29 +0200 Subject: [PATCH 05/11] adapt form --- src/components/Form/Form.vue | 2 +- .../counter/CounterReportsEditModal.vue | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/components/Form/Form.vue b/src/components/Form/Form.vue index 31eca16b3..b46c24ee3 100644 --- a/src/components/Form/Form.vue +++ b/src/components/Form/Form.vue @@ -314,7 +314,7 @@ export default { ); if (validationError) { this.error({status: 400, responseJSON: validationError}); - } else { + } else if (data) { this.success(data); } this.complete(); diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue index 6ff99f9fc..56e24be2e 100644 --- a/src/components/ListPanel/counter/CounterReportsEditModal.vue +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -72,7 +72,26 @@ const {form, set} = useForm(props.activeForm, { await fetch(); - if (data.value) { + if ( + validationError.value && + Object.prototype.hasOwnProperty.call(validationError.value, 'Code') + ) { + // COUNTER speific errors should actually not occur + // because of the form/user input validation + // but consider them for any case as well. + pkp.eventBus.$emit( + 'notify', + validationError.value.Code + + ': ' + + validationError.value.Message + + ' (' + + validationError.value.Data + + ')', + 'warning', + ); + validationError.value = null; + data.value = null; + } else if (data.value) { var blob = new Blob([data.value]); var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); From 4fd8fac81b3f0ef9b2c1f15379fa0310025977fc Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Mon, 26 Aug 2024 11:51:22 +0200 Subject: [PATCH 06/11] adapt counter page --- .../Container/CounterReportsPage.vue | 12 ------- src/components/Container/Page.vue | 2 ++ src/pages/counter/CounterReportsPage.vue | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+), 12 deletions(-) delete mode 100644 src/components/Container/CounterReportsPage.vue create mode 100644 src/pages/counter/CounterReportsPage.vue diff --git a/src/components/Container/CounterReportsPage.vue b/src/components/Container/CounterReportsPage.vue deleted file mode 100644 index 396625750..000000000 --- a/src/components/Container/CounterReportsPage.vue +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/src/components/Container/Page.vue b/src/components/Container/Page.vue index d00f9a05a..eb857f93d 100644 --- a/src/components/Container/Page.vue +++ b/src/components/Container/Page.vue @@ -7,6 +7,7 @@ import ReviewerSubmissionPage from '@/pages/reviewerSubmission/ReviewerSubmissio import JobsPage from '@/pages/jobs/JobsPage.vue'; import FailedJobsPage from '@/pages/jobs/FailedJobsPage.vue'; import FailedJobDetailsPage from '@/pages/jobs/FailedJobDetailsPage.vue'; +import CounterReportsPage from '@/pages/counter/CounterReportsPage.vue'; export default { name: 'Page', @@ -17,6 +18,7 @@ export default { JobsPage, FailedJobsPage, FailedJobDetailsPage, + CounterReportsPage, }, extends: Container, data() { diff --git a/src/pages/counter/CounterReportsPage.vue b/src/pages/counter/CounterReportsPage.vue new file mode 100644 index 000000000..7d810d083 --- /dev/null +++ b/src/pages/counter/CounterReportsPage.vue @@ -0,0 +1,31 @@ + + + From 1ef65d494e2390c566008bbd83578139894d5283 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Thu, 29 Aug 2024 11:53:05 +0200 Subject: [PATCH 07/11] pkp/pkp-lib#10350 fix the check of the COUNTER R5 form field customer_id --- src/components/ListPanel/counter/CounterReportsEditModal.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue index 56e24be2e..0ef388bad 100644 --- a/src/components/ListPanel/counter/CounterReportsEditModal.vue +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -33,6 +33,10 @@ function getReportParams(formSubmitValues) { for (const [key, value] of Object.entries(formSubmitValues)) { switch (key) { case 'customer_id': + if (parseInt(value, 10) >= 0) { + params[key] = value; + } + break; case 'begin_date': case 'end_date': case 'yop': From 7fe2eaea2821122ab92457d76f13af69053264a7 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Tue, 8 Oct 2024 14:12:55 +0200 Subject: [PATCH 08/11] changes according to the second review --- .../counter/CounterReportsEditModal.vue | 5 +- .../counter/CounterReportsListPanel.vue | 199 +++++------------- src/pages/counter/CounterReportsPage.vue | 2 +- 3 files changed, 59 insertions(+), 147 deletions(-) diff --git a/src/components/ListPanel/counter/CounterReportsEditModal.vue b/src/components/ListPanel/counter/CounterReportsEditModal.vue index 0ef388bad..a8f3b6746 100644 --- a/src/components/ListPanel/counter/CounterReportsEditModal.vue +++ b/src/components/ListPanel/counter/CounterReportsEditModal.vue @@ -4,7 +4,7 @@ {{ title }} - + @@ -15,6 +15,7 @@ import SideModalLayoutBasic from '@/components/Modal/SideModalLayoutBasic.vue'; import PkpForm from '@/components/Form/Form.vue'; import {useForm} from '@/composables/useForm'; import {useFetch} from '@/composables/useFetch'; +import {inject} from 'vue'; const props = defineProps({ title: {type: String, required: true}, @@ -22,6 +23,8 @@ const props = defineProps({ activeForm: {type: Object, required: true}, }); +const closeModal = inject('closeModal'); + /** * Get the report parameters * diff --git a/src/components/ListPanel/counter/CounterReportsListPanel.vue b/src/components/ListPanel/counter/CounterReportsListPanel.vue index b4f8cc7a6..aba499d45 100644 --- a/src/components/ListPanel/counter/CounterReportsListPanel.vue +++ b/src/components/ListPanel/counter/CounterReportsListPanel.vue @@ -9,7 +9,7 @@ @@ -23,171 +23,80 @@
- diff --git a/src/pages/counter/CounterReportsPage.vue b/src/pages/counter/CounterReportsPage.vue index 7d810d083..fa75c8b15 100644 --- a/src/pages/counter/CounterReportsPage.vue +++ b/src/pages/counter/CounterReportsPage.vue @@ -23,7 +23,7 @@ import PanelSection from '@/components/Panel/PanelSection.vue'; import CounterReportsListPanel from '@/components/ListPanel/counter/CounterReportsListPanel.vue'; defineProps({ - counterReportsListPanel: {type: Array, required: true}, + counterReportsListPanel: {type: Object, required: true}, usageNotPossible: {type: Boolean, required: true}, title: {type: String, required: true}, description: {type: String, required: true}, From cfd12e63f9a2c2b528a032a158a3cefc46e82703 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Wed, 9 Oct 2024 15:05:30 +0200 Subject: [PATCH 09/11] move counter list panel components to pages/counter/components/ --- src/pages/counter/CounterReportsPage.vue | 2 +- .../counter/components}/CounterReportsEditModal.vue | 0 .../counter/components}/CounterReportsListPanel.vue | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/{components/ListPanel/counter => pages/counter/components}/CounterReportsEditModal.vue (100%) rename src/{components/ListPanel/counter => pages/counter/components}/CounterReportsListPanel.vue (100%) diff --git a/src/pages/counter/CounterReportsPage.vue b/src/pages/counter/CounterReportsPage.vue index fa75c8b15..5c86cf7ac 100644 --- a/src/pages/counter/CounterReportsPage.vue +++ b/src/pages/counter/CounterReportsPage.vue @@ -20,7 +20,7 @@ diff --git a/src/pages/counter/components/CounterReportsListPanel.vue b/src/pages/counter/components/CounterReportsListPanel.vue index aba499d45..da0e2e170 100644 --- a/src/pages/counter/components/CounterReportsListPanel.vue +++ b/src/pages/counter/components/CounterReportsListPanel.vue @@ -34,7 +34,7 @@ import {useModal} from '@/composables/useModal'; import {useFetch} from '@/composables/useFetch'; import {useApiUrl} from '@/composables/useApiUrl'; import {useLocalize} from '@/composables/useLocalize'; -import {ref, onMounted} from 'vue'; +import {ref, computed} from 'vue'; const {t} = useLocalize(); @@ -44,33 +44,19 @@ const props = defineProps({ title: {type: String, required: true}, }); -const items = ref([]); -const isLoadingItems = ref(false); +const items = computed(() => data.value || []); const activeForm = ref(null); const activeFormTitle = ref(''); -onMounted(() => { - /* Load the items */ - getItems(); +const {apiUrl} = useApiUrl(`stats/sushi/reports`); +const { + data, + fetch, + isLoading: isLoadingItems, +} = useFetch(apiUrl, { + method: 'GET', }); - -/** - * Get the list of items (COUNTER R5 reports) from the server - */ -async function getItems() { - isLoadingItems.value = true; - - const {apiUrl} = useApiUrl(`stats/sushi/reports`); - const {data, isSuccess, fetch} = useFetch(apiUrl, { - method: 'GET', - }); - await fetch(); - - if (isSuccess) { - items.value = data.value; - } - isLoadingItems.value = false; -} +fetch(); /** * Open the modal to edit an item @@ -96,7 +82,3 @@ function openEditModal(id) { }); } - - From c551c55604938c8627ebd31b2ea53bf0db379851 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Tue, 15 Oct 2024 08:55:03 +0200 Subject: [PATCH 11/11] fix storybook failure --- src/composables/useForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/composables/useForm.js b/src/composables/useForm.js index f0d2ef049..843ee8fd7 100644 --- a/src/composables/useForm.js +++ b/src/composables/useForm.js @@ -30,7 +30,7 @@ function mapFromSelectedToValue(selected) { return selected.map((iv) => iv.value); } -export function useForm(_form, {customSubmit}) { +export function useForm(_form, {customSubmit} = {}) { const form = ref(_form); if (customSubmit) {