2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 23:00:56 +00:00

report fixes

This commit is contained in:
Rushabh Mehta 2018-03-27 19:25:26 +05:30
parent dd88baaf41
commit 497c2ab742
13 changed files with 113 additions and 40 deletions

View File

@ -1,56 +1,54 @@
const Page = require('frappejs/client/view/page');
const controls = require('frappejs/client/view/controls');
const Form = require('frappejs/client/view/form');
const DataTable = require('frappe-datatable');
const frappe = require('frappejs');
const utils = require('frappejs/client/ui/utils');
const Observable = require('frappejs/utils/observable');
// baseclass for report
// `url` url for report
// `getColumns` return columns
module.exports = class ReportPage extends Page {
constructor({title, }) {
constructor({title, filterFields}) {
super({title: title, hasRoute: true});
this.fullPage = true;
this.filterFields = filterFields;
this.filterWrapper = frappe.ui.add('div', 'filter-toolbar form-inline', this.body);
this.filterWrapper = frappe.ui.add('div', 'filter-toolbar', this.body);
this.tableWrapper = frappe.ui.add('div', 'table-page-wrapper', this.body);
this.btnNew = this.addButton(frappe._('Refresh'), 'btn-primary', async () => {
await this.run();
});
this.filters = {};
this.makeFilters();
}
getColumns() {
// overrride
}
addFilter(field) {
if (!field.fieldname) {
field.fieldname = frappe.slug(field.label);
}
field.placeholder = field.label;
field.inline = true;
this.filters[field.fieldname] = controls.makeControl({field: field, form: this, parent: this.filterWrapper});
return this.filters[field.fieldname];
makeFilters() {
this.form = new Form({
parent: this.filterWrapper,
meta: { fields: this.filterFields },
doc: new Observable(),
inline: true,
container: this
});
}
getFilterValues() {
const values = {};
for (let fieldname in this.filters) {
let control = this.filters[fieldname];
values[fieldname] = control.getInputValue();
if (control.required && !values[fieldname]) {
for (let control of this.form.controlList) {
values[control.fieldname] = control.getInputValue();
if (control.required && !values[control.fieldname]) {
frappe.ui.showAlert({message: frappe._('{0} is mandatory', control.label), color: 'red'});
return false;
}
}
console.log(values);
return values;
}
@ -60,6 +58,16 @@ module.exports = class ReportPage extends Page {
}
async run() {
if (frappe.params && frappe.params.filters) {
for (let key in frappe.params.filters) {
if (this.form.controls[key]) {
this.form.controls[key].setInputValue(frappe.params.filters[key]);
}
}
}
frappe.params = null;
if (!this.datatable) {
this.makeDataTable();
}

View File

@ -30,7 +30,7 @@ module.exports = class TablePage extends Page {
this.filterSelector.reset(this.doctype);
}
if (frappe.params.filters) {
if (frappe.params && frappe.params.filters) {
this.filterSelector.setFilters(frappe.params.filters);
}
frappe.params = null;

View File

@ -86,7 +86,8 @@ html {
.form-inline {
.form-group {
margin-right: $spacer-2;
margin-right: $spacer-3;
margin-bottom: $spacer-3;
}
}

View File

@ -86,8 +86,8 @@ class BaseControl {
if (!this.onlyInput) {
this.makeDescription();
}
if (this.placeholder) {
this.input.setAttribute('placeholder', this.placeholder);
if (this.placeholder || this.inline) {
this.input.setAttribute('placeholder', this.placeholder || this.label);
}
}

View File

@ -0,0 +1,9 @@
const LinkControl = require('./link');
class DynamicLinkControl extends LinkControl {
getTarget() {
return this.doc[this.references];
}
};
module.exports = DynamicLinkControl;

View File

@ -3,6 +3,7 @@ const controlClasses = {
Code: require('./code'),
Data: require('./data'),
Date: require('./date'),
DynamicLink: require('./dynamicLink'),
Currency: require('./currency'),
Float: require('./float'),
Int: require('./int'),

View File

@ -33,8 +33,8 @@ class LinkControl extends BaseControl {
this.input.addEventListener('awesomplete-select', async (e) => {
if (e.text && e.text.value === '__newItem') {
e.preventDefault();
const newDoc = await frappe.getNewDoc(this.target);
const formModal = await frappe.desk.showFormModal(this.target, newDoc.name);
const newDoc = await frappe.getNewDoc(this.getTarget());
const formModal = await frappe.desk.showFormModal(this.getTarget(), newDoc.name);
if (formModal.form.doc.meta.hasField('name')) {
formModal.form.doc.set('name', this.input.value);
}
@ -49,7 +49,7 @@ class LinkControl extends BaseControl {
async getList(query) {
return (await frappe.db.getAll({
doctype: this.target,
doctype: this.getTarget(),
filters: this.getFilters(query, this),
limit: 50
})).map(d => d.name);
@ -58,6 +58,10 @@ class LinkControl extends BaseControl {
getFilters(query) {
return { keywords: ["like", query] }
}
getTarget() {
return this.target;
}
};
module.exports = LinkControl;

View File

@ -4,7 +4,7 @@ const Observable = require('frappejs/utils/observable');
const keyboard = require('frappejs/client/ui/keyboard');
module.exports = class BaseForm extends Observable {
constructor({doctype, parent, submit_label='Submit', container}) {
constructor({doctype, parent, submit_label='Submit', container, meta, inline=false}) {
super();
Object.assign(this, arguments[0]);
this.controls = {};
@ -12,12 +12,21 @@ module.exports = class BaseForm extends Observable {
this.sections = [];
this.links = [];
this.meta = frappe.getMeta(this.doctype);
if (!this.meta) {
this.meta = frappe.getMeta(this.doctype);
}
if (this.setup) {
this.setup();
}
this.make();
this.bindFormEvents();
if (this.doc) {
// bootstrapped with a doc
this.bindEvents(this.doc);
}
}
make() {
@ -25,10 +34,22 @@ module.exports = class BaseForm extends Observable {
return;
}
this.body = frappe.ui.add('div', 'form-body', this.parent);
this.makeToolbar();
if (this.inline) {
this.body = this.parent
} else {
this.body = frappe.ui.add('div', 'form-body', this.parent);
}
if (this.actions) {
this.makeToolbar();
}
this.form = frappe.ui.add('form', 'form-container', this.body);
if (this.inline) {
this.form.classList.add('form-inline');
}
this.form.onValidate = true;
this.makeLayout();
@ -74,6 +95,9 @@ module.exports = class BaseForm extends Observable {
makeControls(fields, parent) {
for(let field of fields) {
if (!field.hidden && controls.getControlClass(field.fieldtype)) {
if (this.inline) {
field.inline = true;
}
let control = controls.makeControl({field: field, form: this, parent: parent});
this.controlList.push(control);
this.controls[field.fieldname] = control;
@ -180,6 +204,8 @@ module.exports = class BaseForm extends Observable {
}
setTitle() {
if (!this.container) return;
const doctypeLabel = this.doc.meta.label || this.doc.meta.name;
if (this.doc.meta.isSingle || this.doc.meta.naming === 'random') {
@ -216,6 +242,8 @@ module.exports = class BaseForm extends Observable {
}
refreshLinks(links) {
if (!this.container) return;
this.container.clearLinks();
for(let link of links) {
// make the link

View File

@ -11,8 +11,8 @@ module.exports = class Page extends Observable {
}
this.make();
this.dropdowns = {};
if(this.title) {
this.wrapper.setAttribute('title', this.title);
this.setTitle(this.title);
}
}

View File

@ -11,6 +11,8 @@ module.exports = {
naming: "name", // {random|autoincrement}
isSingle: 0,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [
{

View File

@ -5,11 +5,13 @@ const naming = require('./naming');
module.exports = class BaseDocument extends Observable {
constructor(data) {
super();
this.fetchValues = {};
this.fetchValuesCache = {};
this.flags = {};
this.setup();
Object.assign(this, data);
frappe.db.on('change', (params) => this.fetchValues[`${params.doctype}:${params.name}`] = {});
// clear fetch-values cache
frappe.db.on('change', (params) => this.fetchValuesCache[`${params.doctype}:${params.name}`] = {});
}
setup() {
@ -30,10 +32,6 @@ module.exports = class BaseDocument extends Observable {
return this._settings;
}
get(fieldname) {
return this[fieldname];
}
// set value and trigger change
async set(fieldname, value) {
if (this[fieldname] !== value) {
@ -298,7 +296,7 @@ module.exports = class BaseDocument extends Observable {
async getFrom(doctype, name, fieldname) {
if (!name) return '';
let _values = this.fetchValues[`${doctype}:${name}`] || (this.fetchValues[`${doctype}:${name}`] = {});
let _values = this.fetchValuesCache[`${doctype}:${name}`] || (this.fetchValuesCache[`${doctype}:${name}`] = {});
if (!_values[fieldname]) {
_values[fieldname] = await frappe.db.getValue(doctype, name, fieldname);
}

View File

@ -65,10 +65,22 @@ module.exports = {
if (!e.status_code || e.status_code !== 404) {
throw e;
}
series = frappe.newDoc({doctype: 'NumberSeries', name: prefix, current: 0});
await series.insert();
await this.createNumberSeries(prefix);
}
let next = await series.next()
return prefix + next;
},
async createNumberSeries(prefix, setting, start=1000) {
if (!(await frappe.db.exists('NumberSeries', prefix))) {
const series = frappe.newDoc({doctype: 'NumberSeries', name: prefix, current: start});
await series.insert();
if (setting) {
const settingDoc = await frappe.getSingle(setting);
settingDoc.numberSeries = series.name;
await settingDoc.update();
}
}
}
}

View File

@ -8,6 +8,16 @@ module.exports = class Observable {
}
}
// getter, setter stubs, so Observable can be used as a simple Document
get(key) {
return this[key];
}
set(key, value) {
this[key] = value;
this.trigger('change', {doc: this, fieldname: key});
}
on(event, listener) {
this._addListener('listeners', event, listener);
if (this._observable.socketClient) {