Bugzilla – Attachment 157760 Details for
Bug 32607
Add record sources CRUD
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 32607: Add record sources admin page
Bug-32607-Add-record-sources-admin-page.patch (text/plain), 25.76 KB, created by
Tomás Cohen Arazi (tcohen)
on 2023-10-24 19:04:52 UTC
(
hide
)
Description:
Bug 32607: Add record sources admin page
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2023-10-24 19:04:52 UTC
Size:
25.76 KB
patch
obsolete
>From 1ba631034b4b9b3621adf3e3321ce063d2752feb Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Agust=C3=ADn=20Moyano?= <agustinmoyano@theke.io> >Date: Fri, 15 Sep 2023 10:49:02 -0300 >Subject: [PATCH] Bug 32607: 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 >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 <tomascohen@theke.io> >--- > admin/record-sources.pl | 37 ++++ > debian/templates/apache-shared-intranet.conf | 5 + > .../prog/en/modules/admin/admin-home.tt | 4 + > .../prog/en/modules/admin/record-sources.tt | 37 ++++ > .../prog/js/vue/components/Page.vue | 55 ++++++ > .../js/vue/components/RecordSources/Edit.vue | 163 ++++++++++++++++++ > .../js/vue/components/RecordSources/List.vue | 142 +++++++++++++++ > .../js/vue/components/RecordSources/Main.vue | 17 ++ > .../prog/js/vue/fetch/record-sources.js | 59 +++++++ > .../prog/js/vue/modules/record-sources.ts | 54 ++++++ > .../prog/js/vue/routes/record-sources.js | 38 ++++ > webpack.config.js | 1 + > 12 files changed, 612 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/Page.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Edit.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/List.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Main.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources.js > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/modules/record-sources.ts > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/routes/record-sources.js > >diff --git a/admin/record-sources.pl b/admin/record-sources.pl >new file mode 100755 >index 00000000000..d3945bdca7c >--- /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 <http://www.gnu.org/licenses>. >+ >+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 b4fe0ea2263..81eb9e204f6 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] >@@ -21,8 +22,12 @@ RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT] > RewriteRule ^(.*)_[0-9]{2}\.[0-9]{7}\.(js|css)$ $1.$2 [L] > > RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT] >+<<<<<<< HEAD > 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] >+>>>>>>> 187c8447271 (Bug 32607: Add record sources admin page) > > Alias "/api" "/usr/share/koha/api" > <Directory "/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 28b17808e1b..8338575cdd7 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 @@ > <dt><a href="/cgi-bin/koha/admin/searchengine/elasticsearch/mappings.pl">Search engine configuration (Elasticsearch)</a></dt> > <dd>Manage indexes, facets, and their mappings to MARC fields and subfields</dd> > [% END %] >+ [% IF ( CAN_user_parameters_manage_record_sources ) %] >+ <dt><a href="/cgi-bin/koha/admin/record-sources">Record sources</a></dt> >+ <dd>Define record sources to import from</dd> >+ [% END %] > </dl> > [% 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 00000000000..e3cec92d32b >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record-sources.tt >@@ -0,0 +1,37 @@ >+[% USE raw %] >+[% USE To %] >+[% USE Asset %] >+[% USE KohaDates %] >+[% USE TablesSettings %] >+[% USE AuthorisedValues %] >+[% SET footerjs = 1 %] >+[% PROCESS 'i18n.inc' %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title> >+ Record sources › Koha >+</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body id="record_sources" class="record_sources"> >+[% WRAPPER 'header.inc' %] >+ [% INCLUDE 'prefs-admin-search.inc' %] >+[% END %] >+ >+<div id="record-source"> <!-- this is closed in intranet-bottom.inc --> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% INCLUDE 'js-patron-format.inc' %] >+ [% INCLUDE 'js-date-format.inc' %] >+ >+ <script> >+ const RESTOAuth2ClientCredentials = [% IF Koha.Preference('RESTOAuth2ClientCredentials') %]true[% ELSE %]false[% END %]; >+ </script> >+ >+ [% Asset.js("js/vue/dist/record-source.js") | $raw %] >+ >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Page.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Page.vue >new file mode 100644 >index 00000000000..b31d8c553bf >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Page.vue >@@ -0,0 +1,55 @@ >+<template> >+ <div :id="id"> >+ <div id="sub-header"> >+ <Breadcrumbs></Breadcrumbs> >+ <Help /> >+ </div> >+ <div class="main container-fluid"> >+ <div class="row"> >+ <template v-if="leftMenu"> >+ <div class="col-sm-10 col-sm-push-2"> >+ <Dialog></Dialog> >+ <slot></slot> >+ </div> >+ <div class="col-sm-2 col-sm-pull-10"> >+ <LeftMenu :title="title"></LeftMenu> >+ </div> >+ </template> >+ <template v-else> >+ <div >+ class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2" >+ > >+ <Dialog></Dialog> >+ <slot></slot> >+ </div> >+ </template> >+ </div> >+ </div> >+ </div> >+</template> >+ >+<script> >+import LeftMenu from "./LeftMenu.vue" >+import Breadcrumbs from "./Breadcrumbs.vue" >+import Help from "./Help.vue" >+import Dialog from "./Dialog.vue" >+export default { >+ name: "Page", >+ components: { >+ LeftMenu, >+ Dialog, >+ Breadcrumbs, >+ Help, >+ }, >+ props: { >+ id: String, >+ title: String, >+ leftMenu: { >+ type: Boolean, >+ default: true, >+ }, >+ }, >+} >+</script> >+ >+<style></style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Edit.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Edit.vue >new file mode 100644 >index 00000000000..e7a0fed8604 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Edit.vue >@@ -0,0 +1,163 @@ >+<template> >+ <div v-if="!initialized">{{ $__("Loading") }}</div> >+ <div v-else id="record_source_edit"> >+ <h1>{{ title }}</h1> >+ <form @submit="processSubmit"> >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label class="required" for="name"> >+ {{ $__("Name") }}: >+ </label> >+ <input >+ id="name" >+ v-model="row.name" >+ :placeholder="$__('Name')" >+ required >+ /> >+ <span class="required">{{ $__("Required") }}</span> >+ </li> >+ <li> >+ <label :for="`user_id`" class="required" >+ >{{ $__("User") }}:</label >+ > >+ <span class="user"> >+ {{ patron_str }} >+ </span> >+ (<a >+ href="#" >+ @click="selectUser()" >+ class="btn btn-default" >+ >{{ $__("Select user") }}</a >+ >) >+ <span class="required">{{ $__("Required") }}</span> >+ </li> >+ <input >+ type="hidden" >+ name="selected_patron_id" >+ id="selected_patron_id" >+ /> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <input type="submit" :value="$__('Submit')" /> >+ <router-link >+ to="../record-sources" >+ role="button" >+ class="cancel" >+ >{{ $__("Cancel") }}</router-link >+ > >+ </fieldset> >+ </form> >+ </div> >+</template> >+ >+<script> >+import { inject } from "vue" >+import { RecordSourcesClient } from "../../fetch/record-sources" >+import { APIClient } from "../../fetch/api-client.js" >+let { >+ patron: { patrons }, >+} = APIClient >+ >+export default { >+ name: "Edit", >+ setup() { >+ const { record_source } = new RecordSourcesClient() >+ const { setMessage } = inject("mainStore") >+ return { >+ setMessage, >+ api: record_source, >+ } >+ }, >+ data() { >+ return { >+ row: { >+ name: "", >+ }, >+ patron_str: "", >+ initialized: false, >+ } >+ }, >+ methods: { >+ processSubmit(event) { >+ event.preventDefault() >+ const _hasValue = value => { >+ return value !== undefined && value !== null && value !== "" >+ } >+ if (!_hasValue(this.row.name) || !_hasValue(this.row.patron_id)) >+ return false >+ let response >+ if (this.row.record_source_id) { >+ const { record_source_id: id, ...row } = this.row >+ response = this.api >+ .update({ id, row }) >+ .then(() => this.$__("Record source updated!")) >+ } else { >+ response = this.api >+ .create({ row: this.row }) >+ .then(() => this.$__("Record source created!")) >+ } >+ return response.then(responseMessage => { >+ this.setMessage(responseMessage) >+ return this.$router.push({ path: "../record-sources" }) >+ }) >+ }, >+ selectUser() { >+ let select_user_window = window.open( >+ "/cgi-bin/koha/members/search.pl?columns=cardnumber,name,category,branch,action&selection_type=select", >+ "PatronPopup", >+ "width=740,height=450,location=yes,toolbar=no," + >+ "scrollbars=yes,resize=yes" >+ ) >+ // This is a bit dirty, the "select user" window should be rewritten and be a Vue component >+ // but that's not for now... >+ select_user_window.addEventListener( >+ "beforeunload", >+ this.newUserSelected, >+ false >+ ) >+ }, >+ newUserSelected() { >+ this.row.patron_id = >+ document.getElementById("selected_patron_id").value >+ this.getUserData() >+ }, >+ getUserData() { >+ if (this.row.patron_id === null) { >+ this.patron_str = "" >+ } >+ else{ >+ patrons.get(this.row.patron_id).then(patron => { >+ this.patron_str = $patron_to_html(patron) >+ }) >+ } >+ }, >+ }, >+ created() { >+ const { id } = this.$route.params >+ if (id !== undefined) { >+ this.api >+ .get({ >+ id, >+ }) >+ .then(response => { >+ Object.keys(response).forEach(key => { >+ this.row[key] = response[key] >+ }) >+ this.getUserData() >+ this.initialized = true >+ }) >+ } else { >+ this.initialized = true >+ } >+ }, >+ computed: { >+ title() { >+ if (!this.row || !this.row.record_source_id) >+ return this.$__("Add record source") >+ return this.$__("Edit %s").format(this.row.name) >+ }, >+ }, >+} >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/List.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/List.vue >new file mode 100644 >index 00000000000..79fe1ccb727 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/List.vue >@@ -0,0 +1,142 @@ >+<template> >+ <div v-if="!initialized">{{ $__("Loading") }}</div> >+ <div v-else> >+ <div id="toolbar" class="btn-toolbar"> >+ <div class="btn-group"> >+ <button class="btn btn-default" @click="newRecordSource"> >+ <i class="fa fa-plus"></i> New record source >+ </button> >+ </div> >+ </div> >+ <h1>{{ title }}</h1> >+ <div v-if="record_sources_count > 0" class="page-section"> >+ <KohaTable >+ ref="table" >+ v-bind="tableOptions" >+ @edit="doEdit" >+ @delete="doRemove" >+ ></KohaTable> >+ </div> >+ <div v-else> >+ {{ $__("There are no record sources defined") }} >+ </div> >+ </div> >+</template> >+ >+<script> >+import { useRouter } from "vue-router" >+import { inject } from "vue" >+import { RecordSourcesClient } from "../../fetch/record-sources" >+import KohaTable from "../KohaTable.vue" >+export default { >+ name: "List", >+ data() { >+ return { >+ title: this.$__("Record sources"), >+ tableOptions: { >+ columns: [ >+ { >+ title: this.$__("Source name"), >+ data: "name", >+ searchable: true, >+ }, >+ { >+ title: this.$__("Patron"), >+ searchable: true, >+ data: "patron.firstname:patron.surname:patron.middle_name", >+ render: (data, type, row) => { >+ if ( row.patron === null ) >+ return "" >+ const { firstname, surname, middle_name } = >+ row.patron >+ return [firstname, middle_name, surname] >+ .filter(part => (part || "").trim()) >+ .join(" ") >+ }, >+ }, >+ { >+ title: this.$__("API token"), >+ data: "api_token", >+ searchable: true, >+ }, >+ ], >+ options: { >+ embed: "patron", >+ }, >+ actions: { >+ "-1": ["edit", "delete"], >+ }, >+ url: "/api/v1/record_sources", >+ }, >+ initialized: false, >+ record_sources_count: 0, >+ } >+ }, >+ setup() { >+ const { setWarning, setMessage, setError, setConfirmationDialog } = >+ inject("mainStore") >+ const { record_source } = new RecordSourcesClient() >+ return { >+ setWarning, >+ setMessage, >+ setError, >+ setConfirmationDialog, >+ api: record_source, >+ } >+ }, >+ beforeRouteEnter(to, from, next) { >+ next(vm => { >+ vm.getRecordSourcesCount().then(() => (vm.initialized = true)) >+ }) >+ }, >+ methods: { >+ async getRecordSourcesCount() { >+ const count = await this.api.count() >+ this.record_sources_count = count >+ }, >+ newRecordSource() { >+ this.$router.push({ path: "record-sources/add" }) >+ }, >+ doEdit(data) { >+ this.$router.push({ >+ path: `record-sources/${data.record_source_id}`, >+ props: { >+ data, >+ }, >+ }) >+ }, >+ doRemove(data, dt) { >+ this.setConfirmationDialog( >+ { >+ title: this.$__( >+ "Are you sure you want to remove this record source?" >+ ), >+ message: data.name, >+ accept_label: this.$__("Yes, remove"), >+ cancel_label: this.$__("No, do not remove"), >+ }, >+ () => { >+ this.api >+ .delete({ >+ id: data.record_source_id, >+ }) >+ .then(response => { >+ if (response) { >+ this.setMessage( >+ this.$__( >+ "Record source '%s' removed" >+ ).format(data.name), >+ true >+ ) >+ dt.draw() >+ } >+ }) >+ } >+ ) >+ }, >+ }, >+ components: { >+ KohaTable, >+ }, >+} >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Main.vue >new file mode 100644 >index 00000000000..aa1e66c1137 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/RecordSources/Main.vue >@@ -0,0 +1,17 @@ >+<template> >+ <Page :left-menu="false"> >+ <router-view></router-view> >+ </Page> >+</template> >+ >+<script> >+import Page from "../Page.vue" >+export default { >+ name: "Main", >+ components: { >+ Page, >+ }, >+} >+</script> >+ >+<style></style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources.js >new file mode 100644 >index 00000000000..5e30639b5d1 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources.js >@@ -0,0 +1,59 @@ >+import HttpClient from "./http-client"; >+ >+export class RecordSourcesClient 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/record-sources.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/record-sources.ts >new file mode 100644 >index 00000000000..7a416ded729 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/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/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/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/record-sources.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/record-sources.js >new file mode 100644 >index 00000000000..e9d55f37647 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/record-sources.js >@@ -0,0 +1,38 @@ >+import { markRaw } from "vue"; >+import Edit from "../components/RecordSources/Edit.vue"; >+import List from "../components/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", >+ component: markRaw(Edit), >+ }, >+ { >+ title: $__("Edit record source"), >+ path: ":id", >+ component: markRaw(Edit), >+ }, >+ ], >+ }, >+ ], >+}; >diff --git a/webpack.config.js b/webpack.config.js >index c22256785a4..413bec58333 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", >+ "record-source": "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/record-sources.ts", > }, > output: { > filename: "[name].js", >-- >2.42.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 32607
:
146410
|
146411
|
146412
|
149777
|
149827
|
149828
|
149829
|
154006
|
154007
|
154008
|
154009
|
154010
|
154438
|
155682
|
155683
|
155684
|
155685
|
155686
|
155958
|
157756
|
157757
|
157758
|
157759
|
157760
|
157761
|
157762
|
161362
|
161363
|
161364
|
161365
|
161366
|
161367
|
161435
|
161436
|
161437
|
161438
|
161439
|
161440
|
161441
|
161474