25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

622 lines
22 KiB

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