From 6d3710a5e8143cdf51d315c364d9702111b6539b 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 --- admin/record_sources.pl | 37 +++++ debian/templates/apache-shared-intranet.conf | 2 + .../prog/en/modules/admin/admin-home.tt | 4 + .../prog/en/modules/admin/record_sources.tt | 34 +++++ .../components/Admin/RecordSources/Edit.vue | 111 ++++++++++++++ .../components/Admin/RecordSources/List.vue | 139 ++++++++++++++++++ .../components/Admin/RecordSources/Main.vue | 34 +++++ .../js/vue/fetch/record_sources-api-client.js | 59 ++++++++ .../js/vue/modules/admin/record_sources.ts | 54 +++++++ .../js/vue/routes/admin/record_sources.js | 40 +++++ webpack.config.js | 1 + 11 files changed, 515 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/Edit.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 b4fe0ea226..835b0812b6 100644 --- a/debian/templates/apache-shared-intranet.conf +++ b/debian/templates/apache-shared-intranet.conf @@ -13,6 +13,7 @@ ScriptAlias /search "/usr/share/koha/intranet/cgi-bin/catalogue/search.pl" # Protect dev package install RewriteEngine on + RewriteRule ^/cgi-bin/koha/(C4|debian|etc|installer/data|install_misc|Koha|misc|selenium|t|test|tmp|xt)/|\.PL$ /notfound [PT] RewriteRule ^/bib/([^\/]*)/?$ /cgi-bin/koha/catalogue/detail.pl?biblionumber=$1 [PT] @@ -23,6 +24,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 28b17808e1..8fcafa7e3f 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 @@ -209,6 +209,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/Edit.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Edit.vue new file mode 100644 index 0000000000..6569421c15 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Edit.vue @@ -0,0 +1,111 @@ + + + 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..ad9271ad1b --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue @@ -0,0 +1,139 @@ + + + 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/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..bc5b84e21b --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record_sources-api-client.js @@ -0,0 +1,59 @@ +import HttpClient from "./http-client"; + +export class RecordSourcesAPIClient extends HttpClient { + constructor() { + super({ + baseURL: "/api/v1/record_sources", + }); + } + + get record_source() { + return { + create: ({ row, headers = {} }) => { + const requestHeaders = { + ...headers, + "Content-Type": "application/json", + }; + return this.post({ + endpoint: "", + headers: requestHeaders, + body: JSON.stringify(row), + }); + }, + delete: ({ id, headers = {} }) => { + return this.delete({ + endpoint: "/" + id, + headers, + }); + }, + update: ({ id, headers = {}, row }) => { + const requestHeaders = { + ...headers, + "Content-Type": "application/json", + }; + return this.put({ + endpoint: "/" + id, + headers: requestHeaders, + body: JSON.stringify(row), + }); + }, + get: ({ id, headers = {} }) => { + return this.get({ + endpoint: "/" + id, + headers, + }); + }, + count: (query = {}) => { + return this.count({ + endpoint: + "?" + + new URLSearchParams({ + _page: 1, + _per_page: 1, + ...(query && { q: JSON.stringify(query) }), + }), + }); + }, + }; + } +} 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..49833980c6 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js @@ -0,0 +1,40 @@ +import { markRaw } from "vue"; +import Edit from "../../components/Admin/RecordSources/Edit.vue"; +import List from "../../components/Admin/RecordSources/List.vue"; +import { $__ } from "../../i18n"; + +export default { + title: $__("Administration"), + path: "", + href: "/cgi-bin/koha/admin/admin-home.pl", + BeforeUnloadEvent() { + window.location.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", + children: [ + { + title: $__("List"), + path: "", + component: markRaw(List), + }, + { + title: $__("Add record source"), + path: "add", + name: "Add", + component: markRaw(Edit), + }, + { + title: $__("Edit record source"), + path: ":id", + name: "Edit", + component: markRaw(Edit), + }, + ], + }, + ], +}; 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.37.1 (Apple Git-137.1)