From 149a6da9ec0508404617bbf400e6c73fff5ce192 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Wed, 24 Jan 2024 16:18:13 -0300 Subject: [PATCH] Bug 35919: Add record sources admin page This patch introduces a Vue.js based record sources managing page. To test it: 1. Apply this patch 2. Build the Vue.js stuff: $ ktd --shell k$ yarn js:build k$ restart_all 3. On the staff interface, go to Administration > Record sources 4. Play with the interface and the offered actions => SUCCESS: Things go well 5. Sign off :-D Signed-off-by: Tomas Cohen Arazi Signed-off-by: Matt Blenkinsop Signed-off-by: Jonathan Druart Signed-off-by: Katrin Fischer --- admin/record_sources.pl | 37 +++++ debian/templates/apache-shared-intranet.conf | 1 + .../prog/en/modules/admin/admin-home.tt | 4 + .../prog/en/modules/admin/record_sources.tt | 34 +++++ .../Admin/RecordSources/FormAdd.vue | 121 +++++++++++++++ .../components/Admin/RecordSources/List.vue | 140 ++++++++++++++++++ .../components/Admin/RecordSources/Main.vue | 34 +++++ .../prog/js/vue/fetch/api-client.js | 2 + .../js/vue/fetch/record-sources-api-client.js | 51 +++++++ .../js/vue/modules/admin/record_sources.ts | 54 +++++++ .../js/vue/routes/admin/record_sources.js | 38 +++++ webpack.config.js | 1 + 12 files changed, 517 insertions(+) create mode 100755 admin/record_sources.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js diff --git a/admin/record_sources.pl b/admin/record_sources.pl new file mode 100755 index 0000000000..9524f32dd6 --- /dev/null +++ b/admin/record_sources.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl + +# Copyright 2023 Theke Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use CGI qw ( -utf8 ); +use C4::Auth qw( get_template_and_user ); +use C4::Output qw( output_html_with_http_headers ); + +my $query = CGI->new; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/record_sources.tt", + query => $query, + type => "intranet", + flagsrequired => { parameters => 'manage_record_sources' }, + } +); + +output_html_with_http_headers $query, $cookie, $template->output; diff --git a/debian/templates/apache-shared-intranet.conf b/debian/templates/apache-shared-intranet.conf index 12abe65045..49b742f868 100644 --- a/debian/templates/apache-shared-intranet.conf +++ b/debian/templates/apache-shared-intranet.conf @@ -23,6 +23,7 @@ RewriteRule ^(.*)_[0-9]{2}\.[0-9]{7}\.(js|css)$ $1.$2 [L] RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT] RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$ RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT] +RewriteRule ^/cgi-bin/koha/admin/record_sources(.*)?$ /cgi-bin/koha/admin/record_sources.pl$1 [PT] Alias "/api" "/usr/share/koha/api" diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index 5c068b3908..565d9a4617 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -218,6 +218,10 @@
Search engine configuration (Elasticsearch)
Manage indexes, facets, and their mappings to MARC fields and subfields
[% END %] + [% IF ( CAN_user_parameters_manage_record_sources ) %] +
Record sources
+
Define record sources to import from
+ [% END %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt new file mode 100644 index 0000000000..533a171ec2 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt @@ -0,0 +1,34 @@ +[% USE raw %] +[% USE To %] +[% USE Asset %] +[% USE KohaDates %] +[% USE TablesSettings %] +[% USE AuthorisedValues %] +[% SET footerjs = 1 %] +[% PROCESS 'i18n.inc' %] +[% INCLUDE 'doc-head-open.inc' %] + + Record sources › Koha + +[% INCLUDE 'doc-head-close.inc' %] + + + +[% WRAPPER 'header.inc' %] + [% INCLUDE 'prefs-admin-search.inc' %] +[% END %] + +
+ +[% MACRO jsinclude BLOCK %] + [% INCLUDE 'calendar.inc' %] + [% INCLUDE 'datatables.inc' %] + [% INCLUDE 'columns_settings.inc' %] + [% INCLUDE 'js-patron-format.inc' %] + [% INCLUDE 'js-date-format.inc' %] + + [% Asset.js("js/vue/dist/admin/record_sources.js") | $raw %] + +[% END %] + +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue new file mode 100644 index 0000000000..2b7994224c --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue @@ -0,0 +1,121 @@ + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue new file mode 100644 index 0000000000..f8776f9b35 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue @@ -0,0 +1,140 @@ + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue new file mode 100644 index 0000000000..057c78a4ae --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js index 294693c238..4bfd3c8dd0 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js @@ -3,6 +3,7 @@ import PatronAPIClient from "./patron-api-client"; import AcquisitionAPIClient from "./acquisition-api-client"; import AVAPIClient from "./authorised-values-api-client"; import ItemAPIClient from "./item-api-client"; +import RecordSourcesAPIClient from "./record-sources-api-client"; import SysprefAPIClient from "./system-preferences-api-client"; import PreservationAPIClient from "./preservation-api-client"; @@ -14,4 +15,5 @@ export const APIClient = { item: new ItemAPIClient(), sysprefs: new SysprefAPIClient(), preservation: new PreservationAPIClient(), + record_sources: new RecordSourcesAPIClient(), }; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js new file mode 100644 index 0000000000..b12882d1dc --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js @@ -0,0 +1,51 @@ +import HttpClient from "./http-client"; + +export class RecordSourcesAPIClient extends HttpClient { + constructor() { + super({ + baseURL: "/api/v1/record_sources", + }); + } + + get record_sources() { + return { + create: record_source => + this.post({ + endpoint: "", + body: record_source, + }), + delete: id => + this.delete({ + endpoint: "/" + id, + }), + update: (record_source, id) => + this.put({ + endpoint: "/" + id, + body: record_source, + }), + get: id => + this.get({ + endpoint: "/" + id, + }), + getAll: (query, params) => + this.getAll({ + endpoint: "/", + query, + params, + headers: {}, + }), + count: (query = {}) => + this.count({ + endpoint: + "?" + + new URLSearchParams({ + _page: 1, + _per_page: 1, + ...(query && { q: JSON.stringify(query) }), + }), + }), + }; + } +} + +export default RecordSourcesAPIClient; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts new file mode 100644 index 0000000000..80f43f4ea2 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts @@ -0,0 +1,54 @@ +import { createApp } from "vue"; +import { createPinia } from "pinia"; +import { createWebHistory, createRouter } from "vue-router"; + +import { library } from "@fortawesome/fontawesome-svg-core"; +import { + faPlus, + faMinus, + faPencil, + faTrash, + faSpinner, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; +import vSelect from "vue-select"; +import { useNavigationStore } from "../../stores/navigation"; +import { useMainStore } from "../../stores/main"; +import routesDef from "../../routes/admin/record_sources"; + +library.add(faPlus, faMinus, faPencil, faTrash, faSpinner); + +const pinia = createPinia(); +const navigationStore = useNavigationStore(pinia); +const mainStore = useMainStore(pinia); +const { removeMessages } = mainStore; +const { setRoutes } = navigationStore; +const routes = setRoutes(routesDef); + +const router = createRouter({ + history: createWebHistory(), + linkExactActiveClass: "current", + routes, +}); + +import App from "../../components/Admin/RecordSources/Main.vue"; +import i18n from "../../i18n"; + +const app = createApp(App); + +const rootComponent = app + .use(i18n) + .use(pinia) + .use(router) + .component("font-awesome-icon", FontAwesomeIcon) + .component("v-select", vSelect); + +app.config.unwrapInjectedRef = true; +app.provide("mainStore", mainStore); +app.provide("navigationStore", navigationStore); +app.mount("#record-source"); + +router.beforeEach(to => { + navigationStore.$patch({ current: to.matched, params: to.params || {} }); + removeMessages(); // This will actually flag the messages as displayed already +}); diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js new file mode 100644 index 0000000000..a85fd4b5f4 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js @@ -0,0 +1,38 @@ +import { markRaw } from "vue"; +import RecordSourcesFormAdd from "../../components/Admin/RecordSources/FormAdd.vue"; +import RecordSourcesList from "../../components/Admin/RecordSources/List.vue"; +import { $__ } from "../../i18n"; + +export default { + title: $__("Administration"), + path: "", + href: "/cgi-bin/koha/admin/admin-home.pl", + is_base: true, + is_default: true, + children: [ + { + title: $__("Record sources"), + path: "/cgi-bin/koha/admin/record_sources", + is_end_node: true, + children: [ + { + path: "", + name: "RecordSourcesList", + component: markRaw(RecordSourcesList), + }, + { + component: markRaw(RecordSourcesFormAdd), + name: "RecordSourcesFormAdd", + path: "add", + title: $__("Add record source"), + }, + { + component: markRaw(RecordSourcesFormAdd), + name: "RecordSourcesFormAddEdit", + path: "edit/:record_source_id", + title: $__("Edit record source"), + }, + ], + }, + ], +}; diff --git a/webpack.config.js b/webpack.config.js index c22256785a..ae87653c24 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,6 +7,7 @@ module.exports = { entry: { erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts", preservation: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts", + "admin/record_sources": "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts", }, output: { filename: "[name].js", -- 2.39.5