You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

753 line
27 KiB

  1. var UI = {
  2. apiMethodName: function (args) {
  3. let methodName = args.method.toLowerCase() + args.db.capitalize();
  4. if (args.method == 'GET') methodName += "s";
  5. console.log('args');
  6. console.log(args);
  7. console.log('methodName:' + methodName);
  8. return methodName;
  9. },
  10. apiGet: function (args) {
  11. if (!args.db) { console.log('apiGet requires db parameter'); }
  12. console.log('apiGet args');
  13. console.log(args);
  14. let methodName = this.apiMethodName(args);
  15. //window.args = args;
  16. window[methodName](args.item)
  17. .then(function (data) {
  18. console.log('apiCall success');
  19. //let result = JSON.stringify(data, null, 2);
  20. console.log('args');
  21. console.log(args);
  22. let apiCallback = [
  23. {
  24. "rl:apiGetCallback": {
  25. "db": args.db,
  26. "template": args.template,
  27. "data": data
  28. }
  29. }
  30. ];
  31. js.callback({ do: apiCallback, to: 'data db ' + args.db, value: data });
  32. })
  33. .catch(function (err) {
  34. console.log('apiCall error');
  35. console.log(err);
  36. });
  37. },
  38. apiPost: function (args) {
  39. if (!args.db) { console.log('apiPost requires db parameter'); }
  40. let methodName = this.apiMethodName(args);
  41. let item = js.replaceProperties('{formDataToJson:.form'+args.db+'}');
  42. console.log(item);
  43. //window.args = args;
  44. window[methodName](item)
  45. .then(function (data) {
  46. console.log('apiCall success');
  47. let result = JSON.stringify(data, null, 2);
  48. let apiCallback = [
  49. {
  50. "rl:apiPostCallback": {
  51. "db": args.db,
  52. "template": args.template,
  53. "data": data
  54. }
  55. }
  56. ];
  57. js.callback({ do: apiCallback });
  58. })
  59. .catch(function (err) {
  60. console.log('apiCall error');
  61. console.log(err);
  62. });
  63. },
  64. apiCall: function (args) {
  65. let method = args.method || "GET";
  66. let db = args.db || "";
  67. let item = args.item || {};
  68. let serverUrl = args.serverUrl || "";
  69. let apiSuccess = args.success;
  70. let apiError = args.error;
  71. window.args = args;
  72. //RESLEVIS_API_BASE = serverUrl;
  73. let methodName = args.method.toLowerCase() + args.db.capitalize();
  74. if (method == 'GET') methodName += "s";
  75. console.log('methodName:' + methodName);
  76. //let result = window[methodName](item);
  77. window[methodName](item)
  78. .then(function (data) {
  79. console.log('apiCall success');
  80. let result = JSON.stringify(data, null, 2);
  81. console.log(data);
  82. console.log({ do: apiSuccess, to: 'data db ' + db, value: data });
  83. let apiCallback = [
  84. {
  85. "rl:apiCallback": {
  86. "db": window.args.db,
  87. "template": window.args.template,
  88. "data": data
  89. }
  90. }
  91. ];
  92. js.do(apiSuccess);
  93. //js.callback({ do: apiSuccess, to: 'data db ' + db, value: data });
  94. })
  95. .catch(function (err) {
  96. console.log('apiCall error');
  97. console.log(err);
  98. let apiCallback = [
  99. {
  100. "rl:apiCallback": {
  101. "db": window.args.db,
  102. "template": window.args.template,
  103. "data": []
  104. }
  105. }
  106. ];
  107. js.do(apiCallback);
  108. //js.callback({ do: apiSuccess, to: 'data db ' + db, value: data });
  109. });
  110. },
  111. capitalize: function (val) {
  112. return String(val).charAt(0).toUpperCase() + String(val).slice(1);
  113. },
  114. getToken: function (args) {
  115. if (args.options.body && typeof args.options.body !== 'string') args.options.body = JSON.stringify(args.options.body);
  116. fetch(args.url, args.options).then(response => response.json()).then(data => {
  117. //console.log('getToken success');
  118. //console.log(data);
  119. js.json.data.user.token = data.access_token;
  120. js.callback({ do: args.success });
  121. }).catch((err) => {
  122. //console.log('getToken error');
  123. //console.log(err);
  124. js.json.data.user.token = data.access_token;
  125. js.callback({ do: args.error });
  126. })
  127. },
  128. init: function () {
  129. },
  130. // Function to generate a form as a JSON structure from a JSON schema
  131. schemaToForm: function (params) {
  132. /* alert(JSON.stringify(params)); */
  133. if (!params.schema || !params.schema.properties) {
  134. return {
  135. html: [
  136. {
  137. tag: 'p',
  138. text: 'schemaToForm Error: Invalid JSON schema provided.'
  139. }
  140. ]
  141. };
  142. }
  143. const formElements = [];
  144. // Iterate through schema properties
  145. for (const [key, prop] of Object.entries(params.schema.properties)) {
  146. const label = prop.description || key;
  147. const required = params.schema.required && params.schema.required.includes(key) ? 'required' : '';
  148. const inputId = `input-${key}`; // Unique ID for accessibility
  149. const hiddenId = (key == 'id' && jsonApp && jsonApp.json.data.settings && !jsonApp.json.data.settings.debug) ? ' hidden' : '';
  150. // Create fieldset for each field
  151. const fieldsetChildren = [
  152. {
  153. "tag": "label",
  154. "attr": {
  155. "class": "label text-primary" + hiddenId,
  156. "data-value": params.db + "/" + key,
  157. "for": key
  158. },
  159. "html": [
  160. {
  161. tag: 'span',
  162. text: label
  163. }
  164. ]
  165. }
  166. ];
  167. // Handle different input types
  168. let inputElement;
  169. switch (prop.type) {
  170. case 'string':
  171. if (prop.format == 'dbid') {
  172. inputElement = {
  173. tag: "select",
  174. attr: {
  175. "data-value": params.db + "/" + key,
  176. "name": key,
  177. "type": 'text',
  178. "value": (params.fields && params.fields[key]) ? params.fields[key] : false,
  179. "placeholder": prop.description || ' ',
  180. "class": 'field select w-full select-primary' + hiddenId,
  181. ...(required && { required: '' })
  182. }
  183. };
  184. inputElement.html = [];
  185. let db = (js.json.data.db) ? js.json.data.db : {};
  186. if (db[key]) {
  187. for (let item of db[key]) {
  188. let id = item.id;
  189. let name = item.name || '';
  190. let attr = { "value": id, "class": "option", "data-value": params.db + "/" + key + "/" + id };
  191. if (id == params.fields[key]) attr.selected = true;
  192. inputElement.html.push(
  193. {
  194. "tag": "option",
  195. "attr": attr,
  196. "text": name
  197. }
  198. )
  199. }
  200. } else {
  201. //js.log('Can\'t load local db: ' + key, 'red');
  202. console.log('%c' + 'Can\'t load local db ' + key, 'color: red');
  203. }
  204. } else if (prop.format == 'date-time') {
  205. // https://unpkg.com/flatpickr@2.0.2/index_.html
  206. inputElement = {
  207. "tag": "input",
  208. "attr": {
  209. //"id": inputId,
  210. "data-value": params.db + "/" + key,
  211. "name": key,
  212. "type": "number", // datetime-local
  213. "value": (params.fields && params.fields[key]) ? new Date(Number(params.fields[key])) : false,
  214. "placeholder": new Date().toLocaleDateString("it-IT", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" }) || ' ',
  215. "data-enable-time": true,
  216. "data-enable-seconds": true,
  217. "data-time_24hr": true,
  218. "data-date-format": "Y-m-d H:i:S",
  219. class: "field input datepicker w-full input-primary" + hiddenId,
  220. ...(required && { required: '' })
  221. },
  222. "on": {
  223. "in": [
  224. {
  225. "js": "flatpickr('.datepicker', {enableSeconds: true, time_24hr: true})"
  226. }
  227. ]
  228. }
  229. };
  230. /* flatpickr("#date-time-flatpickr-demo", {
  231. defaultDate: new Date(),
  232. enableTime: true,
  233. }) */
  234. } else if (prop.enum) { // enum ()
  235. inputElement = {
  236. tag: "select",
  237. attr: {
  238. //"id": inputId,
  239. "data-value": params.db + "/" + key,
  240. "name": key,
  241. "type": 'text',
  242. "value": (params.fields && params.fields[key]) ? params.fields[key] : false,
  243. "placeholder": prop.description || ' ',
  244. "class": 'field select w-full select-primary' + hiddenId,
  245. ...(required && { required: '' })
  246. }
  247. };
  248. inputElement.html = [];
  249. for (let item of prop.enum) {
  250. let attr = { "value": item, "class": "option", "data-value": params.db + "/" + key + "/" + item };
  251. if (params.fields && params.fields[key] && params.fields[key] == item) attr.selected = true;
  252. inputElement.html.push(
  253. {
  254. "tag": "option",
  255. "attr": attr,
  256. "text": String(item)
  257. }
  258. )
  259. }
  260. } else { // string
  261. inputElement = {
  262. tag: 'input',
  263. attr: {
  264. //id: inputId,
  265. "data-value": params.db + "/" + key,
  266. "name": key,
  267. type: 'text',
  268. value: (params.fields && params.fields[key]) ? params.fields[key] : false,
  269. placeholder: prop.description || ' ',
  270. class: 'field input w-full input-primary' + hiddenId,
  271. ...(required && { required: '' })
  272. }
  273. };
  274. }
  275. break;
  276. case 'number':
  277. case 'integer':
  278. inputElement = {
  279. tag: 'input',
  280. attr: {
  281. //id: inputId,
  282. "data-value": params.db + "/" + key,
  283. "name": key,
  284. type: 'number',
  285. value: (params.fields && params.fields[key]) ? params.fields[key] : false,
  286. placeholder: prop.description || ' ',
  287. class: 'field input w-full input-primary',
  288. ...(required && { required: '' })
  289. }
  290. };
  291. break;
  292. case 'boolean':
  293. inputElement = {
  294. tag: 'input',
  295. attr: {
  296. //id: inputId,
  297. "data-value": params.db + "/" + key,
  298. "name": key,
  299. type: 'checkbox',
  300. class: 'field toggle toggle-info',
  301. ...(required && { required: '' })
  302. }
  303. };
  304. if (params.fields[key]) inputElement.attr.checked = true;
  305. break;
  306. case 'array':
  307. inputElement = {
  308. tag: 'textarea',
  309. attr: {
  310. //id: inputId,
  311. "data-value": params.db + "/" + key,
  312. "name": key,
  313. value: (params.fields && params.fields[key]) ? params.fields[key] : false,
  314. placeholder: prop.description || 'Enter values separated by commas',
  315. class: 'field textarea w-full input-primary',
  316. ...(required && { required: '' })
  317. }
  318. };
  319. break;
  320. case 'object':
  321. inputElement = {
  322. tag: 'textarea',
  323. attr: {
  324. //id: inputId,
  325. "data-value": params.db + "/" + key,
  326. "name": key,
  327. placeholder: prop.description || 'Enter JSON object',
  328. class: 'field textarea w-full input-primary',
  329. ...(required && { required: '' })
  330. }
  331. };
  332. break;
  333. default:
  334. inputElement = {
  335. tag: 'input',
  336. attr: {
  337. //id: inputId,
  338. "data-value": params.db + "/" + key,
  339. "name": key,
  340. type: 'text',
  341. value: (params.fields && params.fields[key]) ? params.fields[key] : false,
  342. placeholder: prop.description || ' ',
  343. class: 'field input w-full input-primary',
  344. ...(required && { required: '' })
  345. }
  346. };
  347. }
  348. // Add input element to fieldset
  349. fieldsetChildren.push(inputElement);
  350. // Add fieldset to form elements
  351. formElements.push({
  352. tag: 'fieldset',
  353. attr: {
  354. "class": "fieldset text-center",
  355. "data-value": params.db
  356. },
  357. html: fieldsetChildren
  358. });
  359. /* console.log('fviewRow');
  360. console.log(inputElement); */
  361. }
  362. /* // Add buttons
  363. formElements.push({
  364. tag: 'div',
  365. attr: {
  366. "class": "w-full mt-6 text-center px-[50px] flex flex-wrap items-center justify-between gap-2 "
  367. },
  368. html: [
  369. {
  370. "for": {
  371. "var": "button",
  372. "of": params.buttons,
  373. "do": [
  374. {
  375. "tag": 'button',
  376. "attr": {
  377. "type": "{var button type}",
  378. "class": "btn {var button class}"
  379. },
  380. "text": "{var button title}",
  381. "on": {
  382. "mousedown": "{var button actions}"
  383. }
  384. }
  385. ]
  386. }
  387. }
  388. ]
  389. }); */
  390. // Return the full form structure
  391. return {
  392. html: formElements
  393. };
  394. },
  395. createForm: function (params) {
  396. let appForm = UI.schemaToForm(params);
  397. appForm.selector = params.selector;
  398. jsonApp.do(appForm);
  399. },
  400. createTable: function (params) {
  401. /* console.log('createTable');
  402. console.log(params); */
  403. const tableData = jsonApp.json.data.db[params.db].map((data) => {
  404. return {
  405. ...data,
  406. //dateTime: new Date(Date.now()) // - 1000 * 60 * 60 * Math.floor(Math.random() * 24 * 100)),
  407. }
  408. })
  409. const getTableData = () => {
  410. return [...tableData]
  411. //return [...tableData].sort(() => 0.5 - Math.random())
  412. }
  413. const flexRender = (comp, props) => {
  414. if (typeof comp === "function") {
  415. return comp(props)
  416. }
  417. return comp
  418. }
  419. let data = getTableData()
  420. let version = 0
  421. let columns = js.json.data.ui.pages[params.db].columns;
  422. const state = {
  423. columnPinning: { left: [], right: [] },
  424. pagination: {
  425. pageSize: 10,
  426. pageIndex: 0,
  427. },
  428. globalFilter: "",
  429. columnFilters: [],
  430. columnVisibility: {},
  431. rowSelection: {},
  432. }
  433. const table = TableCore.createTable({
  434. state,
  435. data,
  436. columns,
  437. getCoreRowModel: TableCore.getCoreRowModel(),
  438. getPaginationRowModel:
  439. TableCore.getPaginationRowModel(),
  440. getFilteredRowModel: TableCore.getFilteredRowModel(),
  441. globalFilterFn: "auto",
  442. onStateChange: (updater) => {
  443. const newState =
  444. typeof updater === "function"
  445. ? updater(state)
  446. : updater
  447. Object.assign(state, newState)
  448. },
  449. });
  450. if (!window.table) window.table = {};
  451. window.table[params.db] = {
  452. dbId: params.db,
  453. version,
  454. columns,
  455. pageSizes: [5, 10, 20, 50],
  456. flexRender,
  457. search: "",
  458. get table() {
  459. this.version
  460. return table
  461. },
  462. get visibleRows() {
  463. this.version
  464. return this.table.getRowModel().rows
  465. },
  466. get selectedCount() {
  467. return this.table.getSelectedRowModel().rows.length
  468. },
  469. get totalCount() {
  470. return this.table.getPaginationRowModel().rows
  471. .length
  472. },
  473. get isIndeterminateAllRowsSelected() {
  474. this.version
  475. return (
  476. this.table.getIsSomePageRowsSelected() &&
  477. !this.table.getIsAllPageRowsSelected()
  478. )
  479. },
  480. get allLeafColumns() {
  481. this.version
  482. return this.table.getAllLeafColumns()
  483. },
  484. get pageSize() {
  485. this.version
  486. return this.table.getState().pagination.pageSize
  487. },
  488. get pageIndex() {
  489. this.version
  490. return this.table.getState().pagination.pageIndex
  491. },
  492. get rowCount() {
  493. this.version
  494. return data.length
  495. },
  496. get start() {
  497. this.version
  498. return this.rowCount === 0
  499. ? 0
  500. : this.pageIndex * this.pageSize + 1
  501. },
  502. get end() {
  503. this.version
  504. return Math.min(
  505. this.start + this.pageSize - 1,
  506. this.rowCount
  507. )
  508. },
  509. /* updateInterval(duration) {
  510. console.log('updateInterval:'+this.dbId);
  511. clearInterval(this.interval);
  512. this.interval = setInterval(function (event) {console.log(event); this.dbId}, duration)
  513. }, */
  514. updateData() {
  515. //console.log('updateData:'+this.dbId);
  516. let newData = jsonApp.json.data.db[this.dbId];
  517. this.table.setOptions(prev => ({
  518. ...prev,
  519. data: newData
  520. }))
  521. this.render()
  522. },
  523. setPageIndex(n) {
  524. this.table.setPageIndex(n)
  525. this.render()
  526. },
  527. nextPage() {
  528. this.version
  529. if (this.table.getCanNextPage()) {
  530. this.table.setPageIndex(this.pageIndex + 1)
  531. this.render()
  532. }
  533. },
  534. prevPage() {
  535. this.version
  536. if (this.table.getCanPreviousPage()) {
  537. this.table.setPageIndex(this.pageIndex - 1)
  538. this.render()
  539. }
  540. },
  541. changePageSize(newSize) {
  542. this.table.setPageSize(Number(newSize))
  543. this.render()
  544. },
  545. updateSearch() {
  546. table.setState({
  547. ...table.getState(),
  548. globalFilter: this.search,
  549. })
  550. this.render()
  551. },
  552. getVisibleCells(row) {
  553. this.version
  554. return row.getVisibleCells()
  555. },
  556. isColumnVisible(column) {
  557. this.version
  558. return column.getIsVisible()
  559. },
  560. toggleColumn(column) {
  561. column.toggleVisibility()
  562. this.render()
  563. },
  564. toggleSelectedRow(row) {
  565. row.toggleSelected()
  566. this.render()
  567. },
  568. isRowSelected(row) {
  569. this.version
  570. return row.getIsSelected()
  571. },
  572. toggleAllRowsSelected() {
  573. this.table.toggleAllPageRowsSelected()
  574. this.render()
  575. },
  576. viewRow(row) {
  577. let fields = Alpine.raw(row.original);
  578. //let id = `${row.original.id}`;
  579. js.part({ 'do': 'rl:openPost', arguments: { db: params.db, fields: fields, method: 'UPDATE' } });
  580. },
  581. deleteRow(row) {
  582. let fields = Alpine.raw(row.original);
  583. //let id = `${row.original.id}`;
  584. js.part({ 'do': 'removePost', arguments: { db: params.db, fields: fields } });
  585. },
  586. clearFilters() {
  587. this.search = ""
  588. this.updateSearch()
  589. },
  590. render() {
  591. this.version++
  592. }
  593. }
  594. return window.table[params.db]
  595. },
  596. loadTemplate: function (params) {
  597. console.log('loadTemplate', params);
  598. // add to html the parameters {url, to}
  599. var xmlhttp = new XMLHttpRequest();
  600. xmlhttp.open("GET", params.url, false);
  601. xmlhttp.send();
  602. if (xmlhttp.responseText) {
  603. var responseText = xmlhttp.responseText;
  604. if (params.arguments) {
  605. responseText = js.replacePropertyWithPrefix(responseText, 'arguments', params.arguments);
  606. }
  607. if (params.to)
  608. js.element({ root: js.json, path: params.to, value: responseText });
  609. if (params.selector) {
  610. if (params.prepend)
  611. document.querySelector(params.selector).innerHTML = responseText + document.querySelector(params.selector).innerHTML;
  612. else if (params.empty)
  613. document.querySelector(params.selector).innerHTML = responseText;
  614. else
  615. document.querySelector(params.selector).innerHTML += responseText;
  616. }
  617. } else console.log('Error loading ' + params.url);
  618. }
  619. }
  620. Object.defineProperty(String.prototype, 'capitalize', {
  621. value: function () {
  622. return this.charAt(0).toUpperCase() + this.slice(1);
  623. },
  624. enumerable: false
  625. });
  626. /*
  627. var getToken = function (args) {
  628. //UI.token(args);
  629. if (args.options.body && typeof args.options.body !== 'string') args.options.body = JSON.stringify(args.options.body); fetch(args.url, args.options).then(response => response.json()).then(data => {console.log('fetchJson success'); console.log(data); js.callback({do:args.success});}).catch((err) => {console.log('fetchJson error');console.log(err);js.callback({do:args.error});})
  630. }
  631. */
  632. /*
  633. let args = {
  634. "url": "https://192.168.1.3:10002/realms/API.Server.local/protocol/openid-connect/token",
  635. "options": {
  636. "method": "POST",
  637. "headers": {
  638. "Content-Type": "application/x-www-form-urlencoded"
  639. },
  640. "body": "grant_type=client_credentials&client_id=Fastapi&client_secret=wojuoB7Z5xhlPFrF2lIxJSSdVHCApEgC"
  641. }
  642. };
  643. */
  644. //UI.getToken(args);
  645. //UI.loadTemplate({selector: 'content', url:'./assets/html/tracks.html'});
  646. // components-interactions-form-validations
  647. /* empty css */; (function () {
  648. const t = document.createElement("link").relList
  649. if (t && t.supports && t.supports("modulepreload")) return
  650. for (const e of document.querySelectorAll('link[rel="modulepreload"]')) i(e)
  651. new MutationObserver((e) => {
  652. for (const r of e)
  653. if (r.type === "childList")
  654. for (const o of r.addedNodes)
  655. o.tagName === "LINK" && o.rel === "modulepreload" && i(o)
  656. }).observe(document, { childList: !0, subtree: !0 })
  657. function s(e) {
  658. const r = {}
  659. return (
  660. e.integrity && (r.integrity = e.integrity),
  661. e.referrerPolicy && (r.referrerPolicy = e.referrerPolicy),
  662. e.crossOrigin === "use-credentials"
  663. ? (r.credentials = "include")
  664. : e.crossOrigin === "anonymous"
  665. ? (r.credentials = "omit")
  666. : (r.credentials = "same-origin"),
  667. r
  668. )
  669. }
  670. function i(e) {
  671. if (e.ep) return
  672. e.ep = !0
  673. const r = s(e)
  674. fetch(e.href, r)
  675. }
  676. })()