mirror of
https://github.com/frappe/books.git
synced 2025-02-04 13:08:29 +00:00
Merge pull request #75 from surajshetty3416/master
[Feature] Form links and Report onload filtes
This commit is contained in:
commit
4a242426c3
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -2,8 +2,7 @@
|
|||||||
<button type="button"
|
<button type="button"
|
||||||
:class="['btn btn-sm', 'btn-' + Object.keys(props).find(key => ['primary', 'secondary', 'light', 'dark', 'danger'].includes(key))]"
|
:class="['btn btn-sm', 'btn-' + Object.keys(props).find(key => ['primary', 'secondary', 'light', 'dark', 'danger'].includes(key))]"
|
||||||
v-bind="data.attrs"
|
v-bind="data.attrs"
|
||||||
v-on="listeners"
|
v-on="listeners">
|
||||||
>
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
29
ui/components/Dropdown.vue
Normal file
29
ui/components/Dropdown.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dropdown show">
|
||||||
|
<a class="btn btn-sm btn-secondary dropdown-toggle"
|
||||||
|
href="#"
|
||||||
|
role="button"
|
||||||
|
:id="_uid"
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false">
|
||||||
|
{{ label }}
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right" :aria-labelledby="_uid">
|
||||||
|
<a class="dropdown-item"
|
||||||
|
v-for="option in options"
|
||||||
|
:key="option.label"
|
||||||
|
@click="option.handler">
|
||||||
|
{{ option.label }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['label', 'options']
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
@ -3,6 +3,7 @@
|
|||||||
<form-actions
|
<form-actions
|
||||||
v-if="shouldRenderForm"
|
v-if="shouldRenderForm"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
|
:links="links"
|
||||||
@save="save"
|
@save="save"
|
||||||
@submit="submit"
|
@submit="submit"
|
||||||
@revert="revert"
|
@revert="revert"
|
||||||
@ -37,8 +38,9 @@ export default {
|
|||||||
docLoaded: false,
|
docLoaded: false,
|
||||||
notFound: false,
|
notFound: false,
|
||||||
invalid: false,
|
invalid: false,
|
||||||
invalidFields: []
|
invalidFields: [],
|
||||||
}
|
links: []
|
||||||
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
meta() {
|
meta() {
|
||||||
@ -70,6 +72,8 @@ export default {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.notFound = true;
|
this.notFound = true;
|
||||||
}
|
}
|
||||||
|
this.setLinks();
|
||||||
|
this.doc.on('change', this.setLinks);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async save() {
|
async save() {
|
||||||
@ -91,6 +95,21 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLinks() {
|
||||||
|
if (this.meta.links) {
|
||||||
|
let links = [];
|
||||||
|
for (let link of this.meta.links) {
|
||||||
|
if (link.condition(this)) {
|
||||||
|
link.handler = () => {
|
||||||
|
link.action(this);
|
||||||
|
};
|
||||||
|
links.push(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.links = links;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
this.doc.set('submitted', 1);
|
this.doc.set('submitted', 1);
|
||||||
await this.save();
|
await this.save();
|
||||||
@ -105,7 +124,9 @@ export default {
|
|||||||
if (!isValid && !this.invalidFields.includes(fieldname)) {
|
if (!isValid && !this.invalidFields.includes(fieldname)) {
|
||||||
this.invalidFields.push(fieldname);
|
this.invalidFields.push(fieldname);
|
||||||
} else if (isValid) {
|
} else if (isValid) {
|
||||||
this.invalidFields = this.invalidFields.filter(invalidField => invalidField !== fieldname)
|
this.invalidFields = this.invalidFields.filter(
|
||||||
|
invalidField => invalidField !== fieldname
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -113,7 +134,7 @@ export default {
|
|||||||
const form = this.$el.querySelector('form');
|
const form = this.$el.querySelector('form');
|
||||||
let validity = form.checkValidity();
|
let validity = form.checkValidity();
|
||||||
this.invalid = !validity;
|
this.invalid = !validity;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="frappe-form-actions d-flex justify-content-between align-items-center p-3 border-bottom">
|
<div class="frappe-form-actions d-flex justify-content-between align-items-center p-3 border-bottom">
|
||||||
<h5 class="m-0">{{ title }}</h5>
|
<h5 class="m-0">{{ title }}</h5>
|
||||||
|
<div class="d-flex">
|
||||||
<f-button primary v-if="isDirty" @click="$emit('save')">{{ _('Save') }}</f-button>
|
<f-button primary v-if="isDirty" @click="$emit('save')">{{ _('Save') }}</f-button>
|
||||||
<f-button primary v-if="showSubmit" @click="$emit('submit')">{{ _('Submit') }}</f-button>
|
<f-button primary v-if="showSubmit" @click="$emit('submit')">{{ _('Submit') }}</f-button>
|
||||||
<f-button secondary v-if="showRevert" @click="$emit('revert')">{{ _('Revert') }}</f-button>
|
<f-button secondary v-if="showRevert" @click="$emit('revert')">{{ _('Revert') }}</f-button>
|
||||||
|
<dropdown class="ml-2" v-if="links.length" :label="'Next Action'" :options="links"></dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
|
import Dropdown from '../Dropdown';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['doc'],
|
props: ['doc', 'links'],
|
||||||
|
components: {
|
||||||
|
Dropdown
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
|
@ -4,40 +4,49 @@
|
|||||||
v-for="docfield in filters"
|
v-for="docfield in filters"
|
||||||
:key="docfield.fieldname"
|
:key="docfield.fieldname"
|
||||||
:docfield="docfield"
|
:docfield="docfield"
|
||||||
:value="$data[docfield.fieldname]"
|
:value="$data.filterValues[docfield.fieldname]"
|
||||||
@change="updateValue(docfield.fieldname, $event)"/>
|
@change="updateValue(docfield.fieldname, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import FrappeControl from 'frappejs/ui/components/controls/FrappeControl'
|
import FrappeControl from 'frappejs/ui/components/controls/FrappeControl';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['filters'],
|
props: ['filters', 'filterDefaults'],
|
||||||
data() {
|
data() {
|
||||||
const filterValues = {};
|
const filterValues = {};
|
||||||
for (let filter of this.filters) {
|
for (let filter of this.filters) {
|
||||||
filterValues[filter.fieldname] = '';
|
filterValues[filter.fieldname] =
|
||||||
|
this.filterDefaults[filter.fieldname] || null;
|
||||||
}
|
}
|
||||||
return { filterValues };
|
return { filterValues };
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
const hasOnloadFilters = Object.values(this.filterValues).filter(
|
||||||
|
value => value !== null
|
||||||
|
).length;
|
||||||
|
|
||||||
|
if (hasOnloadFilters) {
|
||||||
|
this.$emit('change', this.filterValues);
|
||||||
|
}
|
||||||
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
dynamicLinkTarget: (reference) => {
|
dynamicLinkTarget: reference => {
|
||||||
return this.filterValues[reference]
|
return this.filterValues[reference];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateValue(fieldname, value) {
|
updateValue(fieldname, value) {
|
||||||
this.filterValues[fieldname] = value;
|
this.filterValues[fieldname] = value;
|
||||||
this.$emit('change', this.filterValues)
|
this.$emit('change', this.filterValues);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
FrappeControl
|
FrappeControl
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,43 +2,46 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h4 class="pb-2">{{ reportConfig.title }}</h4>
|
<h4 class="pb-2">{{ reportConfig.title }}</h4>
|
||||||
<report-filters v-if="reportConfig.filterFields.length" :filters="reportConfig.filterFields" @change="getReportData"></report-filters>
|
<report-filters v-if="reportConfig.filterFields.length" :filters="reportConfig.filterFields" :filterDefaults="filters" @change="getReportData"></report-filters>
|
||||||
<div class="pt-2" ref="datatable" v-once></div>
|
<div class="pt-2" ref="datatable" v-once></div>
|
||||||
</div>
|
</div>
|
||||||
<not-found v-if="!reportConfig" />
|
<not-found v-if="!reportConfig" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import DataTable from 'frappe-datatable'
|
import DataTable from 'frappe-datatable';
|
||||||
import frappe from 'frappejs'
|
import frappe from 'frappejs';
|
||||||
import ReportFilters from './ReportFilters'
|
import ReportFilters from './ReportFilters';
|
||||||
import utils from 'frappejs/client/ui/utils'
|
import utils from 'frappejs/client/ui/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['reportName', 'reportConfig'],
|
name: 'Report',
|
||||||
|
props: ['reportName', 'reportConfig', 'filters'],
|
||||||
computed: {
|
computed: {
|
||||||
reportColumns() {
|
reportColumns() {
|
||||||
return utils.convertFieldsToDatatableColumns(this.reportConfig.getColumns())
|
return utils.convertFieldsToDatatableColumns(
|
||||||
|
this.reportConfig.getColumns()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getReportData(filters) {
|
getReportData(filters) {
|
||||||
frappe.methods[this.reportConfig.method](filters).then(data => {
|
frappe.methods[this.reportConfig.method](filters).then(data => {
|
||||||
if (this.datatable) {
|
if (this.datatable) {
|
||||||
this.datatable.refresh(data || [])
|
this.datatable.refresh(data || []);
|
||||||
} else {
|
} else {
|
||||||
this.datatable = new DataTable(this.$refs.datatable, {
|
this.datatable = new DataTable(this.$refs.datatable, {
|
||||||
columns: this.reportColumns,
|
columns: this.reportColumns,
|
||||||
data: data || [],
|
data: data || []
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ReportFilters,
|
ReportFilters
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user