zet-lib 6.1.0 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,327 +1,366 @@
1
- const express = require('express');
2
- const router = express.Router();
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
3
  const generatorApp = require("./generatorApp");
4
- const configGenerator = require('./config_generator');
5
-
6
- const csrf = require('./csrf');
4
+ const configGenerator = require("./config_generator");
7
5
  const Model = require("./Model");
8
- const fs = require('fs-extra');
9
- //const {connection, Util} = require('zet-lib');
10
- const connection = require('./connection');
11
- const Util = require('./Util');
6
+ const connection = require("./connection");
7
+ const Util = require("./Util");
12
8
 
13
9
  const Api = {};
10
+ const asArray = generatorApp.asArray || ((value) => (Array.isArray(value) ? value : []));
11
+ const isPlainObject = generatorApp.isPlainObject || ((value) => !!value && typeof value === "object" && !Array.isArray(value));
12
+ const hasOwn = (obj, key) => !!obj && Object.prototype.hasOwnProperty.call(obj, key);
13
+ const containerObject = (...args) => generatorApp.containerObject(...args);
14
+ const readFileSafe = (file, fallback = "") => (
15
+ generatorApp.readFileSafe ? generatorApp.readFileSafe(file, fallback) : (() => {
16
+ try { return fs.readFileSync(file, "utf-8"); } catch (err) { return fallback; }
17
+ })()
18
+ );
19
+
20
+ const VIEW_TEMPLATE_KEYS = [
21
+ "index_ejs", "indexcss_ejs", "indexjs_ejs", "form_ejs",
22
+ "create_ejs", "createjs_ejs", "update_ejs", "updatejs_ejs", "updatecss_ejs",
23
+ "import_ejs", "importjs_ejs", "view_ejs",
24
+ ];
25
+
26
+ const FORBIDDEN_NAMES = [
27
+ "group", "copy", "command", "from", "select", "distinct", "where", "year", "month", "day",
28
+ "ignore", "previous", "next", "start", "end", "set", "setof", "show", "size", "row", "rows",
29
+ "return", "order",
30
+ ];
31
+
32
+ const RELATION_TYPES = ["relation", "dropdown_multi", "table", "typeahead", "dragdrop"];
33
+ const RELATION_NAME_TYPES = ["relation", "typeahead"];
34
+
35
+ const stripViewTemplates = (datas) => {
36
+ if (!isPlainObject(datas)) return datas;
37
+ VIEW_TEMPLATE_KEYS.forEach((key) => {
38
+ delete datas[key];
39
+ });
40
+ return datas;
41
+ };
14
42
 
15
- Api.test = async (req, res) => {
16
- //console.log(req.body);
17
- var body = req.body;
18
- res.json(body)
43
+ const emptyDatas = () => ({
44
+ table: "",
45
+ tabs: [],
46
+ labels: {},
47
+ details: {},
48
+ left: [],
49
+ right: [],
50
+ oneColumn: [],
51
+ sorting: [],
52
+ properties: {},
53
+ hardcode_grid: "",
54
+ });
55
+
56
+ const loadDefaultTemplates = () => ({
57
+ router: readFileSafe(path.join(generatorApp.DIRECTORY, "routerApp.ejs")),
58
+ index_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "index.ejs")),
59
+ indexcss_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "indexcss.ejs")),
60
+ indexjs_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "indexjs.ejs")),
61
+ form_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "_form.ejs")),
62
+ create_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "create.ejs")),
63
+ createjs_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "createjs.ejs")),
64
+ update_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "update.ejs")),
65
+ updatejs_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "updatejs.ejs")),
66
+ import_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "import.ejs")),
67
+ importjs_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "importjs.ejs")),
68
+ view_ejs: readFileSafe(path.join(generatorApp.DIRECTORY_GENERATOR_VIEWS, "view.ejs")),
69
+ hardcode_grid: Model.hardcodeGrid || "",
70
+ });
71
+
72
+ const fail = (err) => {
73
+ console.error(err);
74
+ return Util.flashError(err && err.toString ? err.toString() : String(err));
19
75
  };
20
76
 
21
- Api.index = async (req, res) => {
22
- try {
23
- let datas = {table: '', tabs: [], labels: {}, details: {}, hardcode_grid: ""};
24
- let table = req.body.table || "", route = "";
25
- const results = req.body.results || [];
26
- const fields = req.body.fields || []
27
- const zFields = Util.arrayToObject(results, "table");
28
- /*let json = {
29
- datas: datas,
30
- table: table,
31
- rows: {},
32
- route: "",
33
- selects: Model.keys,
34
- }*/
35
- let json;
36
- if (table) {
37
- datas = zFields[table] || {}
38
- if (datas.hasOwnProperty("id")) {
39
- datas.details = datas.details || {};
40
- datas.labels = datas.labels || {};
41
- datas.tabs = datas.tabs || [];
42
- datas.left = datas.left || [];
43
- datas.right = datas.right || [];
44
- datas.properties = datas.properties || {};
45
- datas.hardcode_grid = datas.hardcode_grid || Model.hardcodeGrid;
46
- datas.zapprovals = datas.zapprovals || {};
47
- route = datas.route;
48
- //files
49
- //get contents or get it from views zgenerator/views
50
- datas.router = datas.router || fs.readFileSync(generatorApp.DIRECTORY + "/routerApp.ejs", 'utf-8');
51
- delete datas.index_ejs;
52
- delete datas.indexcss_ejs;
53
- delete datas.indexjs_ejs;
54
- delete datas.form_ejs;
55
- delete datas.create_ejs;
56
- delete datas.createjs_ejs;
57
- delete datas.update_ejs;
58
- delete datas.updatejs_ejs;
59
- delete datas.import_ejs;
60
- delete datas.importjs_ejs;
61
- delete datas.index_ejs;
62
- delete datas.createjs_ejs;
63
- delete datas.updatejs_ejs;
64
- delete datas.importjs_ejs;
65
- delete datas.view_ejs;
66
- delete datas.importjs_ejs;
77
+ const parseJson = (value, fallback = {}) => {
78
+ if (isPlainObject(value)) return value;
79
+ if (typeof value !== "string" || !value.trim()) return fallback;
80
+ try {
81
+ const parsed = JSON.parse(value);
82
+ return isPlainObject(parsed) ? parsed : fallback;
83
+ } catch (err) {
84
+ return fallback;
85
+ }
86
+ };
67
87
 
68
- }
69
- }
88
+ const escapeAttr = (value) => String(value == null ? "" : value)
89
+ .replace(/&/g, "&")
90
+ .replace(/"/g, """)
91
+ .replace(/</g, "&lt;");
70
92
 
71
- if (zFields) {
72
- let rows = await connection.query(connection.showTables);
73
- let arr = [];
74
- rows.map(async (item) => {
75
- let obj = {}
76
- for (let key in item) {
77
- let name = item[key];
78
- obj.name = name;
79
- obj.label = Util.camelize(name);
80
- if (zFields.hasOwnProperty(name)) {
81
- if (zFields[name].name) {
82
- obj.label = zFields[name].name
83
- } else {
84
- let post = {
85
- name: Util.fieldToName(name),
86
- route: name
87
- }
88
- /*await connection.update({
89
- table: "zfields",
90
- data: post,
91
- where: {
92
- table: name
93
- }
94
- });*/
95
- zFields[name].label = Util.fieldToName(name);
96
- }
97
- } else {
98
- let properties = await zFieldsProperty(name, fields);
99
- /*await connection.insert({
100
- table: "zfields",
101
- data: properties
102
- })*/
103
- zFields[name] = properties;
104
- }
105
- }
106
- arr.push(obj)
107
- });
108
- }
109
- //add javascript object ZFIELDS
110
- let obj = {}
111
- for (let keys in zFields) {
112
- for (let key in zFields[keys]) {
113
- if (key == "labels") {
114
- zFields[keys].labels = zFields[keys].labels;
115
- } else if (key == "details") {
116
- zFields[keys].details = zFields[keys].details;
117
- } else if (key == "properties") {
118
- zFields[keys].properties = zFields[keys].properties;
119
- } else if (key == "left") {
120
- zFields[keys].left = zFields[keys].left;
121
- } else if (key == "right") {
122
- zFields[keys].right = zFields[keys].right;
123
- }
124
- }
125
- }
126
- /*
127
- Filter modules
128
- */
129
- //delete zFields.zapprovals;
130
- //delete zFields.zconfig;
131
- //delete zFields.zerror;
132
- //delete zFields.zfields;
133
- //delete zFields.zgrid;
134
- //delete zFields.zmenu;
135
- //delete zFields.znotification;
136
- //delete zFields.zrole;
137
- //delete zFields.zuser;
138
- //delete zFields.zuser_company;
139
- //delete zFields.zcompany;
140
- //delete zFields.zreport;
141
- //delete zFields.zreport_filter;
93
+ const bootstrapColumn = (count) => `col-md-${count > 0 ? 12 / count : 12}`;
142
94
 
143
- delete datas.index_ejs;
144
- delete datas.indexcss_ejs;
145
- delete datas.indexjs_ejs;
146
- delete datas.form_ejs;
147
- delete datas.create_ejs;
148
- delete datas.createjs_ejs;
149
- delete datas.createjs_ejs;
150
- delete datas.updatecss_ejs;
151
- delete datas.update_ejs;
152
- delete datas.updatejs_ejs;
153
- delete datas.importjs_ejs;
154
- delete datas.import_ejs;
155
- delete datas.view_ejs;
95
+ const columnLR = (items, dataName) =>
96
+ `<div class="col-md-6"><ol class="mydragable divboxlittle" data-name="${dataName}">${items}</ol></div>`;
156
97
 
157
- /*
158
- End filter
159
- */
160
- json = {
161
- datas: datas,
162
- table: table,
163
- rows: zFields,
164
- route: route,
165
- selects: Model.keys,
166
- }
167
- res.json(json);
168
- } catch (e) {
169
- console.log(e.toString());
170
- res.status(400).json({message: e.toString()})
171
- }
172
- }
98
+ const columnOne = (items) =>
99
+ `<div class="row sortable"><i class="fa fa-arrows icon-float"></i><div class="col-md-12"><ol class="mydragable divboxlittle" data-name="ONE_COLUMN">${items}</ol></div></div>`;
173
100
 
174
- Api.modal = async (body) => {
175
- try {
176
- let table = body.table || "";
177
- let html = '';
178
- let fields = [];
179
- let datas = {table: '', tabs: [], labels: {}, details: {}, left: [], right: []};
180
- let count = 1;
181
- let tabView = '';
182
- let tabBox = '';
183
- let tabUl = '';
184
- let tabContent = '';
185
- let left = '', right = '', oneColumn = '';
186
- let hasTab = false;
187
- let properties = {};
188
- let rowsFields;
189
- let result = body.result;
190
- const others = result.others || {};
191
- let othersArr = Object.keys(others) || [];
192
- const hasContainer = othersArr.length > 0;
101
+ const dragable_with_icon = (name, label, tab, leftright, type = "") => {
102
+ const myname = tab === "" ? name : `${name}___arr${tab}`;
103
+ const typeName = type && Model.keys ? (Model.keys[type] || "") : "";
104
+ const safeName = escapeAttr(name);
105
+ const safeLabel = escapeAttr(label);
106
+ return `<li>
107
+ <div class="input-group">
108
+ <div class="input-group-prepend">
109
+ <span class="input-group-text modal_setting" data-type="${escapeAttr(typeName)}" data-name="${safeName}" data-label="${safeLabel}" ><i class="fa fa-cog text-info modal_setting" data-type="${escapeAttr(typeName)}" data-name="${safeName}" data-label="${safeLabel}"></i> </span>
110
+ <span class="input-group-text can-copy" data-name="${safeName}" title="click to copy"><i class="fa fa-copy"></i></span>
111
+ <span class="input-group-text" >${safeName}</span>
112
+ <input type="text" class="form-control" data-name="${safeName}" name="${escapeAttr(myname)}" value="${safeLabel}">
113
+ <input type="hidden" name="${escapeAttr(leftright || "LEFT")}" value="${safeName}">
114
+ </div>
115
+ </div><br></li>`;
116
+ };
193
117
 
194
- let leftData = others.LEFT || [];
195
- let rightData = others.RIGHT || [];
196
- let oneColumnData = others.ONE_COLUMN || [];
197
- let leftsNew = [], rightsNew = [], oneColumnsNew = [];
198
- let ALL_FIELDS = {};
118
+ const makeItemsOl = (o, columnName, tabName, datas) => {
119
+ const property = datas && datas.property;
120
+ if (typeof o === "string") {
121
+ return property && property[o] && property[o].type
122
+ ? dragable_with_icon(o, datas.labels && datas.labels[o], tabName, columnName, property[o].type)
123
+ : "";
124
+ }
125
+
126
+ const groups = asArray(o);
127
+ if (!groups.some((row) => asArray(row).length)) return "";
128
+ const colMd = bootstrapColumn(groups.length);
129
+ let html = `<li class="container-nav"> <i class="fa fa-arrows icon-floating"></i><div class="row mt-1 mb-1">`;
130
+ groups.forEach((row) => {
131
+ html += `<div class="${colMd}" style="background-color: rgba(0,0,0,.03)"><ol class="divboxlittle container-box"><li><i data-column="${columnName}" class="fa fa-plus-circle fa-2x add-container text-success"></i> </li> `;
132
+ asArray(row).forEach((myitem) => {
133
+ let field = myitem;
134
+ if (tabName) field = String(field).replace(`___${tabName}`, "");
135
+ if (property && property[field] && property[field].type) {
136
+ html += dragable_with_icon(field, datas.labels && datas.labels[field], tabName, columnName, property[field].type);
137
+ }
138
+ });
139
+ html += `</ol> </div>`;
140
+ });
141
+ html += `</div></li>`;
142
+ return html;
143
+ };
199
144
 
200
- if (table) {
201
- rowsFields = body.rowsFields;
202
- if (result.id) {
203
- datas = {
204
- details: result.details || {},
205
- labels: result.labels || {},
206
- tabs: result.tabs || [],
207
- left: result.left || [],
208
- right: result.right || [],
209
- oneColumn: result.one_column || [],
210
- sorting: result.sorting || [],
211
- property: result.properties || {}
212
- };
213
- let details = datas.details;
214
- properties = datas.property;
215
- let tabs = datas.tabs;
145
+ const renderFieldList = (list, column, tabIndex, datas, useContainer) =>
146
+ asArray(list).map((item) => {
147
+ if (useContainer) return makeItemsOl(item, column, tabIndex, datas);
148
+ return datas.property && datas.property[item] && datas.property[item].type
149
+ ? dragable_with_icon(item, datas.labels && datas.labels[item], tabIndex, column, datas.property[item].type)
150
+ : "";
151
+ }).join("");
152
+
153
+ const tabFieldsFromClassic = (list, arrName) => {
154
+ let found = [];
155
+ asArray(list).forEach((item) => {
156
+ if (isPlainObject(item) && item[arrName]) found = item[arrName];
157
+ });
158
+ return asArray(found);
159
+ };
216
160
 
217
- // Jika ada container, gunakan containerObject untuk memproses data
218
- if (hasContainer) {
219
- ALL_FIELDS = containerObject(leftData, rightData, oneColumnData, tabs);
220
- }
161
+ const zFieldsProperty = (table, fields) => {
162
+ const label = {};
163
+ const details = [];
164
+ const lefts = [];
165
+ const rights = [];
166
+ const nots = Util.nots || [];
167
+ asArray(fields).forEach((item) => {
168
+ if (!item || !item.Field) return;
169
+ label[item.Field] = Util.fieldToName(item.Field);
170
+ if (Util.in_array(item.Field, nots)) return;
171
+ details.push(item.Field);
172
+ if ((details.length) % 2 === 0) rights.push(item.Field);
173
+ else lefts.push(item.Field);
174
+ });
175
+ return {
176
+ table,
177
+ name: Util.fieldToName(table),
178
+ route: table,
179
+ labels: JSON.stringify(label),
180
+ details: JSON.stringify({ notabs: details }),
181
+ left: JSON.stringify(lefts),
182
+ right: JSON.stringify(rights),
183
+ };
184
+ };
221
185
 
222
- if (tabs.length) {
223
- hasTab = true;
224
- }
186
+ const createTable = (postData) => {
187
+ const json = Util.jsonSuccess("Successfully create module");
188
+ if (!isPlainObject(postData)) return Util.flashError("Module Name Empty", "route");
189
+
190
+ const name = String(postData.name || "").trim();
191
+ const route = Util.toName(postData.route);
192
+ if (FORBIDDEN_NAMES.includes(name)) return Util.flashError("Module Name is Forbidden, try using other module name..", "route");
193
+ if (!name) return Util.flashError("Module Name Empty", "route");
194
+ if (Util.in_array(name, configGenerator.notGenerateTable)) return Util.flashError("Module Name Exist", "route");
195
+ if (!route) return Util.flashError("Route Empty", "route");
196
+
197
+ const table = Util.toName(name);
198
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
199
+ return Util.flashError("Invalid table name", "route");
200
+ }
201
+
202
+ const labels = {
203
+ id: "Id",
204
+ company_id: "Company",
205
+ lock: "Lock/Unlock",
206
+ approval_status: "Approval Status",
207
+ approval_history: "Approval History",
208
+ created_at: "Created At",
209
+ updated_at: "Updated At",
210
+ created_by: "Created By",
211
+ updated_by: "Updated By",
212
+ };
213
+
214
+ const post = Object.assign({
215
+ table,
216
+ name,
217
+ route,
218
+ labels: JSON.stringify(labels),
219
+ left: "[]",
220
+ right: "[]",
221
+ sorting: "[2,1]",
222
+ details: JSON.stringify({ notabs: [] }),
223
+ hardcode_grid: Model.hardcodeGrid,
224
+ company_id: 1,
225
+ }, Api.datas);
226
+
227
+ const sql = `
228
+ CREATE TABLE ${table} (
229
+ id BIGSERIAL PRIMARY KEY,
230
+ company_id BIGINT NOT NULL,
231
+ lock smallint default 0,
232
+ approval_status smallint DEFAULT 1,
233
+ approval_history jsonb[] DEFAULT NULL,
234
+ updated_by BIGINT DEFAULT NULL,
235
+ created_by BIGINT DEFAULT NULL,
236
+ created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
237
+ updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
238
+ CONSTRAINT fk_${table}_company_id FOREIGN KEY (company_id) REFERENCES zcompany (id)
239
+
240
+ );`;
225
241
 
226
- if (hasTab) {
227
- let tabLeft = [], tabRight = [], tabOneColum = [];
242
+ json.post = post;
243
+ json.sql = sql;
244
+ return json;
245
+ };
228
246
 
229
- tabUl += '<ul class="nav nav-tabs" id="myTab" role="tablist">';
230
- tabContent += '<div class="tab-content" id="myTabContent">';
231
- tabs.forEach(function (item, i) {
232
- let navlink = i == 0 ? ' active' : '';
233
- let ariaselected = i == 0 ? "true" : "false";
234
- let showActive = i == 0 ? ' show active ' : '';
235
- let n = i + 1;
236
- let arrName = 'arr' + i;
237
- let dynamicsLeft = '', dynamicsRight = '', dynamicsOneColumn = '';
247
+ Api.test = async (req, res) => {
248
+ res.json(req.body || {});
249
+ };
238
250
 
239
- if (hasContainer) {
240
- // Logika untuk container
241
- tabLeft = ALL_FIELDS.tabLeft[arrName] || [];
242
- tabRight = ALL_FIELDS.tabRight[arrName] || [];
243
- tabOneColum = ALL_FIELDS.tabOneColumn[arrName] || [];
251
+ Api.index = async (req, res) => {
252
+ try {
253
+ const body = req.body || {};
254
+ const table = body.table || "";
255
+ const results = asArray(body.results);
256
+ const fields = asArray(body.fields);
257
+ const zFields = Util.arrayToObject(results, "table") || {};
258
+ let datas = emptyDatas();
259
+ let route = "";
260
+
261
+ if (table && zFields[table]) {
262
+ datas = zFields[table];
263
+ if (hasOwn(datas, "id")) {
264
+ datas.details = datas.details || {};
265
+ datas.labels = datas.labels || {};
266
+ datas.tabs = datas.tabs || [];
267
+ datas.left = datas.left || [];
268
+ datas.right = datas.right || [];
269
+ datas.properties = datas.properties || {};
270
+ datas.hardcode_grid = datas.hardcode_grid || Model.hardcodeGrid;
271
+ datas.zapprovals = datas.zapprovals || {};
272
+ route = datas.route;
273
+ datas.router = datas.router || readFileSafe(path.join(generatorApp.DIRECTORY, "routerApp.ejs"));
274
+ stripViewTemplates(datas);
275
+ }
276
+ }
244
277
 
245
- if (tabLeft.length) {
246
- tabLeft.map((o) => {
247
- dynamicsLeft += makeItemsOl(o, "LEFT", i, datas);
248
- });
249
- }
250
- if (tabRight.length) {
251
- tabRight.map((o) => {
252
- dynamicsRight += makeItemsOl(o, "RIGHT", i, datas);
253
- });
254
- }
255
- if (tabOneColum.length) {
256
- tabOneColum.map((o) => {
257
- dynamicsOneColumn += makeItemsOl(o, "ONE_COLUMN", i, datas);
258
- });
259
- }
260
- } else {
261
- // Logika untuk classic
262
- if (datas.left.length) {
263
- datas.left.forEach(function (o) {
264
- if (typeof o == "object") {
265
- for (var key in o) {
266
- if (key == arrName) {
267
- tabLeft = o[key];
268
- }
269
- }
270
- }
271
- });
272
- }
273
- if (datas.right.length) {
274
- datas.right.forEach(function (o) {
275
- if (typeof o == "object") {
276
- for (var key in o) {
277
- if (key == arrName) {
278
- tabRight = o[key];
279
- }
280
- }
281
- }
282
- });
283
- }
284
- if (datas.oneColumn.length) {
285
- datas.oneColumn.forEach(function (o) {
286
- if (typeof o == "object") {
287
- for (var key in o) {
288
- if (key == arrName) {
289
- tabOneColum = o[key];
290
- }
291
- }
292
- }
293
- });
294
- }
278
+ const rows = asArray(await connection.query(connection.showTables));
279
+ for (const item of rows) {
280
+ const name = item && (item.tablename || item.TABLE_NAME || Object.values(item)[0]);
281
+ if (!name || typeof name !== "string") continue;
282
+ if (zFields[name]) {
283
+ if (!zFields[name].name) zFields[name].label = Util.fieldToName(name);
284
+ } else {
285
+ zFields[name] = zFieldsProperty(name, fields);
286
+ }
287
+ }
295
288
 
296
- if (tabLeft.length) {
297
- tabLeft.map((o) => {
298
- if(datas.property[o] && datas.property[o].hasOwnProperty("type") ) {
299
- dynamicsLeft += dragable_with_icon(o, datas.labels[o], i, "LEFT", datas.property[o].type);
300
- }
301
- });
302
- }
303
- if (tabRight.length) {
304
- tabRight.map((o) => {
305
- if(datas.property[o] && datas.property[o].hasOwnProperty("type") ) {
306
- dynamicsRight += dragable_with_icon(o, datas.labels[o], i, "RIGHT", datas.property[o].type);
307
- }
308
- });
309
- }
310
- if (tabOneColum.length) {
311
- tabOneColum.map((o) => {
312
- if(datas.property[o] && datas.property[o].hasOwnProperty("type") ) {
313
- dynamicsOneColumn += dragable_with_icon(o, datas.labels[o], i, "ONE_COLUMN", datas.property[o].type);
314
- }
315
- });
316
- }
317
- }
289
+ stripViewTemplates(datas);
290
+ res.json({
291
+ datas,
292
+ table,
293
+ rows: zFields,
294
+ route,
295
+ selects: Model.keys,
296
+ });
297
+ } catch (e) {
298
+ console.error(e);
299
+ res.status(400).json({ message: e.toString() });
300
+ }
301
+ };
318
302
 
319
- tabView += `<li class="item" draggable="true"><div class='divtabs'>${n}. <span class="tabname"> ${item}</span><input type='hidden' name='tabs[]' value='${item}' /> <button type='button' class='btn btn-sm btn-info edittab' data-toggle="modal" data-target="#modal_tab" data-name="${item}" data-id="${i}" > <i class='fas fa-edit'></i> </button> <button type='button' onclick='deleteTab(this)' class='btn btn-sm btn-danger trashtab'><i class='fas fa-trash'></i> </button></div></li>`;
320
- tabUl += `<li class="nav-item">
321
- <a class="nav-link ${navlink}" id="tabid${i}" data-toggle="tab" href="#tabgo${i}" role="tab" aria-controls="tabgo${i}" aria-selected="${ariaselected}">${item}</a>
303
+ Api.modal = async (body = {}) => {
304
+ try {
305
+ const table = body.table || "";
306
+ const result = body.result || {};
307
+ const others = result.others || {};
308
+ const hasContainer = Object.keys(others).length > 0;
309
+ let datas = emptyDatas();
310
+ let properties = {};
311
+ let html = "";
312
+ let count = 1;
313
+ let tabView = "";
314
+ let tabUl = "";
315
+ let tabContent = "";
316
+ let left = "";
317
+ let right = "";
318
+ let oneColumn = "";
319
+ let ALL_FIELDS = {};
320
+
321
+ if (table && result.id) {
322
+ datas = {
323
+ details: result.details || {},
324
+ labels: result.labels || {},
325
+ tabs: asArray(result.tabs),
326
+ left: asArray(result.left),
327
+ right: asArray(result.right),
328
+ oneColumn: asArray(result.one_column),
329
+ sorting: asArray(result.sorting),
330
+ property: result.properties || {},
331
+ };
332
+ properties = datas.property;
333
+ if (hasContainer) {
334
+ ALL_FIELDS = containerObject(others.LEFT || [], others.RIGHT || [], others.ONE_COLUMN || [], datas.tabs);
335
+ }
336
+
337
+ if (datas.tabs.length) {
338
+ tabUl += '<ul class="nav nav-tabs" id="myTab" role="tablist">';
339
+ tabContent += '<div class="tab-content" id="myTabContent">';
340
+ datas.tabs.forEach((item, i) => {
341
+ const arrName = `arr${i}`;
342
+ const navlink = i === 0 ? " active" : "";
343
+ const ariaselected = i === 0 ? "true" : "false";
344
+ const showActive = i === 0 ? " show active " : "";
345
+ let dynamicsLeft = "";
346
+ let dynamicsRight = "";
347
+ let dynamicsOneColumn = "";
348
+
349
+ if (hasContainer) {
350
+ dynamicsLeft = renderFieldList(ALL_FIELDS.tabLeft[arrName], "LEFT", i, datas, true);
351
+ dynamicsRight = renderFieldList(ALL_FIELDS.tabRight[arrName], "RIGHT", i, datas, true);
352
+ dynamicsOneColumn = renderFieldList(ALL_FIELDS.tabOneColumn[arrName], "ONE_COLUMN", i, datas, true);
353
+ } else {
354
+ dynamicsLeft = renderFieldList(tabFieldsFromClassic(datas.left, arrName), "LEFT", i, datas, false);
355
+ dynamicsRight = renderFieldList(tabFieldsFromClassic(datas.right, arrName), "RIGHT", i, datas, false);
356
+ dynamicsOneColumn = renderFieldList(tabFieldsFromClassic(datas.oneColumn, arrName), "ONE_COLUMN", i, datas, false);
357
+ }
358
+
359
+ tabView += `<li class="item" draggable="true"><div class='divtabs'>${i + 1}. <span class="tabname"> ${item}</span><input type='hidden' name='tabs[]' value='${escapeAttr(item)}' /> <button type='button' class='btn btn-sm btn-info edittab' data-toggle="modal" data-target="#modal_tab" data-name="${escapeAttr(item)}" data-id="${i}" > <i class='fas fa-edit'></i> </button> <button type='button' onclick='deleteTab(this)' class='btn btn-sm btn-danger trashtab'><i class='fas fa-trash'></i> </button></div></li>`;
360
+ tabUl += `<li class="nav-item">
361
+ <a class="nav-link ${navlink}" id="tabid${i}" data-toggle="tab" href="#tabgo${i}" role="tab" aria-controls="tabgo${i}" aria-selected="${ariaselected}">${escapeAttr(item)}</a>
322
362
  </li>`;
323
-
324
- tabContent += `<div class="tab-pane fade ${showActive}" id="tabgo${i}" role="tabpanel" aria-labelledby="tabtabgo${i}">
363
+ tabContent += `<div class="tab-pane fade ${showActive}" id="tabgo${i}" role="tabpanel" aria-labelledby="tabtabgo${i}">
325
364
  <div class="container">
326
365
  <div class="row">
327
366
  <div class="col-md-6"><ol class="mydragable divbox" data-name="LEFT" id="arr${i}">${dynamicsLeft}</ol></div>
@@ -332,864 +371,274 @@ Api.modal = async (body) => {
332
371
  </div>
333
372
  </div>
334
373
  </div>`;
335
- });
336
- tabUl += '</ul>';
337
- tabContent += '</div>';
338
- count = tabs.length + 1;
339
- }
340
- }
341
- }
342
-
343
- // Proses data untuk left, right, dan oneColumn di luar tabs
344
- if (hasContainer) {
345
- // Logika untuk container
346
- let datasLeft = ALL_FIELDS.left || [];
347
- let datasRight = ALL_FIELDS.right || [];
348
- let datasOneColumn = ALL_FIELDS.oneColumn || [];
349
-
350
- if (datasLeft.length) {
351
- datasLeft.forEach(function (item) {
352
- if(!Util.in_array(item, leftsNew)) {
353
- left += makeItemsOl(item, "LEFT", "", datas);
354
- }
355
- });
356
- }
357
- if (datasRight.length) {
358
- datasRight.forEach(function (item) {
359
- if(!Util.in_array(item, rightsNew)) {
360
- right += makeItemsOl(item, "RIGHT", "", datas);
361
- }
362
- });
363
- }
364
- if (datasOneColumn.length) {
365
- datasOneColumn.forEach(function (item) {
366
- if(!Util.in_array(item, oneColumnsNew)) {
367
- oneColumn += makeItemsOl(item, "ONE_COLUMN", "", datas);
368
- }
369
- });
370
- }
371
- } else {
372
- // Logika untuk classic
373
- if (datas.left.length) {
374
- datas.left.forEach(function (item) {
375
- if (properties.hasOwnProperty(item)) {
376
- left += dragable_with_icon(item, datas.labels[item], "", "LEFT", datas.property[item].type);
377
- }
378
- });
379
- }
380
- if (datas.right.length) {
381
- datas.right.forEach(function (item) {
382
- if (properties.hasOwnProperty(item)) {
383
- right += dragable_with_icon(item, datas.labels[item], "", "RIGHT", datas.property[item].type);
384
- }
385
- });
386
- }
387
- if (datas.oneColumn.length) {
388
- datas.oneColumn.forEach(function (item) {
389
- if (properties.hasOwnProperty(item)) {
390
- oneColumn += dragable_with_icon(item, datas.labels[item], "", "ONE_COLUMN", datas.property[item].type);
391
- }
392
- });
393
- }
394
- }
395
-
396
- datas.sorting.forEach(function (item, index) {
397
- if (item == 1) {
398
- html += columnOne(oneColumn);
399
- } else {
400
- html += `<div class="row sortable"><i class="fa fa-arrows icon-floats"></i>${columnLR(left, "LEFT")} ${columnLR(right, "RIGHT")}</div>`;
401
- }
402
- });
403
-
404
- datas.others = others;
405
- let json = {}
406
- json.html = html;
407
- json.datas = datas;
408
- json.tabview = tabView;
409
- json.count = count;
410
- json.tabBox = tabUl + tabContent;
411
-
412
- return json;
413
- } catch (e) {
414
- console.log(e)
415
- return Util.flashError(e.toString());
416
- }
417
- };
418
-
419
- function containerObject(left,right,oneColumn,tabs = []) {
420
-
421
- /*
422
- For generator helper
423
- */
424
-
425
- try {
426
- let obj = {};
427
- let hasTabs = tabs.length;
428
- let leftObj={},rightObj={},oneColumnObj={};
429
- let leftsNew = [], rightsNew = [], oneColumnsNew = [];
430
-
431
- if(hasTabs) {
432
- tabs.forEach(function (tab, i) {
433
- let arrName = `arr${i}`;
434
- if (!leftObj.hasOwnProperty(arrName)) {
435
- leftObj[arrName] = [];
436
- }
437
- if (!rightObj.hasOwnProperty(arrName)) {
438
- rightObj[arrName] = [];
439
- }
440
- if (!oneColumnObj.hasOwnProperty(arrName)) {
441
- oneColumnObj[arrName] = [];
442
- }
443
- });
444
- }
445
-
446
- left.forEach(function (item) {
447
- if(typeof item == "string") {
448
- if(item.includes("___")) {
449
- let arr = item.split("___");
450
- leftObj[arr[1]].push(arr[0]);
451
- leftsNew.push(item)
452
- }
453
- } else {
454
- let keyname = "";
455
- for(let i = 0; i < item.length; i++) {
456
- let zitems = item[i];
457
- if(zitems.length) {
458
- if(zitems[0].includes("___")) {
459
- keyname = zitems[0].split("___")[1];
460
- }
461
- }
462
- }
463
- //console.log(keyname)
464
- if(keyname) {
465
- let myarr = [];
466
- item.forEach(function (myitem) {
467
- let me = []
468
- myitem.forEach(function (inem) {
469
- if(inem.includes("___")) {
470
- me.push(inem.split("___")[0]);
471
- } else {
472
- me.push(inem);
473
- }
474
- })
475
- myarr.push(me)
476
- });
477
- leftObj[keyname].push(myarr);
478
- leftsNew.push(item)
479
- } else {
480
- if(item.includes("___")) {
481
- let arr = item.split("___");
482
- leftObj[arr[1]].push(arr[0]);
483
- leftsNew.push(item)
484
- }
485
- }
486
- }
487
- })
488
-
489
- //right
490
- right.forEach(function (item) {
491
- if(typeof item == "string") {
492
- if(item.includes("___")) {
493
- let arr = item.split("___");
494
- rightObj[arr[1]].push(arr[0]);
495
- rightsNew.push(item)
496
- }
497
- } else {
498
- let keyname = "";
499
- for(let i = 0; i < item.length; i++) {
500
- let zitems = item[i];
501
- if(zitems.length) {
502
- if(zitems[0].includes("___")) {
503
- keyname = zitems[0].split("___")[1];
504
- }
505
- }
506
- }
507
- //console.log(keyname)
508
- if(keyname) {
509
- let myarr = [];
510
- item.forEach(function (myitem) {
511
- let me = []
512
- myitem.forEach(function (inem) {
513
- if(inem.includes("___")) {
514
- me.push(inem.split("___")[0]);
515
- } else {
516
- me.push(inem);
517
- }
518
- });
519
- myarr.push(me)
520
- });
521
- rightObj[keyname].push(myarr);
522
- rightsNew.push(item)
523
- } else {
524
- if(item.includes("___")) {
525
- let arr = item.split("___");
526
- rightObj[arr[1]].push(arr[0]);
527
- rightsNew.push(item)
528
- }
529
- }
530
- }
531
- })
532
-
533
- //oneColumn
534
- oneColumn.forEach(function (item) {
535
- if(typeof item == "string") {
536
- if(item.includes("___")) {
537
- let arr = item.split("___");
538
- oneColumnObj[arr[1]].push(arr[0]);
539
- oneColumnsNew.push(item)
540
- }
541
- } else {
542
- let keyname = "";
543
- for(let i = 0; i < item.length; i++) {
544
- let zitems = item[i];
545
- if(zitems.length) {
546
- if(zitems[0].includes("___")) {
547
- keyname = zitems[0].split("___")[1];
548
- }
549
- }
550
- }
551
- //console.log(keyname)
552
- if(keyname) {
553
- let myarr = [];
554
- item.forEach(function (myitem) {
555
- let me = []
556
- myitem.forEach(function (inem) {
557
- if(inem.includes("___")) {
558
- me.push(inem.split("___")[0]);
559
- } else {
560
- me.push(inem);
561
- }
562
- });
563
- myarr.push(me)
564
- });
565
- oneColumnObj[keyname].push(myarr);
566
- oneColumnsNew.push(item)
567
- } else {
568
- if(item.includes("___")) {
569
- let arr = item.split("___");
570
- oneColumnObj[arr[1]].push(arr[0]);
571
- oneColumnsNew.push(item)
572
- }
573
- }
574
- }
575
374
  });
576
-
577
- //caption left or right
578
- let datasLeft = left.filter(x => !leftsNew.includes(x));
579
- let datasRight = right.filter(x => !rightsNew.includes(x));
580
- let datasOneColumn = oneColumn.filter(x => !oneColumnsNew.includes(x));
581
-
582
- let myObject = {
583
- left : datasLeft || [],
584
- right : datasRight || [],
585
- oneColumn : datasOneColumn || [],
586
- tabLeft : leftObj || [],
587
- tabRight : rightObj|| [],
588
- tabOneColumn : oneColumnObj || [],
589
- };
590
-
591
- return myObject;
592
-
593
- } catch (e) {
594
- console.log(e)
595
- return {};
375
+ tabUl += "</ul>";
376
+ tabContent += "</div>";
377
+ count = datas.tabs.length + 1;
378
+ }
596
379
  }
597
- }
598
-
599
380
 
600
- const makeItemsOl = (o,columnName,tabName, datas) => {
601
- let html = '';
602
- if(typeof o == "string") {
603
- if (datas.property[o] && datas.property[o].hasOwnProperty("type")) {
604
- html += dragable_with_icon(o, datas.labels[o], tabName, columnName, datas.property[o].type);
605
- }
381
+ if (hasContainer) {
382
+ left = renderFieldList(ALL_FIELDS.left, "LEFT", "", datas, true);
383
+ right = renderFieldList(ALL_FIELDS.right, "RIGHT", "", datas, true);
384
+ oneColumn = renderFieldList(ALL_FIELDS.oneColumn, "ONE_COLUMN", "", datas, true);
606
385
  } else {
607
- let hasValues = o.some( function (a) { return a.length });
608
- if(hasValues) {
609
- let columncount = o.length;
610
- let col_md = bootstrapColumn(columncount);
611
- let myhtml = `<li class="container-nav"> <i class="fa fa-arrows icon-floating"></i><div class="row mt-1 mb-1">`;
612
- for(let i =1; i <= columncount; i++) {
613
- let n_i = i -1;
614
- myhtml += `<div class="${col_md}" style="background-color: rgba(0,0,0,.03)"><ol class="divboxlittle container-box"><li><i data-column="${columnName}" class="fa fa-plus-circle fa-2x add-container text-success"></i> </li> `;
615
- if(o[n_i].length) {
616
- o[n_i].forEach(function (myitem) {
617
- if(tabName) {
618
- myitem = myitem.replace('___'+tabName,'')
619
- }
620
- if (datas.property[myitem] && datas.property[myitem].hasOwnProperty("type")) {
621
- myhtml += dragable_with_icon(myitem, datas.labels[myitem], tabName, columnName, datas.property[myitem].type);
622
- }
623
- })
624
- }
625
- myhtml += `</ol> </div>`;
626
- }
627
- myhtml += `</div></li>`;
628
- html += myhtml;
629
- }
630
- }
631
- return html;
632
- }
633
-
634
- const bootstrapColumn = (count) => {
635
- return `col-md-${(12 / count)}`
636
- }
637
-
638
- Api.create = (body) => {
639
- return createTable(body);
640
- }
641
-
642
- Api.properties = (body) => {
643
- try {
644
- //const body = req.body;
645
- //console.log(req.body);
646
- //console.log("ok")
647
- //return;
648
- const details = body.details || [];
649
- const rows = body.rows;
650
- var json = Util.jsonSuccess("Success to update");
651
- if (details.length == 0) {
652
- json = Util.flashError("Please add some data");
653
- return json;
654
- }
655
- const hardcode_grid = body.hardcode_grid || "";
656
-
657
- let left = [], right = [], lefts = [], rights = [], oneColumn = [], oneColumns = [], tabLeft = {},tabRight = {};
658
- const obj = {}
659
- obj.notabs = []
660
- let labels = {};
661
- let hasTab = false;
662
- let tabs = {};
663
-
664
- //check if table is exist or not
665
- const checks = body.checks;
666
- json.create_table = {};
667
- if (!checks) {
668
- const create = createTable(rows[0], true);
669
- json.create_table.sql = create.datas.sql;
670
- json.create_table.post = create.datas.post;
386
+ asArray(datas.left).forEach((item) => {
387
+ if (hasOwn(properties, item)) {
388
+ left += dragable_with_icon(item, datas.labels[item], "", "LEFT", datas.property[item].type);
671
389
  }
672
- labels = rows[0].labels || {};
673
- tabs = !rows[0].tabs ? [] : rows[0].tabs;
674
- if (tabs.length) {
675
- hasTab = true;
676
- tabs.forEach(function (item, i) {
677
- obj['arr' + i] = [];
678
- tabLeft['arr' + i] = [];
679
- tabRight['arr' + i] = [];
680
- });
390
+ });
391
+ asArray(datas.right).forEach((item) => {
392
+ if (hasOwn(properties, item)) {
393
+ right += dragable_with_icon(item, datas.labels[item], "", "RIGHT", datas.property[item].type);
681
394
  }
682
- details.forEach(function (item, index) {
683
- let name = item.name, value = item.value;
684
- if (name.includes("___")) {
685
- const explode = name.split("___");
686
- obj[explode[1]].push(explode[0])
687
- labels[explode[0]] = value;
688
- } else {
689
- if (name == 'LEFT') {
690
- left.push(value);
691
- } else if (name == 'RIGHT') {
692
- right.push(value);
693
- } else if (name == 'ONE_COLUMN') {
694
- oneColumn.push(value);
695
- } else {
696
- obj['notabs'].push(name);
697
- labels[name] = value;
698
- }
699
- }
700
- });
701
-
702
- const sorting = details[1].name == "ONE_COLUMN" ? [1, 2] : [2, 1];
703
- for (let key in obj) {
704
- if (key == "notabs") {
705
- lefts = obj[key].filter((item) => left.includes(item));
706
- rights = obj[key].filter((item) => right.includes(item));
707
- oneColumns = obj[key].filter((item) => oneColumn.includes(item));
708
- } else {
709
- let myobj = {}
710
- myobj[key] = obj[key].filter((item) => left.includes(item));
711
- lefts.push(myobj);
712
-
713
- myobj = {}
714
- myobj[key] = obj[key].filter((item) => right.includes(item));
715
- rights.push(myobj);
716
-
717
- myobj = {}
718
- myobj[key] = obj[key].filter((item) => oneColumn.includes(item));
719
- oneColumns.push(myobj);
720
- }
395
+ });
396
+ asArray(datas.oneColumn).forEach((item) => {
397
+ if (hasOwn(properties, item)) {
398
+ oneColumn += dragable_with_icon(item, datas.labels[item], "", "ONE_COLUMN", datas.property[item].type);
721
399
  }
400
+ });
401
+ }
722
402
 
723
- const post = {}
724
- post.labels = JSON.stringify(labels);
725
- post.details = JSON.stringify(obj);
726
- post.left = JSON.stringify(lefts);
727
- post.right = JSON.stringify(rights);
728
- post.one_column = JSON.stringify(oneColumns);
729
- post.sorting = JSON.stringify(sorting);
730
- post.hardcode_grid = hardcode_grid;
731
- //files
732
-
733
- //get contents or get it from views zgenerator/views
734
- post.router = body.router || fs.readFileSync(generatorApp.DIRECTORY + "/routerApp.ejs", 'utf-8');
735
- post.index_ejs = body.index_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/index.ejs", 'utf-8');
736
- post.indexcss_ejs = body.indexcss_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/indexcss.ejs", 'utf-8');
737
- post.indexjs_ejs = body.indexjs_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/indexjs.ejs", 'utf-8');
738
- post.form_ejs = body.form_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/_form.ejs", 'utf-8');
739
- post.create_ejs = body.create_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/create.ejs", 'utf-8');
740
- post.createjs_ejs = body.createjs_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/createjs.ejs", 'utf-8');
741
- post.update_ejs = body.update_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/update.ejs", 'utf-8');
742
- post.updatejs_ejs = body.updatejs_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/updatejs.ejs", 'utf-8');
743
- post.import_ejs = body.import_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/import.ejs", 'utf-8');
744
- post.importjs_ejs = body.importjs_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/importjs.ejs", 'utf-8');
745
- post.view_ejs = body.view_ejs || fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/view.ejs", 'utf-8');
403
+ asArray(datas.sorting).forEach((item) => {
404
+ html += Number(item) === 1
405
+ ? columnOne(oneColumn)
406
+ : `<div class="row sortable"><i class="fa fa-arrows icon-floats"></i>${columnLR(left, "LEFT")} ${columnLR(right, "RIGHT")}</div>`;
407
+ });
746
408
 
747
- if (post.indexjs_ejs.indexOf(`</script>`) > -1) {
748
- post.indexjs_ejs = Util.replaceAll(post.indexjs_ejs, `</script>`, `</script>`);
749
- }
750
- if (post.createjs_ejs.indexOf(`</script>`) > -1) {
751
- post.createjs_ejs = Util.replaceAll(post.createjs_ejs, `</script>`, `</script>`);
752
- }
753
- if (post.updatejs_ejs.indexOf(`</script>`) > -1) {
754
- post.updatejs_ejs = Util.replaceAll(post.updatejs_ejs, `</script>`, `</script>`);
755
- }
756
- if (post.importjs_ejs.indexOf(`</script>`) > -1) {
757
- post.importjs_ejs = Util.replaceAll(post.importjs_ejs, `</script>`, `</script>`);
758
- }
759
- if (post.view_ejs.indexOf(`</script>`) > -1) {
760
- post.view_ejs = Util.replaceAll(post.view_ejs, `</script>`, `</script>`);
761
- }
762
- json.updateFields = {
763
- post: post,
764
- id: rows[0].id
765
- }
766
- return json;
767
- } catch (e) {
768
- console.log(e)
769
- //res.status(400).json({message: e.toString()})
770
- return Util.flashError(e.toString());
771
- }
409
+ datas.others = others;
410
+ return {
411
+ html,
412
+ datas,
413
+ tabview: tabView,
414
+ count,
415
+ tabBox: tabUl + tabContent,
416
+ };
417
+ } catch (e) {
418
+ return fail(e);
419
+ }
772
420
  };
773
421
 
774
- Api.generate = async (body) => {
775
- try {
776
- console.log('generate');
777
- const json = Util.jsonSuccess("Success");
778
- const result = body.result;
779
- const columns = body.columns;
780
- const constraintList = body.constraintList;
781
- const files = {};
782
- const model = await generatorApp.CREATE_MODEL_API(columns, constraintList, result);
783
- const MYMODEL = model.modelObj;
784
- files.model = model;
785
- files.route = generatorApp.CREATE_ROUTER_API(MYMODEL, result);
786
- files.views = generatorApp.CREATE_VIEWS_API(MYMODEL, result);
787
- json.files = files;
788
- return json;
789
- } catch (e) {
790
- console.log(e)
791
- return Util.flashError(e.toString());
422
+ Api.create = (body) => createTable(body);
423
+ Api.createTable = (data) => createTable(data);
424
+
425
+ Api.properties = (body = {}) => {
426
+ try {
427
+ const details = asArray(body.details);
428
+ const rows = asArray(body.rows);
429
+ if (!details.length) return Util.flashError("Please add some data");
430
+ if (!rows[0]) return Util.flashError("Please add some data");
431
+
432
+ const json = Util.jsonSuccess("Success to update");
433
+ json.create_table = {};
434
+ if (!body.checks) {
435
+ const create = createTable(rows[0]);
436
+ json.create_table.sql = create.sql;
437
+ json.create_table.post = create.post;
792
438
  }
793
- };
794
-
795
- Api.create_field = (body) => {
796
- let json = Util.jsonSuccess("Successfully create field");
797
- console.log(body);
798
- //return false;
799
- try {
800
- let table = body.table || "", position = body.position || "LEFT", label = body.name || "",
801
- type = body.type || "", name = Util.toName(label) || "";
802
- table = table.trim(), label = label.trim(), type = type.trim(), name = name.trim();
803
-
804
- let others = body.others ? JSON.parse(body.others) : {};
805
- let zFields = body.zFields || [];
806
- let details = zFields[0].details;
807
- let labels = zFields[0].labels || {};
808
- let notabs = details.notabs;
809
- let left = zFields[0].left || [];
810
- let right = zFields[0].right || [];
811
- let oneColumn = zFields[0].one_column || [];
812
-
813
- let all = [...left, ...right, ...oneColumn];
814
- all.push('lock');
815
- let properties = zFields[0].properties || {};
816
439
 
817
- //add name with suffix _id if relate to other table
818
- const arr = ['relation', 'typeahead'];
819
- if (Util.in_array(type, arr)) {
820
- name = name + "_id";
821
- }
822
- if (label.length < 2) {
823
- return Util.flashError("Field Name is not complete");
824
- }
825
- if (Util.in_array(name, all)) {
826
- return Util.flashError("Name exist", "");
827
- }
828
- //set position if table go to one column
829
- if (type == "table") {
830
- oneColumn.push(name);
831
- } else {
832
- if (position == "LEFT") {
833
- left.push(name);
834
- } else if (position == "RIGHT") {
835
- right.push(name)
836
- } else {
837
- oneColumn.push(name);
838
- }
839
- }
440
+ const labels = rows[0].labels || {};
441
+ const tabs = asArray(rows[0].tabs);
442
+ const obj = { notabs: [] };
443
+ const tabLeft = {};
444
+ const tabRight = {};
445
+ const left = [];
446
+ const right = [];
447
+ const oneColumn = [];
448
+
449
+ tabs.forEach((_, i) => {
450
+ obj[`arr${i}`] = [];
451
+ tabLeft[`arr${i}`] = [];
452
+ tabRight[`arr${i}`] = [];
453
+ });
840
454
 
841
- /* console.log(JSON.stringify(left))
842
- console.log(JSON.stringify(right))
843
- console.log(JSON.stringify(oneColumn))
844
- console.log(position);*/
455
+ details.forEach((item) => {
456
+ if (!item || item.name == null) return;
457
+ const name = item.name;
458
+ const value = item.value;
459
+ if (String(name).includes("___")) {
460
+ const explode = String(name).split("___");
461
+ if (!obj[explode[1]]) obj[explode[1]] = [];
462
+ obj[explode[1]].push(explode[0]);
463
+ labels[explode[0]] = value;
464
+ return;
465
+ }
466
+ if (name === "LEFT") left.push(value);
467
+ else if (name === "RIGHT") right.push(value);
468
+ else if (name === "ONE_COLUMN") oneColumn.push(value);
469
+ else {
470
+ obj.notabs.push(name);
471
+ labels[name] = value;
472
+ }
473
+ });
845
474
 
846
- let othersLength = Object.keys(others).length;
847
- if(othersLength) {
848
- if (position == "LEFT") {
849
- others.LEFT.push(name);
850
- } else if (position == "RIGHT") {
851
- others.RIGHT.push(name);
852
- } else {
853
- others.ONE_COLUMN.push(name);
854
- }
855
- }
856
- //return false;
475
+ const sorting = details[1] && details[1].name === "ONE_COLUMN" ? [1, 2] : [2, 1];
476
+ let lefts = [];
477
+ let rights = [];
478
+ let oneColumns = [];
479
+ Object.keys(obj).forEach((key) => {
480
+ const filteredLeft = obj[key].filter((item) => left.includes(item));
481
+ const filteredRight = obj[key].filter((item) => right.includes(item));
482
+ const filteredOne = obj[key].filter((item) => oneColumn.includes(item));
483
+ if (key === "notabs") {
484
+ lefts = filteredLeft;
485
+ rights = filteredRight;
486
+ oneColumns = filteredOne;
487
+ } else {
488
+ lefts.push({ [key]: filteredLeft });
489
+ rights.push({ [key]: filteredRight });
490
+ oneColumns.push({ [key]: filteredOne });
491
+ }
492
+ });
857
493
 
858
- notabs.push(name);
859
- let defaultValues = Model[type].defaultValues;
860
- if (defaultValues.hasOwnProperty("tabindex")) {
861
- defaultValues.tabindex = Object.keys(properties).length + 1;
862
- }
863
- if (defaultValues.hasOwnProperty("required")) {
864
- defaultValues.hidden = false;
865
- }
866
- properties[name] = {
867
- label: label,
868
- type: type,
869
- values: defaultValues
870
- }
871
- labels[name] = label;
494
+ const defaults = loadDefaultTemplates();
495
+ const post = {
496
+ labels: JSON.stringify(labels),
497
+ details: JSON.stringify(obj),
498
+ left: JSON.stringify(lefts),
499
+ right: JSON.stringify(rights),
500
+ one_column: JSON.stringify(oneColumns),
501
+ sorting: JSON.stringify(sorting),
502
+ hardcode_grid: body.hardcode_grid || "",
503
+ router: body.router || defaults.router,
504
+ index_ejs: body.index_ejs || defaults.index_ejs,
505
+ indexcss_ejs: body.indexcss_ejs || defaults.indexcss_ejs,
506
+ indexjs_ejs: body.indexjs_ejs || defaults.indexjs_ejs,
507
+ form_ejs: body.form_ejs || defaults.form_ejs,
508
+ create_ejs: body.create_ejs || defaults.create_ejs,
509
+ createjs_ejs: body.createjs_ejs || defaults.createjs_ejs,
510
+ update_ejs: body.update_ejs || defaults.update_ejs,
511
+ updatejs_ejs: body.updatejs_ejs || defaults.updatejs_ejs,
512
+ import_ejs: body.import_ejs || defaults.import_ejs,
513
+ importjs_ejs: body.importjs_ejs || defaults.importjs_ejs,
514
+ view_ejs: body.view_ejs || defaults.view_ejs,
515
+ };
872
516
 
873
- //for relation we need to override values
874
- const relations = ["relation", "dropdown_multi", "table", "typeahead","dragdrop"];
875
- if (Util.in_array(type, relations)) {
876
- var propertyValue = properties[name].values || {}
877
- var relationtable = body.relationtable || "";
878
- var relationfield = body.relationfield || "";
879
- var relationfields = body.relationfields || "";
880
- var relationconcat = body.relationconcat || "";
881
- if (!relationtable.length) {
882
- return Util.flashError("Table Name empty!");
883
- }
884
- if (type != "table") {
885
- if (!relationfield.length) {
886
- return Util.flashError("Label relation empty!");
887
- }
888
- }
889
- propertyValue["table"] = relationtable;
890
- if (type != "table") {
891
- propertyValue["name"] = relationfield;
892
- if (relationconcat == "CONCAT()") {
893
- propertyValue["concat"] = `CONCAT(${relationfield})`;
894
- } else {
895
- propertyValue["concat"] = relationconcat;
896
- }
897
- }
898
- //additional dropdown chain for first time
899
- //TODO simple code
900
- if (relationfields) {
901
- propertyValue["field"] = relationfields;
902
- }
903
- properties[name].values = propertyValue;
904
- }
905
- json.post = {
906
- left: JSON.stringify(left),
907
- right: JSON.stringify(right),
908
- one_column: JSON.stringify(oneColumn),
909
- properties: JSON.stringify(properties),
910
- details: JSON.stringify({notabs: notabs}),
911
- labels: JSON.stringify(labels),
912
- others : JSON.stringify(others)
913
- };
914
- //await connection.update({table: 'zfields', where: {table: table}, data: post})
915
- } catch (err) {
916
- console.log(err.toString())
917
- json = Util.flashError(err.toString())
918
- }
517
+ json.updateFields = { post, id: rows[0].id };
919
518
  return json;
920
- }
921
-
922
-
923
- Api.modal_settings = (body) => {
924
- try {
925
- const json = Util.jsonSuccess("Success")
926
- const name = body.name;
927
- //console.log(body);
928
- let html = "";
929
- let result = body.result;
930
- let properties = result.properties ? result.properties : {};
931
- let property = !properties[name] ? {} : properties[name];
932
- let type = property.type;
933
- //html += `<input type="hidden" value="${req.csrfToken()}" >`;
934
- html += Model.buildWidget(name, type, property.values || {});
935
- json.html = html;
936
- return json;
937
- } catch (e) {
938
- console.log(e)
939
- return Util.flashError(e.toString());
940
- }
941
- }
942
-
943
-
944
- Api.reset = (req,res)=> {
945
- res.json(Api.datas)
946
- }
947
-
948
- Api.datas = {
949
- router : fs.readFileSync(generatorApp.DIRECTORY + "/routerApp.ejs", 'utf-8'),
950
- index_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/index.ejs", 'utf-8'),
951
- indexcss_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/indexcss.ejs", 'utf-8'),
952
- indexjs_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/indexjs.ejs", 'utf-8'),
953
- form_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/_form.ejs", 'utf-8'),
954
- create_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/create.ejs", 'utf-8'),
955
- createjs_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/createjs.ejs", 'utf-8'),
956
- update_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/update.ejs", 'utf-8'),
957
- updatejs_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/updatejs.ejs", 'utf-8'),
958
- import_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/import.ejs", 'utf-8'),
959
- importjs_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/importjs.ejs", 'utf-8'),
960
- view_ejs : fs.readFileSync(generatorApp.DIRECTORY_GENERATOR_VIEWS + "/view.ejs", 'utf-8'),
961
- hardcode_grid : Model.hardcodeGrid
962
- }
963
-
964
- const replaceScript = (string) => {
965
- if (!string) {
966
- return "";
967
- }
968
- let html = string;
969
- if (string.indexOf("script") > -1) {
970
- html = Util.replaceAll(string, `</script>`, `</script>`)
971
- }
972
- return html;
973
- }
974
-
975
- Api.createTable =(data) => {
976
- return createTable(data);
519
+ } catch (e) {
520
+ return fail(e);
521
+ }
977
522
  };
978
523
 
979
- const createTable = (postData, isIgnore) => {
980
- isIgnore = isIgnore || false;
981
- let json = Util.jsonSuccess("Successfully create module");
982
- let labels = {
983
- id: "Id",
984
- company_id: "Company",
985
- lock:"Lock/Unlock",
986
- approval_status:"Approval Status",
987
- approval_history:"Approval History",
988
- created_at: "Created At",
989
- updated_at: "Updated At",
990
- created_by: "Created By",
991
- updated_by: "Updated By"
524
+ Api.generate = async (body = {}) => {
525
+ try {
526
+ const result = body.result || {};
527
+ const model = await generatorApp.CREATE_MODEL_API(body.columns, body.constraintList, result);
528
+ return {
529
+ ...Util.jsonSuccess("Success"),
530
+ files: {
531
+ model,
532
+ route: generatorApp.CREATE_ROUTER_API(model.modelObj, result),
533
+ views: generatorApp.CREATE_VIEWS_API(model.modelObj, result),
534
+ },
992
535
  };
536
+ } catch (e) {
537
+ return fail(e);
538
+ }
539
+ };
993
540
 
994
- let route = Util.toName(postData.route);
995
- let name = postData.name;
996
- name = name.trim();
997
- let forbidden = ['group','copy','command','from','select','distinct','where','year','month','day','ignore','previous','next',
998
- 'start','end','set','setof','show','size','row','rows','return','order'];
999
- if(forbidden.includes(name)) {
1000
- json = Util.flashError("Module Name is Forbidden, try using other module name..", "route");
1001
- return json;
1002
- }
1003
- if (!name.length) {
1004
- json = Util.flashError("Module Name Empty", "route");
1005
- return json;
1006
- }
1007
- if (Util.in_array(name, configGenerator.notGenerateTable)) {
1008
- json = Util.flashError("Module Name Exist", "route");
1009
- return json;
1010
- }
1011
- if (!route.length) {
1012
- json = Util.flashError("Route Empty", "route");
1013
- return json;
1014
- }
1015
- try {
1016
- const datas = Api.datas;
1017
- let post = {
1018
- table: Util.toName(name),
1019
- name: name,
1020
- route: route,
1021
- labels: JSON.stringify(labels),
1022
- left: "[]",
1023
- right: "[]",
1024
- sorting: "[2,1]",
1025
- details: JSON.stringify({
1026
- notabs: []
1027
- }),
1028
- hardcode_grid: Model.hardcodeGrid,
1029
- company_id : 1,
1030
- }
1031
- for(let key in datas) {
1032
- post[key] = datas[key];
1033
- }
1034
- //console.log(datas.router);
1035
-
1036
- let sql = `
1037
- CREATE TABLE ${post.table} (
1038
- id BIGSERIAL PRIMARY KEY,
1039
- company_id BIGINT NOT NULL,
1040
- lock smallint default 0,
1041
- approval_status smallint DEFAULT 1,
1042
- approval_history jsonb[] DEFAULT NULL,
1043
- updated_by BIGINT DEFAULT NULL,
1044
- created_by BIGINT DEFAULT NULL,
1045
- created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
1046
- updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
1047
- CONSTRAINT fk_${post.table}_company_id FOREIGN KEY (company_id) REFERENCES zcompany (id)
1048
-
1049
- );`;
1050
- console.log(sql)
1051
- //await connection.query(sql);
1052
- json.post = post;
1053
- json.sql = sql;
1054
- } catch (e) {
1055
- json = Util.flashError(e.toString(), "")
1056
- }
1057
- //console.log(JSON.stringify(json))
1058
- return json
1059
- }
1060
-
1061
- const columnLR = (items, dataName) => {
1062
- return `<div class="col-md-6"><ol class="mydragable divboxlittle" data-name="${dataName}">${items}</ol></div>`;
1063
- }
1064
-
1065
- const columnOne = (items) => {
1066
- return `<div class="row sortable"><i class="fa fa-arrows icon-float"></i><div class="col-md-12"><ol class="mydragable divboxlittle" data-name="ONE_COLUMN">${items}</ol></div></div>`;
1067
- }
1068
-
1069
- /*
1070
- const fieldsTable = (rowsFields) => {
1071
- let rows = generateFields(rowsFields);
1072
- let arr = [];
1073
- if (rows.length > 0) {
1074
- for (let i = 0; i < rows.length; i++) {
1075
- if (!Util.in_array(rows[i].Field, config.generator.notRenderField))
1076
- arr.push({name: rows[i].Field, label: Util.fieldToName(rows[i].Field)});
1077
- }
1078
- }
1079
- return arr;
1080
- }*/
1081
-
1082
- const generateFields = async (rowsFields) => {
1083
- let rows = []
1084
- //let sql = connection.describeTable(table);
1085
- //let rowsFields = await connection.query(sql);
1086
- for (let k = 0; k < rowsFields.length; k++) {
1087
- let obj = rowsFields[k];
1088
- let Type = obj.Type;
1089
- if (Type.indexOf("character varying") > -1) {
1090
- obj.Type = Util.replaceAll(Type, "character varying", "varchar");
1091
- } else if (Type.indexOf("integer()") > -1) {
1092
- obj.Type = "int(11)";
1093
- } else if (Type.indexOf("smallint()") > -1) {
1094
- obj.Type = "int(4)";
1095
- } else if (Type.indexOf("()")) {
1096
- obj.Type = Util.replaceAll(Type, "()", "");
1097
- }
1098
-
1099
- rows.push(obj)
1100
- }
1101
- return rows;
1102
- }
1103
-
1104
- //drop down chains
1105
- /*
1106
- const chainings = (results, rows, arr) => {
1107
- //var results = await connection.query(connection.showFields(table));
1108
- var obj = {};
1109
- var tableObj = {}
1110
- var ret = {}
1111
- for (var i = 0; i < results.length; i++) {
1112
- var result = results[i];
1113
- if (Util.in_array(result.COLUMN_NAME, arr)) {
1114
- obj[result.COLUMN_NAME] = {
1115
- table: result.REFERENCED_TABLE_NAME
1116
- }
1117
- tableObj[result.REFERENCED_TABLE_NAME] = result.COLUMN_NAME;
1118
- }
1119
- }
1120
-
1121
- for (var key in obj) {
1122
- //var rows = await connection.query(connection.showFields(obj[key].table));
1123
- rows.forEach(function (row) {
1124
- for (var q in obj) {
1125
- console.log(row.REFERENCED_TABLE_NAME + ' == ' + obj[q].table)
1126
- if (row.REFERENCED_TABLE_NAME == obj[q].table) {
1127
- if (!obj[q].chains) {
1128
- obj[q].chains = {};
1129
- }
1130
- obj[q].chains[key] = {
1131
- column: row.COLUMN_NAME,
1132
- table: row.TABLE_NAME
1133
- }
1134
- }
1135
- }
1136
- });
541
+ Api.create_field = (body = {}) => {
542
+ let json = Util.jsonSuccess("Successfully create field");
543
+ try {
544
+ const position = body.position || "LEFT";
545
+ const label = String(body.name || "").trim();
546
+ const type = String(body.type || "").trim();
547
+ let name = String(Util.toName(label) || "").trim();
548
+ const others = parseJson(body.others, {});
549
+ const zFields = asArray(body.zFields);
550
+ const current = zFields[0];
551
+ if (!current) return Util.flashError("Field data is empty");
552
+ if (label.length < 2) return Util.flashError("Field Name is not complete");
553
+ if (!type || !Model[type] || !Model[type].defaultValues) return Util.flashError("Invalid field type");
554
+
555
+ if (Util.in_array(type, RELATION_NAME_TYPES)) name = `${name}_id`;
556
+
557
+ const details = current.details || { notabs: [] };
558
+ const labels = current.labels || {};
559
+ const notabs = asArray(details.notabs);
560
+ const left = asArray(current.left);
561
+ const right = asArray(current.right);
562
+ const oneColumn = asArray(current.one_column);
563
+ const properties = isPlainObject(current.properties) ? current.properties : {};
564
+ const all = [...left, ...right, ...oneColumn, "lock"];
565
+ if (Util.in_array(name, all)) return Util.flashError("Name exist", "");
566
+
567
+ if (type === "table" || (position !== "LEFT" && position !== "RIGHT")) oneColumn.push(name);
568
+ else if (position === "LEFT") left.push(name);
569
+ else right.push(name);
570
+
571
+ const hasOthers = Object.keys(others).length > 0;
572
+ others.LEFT = asArray(others.LEFT);
573
+ others.RIGHT = asArray(others.RIGHT);
574
+ others.ONE_COLUMN = asArray(others.ONE_COLUMN);
575
+ if (hasOthers) {
576
+ if (position === "LEFT") others.LEFT.push(name);
577
+ else if (position === "RIGHT") others.RIGHT.push(name);
578
+ else others.ONE_COLUMN.push(name);
1137
579
  }
1138
- return obj;
1139
- }
1140
- */
1141
580
 
1142
- const zFieldsProperty = async (table, fields) => {
1143
- let data = {}
1144
- data.table = table;
1145
- data.name = Util.fieldToName(table);
1146
- data.route = table;
1147
- let label = {}
1148
- let details = [], lefts = [], rights = [];
1149
- let nots = Util.nots;
1150
- //let fields = await connection.query(connection.showFullFields(table));
1151
- fields.forEach(function (item) {
1152
- label[item.Field] = Util.fieldToName(item.Field);
1153
- });
1154
- data.labels = JSON.stringify(label);
1155
- let num = 1;
1156
- fields.forEach(function (item) {
1157
- if (!Util.in_array(item.Field, nots)) {
1158
- details.push(item.Field);
1159
- if (num % 2 == 0) {
1160
- rights.push(item.Field)
1161
- } else {
1162
- lefts.push(item.Field)
1163
- }
1164
- num++;
1165
- }
1166
- });
1167
- let notabs = {
1168
- notabs: details
581
+ notabs.push(name);
582
+ const defaultValues = { ...(Model[type].defaultValues || {}) };
583
+ if (hasOwn(defaultValues, "tabindex")) defaultValues.tabindex = Object.keys(properties).length + 1;
584
+ if (hasOwn(defaultValues, "required")) defaultValues.hidden = false;
585
+ properties[name] = { label, type, values: defaultValues };
586
+ labels[name] = label;
587
+
588
+ if (Util.in_array(type, RELATION_TYPES)) {
589
+ const propertyValue = properties[name].values || {};
590
+ const relationtable = body.relationtable || "";
591
+ const relationfield = body.relationfield || "";
592
+ if (!relationtable.length) return Util.flashError("Table Name empty!");
593
+ if (type !== "table" && !relationfield.length) return Util.flashError("Label relation empty!");
594
+ propertyValue.table = relationtable;
595
+ if (type !== "table") {
596
+ propertyValue.name = relationfield;
597
+ propertyValue.concat = body.relationconcat === "CONCAT()" ? `CONCAT(${relationfield})` : body.relationconcat;
598
+ }
599
+ if (body.relationfields) propertyValue.field = body.relationfields;
600
+ properties[name].values = propertyValue;
1169
601
  }
1170
602
 
1171
- data.details = JSON.stringify(notabs);
1172
- data.left = JSON.stringify(lefts);
1173
- data.right = JSON.stringify(rights);
1174
- return data;
603
+ json.post = {
604
+ left: JSON.stringify(left),
605
+ right: JSON.stringify(right),
606
+ one_column: JSON.stringify(oneColumn),
607
+ properties: JSON.stringify(properties),
608
+ details: JSON.stringify({ notabs }),
609
+ labels: JSON.stringify(labels),
610
+ others: JSON.stringify(others),
611
+ };
612
+ return json;
613
+ } catch (err) {
614
+ return fail(err);
615
+ }
1175
616
  };
1176
617
 
618
+ Api.modal_settings = (body = {}) => {
619
+ try {
620
+ const result = body.result || {};
621
+ const properties = result.properties || {};
622
+ const property = properties[body.name] || {};
623
+ return {
624
+ ...Util.jsonSuccess("Success"),
625
+ html: Model.buildWidget(body.name, property.type, property.values || {}),
626
+ };
627
+ } catch (e) {
628
+ return fail(e);
629
+ }
630
+ };
1177
631
 
1178
- const dragable_with_icon = (name, label, tab, leftright, type = "") => {
1179
- let myname = tab === "" ? name : name + "___arr" + tab;
1180
- leftright = leftright || "LEFT";
1181
- var typeName = type ? Model.keys[type] : "";
1182
- return `<li>
1183
- <div class="input-group">
1184
- <div class="input-group-prepend">
1185
- <span class="input-group-text modal_setting" data-type="${typeName}" data-name="${name}" data-label="${label}" ><i class="fa fa-cog text-info modal_setting" data-type="${typeName}" data-name="${name}" data-label="${label}"></i> </span>
1186
- <span class="input-group-text can-copy" data-name="${name}" title="click to copy"><i class="fa fa-copy"></i></span>
1187
- <span class="input-group-text" >${name}</span>
1188
- <input type="text" class="form-control" data-name="${name}" name="${myname}" value="${label}">
1189
- <input type="hidden" name="${leftright}" value="${name}">
1190
- </div>
1191
- </div><br></li>`;
632
+ Api.reset = (req, res) => {
633
+ res.json(Api.datas);
1192
634
  };
1193
635
 
636
+ Object.defineProperty(Api, "datas", {
637
+ enumerable: true,
638
+ get() {
639
+ if (!Api._datas) Api._datas = loadDefaultTemplates();
640
+ return Api._datas;
641
+ },
642
+ });
1194
643
 
1195
644
  module.exports = Api;