From 70f5e7913ca5974b403f369878e93593182897c3 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 26 May 2022 11:08:11 +0200 Subject: [PATCH] Bug 32030: Add a route to display a resource Signed-off-by: Jonathan Field Signed-off-by: Martin Renvoize Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- Koha/ERM/EHoldings/Package.pm | 13 + Koha/REST/V1/ERM/EHoldings/Resources.pm | 233 +++++++++++++++ .../definitions/erm_eholdings_package.yaml | 5 + .../definitions/erm_eholdings_resource.yaml | 16 +- .../swagger/paths/erm_eholdings_packages.yaml | 2 + .../paths/erm_eholdings_resources.yaml | 270 ++++++++++++++++++ api/v1/swagger/swagger.yaml | 18 +- .../components/ERM/EHoldingsPackagesShow.vue | 28 ++ .../components/ERM/EHoldingsResourcesShow.vue | 159 +++++++++++ .../components/ERM/EHoldingsTitlesFormAdd.vue | 6 +- ...ue => EHoldingsTitlesFormAddResources.vue} | 0 .../components/ERM/EHoldingsTitlesShow.vue | 4 +- koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js | 39 ++- koha-tmpl/intranet-tmpl/prog/js/vue/routes.js | 13 + 14 files changed, 792 insertions(+), 14 deletions(-) create mode 100644 Koha/REST/V1/ERM/EHoldings/Resources.pm create mode 100644 api/v1/swagger/paths/erm_eholdings_resources.yaml create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResourcesShow.vue rename koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/{EHoldingsResources.vue => EHoldingsTitlesFormAddResources.vue} (100%) diff --git a/Koha/ERM/EHoldings/Package.pm b/Koha/ERM/EHoldings/Package.pm index 23f4a78ad1..2e2edd6802 100644 --- a/Koha/ERM/EHoldings/Package.pm +++ b/Koha/ERM/EHoldings/Package.pm @@ -22,6 +22,7 @@ use Koha::Database; use base qw(Koha::Object); use Koha::ERM::EHoldings::Package::Agreements; +use Koha::ERM::EHoldings::Resources; =head1 NAME @@ -57,6 +58,18 @@ sub package_agreements { return Koha::ERM::EHoldings::Package::Agreements->_new_from_dbic($agreements_rs); } +=head3 resources + +Returns the resources from this package + +=cut + +sub resources { + my ( $self ) = @_; + my $rs = $self->_result->erm_eholdings_resources; + return Koha::ERM::EHoldings::Resources->_new_from_dbic($rs); +} + =head2 Internal methods =head3 _type diff --git a/Koha/REST/V1/ERM/EHoldings/Resources.pm b/Koha/REST/V1/ERM/EHoldings/Resources.pm new file mode 100644 index 0000000000..9c45005dc2 --- /dev/null +++ b/Koha/REST/V1/ERM/EHoldings/Resources.pm @@ -0,0 +1,233 @@ +package Koha::REST::V1::ERM::EHoldings::Resources; + +# 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 Mojo::Base 'Mojolicious::Controller'; + +use Koha::ERM::EHoldings::Resources; + +use Scalar::Util qw( blessed ); +use Try::Tiny qw( catch try ); + +=head1 API + +=head2 Methods + +=head3 list + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $resources_set = Koha::ERM::EHoldings::Resources->new; + my $resources = $c->objects->search( $resources_set ); + return $c->render( status => 200, openapi => $resources ); + } + catch { + $c->unhandled_exception($_); + }; + +} + +=head3 get + +Controller function that handles retrieving a single Koha::ERM::EHoldings::Resource object + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + return try { + my $resource_id = $c->validation->param('resource_id'); + my $resource = $c->objects->find( Koha::ERM::EHoldings::Resources->search, $resource_id ); + + unless ($resource ) { + return $c->render( + status => 404, + openapi => { error => "eHolding title not found" } + ); + } + + return $c->render( + status => 200, + openapi => $resource, + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 add + +Controller function that handles adding a new Koha::ERM::EHoldings::Resource object + +=cut + +sub add { + my $c = shift->openapi->valid_input or return; + + return try { + Koha::Database->new->schema->txn_do( + sub { + + my $body = $c->validation->param('body'); + + my $resource = Koha::ERM::EHoldings::Resource->new_from_api($body)->store; + + $c->res->headers->location($c->req->url->to_string . '/' . $resource->resource_id); + return $c->render( + status => 201, + openapi => $resource->to_api + ); + } + ); + } + catch { + + my $to_api_mapping = Koha::ERM::EHoldings::Resource->new->to_api_mapping; + + if ( blessed $_ ) { + if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) { + return $c->render( + status => 409, + openapi => { error => $_->error, conflict => $_->duplicate_id } + ); + } + elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) { + return $c->render( + status => 400, + openapi => { + error => "Given " + . $to_api_mapping->{ $_->broken_fk } + . " does not exist" + } + ); + } + elsif ( $_->isa('Koha::Exceptions::BadParameter') ) { + return $c->render( + status => 400, + openapi => { + error => "Given " + . $to_api_mapping->{ $_->parameter } + . " does not exist" + } + ); + } + } + + $c->unhandled_exception($_); + }; +} + +=head3 update + +Controller function that handles updating a Koha::ERM::EHoldings::Resource object + +=cut + +sub update { + my $c = shift->openapi->valid_input or return; + + my $resource_id = $c->validation->param('resource_id'); + my $resource = Koha::ERM::EHoldings::Resources->find( $resource_id ); + + unless ($resource) { + return $c->render( + status => 404, + openapi => { error => "eHolding title not found" } + ); + } + + return try { + Koha::Database->new->schema->txn_do( + sub { + + my $body = $c->validation->param('body'); + + $resource->set_from_api($body)->store; + + $c->res->headers->location($c->req->url->to_string . '/' . $resource->resource_id); + return $c->render( + status => 200, + openapi => $resource->to_api + ); + } + ); + } + catch { + my $to_api_mapping = Koha::ERM::EHoldings::Resource->new->to_api_mapping; + + if ( blessed $_ ) { + if ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) { + return $c->render( + status => 400, + openapi => { + error => "Given " + . $to_api_mapping->{ $_->broken_fk } + . " does not exist" + } + ); + } + elsif ( $_->isa('Koha::Exceptions::BadParameter') ) { + return $c->render( + status => 400, + openapi => { + error => "Given " + . $to_api_mapping->{ $_->parameter } + . " does not exist" + } + ); + } + } + + $c->unhandled_exception($_); + }; +}; + +=head3 delete + +=cut + +sub delete { + my $c = shift->openapi->valid_input or return; + + my $resource = Koha::ERM::EHoldings::Resources->find( $c->validation->param('resource_id') ); + unless ($resource) { + return $c->render( + status => 404, + openapi => { error => "eHolding title not found" } + ); + } + + return try { + $resource->delete; + return $c->render( + status => 204, + openapi => q{} + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/api/v1/swagger/definitions/erm_eholdings_package.yaml b/api/v1/swagger/definitions/erm_eholdings_package.yaml index d564b3384c..b3d055973f 100644 --- a/api/v1/swagger/definitions/erm_eholdings_package.yaml +++ b/api/v1/swagger/definitions/erm_eholdings_package.yaml @@ -38,6 +38,11 @@ properties: description: agreements items: $ref: erm_eholdings_package_agreement.yaml + resources: + type: array + description: resources + items: + $ref: erm_eholdings_resource.yaml additionalProperties: false required: diff --git a/api/v1/swagger/definitions/erm_eholdings_resource.yaml b/api/v1/swagger/definitions/erm_eholdings_resource.yaml index b68d6d7710..f5b1ec7469 100644 --- a/api/v1/swagger/definitions/erm_eholdings_resource.yaml +++ b/api/v1/swagger/definitions/erm_eholdings_resource.yaml @@ -3,13 +3,18 @@ type: object properties: resource_id: type: integer - description: Internal resource identifier + description: internally assigned identifier + readOnly: true title_id: - type: integer - description: Internal title identifier + description: foreign key to the title + type: + - integer + - "null" package_id: - type: integer - description: Internal package identifier + description: foreign key to the package + type: + - integer + - "null" started_on: description: Start date type: @@ -25,6 +30,7 @@ properties: type: - string - "null" + additionalProperties: false required: - package_id diff --git a/api/v1/swagger/paths/erm_eholdings_packages.yaml b/api/v1/swagger/paths/erm_eholdings_packages.yaml index 5280960a43..28bd479e6d 100644 --- a/api/v1/swagger/paths/erm_eholdings_packages.yaml +++ b/api/v1/swagger/paths/erm_eholdings_packages.yaml @@ -175,6 +175,7 @@ erm: 1 x-koha-embed: - agreements + - resources put: x-mojo-to: ERM::EHoldings::Packages#update operationId: updateErmEHoldingsPackages @@ -230,6 +231,7 @@ erm: 1 x-koha-embed: - agreements + - resources delete: x-mojo-to: ERM::EHoldings::Packages#delete operationId: deleteErmEHoldingsPackages diff --git a/api/v1/swagger/paths/erm_eholdings_resources.yaml b/api/v1/swagger/paths/erm_eholdings_resources.yaml new file mode 100644 index 0000000000..ed8f8617de --- /dev/null +++ b/api/v1/swagger/paths/erm_eholdings_resources.yaml @@ -0,0 +1,270 @@ +--- +/erm/eholdings/resources: + get: + x-mojo-to: ERM::EHoldings::Resources#list + operationId: listErmEHoldingsResources + tags: + - eholdings + summary: List eholdings resources + produces: + - application/json + parameters: + - description: Case insensitive search on resource_id + in: query + name: resource_id + required: false + type: integer + - description: Case insensitive search on package_id + in: query + name: package_id + required: false + type: integer + - description: Case insensitive search on started_on + in: query + name: started_on + required: false + type: string + - description: Case insensitive search on ended_on + in: query + name: ended_on + required: false + type: string + - description: Case insensitive search on proxy + in: query + name: proxy + required: false + type: string + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + responses: + 200: + description: A list of eHoldings resources + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + type: array + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + post: + x-mojo-to: ERM::EHoldings::Resources#add + operationId: addErmEHoldingsResources + tags: + - eholdings + summary: Add eholding + consumes: + - application/json + produces: + - application/json + parameters: + - description: A JSON object containing information about the new resource + in: body + name: body + required: true + schema: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + responses: + 201: + description: A successfully created resource + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + 400: + description: Bad parameter + schema: + $ref: "../swagger.yaml#/definitions/error" + 401: + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: Ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: Conflict in creating resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 +"/erm/eholdings/resources/{resource_id}": + get: + x-mojo-to: ERM::EHoldings::Resources#get + operationId: getErmEHoldingsResources + tags: + - eholdings + summary: Get resources + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/eholdings_resource_id_pp" + responses: + 200: + description: An eHolding resource + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + 401: + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: Ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + x-koha-embed: + - resources + - resources.package + put: + x-mojo-to: ERM::EHoldings::Resources#update + operationId: updateErmEHoldingsResources + tags: + - eholdings + summary: Update resources + consumes: + - application/json + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/eholdings_resource_id_pp" + - name: body + in: body + description: A JSON object containing new information about existing resource + required: true + schema: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + responses: + 200: + description: A successfully updated resource + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_eholdings_resource" + 400: + description: Bad parameter + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: Ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: Conflict in updating resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + x-koha-embed: + - resources + - resources.package + delete: + x-mojo-to: ERM::EHoldings::Resources#delete + operationId: deleteErmEHoldingsResources + tags: + - eholdings + summary: Delete eHolding resource + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/eholdings_resource_id_pp" + responses: + 204: + description: resource deleted + 400: + description: resource deletion failed + schema: + $ref: "../swagger.yaml#/definitions/error" + 401: + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: Ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: Conflict in deleting resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index fb92ee68ae..e201838497 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -26,10 +26,12 @@ definitions: $ref: ./definitions/erm_agreement.yaml erm_eholdings_title: $ref: ./definitions/erm_eholdings_title.yaml - erm_license: - $ref: ./definitions/erm_license.yaml erm_eholdings_package: $ref: ./definitions/erm_eholdings_package.yaml + erm_eholdings_resource: + $ref: ./definitions/erm_eholdings_resource.yaml + erm_license: + $ref: ./definitions/erm_license.yaml error: $ref: ./definitions/error.yaml fund: @@ -175,6 +177,10 @@ paths: $ref: "./paths/erm_eholdings_titles.yaml#/~1erm~1eholdings~1titles~1{title_id}" /erm/eholdings/packages: $ref: ./paths/erm_eholdings_packages.yaml#/~1erm~1eholdings~1packages + /erm/eholdings/resources: + $ref: ./paths/erm_eholdings_resources.yaml#/~1erm~1eholdings~1resources + "/erm/eholdings/resources/{resource_id}": + $ref: "./paths/erm_eholdings_resources.yaml#/~1erm~1eholdings~1resources~1{resource_id}" "/erm/eholdings/packages/{package_id}": $ref: "./paths/erm_eholdings_packages.yaml#/~1erm~1eholdings~1packages~1{package_id}" /erm/licenses: @@ -351,7 +357,7 @@ parameters: required: true type: integer eholdings_title_id_pp: - description: title internal identifier + description: Title internal identifier in: path name: title_id required: true @@ -362,6 +368,12 @@ parameters: name: package_id required: true type: integer + eholdings_resource_id_pp: + description: Resource internal identifier + in: path + name: resource_id + required: true + type: integer fund_id_pp: description: Fund id in: path diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsPackagesShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsPackagesShow.vue index 9223ed6912..8d2182e7d3 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsPackagesShow.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsPackagesShow.vue @@ -64,6 +64,34 @@ {{ format_date(erm_package.created_on) }} + +
  • + + + + + + + + + + + + +
    Name
    + + {{ r.title.publication_title }} + +
    +
  • diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResourcesShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResourcesShow.vue new file mode 100644 index 0000000000..d5960b65d3 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResourcesShow.vue @@ -0,0 +1,159 @@ + + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAdd.vue index 314cdaa732..71d9c326ae 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAdd.vue @@ -383,7 +383,7 @@ /> - @@ -404,7 +404,7 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResources.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAddResources.vue similarity index 100% rename from koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsResources.vue rename to koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesFormAddResources.vue diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesShow.vue index afe8466462..9f25e6238f 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesShow.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsTitlesShow.vue @@ -251,8 +251,8 @@ > {{ r.package.name }} diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js index 18f9c66cef..3d33203465 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js @@ -110,7 +110,7 @@ export const fetchPackage = async function (package_id) { let erm_package; await fetch(apiUrl, { headers: { - "x-koha-embed": "package_agreements,package_agreements.agreement", + "x-koha-embed": "package_agreements,package_agreements.agreement,resources,resources.title", }, }) .then(checkError) @@ -178,6 +178,43 @@ export const fetchTitles = async function () { return titles; }; +export const fetchResource = async function (resource_id) { + if (!resource_id) return; + const apiUrl = "/api/v1/erm/eholdings/resources/" + resource_id; + let resource; + await fetch(apiUrl, { + headers: { + "x-koha-embed": "title,package", + }, + }) + .then(checkError) + .then( + (result) => { + resource = result; + }, + (error) => { + setError(error); + } + ); + return resource; +}; + +export const fetchresources = async function () { + const apiUrl = "/api/v1/erm/eholdings/resources"; + let resources; + await fetch(apiUrl) + .then(checkError) + .then( + (result) => { + resources = result; + }, + (error) => { + setError(error); + } + ); + return resources; +}; + function checkError(response) { if (response.status >= 200 && response.status <= 299) { return response.json(); diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js index 835a872adb..50a3bbaf6e 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes.js @@ -8,6 +8,7 @@ import EHoldingsPackagesList from "./components/ERM/EHoldingsPackagesList.vue"; import EHoldingsPackagesShow from "./components/ERM/EHoldingsPackagesShow.vue"; import EHoldingsPackagesFormAdd from "./components/ERM/EHoldingsPackagesFormAdd.vue"; import EHoldingsPackagesFormConfirmDelete from "./components/ERM/EHoldingsPackagesFormConfirmDelete.vue"; +import EHoldingsResourcesShow from "./components/ERM/EHoldingsResourcesShow.vue"; import EHoldingsTitlesList from "./components/ERM/EHoldingsTitlesList.vue"; import EHoldingsTitlesShow from "./components/ERM/EHoldingsTitlesShow.vue"; import EHoldingsTitlesFormAdd from "./components/ERM/EHoldingsTitlesFormAdd.vue"; @@ -245,6 +246,18 @@ export const routes = [ view: "edit", }, }, + { + path: "/cgi-bin/koha/erm/eholdings/resources/:resource_id", + component: EHoldingsResourcesShow, + meta: { + breadcrumb: [ + breadcrumbs.home, + breadcrumbs.erm_home, + breadcrumbs.eholdings.home, + ], + view: "show", + }, + }, { path: "/cgi-bin/koha/erm/licenses", component: LicensesList, -- 2.39.5