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 <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:
parent
f86f0041cb
commit
b9d90163ac
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<div class="file_information">
|
||||
<span v-if="!document.file_name">
|
||||
{{ $__("Select a file") }}
|
||||
<input
|
||||
type="file"
|
||||
@change="selectFile($event, counter)"
|
||||
:id="`file_${counter}`"
|
||||
:name="`file_${counter}`"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $__("Update file") }}
|
||||
<input
|
||||
type="file"
|
||||
@change="selectFile($event, counter)"
|
||||
:id="`file_${counter}`"
|
||||
:name="`file_${counter}`"
|
||||
/>
|
||||
</span>
|
||||
<ol>
|
||||
<li v-show="document.file_name">
|
||||
{{ $__("File name") }}:
|
||||
<span>{{ document.file_name }}</span>
|
||||
</li>
|
||||
<li v-show="document.file_type">
|
||||
{{ $__("File type") }}:
|
||||
<span>{{ document.file_type }}</span>
|
||||
</li>
|
||||
<li v-show="document.file_name">
|
||||
{{ $__("File description") }}:
|
||||
<input
|
||||
:id="`file_description_${counter}`"
|
||||
type="text"
|
||||
class="file_description"
|
||||
:name="`file_description_${counter}`"
|
||||
v-model="document.file_description"
|
||||
:placeholder="$__('File description')"
|
||||
/>
|
||||
</li>
|
||||
<li v-show="document.uploaded_on">
|
||||
{{ $__("Uploaded on") }}:
|
||||
<span>{{ format_date(document.uploaded_on) }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
counter: String,
|
||||
document: Object,
|
||||
},
|
||||
setup() {
|
||||
const format_date = $date;
|
||||
return { format_date };
|
||||
},
|
||||
methods: {
|
||||
selectFile(e, i) {
|
||||
let files = e.target.files;
|
||||
if (!files) return;
|
||||
let file = files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => this.loadFile(file.name, e.target.result, i);
|
||||
reader.readAsBinaryString(file);
|
||||
},
|
||||
loadFile(filename, content, i) {
|
||||
this.document.file_name = filename;
|
||||
this.document.file_content = btoa(content);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
@ -15,7 +15,15 @@
|
|||
>
|
||||
</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<li v-for="(attr, index) in subFields" v-bind:key="index">
|
||||
<FormElement
|
||||
:resource="agreement_license"
|
||||
:attr="attr"
|
||||
:index="index"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<label :for="`license_id_${counter}`" class="required"
|
||||
>{{ $__("License") }}:</label
|
||||
>
|
||||
|
|
@ -83,7 +91,7 @@
|
|||
v-model="agreement_license.uri"
|
||||
:placeholder="$__('URI')"
|
||||
/>
|
||||
</li>
|
||||
</li> -->
|
||||
</ol>
|
||||
</fieldset>
|
||||
<a v-if="license_count > 0" class="btn btn-default" @click="addLicense"
|
||||
|
|
@ -95,7 +103,8 @@
|
|||
|
||||
<script>
|
||||
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,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,15 @@
|
|||
>
|
||||
</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<li v-for="(attr, index) in subFields" v-bind:key="index">
|
||||
<FormElement
|
||||
:resource="period"
|
||||
:attr="attr"
|
||||
:index="counter"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<label :for="`started_on_${counter}`" class="required"
|
||||
>{{ $__("Start date") }}:
|
||||
</label>
|
||||
|
|
@ -57,7 +65,7 @@
|
|||
:name="`notes_${counter}`"
|
||||
v-model="period.notes"
|
||||
/>
|
||||
</li>
|
||||
</li> -->
|
||||
</ol>
|
||||
</fieldset>
|
||||
<a class="btn btn-default" @click="addPeriod"
|
||||
|
|
@ -67,7 +75,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import flatPickr from "vue-flatpickr-component";
|
||||
import FormElement from "../FormElement.vue";
|
||||
export default {
|
||||
name: "AgreementPeriods",
|
||||
data() {
|
||||
|
|
@ -77,6 +85,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
periods: Array,
|
||||
subFields: Array,
|
||||
},
|
||||
methods: {
|
||||
addPeriod() {
|
||||
|
|
@ -92,7 +101,7 @@ export default {
|
|||
},
|
||||
},
|
||||
components: {
|
||||
flatPickr,
|
||||
FormElement,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,16 @@
|
|||
>
|
||||
</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<li v-for="(attr, index) in subFields" v-bind:key="index">
|
||||
<FormElement
|
||||
:resource="relationship"
|
||||
:attr="attr"
|
||||
:index="counter"
|
||||
:options="agreements"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<label
|
||||
:for="`related_agreement_id_${counter}`"
|
||||
class="required"
|
||||
|
|
@ -72,7 +81,7 @@
|
|||
v-model="relationship.notes"
|
||||
:placeholder="$__('Notes')"
|
||||
/>
|
||||
</li>
|
||||
</li> -->
|
||||
</ol>
|
||||
</fieldset>
|
||||
<a
|
||||
|
|
@ -90,8 +99,10 @@
|
|||
|
||||
<script>
|
||||
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",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -10,10 +10,16 @@
|
|||
<fieldset class="rows">
|
||||
<ol>
|
||||
<li
|
||||
v-for="(attr, index) in resource_attrs"
|
||||
v-for="(attr, index) in resource_attrs.filter(
|
||||
attr => attr.type !== 'relationship'
|
||||
)"
|
||||
v-bind:key="index"
|
||||
>
|
||||
<FormElement :resource="agreement" :attr="attr" />
|
||||
<FormElement
|
||||
:resource="agreement"
|
||||
:attr="attr"
|
||||
:index="index"
|
||||
/>
|
||||
</li>
|
||||
</ol>
|
||||
</fieldset>
|
||||
|
|
@ -23,13 +29,21 @@
|
|||
@additional-fields-changed="additionalFieldsChanged"
|
||||
/>
|
||||
<!-- These relationships need DRY -->
|
||||
<AgreementPeriods :periods="agreement.periods" />
|
||||
<template
|
||||
v-for="(attr, index) in resource_attrs.filter(
|
||||
attr => attr.type === 'relationship'
|
||||
)"
|
||||
v-bind:key="'rel-' + index"
|
||||
>
|
||||
<FormElement :resource="agreement" :attr="attr" />
|
||||
</template>
|
||||
<!-- <AgreementPeriods :periods="agreement.periods" />
|
||||
<UserRoles
|
||||
:user_type="$__('Agreement user %s')"
|
||||
:user_roles="agreement.user_roles"
|
||||
:av_user_roles="authorisedValues['av_user_roles']"
|
||||
/>
|
||||
<AgreementLicenses
|
||||
:av_user_roles="av_user_roles"
|
||||
/> -->
|
||||
<!-- <AgreementLicenses
|
||||
:agreement_licenses="agreement.agreement_licenses"
|
||||
:av_agreement_license_statuses="
|
||||
authorisedValues['av_agreement_license_statuses']
|
||||
|
|
@ -37,15 +51,15 @@
|
|||
:av_agreement_license_location="
|
||||
authorisedValues['av_agreement_license_location']
|
||||
"
|
||||
/>
|
||||
<AgreementRelationships
|
||||
/> -->
|
||||
<!-- <AgreementRelationships
|
||||
:agreement_id="agreement.agreement_id"
|
||||
:relationships="agreement.agreement_relationships"
|
||||
:av_agreement_relationships="
|
||||
authorisedValues['av_agreement_relationships']
|
||||
"
|
||||
/>
|
||||
<Documents :documents="agreement.documents" />
|
||||
<Documents :documents="agreement.documents" /> -->
|
||||
<!-- These relationships need DRY -->
|
||||
<fieldset class="action">
|
||||
<ButtonSubmit />
|
||||
|
|
|
|||
|
|
@ -15,7 +15,15 @@
|
|||
>
|
||||
</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<li v-for="(attr, index) in subFields" v-bind:key="index">
|
||||
<FormElement
|
||||
:resource="document"
|
||||
:attr="attr"
|
||||
:index="counter"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<label>{{ $__("File") }}:</label>
|
||||
<div class="file_information">
|
||||
<span v-if="!document.file_name">
|
||||
|
|
@ -96,7 +104,7 @@
|
|||
v-model="document.notes"
|
||||
:placeholder="$__('Notes')"
|
||||
/>
|
||||
</li>
|
||||
</li> -->
|
||||
</ol>
|
||||
</fieldset>
|
||||
<a class="btn btn-default" @click="addDocument"
|
||||
|
|
@ -106,7 +114,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import FormElement from "../FormElement.vue";
|
||||
export default {
|
||||
components: { FormElement },
|
||||
setup() {
|
||||
const format_date = $date;
|
||||
return { format_date };
|
||||
|
|
@ -142,6 +152,7 @@ export default {
|
|||
name: "Documents",
|
||||
props: {
|
||||
documents: Array,
|
||||
subFields: Array,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,15 @@
|
|||
>
|
||||
</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<li v-for="(attr, index) in subFields" v-bind:key="index">
|
||||
<FormElement
|
||||
:resource="user_role"
|
||||
:attr="attr"
|
||||
:index="counter"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<label :for="`user_id_${counter}`" class="required"
|
||||
>{{ $__("User") }}:</label
|
||||
>
|
||||
|
|
@ -30,8 +38,8 @@
|
|||
><i class="fa fa-plus"></i> {{ $__("Select user") }}</a
|
||||
>
|
||||
<span class="required">{{ $__("Required") }}</span>
|
||||
</li>
|
||||
<li>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<label :for="`user_role_${counter}`" class="required"
|
||||
>{{ $__("Role") }}:</label
|
||||
>
|
||||
|
|
@ -52,7 +60,7 @@
|
|||
</template>
|
||||
</v-select>
|
||||
<span class="required">{{ $__("Required") }}</span>
|
||||
</li>
|
||||
</li> -->
|
||||
</ol>
|
||||
</fieldset>
|
||||
<input
|
||||
|
|
@ -68,13 +76,16 @@
|
|||
|
||||
<script>
|
||||
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 => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<flatPickr
|
||||
:id="id"
|
||||
v-model="model"
|
||||
:required="required"
|
||||
:config="fp_config"
|
||||
:data-date_to="date_to"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import flatPickr from "vue-flatpickr-component";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
id: String,
|
||||
modelValue: String,
|
||||
required: Boolean,
|
||||
date_to: String,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
return {
|
||||
fp_config: flatpickr_defaults,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:modelValue", value);
|
||||
},
|
||||
},
|
||||
},
|
||||
components: { flatPickr },
|
||||
name: "FlatPickrWrapper",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<div v-if="attr.type == 'text'">
|
||||
<label :for="attr.name" :class="{ required: attr.required }"
|
||||
<label
|
||||
:for="`${attr.name}${index}`"
|
||||
:class="{ required: attr.required }"
|
||||
>{{ attr.label }}:</label
|
||||
>
|
||||
<input
|
||||
:id="attr.name"
|
||||
:id="`${attr.name}${index}`"
|
||||
v-model="resource[attr.name]"
|
||||
:placeholder="attr.label"
|
||||
:required="attr.required ? true : false"
|
||||
|
|
@ -12,11 +14,13 @@
|
|||
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
|
||||
</div>
|
||||
<div v-else-if="attr.type == 'textarea'">
|
||||
<label :for="attr.name" :class="{ required: attr.required }"
|
||||
<label
|
||||
:for="`${attr.name}${index}`"
|
||||
:class="{ required: attr.required }"
|
||||
>{{ attr.label }}:</label
|
||||
>
|
||||
<textarea
|
||||
:id="attr.name"
|
||||
:id="`${attr.name}${index}`"
|
||||
v-model="resource[attr.name]"
|
||||
:rows="attr.text_area_rows"
|
||||
:cols="attr.text_area_col"
|
||||
|
|
@ -26,8 +30,8 @@
|
|||
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
|
||||
</div>
|
||||
<div v-else-if="attr.type == 'boolean'">
|
||||
<label :for="attr.name">{{ attr.label }}:</label>
|
||||
<label class="radio" :for="attr.name + '_yes'"
|
||||
<label :for="`${attr.name}${index}`">{{ attr.label }}:</label>
|
||||
<label class="radio" :for="`${attr.name}${index}` + '_yes'"
|
||||
>{{ $__("Yes") }}:
|
||||
<input
|
||||
type="radio"
|
||||
|
|
@ -48,16 +52,18 @@
|
|||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div v-else-if="attr.type == 'av'">
|
||||
<label :for="attr.name" :class="{ required: attr.required }"
|
||||
<div v-else-if="attr.type == 'select'">
|
||||
<label
|
||||
:for="`${attr.name}${index}`"
|
||||
:class="{ required: attr.required }"
|
||||
>{{ attr.label }}:</label
|
||||
>
|
||||
<v-select
|
||||
:id="attr.name"
|
||||
:id="`${attr.name}${index}`"
|
||||
v-model="resource[attr.name]"
|
||||
label="description"
|
||||
:reduce="av => av.value"
|
||||
:options="attr.options"
|
||||
:label="attr.selectLabel"
|
||||
:reduce="av => av[attr.requiredKey]"
|
||||
:options="selectOptions"
|
||||
:required="!resource[attr.name] && attr.required"
|
||||
:disabled="attr.disabled"
|
||||
>
|
||||
|
|
@ -72,26 +78,95 @@
|
|||
</v-select>
|
||||
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
attr.type == 'component' && attr.component == 'FormSelectVendors'
|
||||
"
|
||||
>
|
||||
<label :for="attr.name">{{ attr.label }}:</label>
|
||||
<FormSelectVendors :id="attr.name" v-model="resource[attr.name]">
|
||||
</FormSelectVendors>
|
||||
<div v-else-if="attr.type == 'component'">
|
||||
<label :for="attr.name" :class="{ required: attr.required }"
|
||||
>{{ attr.label }}:</label
|
||||
>
|
||||
<component
|
||||
v-if="isVModelRequired(attr.componentPath)"
|
||||
:is="requiredComponent"
|
||||
v-bind="requiredProps()"
|
||||
v-model="resource[attr.name]"
|
||||
></component>
|
||||
<component
|
||||
v-else
|
||||
:is="requiredComponent"
|
||||
v-bind="requiredProps()"
|
||||
></component>
|
||||
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
|
||||
</div>
|
||||
<template v-else-if="attr.type == 'relationship'">
|
||||
<component :is="requiredComponent" v-bind="requiredProps()"></component>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormSelectVendors from "./FormSelectVendors.vue";
|
||||
import { defineAsyncComponent } from "vue";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
resource: null,
|
||||
attr: null,
|
||||
resource: Object | null,
|
||||
attr: Object | null,
|
||||
index: Number | null,
|
||||
options: Array,
|
||||
},
|
||||
components: {
|
||||
FormSelectVendors,
|
||||
computed: {
|
||||
requiredComponent() {
|
||||
return defineAsyncComponent(
|
||||
() => import(`${this.attr.componentPath}`)
|
||||
);
|
||||
},
|
||||
selectOptions() {
|
||||
if (this.attr.options) {
|
||||
return this.attr.options;
|
||||
}
|
||||
return this.options;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
requiredProps() {
|
||||
if (!this.attr.props) {
|
||||
return {};
|
||||
}
|
||||
const props = Object.keys(this.attr.props).reduce((acc, key) => {
|
||||
// This might be better in a switch statement
|
||||
const prop = this.attr.props[key];
|
||||
if (prop.type === "resource") {
|
||||
acc[key] = this.resource;
|
||||
}
|
||||
if (prop.type === "resourceProperty") {
|
||||
acc[key] = this.resource[prop.resourceProperty];
|
||||
}
|
||||
if (prop.type === "av") {
|
||||
acc[key] = prop.av;
|
||||
}
|
||||
if (prop.type === "string") {
|
||||
if (prop.indexRequired && this.index > -1) {
|
||||
acc[key] = `${prop.value}${this.index}`;
|
||||
} else {
|
||||
acc[key] = prop.value;
|
||||
}
|
||||
}
|
||||
if (prop.type === "boolean") {
|
||||
acc[key] = prop.value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
if (this.attr.subFields?.length) {
|
||||
props.subFields = this.attr.subFields;
|
||||
}
|
||||
return props;
|
||||
},
|
||||
isVModelRequired(componentPath) {
|
||||
let vModelRequired = true;
|
||||
const componentsNotRequiringVModel = ["PatronSearch", "Documents"];
|
||||
componentsNotRequiringVModel.forEach(component => {
|
||||
if (componentPath.includes(component)) {
|
||||
vModelRequired = false;
|
||||
}
|
||||
});
|
||||
return vModelRequired;
|
||||
},
|
||||
},
|
||||
name: "FormElement",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<span class="user">
|
||||
{{ resource.patron_str }}
|
||||
</span>
|
||||
|
||||
<a
|
||||
href="#patron_search_modal"
|
||||
@click="selectUser(counter)"
|
||||
class="btn btn-default"
|
||||
data-bs-toggle="modal"
|
||||
><i class="fa fa-plus"></i> {{ $__("Select user") }}</a
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { APIClient } from "../fetch/api-client.js";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
resource: Object,
|
||||
counter: String,
|
||||
label: String,
|
||||
required: Boolean,
|
||||
},
|
||||
beforeCreate() {
|
||||
this.resource.patron_str = $patron_to_html(this.resource.patron);
|
||||
},
|
||||
methods: {
|
||||
selectUser(counter) {
|
||||
// This is a bit dirty, the "select user" window should be rewritten and be a Vue component
|
||||
// but that's not for now...
|
||||
$(document).on(
|
||||
"hidden.bs.modal",
|
||||
"#patron_search_modal",
|
||||
this.newUserSelected
|
||||
);
|
||||
// this.selected_user_counter = counter
|
||||
},
|
||||
newUserSelected(e) {
|
||||
// let c = this.selected_user_counter
|
||||
let selected_patron_id =
|
||||
document.getElementById("selected_patron_id").value;
|
||||
let patron;
|
||||
const client = APIClient.patron;
|
||||
// FIXME We are missing a "loading..."
|
||||
client.patrons.get(selected_patron_id).then(p => {
|
||||
patron = p;
|
||||
this.resource.patron = patron;
|
||||
this.resource.patron_str = $patron_to_html(patron);
|
||||
this.resource.user_id = patron.patron_id;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
Loading…
Reference in New Issue