Bug 38201: Migrate waiting lists to the composition API

Signed-off-by: Michaela Sieber <michaela.sieber@kit.edu>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Matt Blenkinsop 2025-05-28 16:53:09 +01:00 committed by Lucas Gass
parent 655c4ac714
commit 7bf362eed3
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
2 changed files with 197 additions and 181 deletions

View File

@ -16,7 +16,7 @@ export default {
id: String,
modelValue: Boolean,
name: String,
value: Boolean,
value: Boolean | String,
checked: Boolean,
changeMethod: {
type: Function,

View File

@ -1,11 +1,17 @@
<template>
<BaseResource
:routeAction="routeAction"
:instancedResource="this"
></BaseResource>
</template>
<script>
import { inject } from "vue";
import BaseResource from "../BaseResource.vue";
import { useBaseResource } from "../../composables/base-resource.js";
import { storeToRefs } from "pinia";
import { APIClient } from "../../fetch/api-client.js";
export default {
extends: BaseResource,
props: {
routeAction: String,
},
@ -14,122 +20,88 @@ export default {
const { config, itemsRecentlyAddedToWaitingList } =
storeToRefs(PreservationStore);
return {
...BaseResource.setup({
resourceName: "item",
nameAttr: "biblio.title",
idAttr: "itemnumber",
listComponent: "WaitingList",
apiClient: APIClient.preservation.waiting_list_items,
resourceTableUrl:
APIClient.preservation.httpClient._baseURL +
"/waiting-list/items",
i18n: {
deleteConfirmationMessage: __(
"Are you sure you want to remove this item from the waiting list?"
),
deleteSuccessMessage: __(
"Item removed from the waiting list"
),
displayName: __("Item"),
displayNameLowerCase: __("item"),
displayNamePlural: __("Items"),
editLabel: null,
emptyListMessage: __(
"There are no items in the waiting list"
),
newLabel: __("Add to waiting list"),
},
config,
itemsRecentlyAddedToWaitingList,
}),
};
},
data() {
const tableFilters = this.getTableFilterFormElements();
const defaults = this.getFilterValues(this.$route.query, tableFilters);
return {
resourceAttrs: [
{
name: this.idAttr,
label: this.$__("ID"),
type: "text",
hideIn: ["List"],
},
{
name: "biblio.title",
label: this.$__("Title"),
type: "text",
tableColumnDefinition: {
data: "biblio.title",
title: __("Title"),
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
return `<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=${row.biblio.biblio_id}">${row.biblio.title}</a>`;
},
const additionalToolbarButtons = (resource, componentData) => {
const { instancedResource } = componentData;
const addItemsToWaitingList = (result, itemList) => {
let items = [];
itemList.barcode_list
.split("\n")
.forEach(barcode => items.push({ barcode }));
const client = APIClient.preservation;
client.waiting_list_items.createAll(items).then(
result => {
if (result.length) {
if (result.length != items.length) {
instancedResource.setWarning(
instancedResource
.$__(
"%s new items added. %s items not found."
)
.format(
result.length,
items.length - result.length
),
true
);
} else {
instancedResource.setMessage(
instancedResource
.$__("%s new items added.")
.format(result.length),
true
);
}
instancedResource.itemsRecentlyAddedToWaitingList =
result;
if (instancedResource.$refs.table) {
instancedResource.$refs.table.redraw(
"/api/v1/preservation/waiting-list/items"
);
} else {
instancedResource.refreshTemplateState();
}
} else {
instancedResource.setWarning(
instancedResource.$__("No items added")
);
}
},
},
{
name: "biblio.author",
label: this.$__("Author"),
type: "text",
},
{
name: "callnumber",
label: this.$__("Call number"),
type: "text",
},
{
name: "external_id",
label: this.$__("Barcode"),
type: "text",
},
],
tableOptions: {
url: "/api/v1/preservation/waiting-list/items",
options: { embed: "biblio" },
add_filters: true,
actions: {
0: ["show"],
1: ["show"],
"-1": [
{
removeItem: {
text: this.$__("Remove"),
icon: "fa fa-close",
callback: this.doRemoveItem,
},
},
],
},
},
tableFilters,
};
},
methods: {
additionalToolbarButtons(resource, componentData) {
let addItemsToWaitingList = this.addItemsToWaitingList;
let addItemsToTrain = this.addItemsToTrain;
let itemsRecentlyAddedToWaitingList =
this.itemsRecentlyAddedToWaitingList;
error => {}
);
itemList = "";
};
const addItemsToTrain = (result, { train_id_selected_for_add }) => {
let item_ids =
instancedResource.itemsRecentlyAddedToWaitingList.map(
i => i.item_id
);
instancedResource.router.push({
name: "TrainsFormAddItems",
params: {
train_id: train_id_selected_for_add,
item_ids: item_ids.join(","),
},
});
};
return {
list: [
{
onClick: () =>
this.setConfirmationDialog(
instancedResource.setConfirmationDialog(
{
title: this.$__(
title: instancedResource.$__(
"Add items to waiting list"
),
accept_label: this.$__("Save"),
cancel_label: this.$__("Cancel"),
accept_label: instancedResource.$__("Save"),
cancel_label:
instancedResource.$__("Cancel"),
inputs: [
{
name: "barcode_list",
type: "textarea",
label: this.$__("Barcode list"),
label: instancedResource.$__(
"Barcode list"
),
required: true,
},
],
@ -137,23 +109,25 @@ export default {
addItemsToWaitingList
),
icon: "plus",
title: this.$__("Add to waiting list"),
title: instancedResource.$__("Add to waiting list"),
},
itemsRecentlyAddedToWaitingList.length > 0
instancedResource.itemsRecentlyAddedToWaitingList.length > 0
? {
onClick: () =>
this.setConfirmationDialog(
instancedResource.setConfirmationDialog(
{
title: this.$__(
title: instancedResource.$__(
"Add items to a train"
),
accept_label: this.$__("Save"),
cancel_label: this.$__("Cancel"),
accept_label:
instancedResource.$__("Save"),
cancel_label:
instancedResource.$__("Cancel"),
inputs: [
{
name: "train_id_selected_for_add",
type: "relationshipSelect",
label: this.$__(
label: instancedResource.$__(
"Select a train"
),
required: true,
@ -170,92 +144,107 @@ export default {
addItemsToTrain
),
icon: "plus",
title: this.$__(
title: instancedResource.$__(
"Add last %s items to a train".format(
itemsRecentlyAddedToWaitingList.length
instancedResource
.itemsRecentlyAddedToWaitingList
.length
)
),
}
: {},
],
};
},
defaultToolbarButtons() {
};
const defaultToolbarButtons = () => {
return {
list: [],
};
},
addItemsToWaitingList(result, itemList) {
let items = [];
itemList.barcode_list
.split("\n")
.forEach(barcode => items.push({ barcode }));
const client = APIClient.preservation;
client.waiting_list_items.createAll(items).then(
result => {
if (result.length) {
if (result.length != items.length) {
this.setWarning(
this.$__(
"%s new items added. %s items not found."
).format(
result.length,
items.length - result.length
),
true
);
} else {
this.setMessage(
this.$__("%s new items added.").format(
result.length
),
true
);
}
this.itemsRecentlyAddedToWaitingList = result;
if (this.$refs.table) {
this.$refs.table.redraw(
"/api/v1/preservation/waiting-list/items"
);
} else {
this.refreshTemplateState();
}
} else {
this.setWarning(this.$__("No items added"));
}
},
error => {}
);
itemList = "";
},
addItemsToTrain(result, train_id) {
let item_ids = this.itemsRecentlyAddedToWaitingList.map(
i => i.item_id
);
this.$router.push({
name: "TrainsFormAddItems",
params: {
train_id: train_id,
item_ids: item_ids.join(","),
},
});
},
doRemoveItem(item, dt, event) {
this.setConfirmationDialog(
};
const baseResource = useBaseResource({
resourceName: "item",
nameAttr: "biblio.title",
idAttr: "itemnumber",
listComponent: "WaitingList",
apiClient: APIClient.preservation.waiting_list_items,
resourceTableUrl:
APIClient.preservation.httpClient._baseURL +
"/waiting-list/items",
i18n: {
deleteConfirmationMessage: __(
"Are you sure you want to remove this item from the waiting list?"
),
deleteSuccessMessage: __("Item removed from the waiting list"),
displayName: __("Item"),
displayNameLowerCase: __("item"),
displayNamePlural: __("Items"),
editLabel: null,
emptyListMessage: __("There are no items in the waiting list"),
newLabel: __("Add to waiting list"),
},
config,
itemsRecentlyAddedToWaitingList,
props,
additionalToolbarButtons,
defaultToolbarButtons,
resourceAttrs: [
{
title: this.$__(
name: "itemnumber",
label: __("ID"),
type: "text",
hideIn: ["List"],
},
{
name: "biblio.title",
label: __("Title"),
type: "text",
tableColumnDefinition: {
data: "biblio.title",
title: __("Title"),
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
return `<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=${row.biblio.biblio_id}">${row.biblio.title}</a>`;
},
},
},
{
name: "biblio.author",
label: __("Author"),
type: "text",
},
{
name: "callnumber",
label: __("Call number"),
type: "text",
},
{
name: "external_id",
label: __("Barcode"),
type: "text",
},
],
});
const doRemoveItem = (item, dt, event) => {
baseResource.setConfirmationDialog(
{
title: baseResource.$__(
"Are you sure you want to remove this item from the waiting list?"
),
message: item.barcode,
accept_label: this.$__("Yes, remove"),
cancel_label: this.$__("No, do not remove"),
accept_label: baseResource.$__("Yes, remove"),
cancel_label: baseResource.$__("No, do not remove"),
},
() => {
const client = APIClient.preservation;
client.waiting_list_items.delete(item.item_id).then(
success => {
this.setMessage(
this.$__("Item removed from the waiting list"),
baseResource.setMessage(
baseResource.$__(
"Item removed from the waiting list"
),
true
);
dt.draw();
@ -264,8 +253,35 @@ export default {
);
}
);
},
};
const tableOptions = {
url: "/api/v1/preservation/waiting-list/items",
options: { embed: "biblio" },
add_filters: true,
actions: {
0: ["show"],
1: ["show"],
"-1": [
{
removeItem: {
text: baseResource.$__("Remove"),
icon: "fa fa-close",
callback: doRemoveItem,
},
},
],
},
};
return {
...baseResource,
tableOptions,
};
},
emits: ["select-resource"],
name: "WaitingListResource",
components: {
BaseResource,
},
};
</script>