mirror of
https://github.com/frappe/books.git
synced 2024-11-14 01:14:03 +00:00
added forms + controls
This commit is contained in:
parent
3b8ea0755c
commit
d9e306b641
23
frappe/client/index.js
Normal file
23
frappe/client/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const common = require('frappe-core/frappe/common');
|
||||||
|
const Database = require('frappe-core/frappe/backends/rest_client').Database;
|
||||||
|
const frappe = require('frappe-core');
|
||||||
|
frappe.ui = require('./ui');
|
||||||
|
frappe.view = require('./view');
|
||||||
|
const Router = require('./view/router').Router;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async start({server, container}) {
|
||||||
|
window.frappe = frappe;
|
||||||
|
frappe.init();
|
||||||
|
common.init_libs(frappe);
|
||||||
|
|
||||||
|
frappe.db = await new Database({
|
||||||
|
server: server,
|
||||||
|
fetch: window.fetch.bind()
|
||||||
|
});
|
||||||
|
|
||||||
|
frappe.view.init({container: container});
|
||||||
|
frappe.router = new Router();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
33
frappe/client/ui/index.js
Normal file
33
frappe/client/ui/index.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
add(tag, className, parent) {
|
||||||
|
let element = document.createElement(tag);
|
||||||
|
if (className) {
|
||||||
|
for (let c of className.split(' ')) {
|
||||||
|
this.add_class(element, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parent) {
|
||||||
|
parent.appendChild(element);
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
},
|
||||||
|
|
||||||
|
add_class(element, className) {
|
||||||
|
if (element.classList) {
|
||||||
|
element.classList.add(className);
|
||||||
|
} else {
|
||||||
|
element.className += " " + className;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
remove_class(element, className) {
|
||||||
|
if (element.classList) {
|
||||||
|
element.classList.remove(className);
|
||||||
|
} else {
|
||||||
|
element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
90
frappe/client/view/controls/base.js
Normal file
90
frappe/client/view/controls/base.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
|
class BaseControl {
|
||||||
|
constructor(docfield, parent) {
|
||||||
|
Object.assign(this, docfield);
|
||||||
|
if (!this.fieldname) {
|
||||||
|
this.fieldname = frappe.slug(this.label);
|
||||||
|
}
|
||||||
|
this.parent = parent;
|
||||||
|
if (this.setup) {
|
||||||
|
this.setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
|
||||||
|
this.doc.add_handler(this.fieldname, () => {
|
||||||
|
this.set_doc_value();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.set_doc_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.make();
|
||||||
|
this.set_doc_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
set_doc_value() {
|
||||||
|
if (this.doc) {
|
||||||
|
this.set_input_value(this.doc.get(this.fieldname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
make() {
|
||||||
|
if (!this.form_group) {
|
||||||
|
this.make_form_group();
|
||||||
|
this.make_label();
|
||||||
|
this.make_input();
|
||||||
|
this.make_description();
|
||||||
|
this.bind_change_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
make_form_group() {
|
||||||
|
this.form_group = frappe.ui.add('div', 'form-group', this.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
make_label() {
|
||||||
|
this.label_element = frappe.ui.add('label', null, this.form_group);
|
||||||
|
this.label_element.textContent = this.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
make_input() {
|
||||||
|
this.input = frappe.ui.add('input', 'form-control', this.form_group);
|
||||||
|
this.input.setAttribute('type', this.fieldname);
|
||||||
|
}
|
||||||
|
|
||||||
|
make_description() {
|
||||||
|
if (this.description) {
|
||||||
|
this.description_element = frappe.ui.add('small', 'form-text text-muted', this.form_group);
|
||||||
|
this.description_element.textContent = this.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_input_value(value) {
|
||||||
|
this.input.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_input_value() {
|
||||||
|
return await this.parse(this.input.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async parse(value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_change_event() {
|
||||||
|
this.input.addEventListener('change', () => this.handle_change(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
async handle_change(e) {
|
||||||
|
let value = await this.get_input_value();
|
||||||
|
value = await this.validate(value);
|
||||||
|
await this.doc.set(this.fieldname, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BaseControl;
|
10
frappe/client/view/controls/data.js
Normal file
10
frappe/client/view/controls/data.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const BaseControl = require('./base');
|
||||||
|
|
||||||
|
class DataControl extends BaseControl {
|
||||||
|
make() {
|
||||||
|
super.make();
|
||||||
|
this.input.setAttribute('type', 'text');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DataControl;
|
16
frappe/client/view/controls/index.js
Normal file
16
frappe/client/view/controls/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const control_classes = {
|
||||||
|
Data: require('./data')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
get_control_class(fieldtype) {
|
||||||
|
return control_classes[fieldtype];
|
||||||
|
},
|
||||||
|
make_control(field, parent) {
|
||||||
|
const control_class = this.get_control_class(field.fieldtype);
|
||||||
|
let control = new control_class(field, parent);
|
||||||
|
control.make();
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
}
|
66
frappe/client/view/form.js
Normal file
66
frappe/client/view/form.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
const controls = require('./controls');
|
||||||
|
|
||||||
|
class Form {
|
||||||
|
constructor({doctype, parent, submit_label='Submit'}) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.doctype = doctype;
|
||||||
|
this.submit_label = submit_label;
|
||||||
|
|
||||||
|
this.controls = {};
|
||||||
|
this.controls_list = [];
|
||||||
|
|
||||||
|
this.meta = frappe.get_meta(this.doctype);
|
||||||
|
}
|
||||||
|
|
||||||
|
make() {
|
||||||
|
this.body = frappe.ui.add('form', null, this.parent);
|
||||||
|
for(let df of this.meta.fields) {
|
||||||
|
if (controls.get_control_class(df.fieldtype)) {
|
||||||
|
let control = controls.make_control(df, this.body);
|
||||||
|
this.controls_list.push(control);
|
||||||
|
this.controls[df.fieldname] = control;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.make_submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
make_submit() {
|
||||||
|
this.submit_btn = frappe.ui.add('button', 'btn btn-primary', this.body);
|
||||||
|
this.submit_btn.setAttribute('type', 'submit');
|
||||||
|
this.submit_btn.textContent = this.submit_label;
|
||||||
|
this.submit_btn.addEventListener('click', (event) => {
|
||||||
|
this.submit();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async use(doc, is_new = false) {
|
||||||
|
if (this.doc) {
|
||||||
|
// clear handlers of outgoing doc
|
||||||
|
this.doc.clear_handlers();
|
||||||
|
}
|
||||||
|
this.doc = doc;
|
||||||
|
this.is_new = is_new;
|
||||||
|
for (let control of this.controls_list) {
|
||||||
|
control.bind(this.doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async submit() {
|
||||||
|
if (this.is_new) {
|
||||||
|
await this.doc.insert();
|
||||||
|
} else {
|
||||||
|
await this.doc.update();
|
||||||
|
}
|
||||||
|
await this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
for(let control of this.controls_list) {
|
||||||
|
control.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {Form: Form};
|
20
frappe/client/view/index.js
Normal file
20
frappe/client/view/index.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
init({container, main, sidebar}) {
|
||||||
|
frappe.container = container;
|
||||||
|
|
||||||
|
if (sidebar) {
|
||||||
|
frappe.sidebar = sidebar;
|
||||||
|
} else {
|
||||||
|
frappe.sidebar = frappe.ui.add('div', 'sidebar', frappe.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (main) {
|
||||||
|
frappe.main = main;
|
||||||
|
} else {
|
||||||
|
frappe.main = frappe.ui.add('div', 'main', frappe.container);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
@ -13,9 +13,9 @@ class ListView {
|
|||||||
this.rows = [];
|
this.rows = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async render() {
|
async run() {
|
||||||
this.make_body();
|
this.make_body();
|
||||||
let data = await this.meta.get_list(this.start, this.page_length);
|
let data = await this.meta.get_list({start:this.start, limit:this.page_length});
|
||||||
|
|
||||||
for (let i=0; i< data.length; i++) {
|
for (let i=0; i< data.length; i++) {
|
||||||
this.render_row(this.start + i, data[i]);
|
this.render_row(this.start + i, data[i]);
|
||||||
@ -24,19 +24,18 @@ class ListView {
|
|||||||
|
|
||||||
make_body() {
|
make_body() {
|
||||||
if (!this.body) {
|
if (!this.body) {
|
||||||
this.body = $('<div class="list-body"></div>')
|
this.body = frappe.ui.add('div', 'list-body', this.parent);
|
||||||
.appendTo(frappe.main);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_row(i, data) {
|
render_row(i, data) {
|
||||||
let row = this.get_row(i);
|
let row = this.get_row(i);
|
||||||
row.html(this.meta.get_row_html(data));
|
row.innerHTML = this.meta.get_row_html(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_row(i) {
|
get_row(i) {
|
||||||
if (!this.rows[i]) {
|
if (!this.rows[i]) {
|
||||||
this.rows[i] = $('<div class="list-row"></div>').appendTo(this.body);
|
this.rows[i] = frappe.ui.add('div', 'list-row', this.body);
|
||||||
}
|
}
|
||||||
return this.rows[i];
|
return this.rows[i];
|
||||||
}
|
}
|
24
frappe/client/view/page.js
Normal file
24
frappe/client/view/page.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
|
class Page {
|
||||||
|
constructor(title) {
|
||||||
|
this.title = title;
|
||||||
|
this.make();
|
||||||
|
}
|
||||||
|
make() {
|
||||||
|
this.body = frappe.ui.add('div', 'page hide', frappe.main);
|
||||||
|
}
|
||||||
|
hide() {
|
||||||
|
frappe.ui.add_class(this.body, 'hide');
|
||||||
|
}
|
||||||
|
show() {
|
||||||
|
if (frappe.router.current_page) {
|
||||||
|
frappe.router.current_page.hide();
|
||||||
|
}
|
||||||
|
frappe.ui.remove_class(this.body, 'hide');
|
||||||
|
frappe.router.current_page = this;
|
||||||
|
document.title = this.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Page: Page };
|
82
frappe/client/view/router.js
Normal file
82
frappe/client/view/router.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
|
class Router {
|
||||||
|
constructor() {
|
||||||
|
this.current_page = null;
|
||||||
|
this.routes = {};
|
||||||
|
this.listen();
|
||||||
|
}
|
||||||
|
|
||||||
|
add(route, handler) {
|
||||||
|
let page = {handler: handler};
|
||||||
|
|
||||||
|
// '/todo/:name/:place'.match(/:([^/]+)/g);
|
||||||
|
page.param_keys = route.match(/:([^/]+)/g);
|
||||||
|
|
||||||
|
if (page.param_keys) {
|
||||||
|
// make expression
|
||||||
|
// '/todo/:name/:place'.replace(/\/:([a-z1-9]+)/g, "\/([a-z0-9]+)");
|
||||||
|
page.expression = route.replace(/\/:([a-z1-9]+)/g, "\/([a-z0-9]+)");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.routes[route] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen() {
|
||||||
|
window.onhashchange = this.changed.bind(this);
|
||||||
|
this.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
async changed(event) {
|
||||||
|
if (window.location.hash.length > 0) {
|
||||||
|
const page_name = window.location.hash.substr(1);
|
||||||
|
this.show(page_name);
|
||||||
|
} else if (this.routes['default']) {
|
||||||
|
this.show('default');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show(route) {
|
||||||
|
if (!route) {
|
||||||
|
route = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route[0]==='#') {
|
||||||
|
route = route.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let page = this.match(route);
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
if (typeof page.handler==='function') {
|
||||||
|
page.handler(page.params);
|
||||||
|
} else {
|
||||||
|
page.handler.show(page.params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match(route) {
|
||||||
|
for(let key in this.routes) {
|
||||||
|
let page = this.routes[key];
|
||||||
|
|
||||||
|
if (page.param_keys) {
|
||||||
|
let matches = route.match(new RegExp(page.expression));
|
||||||
|
if (matches && matches.length == page.param_keys.length + 1) {
|
||||||
|
let params = {}
|
||||||
|
for (let i=0; i < page.param_keys.length; i++) {
|
||||||
|
params[page.param_keys[i].substr(1)] = matches[i + 1];
|
||||||
|
}
|
||||||
|
return {handler:page.handler, params: params};
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (key === route) {
|
||||||
|
return {handler:page.handler};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {Router: Router};
|
@ -22,22 +22,6 @@ module.exports = {
|
|||||||
this.meta_cache = {};
|
this.meta_cache = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
init_view({container, main, sidebar}) {
|
|
||||||
this.container = container;
|
|
||||||
|
|
||||||
if (sidebar) {
|
|
||||||
this.sidebar = sidebar;
|
|
||||||
} else {
|
|
||||||
this.sidebar = $('<div class="sidebar"></div>').appendTo(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (main) {
|
|
||||||
this.main = main;
|
|
||||||
} else {
|
|
||||||
this.main = $('<div class="main"></div>').appendTo(this.container);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get_meta(doctype) {
|
get_meta(doctype) {
|
||||||
if (!this.meta_cache[doctype]) {
|
if (!this.meta_cache[doctype]) {
|
||||||
this.meta_cache[doctype] = new (this.models.get_meta_class(doctype))(this.models.get('DocType', doctype));
|
this.meta_cache[doctype] = new (this.models.get_meta_class(doctype))(this.models.get('DocType', doctype));
|
||||||
|
@ -11,6 +11,10 @@ class Document {
|
|||||||
// add handlers
|
// add handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_handlers() {
|
||||||
|
this.handlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
add_handler(key, method) {
|
add_handler(key, method) {
|
||||||
if (!this.handlers[key]) {
|
if (!this.handlers[key]) {
|
||||||
this.handlers[key] = [];
|
this.handlers[key] = [];
|
||||||
|
@ -5,6 +5,12 @@ class Meta extends Document {
|
|||||||
constructor(data) {
|
constructor(data) {
|
||||||
super(data);
|
super(data);
|
||||||
this.event_handlers = {};
|
this.event_handlers = {};
|
||||||
|
this.list_options = {
|
||||||
|
fields: ['name', 'modified']
|
||||||
|
};
|
||||||
|
if (this.setup_meta) {
|
||||||
|
this.setup_meta();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_field(fieldname) {
|
get_field(fieldname) {
|
||||||
@ -24,6 +30,15 @@ class Meta extends Document {
|
|||||||
this.event_handlers[key].push(fn);
|
this.event_handlers[key].push(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async set(fieldname, value) {
|
||||||
|
this[fieldname] = value;
|
||||||
|
await this.trigger(fieldname);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(fieldname) {
|
||||||
|
return this[fieldname];
|
||||||
|
}
|
||||||
|
|
||||||
get_valid_fields() {
|
get_valid_fields() {
|
||||||
if (!this._valid_fields) {
|
if (!this._valid_fields) {
|
||||||
this._valid_fields = [];
|
this._valid_fields = [];
|
||||||
@ -62,15 +77,26 @@ class Meta extends Document {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger(key) {
|
async trigger(key, event = {}) {
|
||||||
|
|
||||||
|
Object.assign(event, {
|
||||||
|
doc: this,
|
||||||
|
name: key
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.event_handlers[key]) {
|
||||||
|
for (var handler of this.event_handlers[key]) {
|
||||||
|
await handler(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// views
|
// collections
|
||||||
async get_list(start, limit=20) {
|
async get_list({start, limit=20, filters}) {
|
||||||
return await frappe.db.get_all({
|
return await frappe.db.get_all({
|
||||||
doctype: this.name,
|
doctype: this.name,
|
||||||
fields: ['name'],
|
fields: this.list_options.fields,
|
||||||
|
filters: filters,
|
||||||
start: start,
|
start: start,
|
||||||
limit: limit
|
limit: limit
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
const frappe = require('frappe-core');
|
const frappe = require('frappe-core');
|
||||||
|
|
||||||
class todo_meta extends frappe.meta.Meta {
|
class todo_meta extends frappe.meta.Meta {
|
||||||
async get_list(start, limit=20) {
|
setup_meta() {
|
||||||
return await frappe.db.get_all({
|
Object.assign(this, require('./todo.json'));
|
||||||
doctype: 'ToDo',
|
this.name = 'ToDo';
|
||||||
fields: ['name', 'subject', 'status', 'description'],
|
this.list_options.fields = ['name', 'subject', 'status', 'description'];
|
||||||
start: start,
|
|
||||||
limit: limit
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_row_html(data) {
|
get_row_html(data) {
|
||||||
return `<a href="/view/todo/${data.name}">${data.subject}</a>`;
|
return `<a href="#todo/${data.name}">${data.subject}</a>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ const models = require('frappe-core/frappe/server/models');
|
|||||||
const common = require('frappe-core/frappe/common');
|
const common = require('frappe-core/frappe/common');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
|
||||||
async function init({backend, connection_params}) {
|
module.exports = {
|
||||||
|
async init() {
|
||||||
await frappe.init();
|
await frappe.init();
|
||||||
common.init_libs(frappe);
|
common.init_libs(frappe);
|
||||||
await frappe.login();
|
await frappe.login();
|
||||||
@ -17,19 +18,20 @@ async function init({backend, connection_params}) {
|
|||||||
// walk and find models
|
// walk and find models
|
||||||
models.init();
|
models.init();
|
||||||
|
|
||||||
// database
|
},
|
||||||
|
|
||||||
|
async start({backend, connection_params, static}) {
|
||||||
|
await this.init();
|
||||||
|
|
||||||
|
// database
|
||||||
frappe.db = await new backends[backend].Database(connection_params);
|
frappe.db = await new backends[backend].Database(connection_params);
|
||||||
await frappe.db.connect();
|
await frappe.db.connect();
|
||||||
await frappe.db.migrate();
|
await frappe.db.migrate();
|
||||||
}
|
|
||||||
|
|
||||||
async function start({backend, connection_params}) {
|
|
||||||
await init({backend, connection_params});
|
|
||||||
|
|
||||||
// app
|
// app
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
app.use(express.static('./'));
|
||||||
|
|
||||||
// routes
|
// routes
|
||||||
rest_server.setup(app);
|
rest_server.setup(app);
|
||||||
@ -37,9 +39,7 @@ async function start({backend, connection_params}) {
|
|||||||
// listen
|
// listen
|
||||||
frappe.app = app;
|
frappe.app = app;
|
||||||
frappe.server = app.listen(frappe.config.port);
|
frappe.server = app.listen(frappe.config.port);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
init: init,
|
|
||||||
start: start
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
const frappe = require('frappe-core');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
setup() {
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user