From 8069a89d029eedadafa9c60d2b9f0311e045c9f2 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 10 May 2022 15:59:32 +0200 Subject: [PATCH] Bug 32030: Use router for current view and object_id And improve breadcrumb Signed-off-by: Jonathan Field Signed-off-by: Martin Renvoize Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- .../vue/components/ERM/AgreementPeriods.vue | 7 +- .../vue/components/ERM/AgreementUserRoles.vue | 2 + .../prog/js/vue/components/ERM/Agreements.vue | 47 ------ .../vue/components/ERM/AgreementsFormAdd.vue | 45 +++--- .../ERM/AgreementsFormConfirmDelete.vue | 35 ++--- .../js/vue/components/ERM/AgreementsList.vue | 14 +- .../js/vue/components/ERM/AgreementsShow.vue | 38 ++--- .../vue/components/ERM/AgreementsToolbar.vue | 17 +- .../prog/js/vue/components/ERM/Dialog.vue | 7 +- .../prog/js/vue/components/ERM/ERMMain.vue | 7 - .../prog/js/vue/components/ERM/Licenses.vue | 47 ------ .../js/vue/components/ERM/LicensesFormAdd.vue | 43 +++-- .../ERM/LicensesFormConfirmDelete.vue | 42 +++-- .../js/vue/components/ERM/LicensesList.vue | 15 +- .../js/vue/components/ERM/LicensesShow.vue | 41 +++-- .../js/vue/components/ERM/LicensesToolbar.vue | 17 +- koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js | 38 +++++ .../intranet-tmpl/prog/js/vue/main-erm.ts | 52 +----- koha-tmpl/intranet-tmpl/prog/js/vue/routes.js | 148 ++++++++++++++++++ .../intranet-tmpl/prog/js/vue/stores/main.js | 7 - 20 files changed, 323 insertions(+), 346 deletions(-) delete mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Agreements.vue delete mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Licenses.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/routes.js diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue index 979528f172..7ff66eb018 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue @@ -68,12 +68,17 @@ import flatPickr from 'vue-flatpickr-component' export default { name: 'AgreementPeriods', data() { - return { fp_config: flatpickr_defaults, dates_fixed: 0 } + return { + fp_config: flatpickr_defaults, + dates_fixed: 0, + } }, props: { periods: Array }, beforeUpdate() { + if (!this.periods) return + if (!this.dates_fixed) { this.periods.forEach(p => { p.started_on = $date(p.started_on) diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementUserRoles.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementUserRoles.vue index fe9cf75753..5fd66a6dbe 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementUserRoles.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementUserRoles.vue @@ -71,6 +71,8 @@ export default { user_roles: Array, }, beforeUpdate() { + if (!this.user_roles) return + this.user_roles.forEach(u => { u.patron_str = $patron_to_html(u.patron) }) diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Agreements.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Agreements.vue deleted file mode 100644 index fa7fcbfafd..0000000000 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Agreements.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue index 7bfdc6f37e..d34d9adc3d 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue @@ -176,11 +176,11 @@
- CancelCancel
@@ -194,6 +194,7 @@ import AgreementLicenses from './AgreementLicenses.vue' import { useVendorStore } from "../../stores/vendors" import { useAVStore } from "../../stores/authorised_values" import { useMainStore } from "../../stores/main" +import { fetchAgreement } from '../../fetch' import { storeToRefs } from "pinia" export default { @@ -211,7 +212,7 @@ export default { } = storeToRefs(AVStore) const mainStore = useMainStore() - const { setMessage, setError, resetMessages, setCurrentView } = mainStore + const { setMessage, setError, resetMessages } = mainStore return { vendors, @@ -221,7 +222,7 @@ export default { av_agreement_user_roles, av_agreement_license_statuses, av_agreement_license_location, - setMessage, setError, resetMessages, setCurrentView, + setMessage, setError, resetMessages, } }, data() { @@ -242,26 +243,20 @@ export default { } } }, - created() { - if (!this.agreement_id) return - const apiUrl = '/api/v1/erm/agreements/' + this.agreement_id - - fetch(apiUrl, { - headers: { - 'x-koha-embed': 'periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license' - } - }) - .then(res => res.json()) - .then( - (result) => { - this.agreement = result - }, - (error) => { - this.setError(error) - } - ) + beforeRouteEnter(to, from, next) { + if (to.params.agreement_id) { + next(vm => { + vm.agreement = vm.getAgreement(to.params.agreement_id) + }) + } else { + next() + } }, methods: { + async getAgreement(agreement_id) { + const agreement = await fetchAgreement(agreement_id) + this.agreement = agreement + }, onSubmit(e) { e.preventDefault() @@ -300,10 +295,10 @@ export default { fetch(apiUrl, options) .then(response => { if (response.status == 200) { - this.setCurrentView('list') + this.$router.push("/cgi-bin/koha/erm/agreements") this.setMessage('Agreement updated') } else if (response.status == 201) { - this.setCurrentView('list') + this.$router.push("/cgi-bin/koha/erm/agreements") this.setMessage('Agreement created') } else { this.setError(response.message || response.statusText) diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormConfirmDelete.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormConfirmDelete.vue index 59806ba257..924d16e5c0 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormConfirmDelete.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormConfirmDelete.vue @@ -17,11 +17,11 @@
- No, do not deleteNo, do not delete
@@ -30,13 +30,14 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Dialog.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Dialog.vue index 9e20c51eeb..ba665d5c6e 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Dialog.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Dialog.vue @@ -6,11 +6,16 @@ \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue index 41712aa449..4a8e3cf630 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue @@ -17,7 +17,6 @@
  • Agreements Licenses - - - - - - - - - diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue index 5bd9a01c21..5ca08fbf37 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue @@ -96,11 +96,11 @@
    - CancelCancel
    @@ -111,6 +111,7 @@ import flatPickr from 'vue-flatpickr-component' import { useAVStore } from "../../stores/authorised_values" import { useMainStore } from "../../stores/main" +import { fetchLicense } from '../../fetch' import { storeToRefs } from "pinia" export default { @@ -123,12 +124,12 @@ export default { } = storeToRefs(AVStore) const mainStore = useMainStore() - const { setMessage, setError, resetMessages, setCurrentView } = mainStore + const { setMessage, setError, resetMessages } = mainStore return { av_license_types, av_license_statuses, - setMessage, setError, resetMessages, setCurrentView, + setMessage, setError, resetMessages, } }, data() { @@ -153,22 +154,20 @@ export default { this.dates_fixed = 1 } }, - created() { - if (!this.license_id) return - const apiUrl = '/api/v1/erm/licenses/' + this.license_id - - fetch(apiUrl) - .then(res => res.json()) - .then( - (result) => { - this.license = result - }, - (error) => { - this.setError(error) - } - ) + beforeRouteEnter(to, from, next) { + if (to.params.license_id) { + next(vm => { + vm.license = vm.getLicense(to.params.license_id) + }) + } else { + next() + } }, methods: { + async getLicense(license_id) { + const license = await fetchLicense(license_id) + this.license = license + }, onSubmit(e) { e.preventDefault() @@ -196,13 +195,13 @@ export default { fetch(apiUrl, options) .then(response => { if (response.status == 200) { - this.setCurrentView('list') + this.$router.push("/cgi-bin/koha/erm/licenses") this.setMessage('License updated') } else if (response.status == 201) { - this.setCurrentView('list') + this.$router.push("/cgi-bin/koha/erm/licenses") this.setMessage('License created') } else { - this.setError( response.message || response.statusText) + this.setError(response.message || response.statusText) } }, (error) => { this.setError(error) diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue index 2b3c10cf4b..e49bbf909d 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue @@ -16,11 +16,11 @@
    - No, do not deleteNo, do not delete
    @@ -29,13 +29,14 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue index d49c49ae7a..657a69aa50 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue @@ -13,7 +13,6 @@ import ButtonEdit from "./ButtonEdit.vue" import ButtonDelete from "./ButtonDelete.vue" import { createVNode, defineComponent, render, resolveComponent } from 'vue' import { useAVStore } from "../../stores/authorised_values" -import { useMainStore } from "../../stores/main" import { storeToRefs } from "pinia" export default { @@ -24,14 +23,9 @@ export default { av_license_statuses, } = storeToRefs(AVStore) - const mainStore = useMainStore() - const { current_object_id } = storeToRefs(mainStore) - const { setCurrentView } = mainStore - return { av_license_types, av_license_statuses, - setCurrentView, current_object_id, } }, created() { @@ -201,16 +195,13 @@ export default { }, methods: { show_license: function (license_id) { - this.setCurrentView('show') - this.current_object_id = license_id + this.$router.push("/cgi-bin/koha/erm/licenses/" + license_id) }, edit_license: function (license_id) { - this.setCurrentView('add-form') - this.current_object_id = license_id + this.$router.push("/cgi-bin/koha/erm/licenses/edit/" + license_id) }, delete_license: function (license_id) { - this.setCurrentView('confirm-delete-form') - this.current_object_id = license_id + this.$router.push("/cgi-bin/koha/erm/licenses/delete/" + license_id) }, }, props: { diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue index 920515a1e9..3f5af54837 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue @@ -40,8 +40,11 @@
    - CloseClose
    @@ -51,6 +54,7 @@ import { useAVStore } from "../../stores/authorised_values" import { useMainStore } from "../../stores/main" import { storeToRefs } from "pinia" +import { fetchLicense } from "../../fetch" export default { setup() { @@ -69,14 +73,14 @@ export default { } = storeToRefs(AVStore) const mainStore = useMainStore() - const { setError, setCurrentView } = mainStore + const { setError } = mainStore return { format_date, get_lib_from_av, av_license_types, av_license_statuses, - setError, setCurrentView, + setError, } }, data() { @@ -92,25 +96,20 @@ export default { } } }, - created() { - if (!this.license_id) return - const apiUrl = '/api/v1/erm/licenses/' + this.license_id - - fetch(apiUrl) - .then(res => res.json()) - .then( - (result) => { - this.license = result - }, - (error) => { - this.setError(error) - } - ) + beforeRouteEnter(to, from, next) { + if (to.params.license_id) { + next(vm => { + vm.license = vm.getLicense(to.params.license_id) + }) + } else { + next() + } }, methods: { - }, - props: { - license_id: Number, + async getLicense(license_id) { + const license = await fetchLicense(license_id) + this.license = license + }, }, components: { }, diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesToolbar.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesToolbar.vue index 8f524162e1..18592e9e66 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesToolbar.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesToolbar.vue @@ -1,24 +1,13 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js new file mode 100644 index 0000000000..dec157a559 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js @@ -0,0 +1,38 @@ +export const fetchAgreement = async function (agreement_id) { + if (!agreement_id) return; + const apiUrl = "/api/v1/erm/agreements/" + agreement_id; + let agreement; + await fetch(apiUrl, { + headers: { + "x-koha-embed": + "periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license", + }, + }) + .then((res) => res.json()) + .then( + (result) => { + agreement = result; + }, + (error) => { + this.setError(error); + } + ); + return agreement; +}; + +export const fetchLicense = async function (license_id) { + if (!license_id) return; + const apiUrl = "/api/v1/erm/licenses/" + license_id; + let license; + await fetch(apiUrl) + .then((res) => res.json()) + .then( + (result) => { + license = result; + }, + (error) => { + this.setError(error); + } + ); + return license; +}; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts index 62b1e62df7..3189be89f1 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts @@ -1,6 +1,6 @@ import { createApp } from "vue"; import { createWebHistory, createRouter } from "vue-router"; -import { createPinia } from 'pinia' +import { createPinia } from "pinia"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faPlus, faPencil, faTrash } from "@fortawesome/free-solid-svg-icons"; @@ -9,54 +9,8 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; library.add(faPlus, faPencil, faTrash); import App from "./components/ERM/ERMMain.vue"; -import ERMHome from "./components/ERM/ERMHome.vue"; -import Agreements from "./components/ERM/Agreements.vue"; -import Licenses from "./components/ERM/Licenses.vue"; -const Bar = { template: "
    bar
    " }; -const routes = [ - { - path: "/cgi-bin/koha/erm/erm.pl", - component: ERMHome, - meta: { - breadcrumb: [ - { text: "Home", path: "/cgi-bin/koha/mainpage.pl" }, - { - text: "Electronic resources management", - path: "/cgi-bin/koha/erm/erm.pl", - }, - ], - }, - }, - { - path: "/cgi-bin/koha/erm/agreements", - component: Agreements, - meta: { - breadcrumb: [ - { text: "Home", path: "/cgi-bin/koha/mainpage.pl" }, - { - text: "Electronic resources management", - path: "/cgi-bin/koha/erm/erm.pl", - }, - { text: "Agreements", path: "/cgi-bin/koha/erm/agreements" }, - ], - }, - }, - { - path: "/cgi-bin/koha/erm/licenses", - component: Licenses, - meta: { - breadcrumb: [ - { text: "Home", path: "/cgi-bin/koha/mainpage.pl" }, - { - text: "Electronic resources management", - path: "/cgi-bin/koha/erm/erm.pl", - }, - { text: "Licenses", path: "/cgi-bin/koha/erm/licenses" }, - ], - }, - }, -]; +import { routes } from "./routes"; const router = createRouter({ history: createWebHistory(), routes }); @@ -64,4 +18,4 @@ createApp(App) .use(createPinia()) .use(router) .component("font-awesome-icon", FontAwesomeIcon) - .mount("#erm"); \ No newline at end of file + .mount("#erm"); diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js new file mode 100644 index 0000000000..0d1a7228d9 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js @@ -0,0 +1,148 @@ +import ERMHome from "./components/ERM/ERMHome.vue"; +import Agreements from "./components/ERM/Agreements.vue"; +import AgreementsShow from "./components/ERM/AgreementsShow.vue"; +import AgreementsFormAdd from "./components/ERM/AgreementsFormAdd.vue"; +import AgreementsFormConfirmDelete from "./components/ERM/AgreementsFormConfirmDelete.vue"; +import Licenses from "./components/ERM/Licenses.vue"; +import LicensesShow from "./components/ERM/LicensesShow.vue"; +import LicensesFormAdd from "./components/ERM/LicensesFormAdd.vue"; +import LicensesFormConfirmDelete from "./components/ERM/LicensesFormConfirmDelete.vue"; + +const breadcrumbs = { + home: { text: "Home", path: "/cgi-bin/koha/mainpage.pl" }, + erm_home: { + text: "Electronic resources management", + path: "/cgi-bin/koha/erm/erm.pl", + }, + agreements: { text: "Agreements", path: "/cgi-bin/koha/erm/agreements" }, + licenses: { text: "Licenses", path: "/cgi-bin/koha/erm/licenses" }, +}; +export const routes = [ + { + path: "/cgi-bin/koha/erm/erm.pl", + component: ERMHome, + meta: { + breadcrumb: [breadcrumbs.home, breadcrumbs.erm_home], + }, + }, + { + path: "/cgi-bin/koha/erm/agreements", + component: Agreements, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.agreements, + ], + view: "list", + }, + }, + { + path: "/cgi-bin/koha/erm/agreements/:agreement_id", + component: AgreementsShow, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.agreements, + ], + view: "show", + }, + }, + { + path: "/cgi-bin/koha/erm/agreements/delete/:agreement_id", + component: AgreementsFormConfirmDelete, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.agreements, + ], + view: "confirm-delete", + }, + }, + { + path: "/cgi-bin/koha/erm/agreements/add", + component: AgreementsFormAdd, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.agreements, + ], + view: "add", + }, + }, + { + path: "/cgi-bin/koha/erm/agreements/edit/:agreement_id", + component: AgreementsFormAdd, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.agreements, + ], + view: "edit", + }, + }, + { + path: "/cgi-bin/koha/erm/licenses", + component: Licenses, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.licenses, + ], + view: "list", + }, + }, + { + path: "/cgi-bin/koha/erm/licenses/:license_id", + component: LicensesShow, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.licenses, + ], + view: "show", + }, + }, + { + path: "/cgi-bin/koha/erm/licenses/delete/:license_id", + component: LicensesFormConfirmDelete, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.licenses, + ], + view: "confirm-delete-form", + }, + }, + { + path: "/cgi-bin/koha/erm/licenses/add", + component: LicensesFormAdd, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.licenses, + ], + view: "add", + }, + }, + { + path: "/cgi-bin/koha/erm/licenses/edit/:license_id", + component: LicensesFormAdd, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.licenses, + ], + view: "edit", + }, + }, +]; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/main.js b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/main.js index a48f967cf7..e4c6c462db 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/main.js +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/main.js @@ -2,17 +2,10 @@ import { defineStore } from 'pinia' export const useMainStore = defineStore('main', { state: () => ({ - current_view: 'list', - current_object_id: null, message: null, error: null, }), actions: { - setCurrentView(view) { - this.current_view = view; - this.error = null; - this.message = null; - }, setMessage(message) { this.error = null; this.message = message; -- 2.39.5