Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

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