From b9d90163ac1aff68f7566e158285331a9dff025e Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Fri, 22 Nov 2024 16:03:10 +0000 Subject: [PATCH] Bug 38201: DRY form components This patch continues the work to DRY form components It creates reusable components for PatronSearch and Documents as well as moving logic into the FormElement and BaseResource components Signed-off-by: Michaela Sieber Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass --- .../prog/js/vue/components/BaseResource.vue | 20 ++ .../prog/js/vue/components/DocumentSelect.vue | 76 ++++ .../vue/components/ERM/AgreementLicenses.vue | 19 +- .../vue/components/ERM/AgreementPeriods.vue | 17 +- .../components/ERM/AgreementRelationships.vue | 16 +- .../vue/components/ERM/AgreementResource.vue | 336 ++++++++++++++++-- .../vue/components/ERM/AgreementsFormAdd.vue | 32 +- .../prog/js/vue/components/ERM/Documents.vue | 15 +- .../prog/js/vue/components/ERM/UserRoles.vue | 19 +- .../js/vue/components/FlatPickrWrapper.vue | 42 +++ .../prog/js/vue/components/FormElement.vue | 125 +++++-- .../prog/js/vue/components/PatronSearch.vue | 58 +++ 12 files changed, 693 insertions(+), 82 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/DocumentSelect.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/FlatPickrWrapper.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/PatronSearch.vue diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/BaseResource.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/BaseResource.vue index f298bc1daf..72ef9aff71 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/BaseResource.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/BaseResource.vue @@ -137,6 +137,26 @@ export default { attr => attr.show_in_table ); }, + assignAVs(attrs) { + attrs.forEach(attr => { + if (attr.type === "select" && typeof attr.av_cat === "string") { + const av_key = attr.av_cat; + attr.options = this[av_key]; + attr.requiredKey = "value"; + attr.selectLabel = "description"; + } + if (attr.type == "relationship" && attr.props) { + Object.keys(attr.props).forEach(key => { + if (attr.props[key].type == "av") { + attr.props[key].av = this[key]; + } + }); + } + if (attr.subFields?.length) { + this.assignAVs(attr.subFields); + } + }); + }, }, name: "BaseResource", props: { diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/DocumentSelect.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/DocumentSelect.vue new file mode 100644 index 0000000000..68f5041cb1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/DocumentSelect.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementLicenses.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementLicenses.vue index 40ea3457da..5ce60a92eb 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementLicenses.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementLicenses.vue @@ -15,7 +15,15 @@ >
    -
  1. +
  2. + +
  3. + +
import { APIClient } from "../../fetch/api-client.js"; -import InfiniteScrollSelect from "../InfiniteScrollSelect.vue"; +import FormElement from "../FormElement.vue"; +// import InfiniteScrollSelect from "../InfiniteScrollSelect.vue" export default { name: "AgreementLicenses", @@ -108,6 +117,7 @@ export default { av_agreement_license_statuses: Array, av_agreement_license_location: Array, agreement_licenses: Array, + subFields: Array, }, beforeCreate() { const client = APIClient.erm; @@ -135,7 +145,8 @@ export default { }, }, components: { - InfiniteScrollSelect, + // InfiniteScrollSelect, + FormElement, }, }; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue index 6ca2ee9c07..0817d8fec4 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue @@ -15,7 +15,15 @@ >
    -
  1. +
  2. + +
  3. + +
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementRelationships.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementRelationships.vue index 91057e1469..127ab65380 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementRelationships.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementRelationships.vue @@ -15,7 +15,16 @@ >
    -
  1. +
  2. + +
  3. + +
import { APIClient } from "../../fetch/api-client.js"; +import FormElement from "../FormElement.vue"; export default { + components: { FormElement }, data() { return { agreements: [], @@ -125,6 +136,7 @@ export default { agreement_id: Number, av_agreement_relationships: Array, relationships: Array, + subFields: Array, }, name: "AgreementRelationships", }; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementResource.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementResource.vue index 87b573cfdb..4bbf53aa9c 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementResource.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementResource.vue @@ -55,9 +55,15 @@ export default { { name: "vendor_id", type: "component", - component: "FormSelectVendors", label: __("Vendor"), - show_in_table: true, + componentPath: "./FormSelectVendors.vue", + props: { + id: { + type: "string", + value: "license_id_", + indexRequired: true, + }, + }, }, { name: "description", @@ -70,14 +76,14 @@ export default { { name: "status", required: true, - type: "av", + type: "select", label: __("Status"), av_cat: "av_agreement_statuses", show_in_table: true, }, { name: "closure_reason", - type: "av", + type: "select", label: __("Closure reason"), av_cat: "av_agreement_closure_reasons", show_in_table: true, @@ -90,7 +96,7 @@ export default { }, { name: "renewal_priority", - type: "av", + type: "select", label: __("Renewal priority"), av_cat: "av_agreement_renewal_priorities", show_in_table: true, @@ -102,40 +108,306 @@ export default { text_area_cols: 50, label: __("License info"), }, - // { - // name: "periods", - // type: "relationship", - // }, - // { - // name: "user_roles", - // type: "relationship", - // }, - // { - // name: "licenses", - // type: "relationship", - // }, - // { - // name: "agreements", - // type: "relationship", - // }, - // { - // name: "documents", - // type: "relationship", - // }, + { + name: "periods", + type: "relationship", + label: __("Periods"), + componentPath: "./ERM/AgreementPeriods.vue", + props: { + periods: { + type: "resourceProperty", + resourceProperty: "periods", + }, + }, + subFields: [ + { + name: "started_on", + type: "component", + label: __("Start date"), + componentPath: "./FlatPickrWrapper.vue", + required: true, + props: { + id: { + type: "string", + value: "started_on_", + indexRequired: true, + }, + required: { + type: "boolean", + value: true, + }, + date_to: { + type: "string", + value: "ended_on_", + indexRequired: true, + }, + }, + }, + { + name: "ended_on", + type: "component", + label: __("End date"), + componentPath: "./FlatPickrWrapper.vue", + required: false, + props: { + id: { + type: "string", + value: "ended_on_", + indexRequired: true, + }, + }, + }, + { + name: "cancellation_deadline", + type: "component", + label: __("Cancellation deadline"), + componentPath: "./FlatPickrWrapper.vue", + required: false, + props: { + id: { + type: "string", + value: "cancellation_deadline_", + indexRequired: true, + }, + }, + }, + { + name: "notes", + required: false, + type: "text", + label: __("Notes"), + }, + ], + }, + { + name: "user_roles", + type: "relationship", + label: __("Users"), + componentPath: "./ERM/UserRoles.vue", + props: { + user_roles: { + type: "resourceProperty", + resourceProperty: "user_roles", + }, + av_user_roles: { + type: "av", + av: null, + }, + user_type: { + type: "string", + value: __("Agreement user %s"), + }, + }, + subFields: [ + { + name: "user_id", + type: "component", + label: __("User"), + componentPath: "./PatronSearch.vue", + required: true, + props: { + name: { + type: "string", + value: "user_id", + }, + required: { + type: "boolean", + value: true, + }, + resource: { + type: "resource", + value: null, + }, + counter: { + type: "string", + value: "", + indexRequired: true, + }, + label: { + type: "string", + value: __("User"), + }, + }, + }, + { + name: "role", + type: "select", + label: __("Role"), + av_cat: "av_user_roles", + required: true, + }, + ], + }, + { + name: "licenses", + type: "relationship", + label: __("Licenses"), + componentPath: "./ERM/AgreementLicenses.vue", + props: { + agreement_licenses: { + type: "resourceProperty", + resourceProperty: "agreement_licenses", + }, + av_agreement_license_statuses: { + type: "av", + av: null, + }, + av_agreement_license_location: { + type: "av", + av: null, + }, + }, + subFields: [ + { + name: "license_id", + type: "component", + label: __("License"), + componentPath: "./InfiniteScrollSelect.vue", + required: true, + props: { + id: { + type: "string", + value: "license_id_", + indexRequired: true, + }, + selectedData: { + type: "resourceProperty", + resourceProperty: "license", + }, + dataType: { + type: "string", + value: "licenses", + }, + dataIdentifier: { + type: "string", + value: "license_id", + }, + label: { + type: "string", + value: "name", + }, + required: { + type: "boolean", + value: true, + }, + }, + }, + { + name: "status", + type: "select", + label: __("Status"), + av_cat: "av_agreement_license_statuses", + }, + { + name: "physical_location", + type: "select", + label: __("Physical location"), + av_cat: "av_agreement_license_location", + }, + { + name: "notes", + required: false, + type: "text", + label: __("Notes"), + }, + { + name: "uri", + required: false, + type: "text", + label: __("URI"), + }, + ], + }, + { + name: "relationships", + type: "relationship", + componentPath: "./ERM/AgreementRelationships.vue", + props: { + agreement_id: { + type: "resourceProperty", + resourceProperty: "agreement_id", + }, + av_agreement_relationships: { + type: "av", + av: null, + }, + relationships: { + type: "resourceProperty", + resourceProperty: "agreement_relationships", + }, + }, + subFields: [ + { + name: "related_agreement_id", + type: "select", + label: __("Related agreement"), + requiredKey: "agreement_id", + selectLabel: "name", + }, + { + name: "relationship", + type: "select", + label: __("Relationship"), + av_cat: "av_agreement_relationships", + }, + { + name: "notes", + required: false, + type: "text", + label: __("Notes"), + }, + ], + }, + { + name: "documents", + type: "relationship", + componentPath: "./ERM/Documents.vue", + props: { + documents: { + type: "resourceProperty", + resourceProperty: "documents", + }, + }, + subFields: [ + { + name: "document", + type: "component", + componentPath: "./DocumentSelect.vue", + label: __("File"), + props: { + counter: { + type: "string", + value: "", + indexRequired: true, + }, + document: { + type: "resource", + value: null, + }, + }, + }, + { + name: "uri", + required: false, + type: "text", + label: __("URI"), + }, + { + name: "notes", + required: false, + type: "text", + label: __("Notes"), + }, + ], + }, ], }; }, created() { //IMPROVEME: We need this for now to assign the correct av array from setup to the attr options in data - this.resource_attrs.forEach(attr => { - if (typeof attr.av_cat === "string") { - const av_key = attr.av_cat; - attr.options = this[av_key]; - } - }); + this.assignAVs(this.resource_attrs); this.getResourceTableColumns(); }, - methods: {}, name: "AgreementResource", }; diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue index 61107b42c1..281cd37c2c 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue @@ -10,10 +10,16 @@
  1. - +
@@ -23,13 +29,21 @@ @additional-fields-changed="additionalFieldsChanged" /> - + + + +
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Documents.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Documents.vue index fb062a0393..7d34280e25 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Documents.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Documents.vue @@ -15,7 +15,15 @@ >
    -
  1. +
  2. + +
  3. + +
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UserRoles.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UserRoles.vue index ccba1c2067..18982317c0 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UserRoles.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UserRoles.vue @@ -14,7 +14,15 @@ >
    -
  1. +
  2. + +
  3. + + +
import { APIClient } from "../../fetch/api-client.js"; +import FormElement from "../FormElement.vue"; export default { + components: { FormElement }, name: "UserRoles", props: { user_type: String, av_user_roles: Array, user_roles: Array, + subFields: Array, }, beforeCreate() { this.user_roles.forEach(u => { diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/FlatPickrWrapper.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/FlatPickrWrapper.vue new file mode 100644 index 0000000000..5f6004792b --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/FlatPickrWrapper.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/FormElement.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/FormElement.vue index 1527b26536..e699f46395 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/FormElement.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/FormElement.vue @@ -1,10 +1,12 @@