zet-lib 3.1.6 → 3.2.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.
package/lib/Model.js CHANGED
@@ -1042,9 +1042,6 @@ Model.number = {
1042
1042
  "defaultValue",
1043
1043
  "inputGroupLeft",
1044
1044
  "inputGroupRight",
1045
- "digitDecimal",
1046
- "decimalPlaces",
1047
- "thousandSeparator",
1048
1045
  "information",
1049
1046
  ],
1050
1047
  attributes: ["min", "max"],
@@ -1058,9 +1055,6 @@ Model.number = {
1058
1055
  defaultValue: "Default Value",
1059
1056
  inputGroupLeft: "Input Group Left",
1060
1057
  inputGroupRight: "Input Group Right",
1061
- digitDecimal:"Digit Decimal",
1062
- decimalPlaces:"Decimal Places",
1063
- thousandSeparator:"Use 1000 Separator",
1064
1058
  information: "Additional Information",
1065
1059
  },
1066
1060
  defaultValues: {
@@ -1073,9 +1067,6 @@ Model.number = {
1073
1067
  defaultValue: null,
1074
1068
  inputGroupLeft: "",
1075
1069
  inputGroupRight: "",
1076
- digitDecimal: 0,
1077
- decimalPlaces:",",
1078
- thousandSeparator:".",
1079
1070
  information: "",
1080
1071
  },
1081
1072
  typies: {
@@ -1115,18 +1106,6 @@ Model.number = {
1115
1106
  tag: "input",
1116
1107
  type: "text",
1117
1108
  },
1118
- digitDecimal: {
1119
- tag: "input",
1120
- type: "number",
1121
- },
1122
- decimalPlaces: {
1123
- tag: "input",
1124
- type: "text",
1125
- },
1126
- thousandSeparator: {
1127
- tag: "input",
1128
- type: "text",
1129
- },
1130
1109
  information: {
1131
1110
  tag: "textarea",
1132
1111
  type: "",
@@ -2418,7 +2397,8 @@ Model.relation = {
2418
2397
  "hidden",
2419
2398
  "isSearch",
2420
2399
  "order_by",
2421
- "import_field"
2400
+ "import_field",
2401
+ "relation_info"
2422
2402
  ],
2423
2403
  labels: {
2424
2404
  required: "Required",
@@ -2435,7 +2415,8 @@ Model.relation = {
2435
2415
  hidden: "Hidden",
2436
2416
  isSearch:"Auto complete Search",
2437
2417
  order_by : "Order By",
2438
- import_field :"Default Import Field (id)"
2418
+ import_field :"Default Import Field (id)",
2419
+ relation_info : "Relation Data"
2439
2420
  },
2440
2421
  defaultValues: {
2441
2422
  required: false,
@@ -2452,7 +2433,8 @@ Model.relation = {
2452
2433
  hidden: false,
2453
2434
  isSearch:false,
2454
2435
  order_by : "",
2455
- import_field :"id"
2436
+ import_field :"id",
2437
+ relation_info : "",
2456
2438
  },
2457
2439
  typies: {
2458
2440
  required: {
@@ -2515,6 +2497,10 @@ Model.relation = {
2515
2497
  tag: "input",
2516
2498
  type: "text",
2517
2499
  },
2500
+ relation_info : {
2501
+ tag: "textarea",
2502
+ rows: "3",
2503
+ },
2518
2504
  },
2519
2505
  comment: (obj) => {
2520
2506
  return `select`;
@@ -392,6 +392,16 @@ me.prepare = (MYMODEL) => {
392
392
  widgets[key].please_select = property.values.please_select;
393
393
  widgets[key].order_by = property.values.order_by;
394
394
  widgets[key].import_field = property.values.import_field || "id";
395
+ widgets[key].relation_info = property.values.relation_info ? true : false;
396
+ if(widgets[key].relation_info) {
397
+ //create file info to runtime
398
+ let dirInfo = `${dirRoot}/public/runtime/info/${MYMODEL.table}`
399
+ //Util.writeFile(`${dirRoot}/runtime/info/${MYMODEL.tab}`)
400
+ if(!fs.existsSync(dirInfo)) {
401
+ fs.mkdirSync(dirInfo, { recursive: true });
402
+ }
403
+ fs.writeFileSync(`${dirInfo}/${key}.txt`, property.values.relation_info);
404
+ }
395
405
  break;
396
406
  case "dragdrop":
397
407
  widgets[key].table = property.values.table;
package/lib/io.js CHANGED
@@ -1,5 +1,5 @@
1
- const io = require('socket.io')();
2
-
1
+ const { Server } = require('socket.io');
2
+ const io = new Server(); // TANPA listen/attach di sini
3
3
  //room = token
4
4
  let socketArray = [];
5
5
 
@@ -19,7 +19,7 @@ io.on('connection', function (socket) {
19
19
  });
20
20
  // Unset session data via socket
21
21
  socket.on('checksession', function() {
22
- // console.log('Received checksession message');
22
+ // console.log('Received checksession message');
23
23
  // console.log('socket.handshake session data is %j.', socket.handshake.session);
24
24
  socket.emit('checksession', socket.handshake.session);
25
25
  });
package/lib/zAppRouter.js CHANGED
@@ -2269,4 +2269,90 @@ router.post("/zcompress-dropbox", async (req, res) => {
2269
2269
  res.json(Util.jsonSuccess("Compress all images completed..."));
2270
2270
  });
2271
2271
 
2272
+ router.post('/zcall-information_info', async(req,res) => {
2273
+ let data = ''
2274
+ try {
2275
+ const {table, elementId, myvalue} = req.body;
2276
+ let content = Util.readFile(`${dirRoot}/public/runtime/info/${table}/${elementId}.txt`)
2277
+ data = content;
2278
+
2279
+ // Fungsi untuk mengekstrak semua field dari template
2280
+ const extractFields = (template) => {
2281
+ const regex = /\{\{([^}]+)\}\}/g;
2282
+ const fields = [];
2283
+ let match;
2284
+ while ((match = regex.exec(template)) !== null) {
2285
+ fields.push(match[1].trim());
2286
+ }
2287
+ return [...new Set(fields)]; // Remove duplicates
2288
+ };
2289
+
2290
+ if(content){
2291
+ let others = {}
2292
+ const MYMODELS = myCache.get("MYMODELS");
2293
+ let mymodel = MYMODELS[table];
2294
+ let mytable = mymodel.widgets[elementId].table;
2295
+ //console.log(mymodel);
2296
+ const result = await connection.result({
2297
+ table: mytable,
2298
+ where: {
2299
+ id: myvalue,
2300
+ },
2301
+ });
2302
+ //others = Object.assign({}, result);
2303
+ let fields = extractFields(content);
2304
+ fields.map((item) => {
2305
+ if(item.includes(".")){
2306
+ let name = item.split(".")[0];
2307
+ others[name] = {};
2308
+ }
2309
+ })
2310
+
2311
+ for(let key in others){
2312
+ let modelkey = MYMODELS[mytable].widgets[key].table;
2313
+ const resultkey = await connection.result({
2314
+ table: modelkey,
2315
+ where: {
2316
+ id: result[key],
2317
+ },
2318
+ });
2319
+ others[key] = resultkey;
2320
+ ///disini saya ingin replace content dengan format {{}}
2321
+ //data = data.replace(`{{${key}}}`, resultkey[key]);
2322
+
2323
+ }
2324
+ let dataReplace = result;
2325
+ for(let key in others){
2326
+ dataReplace[key] = others[key];
2327
+ }
2328
+ console.log(dataReplace);
2329
+
2330
+ //saya ingin replace data dengan dataReplace
2331
+ // Fungsi untuk mendapatkan nilai dari path nested object
2332
+ const getNestedValue = (obj, path) => {
2333
+ const keys = path.split('.');
2334
+ let value = obj;
2335
+ for (const key of keys) {
2336
+ if (value && typeof value === 'object' && key in value) {
2337
+ value = value[key];
2338
+ } else {
2339
+ return ''; // Return empty string if path not found
2340
+ }
2341
+ }
2342
+ return value !== null && value !== undefined ? String(value) : '';
2343
+ };
2344
+
2345
+ // Replace semua placeholder {{field}} dengan nilai dari dataReplace
2346
+ data = content.replace(/\{\{([^}]+)\}\}/g, (match, fieldPath) => {
2347
+ const trimmedPath = fieldPath.trim();
2348
+ return getNestedValue(dataReplace, trimmedPath);
2349
+ });
2350
+
2351
+ }
2352
+ } catch (e) {
2353
+ console.log(e)
2354
+ }
2355
+ res.json(data)
2356
+ })
2357
+
2272
2358
  module.exports = router;
package/lib/zRoute.js CHANGED
@@ -4175,6 +4175,8 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
4175
4175
  let joinsFields = [];
4176
4176
  let selectize = [];
4177
4177
  let moneys = [];
4178
+ let hasRelationInfo = false;
4179
+ let relationInfos = [];
4178
4180
  if (MYMODEL.joins) {
4179
4181
  joinsFields = MYMODEL.joins.list;
4180
4182
  }
@@ -4267,6 +4269,11 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
4267
4269
  selectize.push(key);
4268
4270
  hasSelectize = true;
4269
4271
  }
4272
+ if (widgets[key].relation_info) {
4273
+ hasRelationInfo = true;
4274
+ relationInfos.push(key);
4275
+ }
4276
+
4270
4277
  }
4271
4278
  }
4272
4279
  }
@@ -4276,6 +4283,27 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
4276
4283
  headObj.datepicker = datePickerObj.head;
4277
4284
  endObj.datepicker = datePickerObj.end;
4278
4285
  }
4286
+ if(hasRelationInfo){
4287
+ scriptForm += `function callRelationInfo(table, elementId, myvalue) {
4288
+ ajaxPost('/zcall-information_info',{table: table, elementId: elementId, myvalue: myvalue}, function (data) {
4289
+ let elemclass = 'information_' + elementId;
4290
+ if($("."+elemclass).length > 0){
4291
+ $("."+elemclass).html(data);
4292
+ } else {
4293
+ $(".div"+elementId).append('<div class="' + elemclass + ' mt-2 boxy">' + data + '</div>');
4294
+ }
4295
+ })
4296
+ } \r\n`
4297
+ let infoScript = '';
4298
+ relationInfos.map((relationInfo) => {
4299
+ infoScript += `$("#${relationInfo}").on('change', function () {
4300
+ callRelationInfo('${MYMODEL.table}','${relationInfo}', $(this).val())
4301
+ })
4302
+ callRelationInfo('${MYMODEL.table}','${relationInfo}', $("#${relationInfo}").val()) \r\n`
4303
+ })
4304
+
4305
+ scriptForm += `$(function() {${infoScript}});`;
4306
+ }
4279
4307
  if (hasNumber) {
4280
4308
  let numberObj = moduleLib.number(req, res);
4281
4309
  scriptForm += numberObj.script;
@@ -6178,84 +6206,211 @@ zRoute.history = async (
6178
6206
  users,
6179
6207
  results = []
6180
6208
  ) => {
6181
- //html
6182
- let html = "";
6183
- let unhistories = [
6184
- "created_by",
6185
- "updated_by",
6186
- "created_at",
6187
- "updated_at",
6188
- "company_id",
6189
- "id",
6190
- ];
6191
- let arrHistories = [];
6192
- let arrDataAttributes = [];
6193
- let objectType = [
6194
- "dropzone",
6195
- "dropdown_multi",
6196
- "dropdown_checkbox",
6197
- "array",
6198
- "json_array",
6199
- "table",
6200
- "json",
6201
- ];
6202
- const widgets = MYMODEL.widgets;
6203
- let fields = Object.keys(MYMODEL.labels);
6204
- if (results.length == 0) {
6205
- html = "No History...";
6206
- } else {
6207
- for (const result of results) {
6208
- let obj = {};
6209
- let data1 = result.data_1;
6210
- let data2 = result.data_2;
6211
-
6212
- for (const key in data1) {
6213
- if (!unhistories.includes(key)) {
6214
- if (fields.includes(key)) {
6215
- if (data1[key] || data2[key]) {
6216
- let name = MYMODEL.widgets[key].name;
6217
- if (objectType.includes(name)) {
6218
- if (JSON.stringify(data1[key]) != JSON.stringify(data2[key])) {
6219
- obj[key] = [data1[key], data2[key]];
6220
- }
6221
- } else {
6222
- if (data1[key] != data2[key]) {
6223
- obj[key] = [data1[key], data2[key]];
6209
+ try {
6210
+ //html
6211
+ let html = "";
6212
+
6213
+ // Validasi input parameter
6214
+ if (!MYMODEL || !MYMODEL.widgets || !MYMODEL.labels) {
6215
+ return "Invalid model configuration";
6216
+ }
6217
+
6218
+ if (!users || typeof users !== 'object') {
6219
+ users = {};
6220
+ }
6221
+
6222
+ if (!Array.isArray(results)) {
6223
+ results = [];
6224
+ }
6225
+
6226
+ let unhistories = [
6227
+ "created_by",
6228
+ "updated_by",
6229
+ "created_at",
6230
+ "updated_at",
6231
+ "company_id",
6232
+ "id",
6233
+ ];
6234
+ let arrHistories = [];
6235
+ let arrDataAttributes = [];
6236
+ let objectType = [
6237
+ "dropzone",
6238
+ "dropdown_multi",
6239
+ "dropdown_checkbox",
6240
+ "array",
6241
+ "json_array",
6242
+ "table",
6243
+ "json",
6244
+ ];
6245
+ const widgets = MYMODEL.widgets;
6246
+ let fields = Object.keys(MYMODEL.labels || {});
6247
+
6248
+ if (results.length == 0) {
6249
+ html = "No History...";
6250
+ } else {
6251
+ for (const result of results) {
6252
+ try {
6253
+ if (!result || typeof result !== 'object') {
6254
+ continue;
6255
+ }
6256
+
6257
+ let obj = {};
6258
+ let data1 = result.data_1 || {};
6259
+ let data2 = result.data_2 || {};
6260
+
6261
+ if (!data1 || typeof data1 !== 'object') {
6262
+ data1 = {};
6263
+ }
6264
+ if (!data2 || typeof data2 !== 'object') {
6265
+ data2 = {};
6266
+ }
6267
+
6268
+ for (const key in data1) {
6269
+ try {
6270
+ if (!unhistories.includes(key)) {
6271
+ if (fields.includes(key)) {
6272
+ if (data1[key] || data2[key]) {
6273
+ // Validasi widget exists
6274
+ if (!MYMODEL.widgets[key] || !MYMODEL.widgets[key].name) {
6275
+ continue;
6276
+ }
6277
+
6278
+ let name = MYMODEL.widgets[key].name;
6279
+ if (objectType.includes(name)) {
6280
+ try {
6281
+ if (JSON.stringify(data1[key]) != JSON.stringify(data2[key])) {
6282
+ obj[key] = [data1[key], data2[key]];
6283
+ }
6284
+ } catch (jsonError) {
6285
+ // Jika JSON.stringify error, gunakan perbandingan biasa
6286
+ if (data1[key] != data2[key]) {
6287
+ obj[key] = [data1[key], data2[key]];
6288
+ }
6289
+ }
6290
+ } else {
6291
+ if (data1[key] != data2[key]) {
6292
+ obj[key] = [data1[key], data2[key]];
6293
+ }
6294
+ }
6295
+ }
6224
6296
  }
6225
6297
  }
6298
+ } catch (keyError) {
6299
+ // Skip key yang error, lanjut ke key berikutnya
6300
+ console.error(`Error processing key ${key}:`, keyError);
6301
+ continue;
6226
6302
  }
6227
6303
  }
6304
+
6305
+ if (Object.keys(obj).length > 0) {
6306
+ arrHistories.push(obj);
6307
+ arrDataAttributes.push({
6308
+ date1: result.data_1_date || null,
6309
+ date2: result.data_2_date || null,
6310
+ by1: (result.data_1 && result.data_1.updated_by) || null,
6311
+ by2: result.created_by || null,
6312
+ });
6313
+ }
6314
+ } catch (resultError) {
6315
+ // Skip result yang error, lanjut ke result berikutnya
6316
+ console.error('Error processing result:', resultError);
6317
+ continue;
6228
6318
  }
6229
6319
  }
6230
- if (Object.keys(obj).length > 0) {
6231
- arrHistories.push(obj);
6232
- arrDataAttributes.push({
6233
- date1: result.data_1_date,
6234
- date2: result.data_2_date,
6235
- by1: result.data_1.updated_by,
6236
- by2: result.created_by,
6237
- });
6238
- }
6239
- }
6240
6320
 
6241
- let index = 0;
6242
- for (const item of arrHistories) {
6243
- let obj1 = {};
6244
- let obj2 = {};
6245
- for (let key in item) {
6246
- obj1[key] = item[key][0];
6247
- obj2[key] = item[key][1];
6248
- }
6249
- let viewFormsSync1 = await zRoute.viewFormsSync(req, res, MYMODEL, obj1);
6250
- let viewFormsSync2 = await zRoute.viewFormsSync(req, res, MYMODEL, obj2);
6251
- let html1 = "";
6252
- let html2 = "";
6253
- for (let key in item) {
6254
- html1 += viewFormsSync1.build[key];
6255
- html2 += viewFormsSync2.build[key];
6256
- }
6321
+ let index = 0;
6322
+ for (const item of arrHistories) {
6323
+ try {
6324
+ if (!item || typeof item !== 'object') {
6325
+ index++;
6326
+ continue;
6327
+ }
6328
+
6329
+ let obj1 = {};
6330
+ let obj2 = {};
6331
+ for (let key in item) {
6332
+ if (Array.isArray(item[key]) && item[key].length >= 2) {
6333
+ obj1[key] = item[key][0];
6334
+ obj2[key] = item[key][1];
6335
+ }
6336
+ }
6337
+
6338
+ let viewFormsSync1, viewFormsSync2;
6339
+ try {
6340
+ viewFormsSync1 = await zRoute.viewFormsSync(req, res, MYMODEL, obj1);
6341
+ viewFormsSync2 = await zRoute.viewFormsSync(req, res, MYMODEL, obj2);
6342
+ } catch (viewFormsError) {
6343
+ console.error('Error in viewFormsSync:', viewFormsError);
6344
+ index++;
6345
+ continue;
6346
+ }
6347
+
6348
+ if (!viewFormsSync1 || !viewFormsSync1.build) {
6349
+ viewFormsSync1 = { build: {} };
6350
+ }
6351
+ if (!viewFormsSync2 || !viewFormsSync2.build) {
6352
+ viewFormsSync2 = { build: {} };
6353
+ }
6354
+
6355
+ let html1 = "";
6356
+ let html2 = "";
6357
+ for (let key in item) {
6358
+ html1 += (viewFormsSync1.build[key] || '');
6359
+ html2 += (viewFormsSync2.build[key] || '');
6360
+ }
6361
+
6362
+ // Validasi arrDataAttributes[index]
6363
+ const dataAttr = arrDataAttributes[index] || {};
6364
+ const date1 = dataAttr.date1 || null;
6365
+ const date2 = dataAttr.date2 || null;
6366
+ const by1 = dataAttr.by1 || null;
6367
+ const by2 = dataAttr.by2 || null;
6257
6368
 
6258
- html += `<div class="row">
6369
+ // Validasi users sebelum mengakses fullname
6370
+ let user1Fullname = '';
6371
+ let user2Fullname = '';
6372
+
6373
+ try {
6374
+ if (by1 && users[by1] && users[by1].fullname) {
6375
+ user1Fullname = users[by1].fullname;
6376
+ } else {
6377
+ user1Fullname = by1 || 'Unknown';
6378
+ }
6379
+ } catch (user1Error) {
6380
+ user1Fullname = by1 || 'Unknown';
6381
+ }
6382
+
6383
+ try {
6384
+ if (by2 && users[by2] && users[by2].fullname) {
6385
+ user2Fullname = users[by2].fullname;
6386
+ } else {
6387
+ user2Fullname = by2 || 'Unknown';
6388
+ }
6389
+ } catch (user2Error) {
6390
+ user2Fullname = by2 || 'Unknown';
6391
+ }
6392
+
6393
+ // Format date dengan error handling
6394
+ let formattedDate1 = '';
6395
+ let formattedDate2 = '';
6396
+
6397
+ try {
6398
+ if (date1 && Util && Util.dateFormat) {
6399
+ formattedDate1 = Util.dateFormat(date1, "DD MMM YYYY HH:mm") || "";
6400
+ }
6401
+ } catch (date1Error) {
6402
+ formattedDate1 = '';
6403
+ }
6404
+
6405
+ try {
6406
+ if (date2 && Util && Util.dateFormat) {
6407
+ formattedDate2 = Util.dateFormat(date2, "DD MMM YYYY HH:mm") || "";
6408
+ }
6409
+ } catch (date2Error) {
6410
+ formattedDate2 = '';
6411
+ }
6412
+
6413
+ html += `<div class="row">
6259
6414
  <!-- timeline item 1 left dot -->
6260
6415
  <div class="col-auto text-center flex-column d-none d-sm-flex">
6261
6416
  <div class="row h-50">
@@ -6276,15 +6431,7 @@ zRoute.history = async (
6276
6431
  <div class="col-md-6">
6277
6432
  <div class="card">
6278
6433
  <div class="card-body">
6279
- <div class="float-end text-muted text-end">${
6280
- Util.dateFormat(
6281
- arrDataAttributes[index]
6282
- .date1,
6283
- "DD MMM YYYY HH:mm"
6284
- ) || ""
6285
- }<br><small>${
6286
- users[arrDataAttributes[index].by1].fullname
6287
- }</small></div>
6434
+ <div class="float-end text-muted text-end">${formattedDate1}<br><small>${user1Fullname}</small></div>
6288
6435
  <h4 class="card-title text-muted">Semula</h4>
6289
6436
  <div class="card-text">${html1}</div>
6290
6437
  </div>
@@ -6293,15 +6440,7 @@ zRoute.history = async (
6293
6440
  <div class="col-md-6">
6294
6441
  <div class="card">
6295
6442
  <div class="card-body">
6296
- <div class="float-end text-muted text-end">${
6297
- Util.dateFormat(
6298
- arrDataAttributes[index]
6299
- .date2,
6300
- "DD MMM YYYY HH:mm"
6301
- ) || ""
6302
- } <br><small>${
6303
- users[arrDataAttributes[index].by2].fullname
6304
- }</small></div>
6443
+ <div class="float-end text-muted text-end">${formattedDate2} <br><small>${user2Fullname}</small></div>
6305
6444
  <h4 class="card-title text-success">Menjadi </h4>
6306
6445
  <div class="card-text">${html2}</div>
6307
6446
  </div>
@@ -6311,10 +6450,20 @@ zRoute.history = async (
6311
6450
  </div>
6312
6451
  </div>`;
6313
6452
 
6314
- index++;
6453
+ index++;
6454
+ } catch (itemError) {
6455
+ // Skip item yang error, lanjut ke item berikutnya
6456
+ console.error(`Error processing history item at index ${index}:`, itemError);
6457
+ index++;
6458
+ continue;
6459
+ }
6460
+ }
6315
6461
  }
6462
+ return html;
6463
+ } catch (error) {
6464
+ console.error('Error in zRoute.history:', error);
6465
+ return "Error loading history. Please try again later.";
6316
6466
  }
6317
- return html;
6318
6467
  };
6319
6468
 
6320
6469
  zRoute.tableBody = (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zet-lib",
3
- "version": "3.1.6",
3
+ "version": "3.2.1",
4
4
  "description": "zet is a library that part of zet generator.",
5
5
  "engines": {
6
6
  "node": ">=18"