Bugzilla – Attachment 174151 Details for
Bug 38010
Migrate vendors to Vue
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 38010: Add vue app and list component
Bug-38010-Add-vue-app-and-list-component.patch (text/plain), 31.78 KB, created by
Matt Blenkinsop
on 2024-11-07 11:56:01 UTC
(
hide
)
Description:
Bug 38010: Add vue app and list component
Filename:
MIME Type:
Creator:
Matt Blenkinsop
Created:
2024-11-07 11:56:01 UTC
Size:
31.78 KB
patch
obsolete
>From 7e76caee7f1405402253d114fb8d6c06ef871d20 Mon Sep 17 00:00:00 2001 >From: Matt Blenkinsop <matt.blenkinsop@ptfs-europe.com> >Date: Wed, 11 Sep 2024 09:11:32 +0000 >Subject: [PATCH] Bug 38010: Add vue app and list component > >This patch adds the base vue app as well as the component to list vendors >--- > acqui/booksellers.pl | 10 + > acqui/vendors.pl | 54 ++++ > api/v1/swagger/definitions/vendor.yaml | 3 + > .../swagger/paths/acquisitions_vendors.yaml | 1 + > debian/templates/apache-shared-intranet.conf | 1 + > .../prog/en/includes/acquisitions-toolbar.inc | 2 +- > .../prog/en/modules/acqui/acqui-home.tt | 8 +- > .../prog/en/modules/acqui/booksellers.tt | 2 +- > .../prog/en/modules/acqui/vendors.tt | 47 ++++ > .../prog/js/vue/components/Vendors/Home.vue | 9 + > .../prog/js/vue/components/Vendors/Main.vue | 154 +++++++++++ > .../js/vue/components/Vendors/VendorList.vue | 250 ++++++++++++++++++ > .../js/vue/fetch/acquisition-api-client.js | 33 ++- > .../prog/js/vue/modules/vendors.ts | 62 +++++ > .../prog/js/vue/routes/vendors.js | 43 +++ > .../prog/js/vue/stores/authorised-values.js | 2 + > .../prog/js/vue/stores/vendors.js | 7 + > rspack.config.js | 3 +- > webpack.config.js | 1 + > 19 files changed, 682 insertions(+), 10 deletions(-) > create mode 100755 acqui/vendors.pl > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/acqui/vendors.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Home.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Main.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorList.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/routes/vendors.js > >diff --git a/acqui/booksellers.pl b/acqui/booksellers.pl >index beaf0e7b0bc..e2784430329 100755 >--- a/acqui/booksellers.pl >+++ b/acqui/booksellers.pl >@@ -172,4 +172,14 @@ $template->param( > ); > $template->{VARS}->{'allbaskets'} = $allbaskets; > >+ >+ >+$template->param( >+ loop_suppliers => $loop_suppliers, >+ supplier => ( $booksellerid || $supplier ), >+ count => $supplier_count, >+ has_budgets => $has_budgets, >+); >+$template->{VARS}->{'allbaskets'} = $allbaskets; >+ > output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/acqui/vendors.pl b/acqui/vendors.pl >new file mode 100755 >index 00000000000..a160284308c >--- /dev/null >+++ b/acqui/vendors.pl >@@ -0,0 +1,54 @@ >+#!/usr/bin/perl >+ >+# Copyright 2024 PTFS Europe >+# >+# 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 C4::Auth qw( get_template_and_user haspermission ); >+use C4::Output qw( output_html_with_http_headers ); >+use CGI qw ( -utf8 ); >+ >+use C4::Context; >+ >+use Koha::Acquisition::Currencies; >+ >+my $query = CGI->new; >+my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user( >+ { >+ template_name => 'acqui/vendors.tt', >+ query => $query, >+ type => 'intranet', >+ flagsrequired => { acquisition => '*' }, >+ } >+); >+ >+my $user_permissions = {}; >+my $var_data = $template->{VARS}; >+foreach my $key ( keys %{$var_data} ) { >+ $user_permissions->{$key} = $var_data->{$key} if ( $key =~ /CAN_user_(.*)/ ); >+} >+ >+my @gst_values = map { option => $_ + 0.0 }, split( '\|', C4::Context->preference("TaxRates") ); >+ >+$template->param( >+ user_permissions => $user_permissions, >+ currencies => Koha::Acquisition::Currencies->search->unblessed, >+ gst_values => \@gst_values, >+ edifact => C4::Context->preference('EDIFACT') >+); >+ >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/api/v1/swagger/definitions/vendor.yaml b/api/v1/swagger/definitions/vendor.yaml >index 6918d004696..87a5c4440dc 100644 >--- a/api/v1/swagger/definitions/vendor.yaml >+++ b/api/v1/swagger/definitions/vendor.yaml >@@ -119,6 +119,9 @@ properties: > description: List of aliases > items: > $ref: "vendor_alias.yaml" >+ baskets: >+ type: array >+ description: List of baskets > subscriptions: > type: array > description: List of subscriptions >diff --git a/api/v1/swagger/paths/acquisitions_vendors.yaml b/api/v1/swagger/paths/acquisitions_vendors.yaml >index aaaed8c534b..e671dea9742 100644 >--- a/api/v1/swagger/paths/acquisitions_vendors.yaml >+++ b/api/v1/swagger/paths/acquisitions_vendors.yaml >@@ -35,6 +35,7 @@ > type: string > enum: > - aliases >+ - baskets > - subscriptions > collectionFormat: csv > responses: >diff --git a/debian/templates/apache-shared-intranet.conf b/debian/templates/apache-shared-intranet.conf >index 49b742f868a..da68e9dfb4d 100644 >--- a/debian/templates/apache-shared-intranet.conf >+++ b/debian/templates/apache-shared-intranet.conf >@@ -24,6 +24,7 @@ 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] >+RewriteRule ^/cgi-bin/koha/vendors(.*)?$ /cgi-bin/koha/acqui/vendors.pl$1 [PT] > > Alias "/api" "/usr/share/koha/api" > <Directory "/usr/share/koha/api"> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc >index cba26b92581..9614214a35d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc >@@ -30,7 +30,7 @@ > <div class="btn-group"><a class="btn btn-default" id="receive" href="/cgi-bin/koha/acqui/parcels.pl?booksellerid=[% booksellerid | html %]"><i class="fa fa-inbox"></i> Receive shipments</a></div> > [% END %] > [% ELSIF ( CAN_user_acquisition_vendors_manage ) %] >- <div class="btn-group"><a class="btn btn-default" href="/cgi-bin/koha/acqui/supplier.pl?op=enter"><i class="fa fa-plus"></i> New vendor</a></div> >+ <div class="btn-group"><a class="btn btn-default" href="/cgi-bin/koha/vendors"><i class="fa fa-plus"></i> New vendor</a></div> > [% END %] > </div> > <!-- / acquisitions-toolbar.inc --> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/acqui-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/acqui-home.tt >index 533cc7285e8..c8e18c09156 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/acqui-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/acqui-home.tt >@@ -49,12 +49,8 @@ > <div class="col"> > <div id="acqui_acqui_home_order"> > <fieldset> >- <legend>Search vendors</legend> >- <form name="findsupplier" action="/cgi-bin/koha/acqui/booksellers.pl" method="get"> >- <p><label for="supplierpage">Vendor: </label><input type="text" size="25" name="supplier" id="supplierpage" class="focus" /> >- <input type="submit" class="btn btn-primary" value="Search" /> >- </p> >- </form> >+ <legend>View vendors</legend> >+ <a href="/cgi-bin/koha/vendors" class="btn btn-default">Vendor list</a> > </fieldset> > </div> > </div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/booksellers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/booksellers.tt >index 726e10188ab..3b4d5e03929 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/booksellers.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/booksellers.tt >@@ -13,7 +13,7 @@ > [% INCLUDE 'doc-head-close.inc' %] > <style> > #vendors td{ >- vertical-align: top; >+ vertical-align: top; > } > </style> > </head> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/vendors.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/vendors.tt >new file mode 100644 >index 00000000000..4497e3362a1 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/vendors.tt >@@ -0,0 +1,47 @@ >+[% USE raw %] >+[% USE To %] >+[% USE Asset %] >+[% USE KohaDates %] >+[% USE TablesSettings %] >+[% PROCESS 'i18n.inc' %] >+[% SET footerjs = 1 %] >+[% PROCESS 'patron-search.inc' %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>[% FILTER collapse %] >+ [% t("Vendors") | html %] › >+ [% t("Koha") | html %] >+[% END %]</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body id="acq_booksellers" class="acq"> >+[% WRAPPER 'header.inc' %] >+ [% INCLUDE 'acquisitions-search.inc' %] >+[% END %] >+ >+<div id="__vendors"> <!-- this is closed in intranet-bottom.inc --> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'calendar.inc' %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% INCLUDE 'js-patron-format.inc' %] >+ [% INCLUDE 'js-date-format.inc' %] >+ >+ <script> >+ const userPermissions = [% To.json(user_permissions) | $raw %]; >+ const currencies = [% To.json(currencies) | $raw %]; >+ const gstValues = [% To.json(gst_values) | $raw %]; >+ const edifact = [% To.json(edifact) | $raw %] >+ const viewBaskets = [% To.json(viewbaskets) | $raw %] >+ </script> >+ >+ >+ [% Asset.js("js/vue/dist/acquisitions.js") | $raw %] >+ [% INCLUDE 'select2.inc' %] >+ [% SET columns = ['cardnumber','name','category','branch','action'] %] >+ [% PROCESS patron_search_modal columns => columns, modal_title => t("Select user") %] >+ [% PROCESS patron_search_js columns => columns, filter => erm_users, actions => ["select"], preview_on_name_click => 1 %] >+ >+[% END %] >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Home.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Home.vue >new file mode 100644 >index 00000000000..df90ee491ad >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Home.vue >@@ -0,0 +1,9 @@ >+<template> >+ <h1>Vendors</h1> >+</template> >+ >+<script> >+export default {} >+</script> >+ >+<style></style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Main.vue >new file mode 100644 >index 00000000000..b6cb622e039 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/Main.vue >@@ -0,0 +1,154 @@ >+<template> >+ <div v-if="initialized"> >+ <div id="sub-header"> >+ <Breadcrumbs /> >+ <Help /> >+ </div> >+ <div class="main container-fluid"> >+ <div class="row"> >+ <div class="col-md-10 order-md-2 order-sm-1"> >+ <main> >+ <Dialog /> >+ <router-view /> >+ </main> >+ </div> >+ >+ <div class="col-md-2 order-sm-2 order-md-1"> >+ <LeftMenu :title="$__('Vendors')"></LeftMenu> >+ </div> >+ </div> >+ </div> >+ </div> >+ <div class="main container-fluid" v-else> >+ <Dialog /> >+ </div> >+</template> >+ >+<script> >+import { inject } from "vue" >+import Breadcrumbs from "../Breadcrumbs.vue" >+import Help from "../Help.vue" >+import LeftMenu from "../LeftMenu.vue" >+import Dialog from "../Dialog.vue" >+import "vue-select/dist/vue-select.css" >+import { storeToRefs } from "pinia" >+import { APIClient } from "../../fetch/api-client" >+ >+export default { >+ setup() { >+ const vendorStore = inject("vendorStore") >+ >+ const AVStore = inject("AVStore") >+ >+ const mainStore = inject("mainStore") >+ >+ const { loading, loaded, setError } = mainStore >+ >+ return { >+ vendorStore, >+ AVStore, >+ setError, >+ loading, >+ loaded, >+ AVStore, >+ } >+ }, >+ beforeCreate() { >+ this.loading() >+ >+ const fetchConfig = () => { >+ let promises = [] >+ >+ const av_client = APIClient.authorised_values >+ const authorised_values = { >+ av_vendor_types: "VENDOR_TYPE", >+ av_vendor_interface_types: "VENDOR_INTERFACE_TYPE", >+ } >+ >+ let av_cat_array = Object.keys(authorised_values).map(function ( >+ av_cat >+ ) { >+ return '"' + authorised_values[av_cat] + '"' >+ }) >+ >+ promises.push( >+ av_client.values >+ .getCategoriesWithValues(av_cat_array) >+ .then(av_categories => { >+ Object.entries(authorised_values).forEach( >+ ([av_var, av_cat]) => { >+ const av_match = av_categories.find( >+ element => element.category_name == av_cat >+ ) >+ this.AVStore[av_var] = >+ av_match.authorised_values >+ } >+ ) >+ }) >+ ) >+ >+ return Promise.all(promises) >+ } >+ >+ fetchConfig().then(() => { >+ this.vendorStore.currencies = currencies >+ this.vendorStore.gstValues = gstValues.map(gv => { >+ return { >+ label: `${(gv.option * 100).toFixed(2)}%`, >+ value: gv.option, >+ } >+ }) >+ this.loaded() >+ this.initialized = true >+ }) >+ }, >+ data() { >+ return { >+ initialized: true, >+ } >+ }, >+ methods: {}, >+ components: { >+ Breadcrumbs, >+ Dialog, >+ Help, >+ LeftMenu, >+ }, >+} >+</script> >+ >+<style> >+#menu ul ul, >+#navmenulist ul ul { >+ padding-left: 2em; >+ font-size: 100%; >+} >+ >+form .v-select { >+ display: inline-block; >+ background-color: white; >+ width: 30%; >+} >+ >+.v-select, >+input:not([type="submit"]):not([type="search"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]), >+textarea { >+ border-color: rgba(60, 60, 60, 0.26); >+ border-width: 1px; >+ border-radius: 4px; >+ min-width: 30%; >+} >+.flatpickr-input { >+ width: 30%; >+} >+#navmenulist ul li a.current.disabled { >+ background-color: inherit; >+ border-left: 5px solid #e6e6e6; >+ color: #000; >+} >+#navmenulist ul li a.disabled { >+ color: #666; >+ pointer-events: none; >+ font-weight: 700; >+} >+</style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorList.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorList.vue >new file mode 100644 >index 00000000000..e4d3416a583 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorList.vue >@@ -0,0 +1,250 @@ >+<template> >+ <div v-if="!initialized">{{ $__("Loading") }}</div> >+ <div v-else id="vendors_list"> >+ <Toolbar> >+ <ToolbarButton >+ :to="{ name: 'VendorList' }" >+ icon="plus" >+ :title="$__('New vendor')" >+ /> >+ </Toolbar> >+ <div v-if="vendor_count > 0" class="page-section"> >+ <KohaTable >+ ref="table" >+ v-bind="tableOptions" >+ @show="doShow" >+ @edit="doEdit" >+ @delete="doDelete" >+ @select="doSelect" >+ ></KohaTable> >+ </div> >+ <div v-else class="alert alert-info"> >+ {{ $__("There are no vendors defined") }} >+ </div> >+ </div> >+</template> >+ >+<script> >+import flatPickr from "vue-flatpickr-component" >+import Toolbar from "../Toolbar.vue" >+import ToolbarButton from "../ToolbarButton.vue" >+import { inject, ref, reactive } from "vue" >+import { APIClient } from "../../fetch/api-client.js" >+import { storeToRefs } from "pinia" >+import { build_url } from "../../composables/datatables" >+import KohaTable from "../KohaTable.vue" >+ >+export default { >+ setup() { >+ const vendorStore = inject("vendorStore") >+ const { vendors } = storeToRefs(vendorStore) >+ >+ const { setConfirmationDialog, setMessage } = inject("mainStore") >+ >+ const { get_lib_from_av, map_av_dt_filter } = inject("AVStore") >+ >+ const table = ref() >+ >+ // const filters = reactive({ >+ // by_expired: false, >+ // max_expiration_date: "", >+ // by_mine: false, >+ // }) >+ return { >+ vendors, >+ get_lib_from_av, >+ map_av_dt_filter, >+ table, >+ setConfirmationDialog, >+ setMessage, >+ escape_str, >+ // filters, >+ } >+ }, >+ data() { >+ return { >+ fp_config: flatpickr_defaults, >+ vendor_count: 0, >+ initialized: false, >+ tableOptions: { >+ columns: this.getTableColumns(), >+ options: { embed: "aliases,baskets,subscriptions" }, >+ url: () => this.table_url(), >+ add_filters: true, >+ filters_options: { >+ 1: [ >+ { _id: 0, _str: this.$__("Inactive") }, >+ { _id: 1, _str: this.$__("Active") }, >+ ], >+ ...(this.map_av_dt_filter("av_vendor_types").length && { >+ 2: () => this.map_av_dt_filter("av_vendor_types"), >+ }), >+ }, >+ actions: { >+ 0: ["show"], >+ "-1": ["edit", "delete"], >+ }, >+ }, >+ before_route_entered: false, >+ building_table: false, >+ } >+ }, >+ beforeRouteEnter(to, from, next) { >+ next(vm => { >+ vm.getVendorCount().then(() => (vm.initialized = true)) >+ }) >+ }, >+ methods: { >+ async getVendorCount() { >+ const client = APIClient.acquisition >+ await client.vendors.count().then( >+ count => { >+ this.vendor_count = count >+ }, >+ error => {} >+ ) >+ }, >+ doShow: function ({ id }, dt, event) { >+ event.preventDefault() >+ this.$router.push({ >+ name: "VendorShow", >+ params: { vendor_id: id }, >+ }) >+ }, >+ doEdit: function ({ id }, dt, event) { >+ this.$router.push({ >+ name: "Home", >+ }) >+ }, >+ doDelete: function (vendor, dt, event) { >+ this.setConfirmationDialog( >+ { >+ title: this.$__( >+ "Are you sure you want to remove this vendor?" >+ ), >+ message: vendor.name, >+ accept_label: this.$__("Yes, delete"), >+ cancel_label: this.$__("No, do not delete"), >+ }, >+ () => { >+ const client = APIClient.erm >+ client.vendors.delete(vendor.id).then( >+ success => { >+ this.setMessage( >+ this.$__("Vendor %s deleted").format( >+ vendor.name >+ ), >+ true >+ ) >+ dt.draw() >+ }, >+ error => {} >+ ) >+ } >+ ) >+ }, >+ doSelect: function (vendor, dt, event) { >+ this.$emit("select-vendor", vendor.id) >+ this.$emit("close") >+ }, >+ table_url: function () { >+ let url = "/api/v1/acquisitions/vendors" >+ return url >+ }, >+ getTableColumns: function () { >+ const escape_str = this.escape_str >+ const get_lib_from_av = this.get_lib_from_av >+ >+ return [ >+ { >+ title: __("Name"), >+ data: "me.name:me.id", >+ searchable: true, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return ( >+ '<a href="/cgi-bin/koha/vendors/' + >+ row.id + >+ '" class="show">' + >+ escape_str(`${row.name} (#${row.id})`) + >+ "</a>" >+ ) >+ }, >+ }, >+ { >+ title: __("Status"), >+ data: "active", >+ searchable: true, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str( >+ row.active ? __("Active") : __("Inactive") >+ ) >+ }, >+ }, >+ { >+ title: __("Type"), >+ data: "type", >+ searchable: true, >+ orderable: true, >+ render(data, type, row, meta) { >+ return get_lib_from_av("av_vendor_types", row.type) >+ }, >+ }, >+ { >+ title: __("Currency"), >+ data: "invoice_currency", >+ searchable: true, >+ orderable: true, >+ }, >+ { >+ title: __("Baskets"), >+ data: "baskets", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return row.baskets.length >+ ? '<a href="/cgi-bin/koha/vendors/' + >+ row.id + >+ '" class="show">' + >+ escape_str( >+ `${row.baskets.length} basket(s)` >+ ) + >+ "</a>" >+ : escape_str(__("No baskets")) >+ }, >+ }, >+ { >+ title: __("Subscriptions"), >+ data: "subscriptions", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return row.subscriptions.length >+ ? '<a href="/cgi-bin/koha/serials/serials-search.pl?bookseller_filter=' + >+ row.name + >+ "&searched=1" + >+ '" class="show">' + >+ escape_str( >+ `${row.subscriptions.length} subscription(s)` >+ ) + >+ "</a>" >+ : escape_str(__("No subscriptions")) >+ }, >+ }, >+ ] >+ }, >+ }, >+ components: { flatPickr, Toolbar, ToolbarButton, KohaTable }, >+ name: "VendorList", >+ emits: ["select-vendor", "close"], >+} >+</script> >+ >+<style scoped> >+.filters > label[for="by_mine_filter"], >+.filters > input[type="checkbox"], >+.filters > input[type="button"] { >+ margin-left: 1rem; >+} >+</style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/acquisition-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/acquisition-api-client.js >index 72f1a1d79c8..2f1417fe4c2 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/acquisition-api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/acquisition-api-client.js >@@ -9,15 +9,46 @@ export class AcquisitionAPIClient extends HttpClient { > > get vendors() { > return { >+ get: id => >+ this.get({ >+ endpoint: "vendors/" + id, >+ headers: { >+ "x-koha-embed": "aliases", >+ }, >+ }), > getAll: (query, params) => > this.getAll({ > endpoint: "vendors", > query, > params, > headers: { >- "x-koha-embed": "aliases", >+ "x-koha-embed": "aliases,baskets", > }, > }), >+ delete: id => >+ this.delete({ >+ endpoint: "vendors/" + id, >+ }), >+ create: vendor => >+ this.post({ >+ endpoint: "vendors", >+ body: vendor, >+ }), >+ update: (vendor, id) => >+ this.put({ >+ endpoint: "vendors/" + id, >+ body: vendor, >+ }), >+ count: (query = {}) => >+ this.count({ >+ endpoint: >+ "vendors?" + >+ new URLSearchParams({ >+ _page: 1, >+ _per_page: 1, >+ ...(query && { q: JSON.stringify(query) }), >+ }), >+ }), > }; > } > } >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts >new file mode 100644 >index 00000000000..26e61adf75f >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts >@@ -0,0 +1,62 @@ >+import { createApp } from "vue"; >+import { createWebHistory, createRouter } from "vue-router"; >+import { createPinia } from "pinia"; >+ >+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"; >+ >+library.add(faPlus, faMinus, faPencil, faTrash, faSpinner); >+ >+import App from "../components/Vendors/Main.vue"; >+ >+import { routes as routesDef } from "../routes/vendors"; >+ >+import { useMainStore } from "../stores/main"; >+import { useVendorStore } from "../stores/vendors"; >+import { useAVStore } from "../stores/authorised-values"; >+import { useNavigationStore } from "../stores/navigation"; >+import i18n from "../i18n"; >+ >+const pinia = createPinia(); >+ >+const mainStore = useMainStore(pinia); >+const AVStore = useAVStore(pinia); >+const navigationStore = useNavigationStore(pinia); >+const routes = navigationStore.setRoutes(routesDef); >+ >+const router = createRouter({ >+ history: createWebHistory(), >+ linkActiveClass: "current", >+ routes, >+}); >+ >+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("vendorStore", useVendorStore(pinia)); >+app.provide("mainStore", mainStore); >+app.provide("AVStore", AVStore); >+app.provide("navigationStore", navigationStore); >+ >+app.mount("#__vendors"); >+ >+const { removeMessages } = mainStore; >+router.beforeEach((to, from) => { >+ 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/vendors.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/vendors.js >new file mode 100644 >index 00000000000..8a2908e57cb >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/vendors.js >@@ -0,0 +1,43 @@ >+import { markRaw } from "vue"; >+ >+import Home from "../components/Vendors/Home.vue"; >+import VendorList from "../components/Vendors/VendorList.vue"; >+import VendorShow from "../components/Vendors/VendorShow.vue"; >+ >+import { $__ } from "../i18n"; >+ >+export const routes = [ >+ { >+ path: "/cgi-bin/koha/acqui/booksellers.pl", >+ is_default: true, >+ is_base: true, >+ title: $__("Vendors"), >+ children: [ >+ { >+ path: "", >+ name: "Home", >+ component: markRaw(Home), >+ is_navigation_item: false, >+ }, >+ { >+ path: "/cgi-bin/koha/vendors", >+ title: $__("Vendor list"), >+ icon: "fa fa-check-circle", >+ is_end_node: true, >+ children: [ >+ { >+ path: "", >+ name: "VendorList", >+ component: markRaw(VendorList), >+ }, >+ { >+ path: ":vendor_id", >+ name: "VendorShow", >+ component: markRaw(VendorShow), >+ title: $__("Show vendor"), >+ }, >+ ], >+ }, >+ ], >+ }, >+]; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/authorised-values.js b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/authorised-values.js >index ef77373d689..ebe6a80b5fc 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/authorised-values.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/authorised-values.js >@@ -42,6 +42,8 @@ export const useAVStore = defineStore("authorised_values", { > av_database_reports_metrics: [], > av_title_reports_metrics: [], > av_item_reports_metrics: [], >+ av_vendor_types: [], >+ av_vendor_interface_types: [], > }), > actions: { > get_lib_from_av(arr_name, av) { >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/vendors.js b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/vendors.js >index 3f8fdfdfc2c..34b3351af89 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/vendors.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/vendors.js >@@ -3,5 +3,12 @@ import { defineStore } from "pinia"; > export const useVendorStore = defineStore("vendors", { > state: () => ({ > vendors: [], >+ currencies: [], >+ gstValues: [], >+ config: { >+ settings: { >+ edifact: false, >+ }, >+ }, > }), > }); >diff --git a/rspack.config.js b/rspack.config.js >index 6a8e40c4f6e..3fa96ce5f91 100644 >--- a/rspack.config.js >+++ b/rspack.config.js >@@ -13,6 +13,7 @@ module.exports = { > "./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", >+ vendors: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts", > }, > output: { > filename: "[name].js", >@@ -72,4 +73,4 @@ module.exports = { > "datatables.net-buttons/js/buttons.print": "DataTable", > "datatables.net-buttons/js/buttons.colVis": "DataTable", > }, >-}; >+}; >\ No newline at end of file >diff --git a/webpack.config.js b/webpack.config.js >index ae87653c244..b80cebdb653 100644 >--- a/webpack.config.js >+++ b/webpack.config.js >@@ -8,6 +8,7 @@ module.exports = { > 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", >+ vendors: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/vendors.ts", > }, > output: { > filename: "[name].js", >-- >2.39.3 (Apple Git-146)
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 38010
:
174119
|
174120
|
174121
|
174122
|
174123
|
174124
|
174125
|
174126
|
174128
|
174129
|
174130
|
174131
|
174132
|
174133
|
174134
|
174135
|
174136
|
174137
|
174138
|
174139
|
174140
|
174141
|
174142
|
174143
|
174144
|
174145
|
174146
|
174147
|
174148
|
174151
|
174152
|
174153
|
174154
|
174155
|
174156
|
174157
|
174158
|
174159
|
174160
|
174161
|
174162
|
174163
|
174164
|
174165
|
174166
|
174167
|
174168
|
174169
|
174170
|
174171
|
174172
|
174173
|
174174
|
174175
|
174176
|
174177
|
174178
|
174179
|
174194
|
174196
|
174197
|
174198
|
174199
|
174200
|
174201
|
174202
|
174203
|
174204
|
174205
|
174206
|
174207
|
174208
|
174209
|
174210
|
174211
|
174212
|
174213
|
174214
|
174215
|
174216
|
174217
|
174218
|
174220
|
174221
|
174222
|
174223
|
174224
|
174225
|
174226
|
174248
|
174266
|
174267
|
174269
|
174270
|
174273
|
174327
|
174328
|
174329
|
174330
|
174331
|
174332
|
174333
|
174334
|
174335
|
174336
|
174337
|
174338
|
174339
|
174340
|
174341
|
174342
|
174343
|
174344
|
174345
|
174346
|
174347
|
174348
|
174349
|
174350
|
174351
|
174352
|
174353
|
174354
|
174355
|
174356
|
174357
|
174358
|
174359
|
174360
|
174603