@dasidev/dasi-ui 1.0.0

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.
Files changed (450) hide show
  1. package/README.md +346 -0
  2. package/bin/dasi-cli.cjs +184 -0
  3. package/dist/date-selector-test-BlukYeWl.js +91 -0
  4. package/dist/favicon.ico +0 -0
  5. package/dist/html2canvas.esm-CKxSAI8P.js +4886 -0
  6. package/dist/img/brand/ic_pln.svg +12 -0
  7. package/dist/img/brand/mapp_power_logo.svg +21 -0
  8. package/dist/img/common/pltu_ulumbu_flores_ntt.jpeg +0 -0
  9. package/dist/index-BQSA2aPs.js +126556 -0
  10. package/dist/index.es-DQWt-PZn.js +5769 -0
  11. package/dist/index.es.js +11 -0
  12. package/dist/index.umd.js +8564 -0
  13. package/dist/informasi-gudang-BmoEy2RL.js +164 -0
  14. package/dist/informasi-gudang-DXfS46Nh.js +50 -0
  15. package/dist/purify.es-C-9oolON.js +546 -0
  16. package/dist/scripts/pdf.worker.min.js +29 -0
  17. package/dist/scripts/pdf.worker.min.mjs +29 -0
  18. package/dist/scripts/pdf.worker.mjs +57722 -0
  19. package/dist/scripts/pdf.worker.mjs.map +1 -0
  20. package/dist/style.css +1 -0
  21. package/dist/test-schema-JFghGc0_.js +8 -0
  22. package/dist/test-schema-uusFsJe4.js +438 -0
  23. package/dist/types-l0sNRNKZ.js +1 -0
  24. package/package.json +178 -0
  25. package/src/App.vue +18 -0
  26. package/src/__tests__/index.test.ts +9 -0
  27. package/src/api/api.ts +117 -0
  28. package/src/assets/app-selector.svg +3 -0
  29. package/src/assets/dasi.png +0 -0
  30. package/src/assets/foto_ss.svg +21 -0
  31. package/src/assets/icons/circle-blue.svg +4 -0
  32. package/src/assets/icons/circle-gray.svg +15 -0
  33. package/src/assets/icons/circle-green.svg +4 -0
  34. package/src/assets/icons/circle-orange.svg +4 -0
  35. package/src/assets/icons/circle-purple.svg +4 -0
  36. package/src/assets/icons/circle-red.svg +15 -0
  37. package/src/assets/icons/harbor.svg +12 -0
  38. package/src/assets/icons/ic-box-red.svg +8 -0
  39. package/src/assets/icons/ic-chevron-right.svg +1 -0
  40. package/src/assets/icons/ic-loading.svg +9 -0
  41. package/src/assets/icons/ic-reset.svg +16 -0
  42. package/src/assets/icons/ic-sailing.svg +5 -0
  43. package/src/assets/icons/icon-app-selector.svg +3 -0
  44. package/src/assets/icons/icon-browser-check.svg +4 -0
  45. package/src/assets/icons/icon-calendar.svg +3 -0
  46. package/src/assets/icons/icon-chart-bar.svg +3 -0
  47. package/src/assets/icons/icon-chart-doc.svg +16 -0
  48. package/src/assets/icons/icon-chart-line.svg +10 -0
  49. package/src/assets/icons/icon-chart-mix.svg +15 -0
  50. package/src/assets/icons/icon-chart-pie.svg +11 -0
  51. package/src/assets/icons/icon-continue.svg +12 -0
  52. package/src/assets/icons/icon-dashboard-2.svg +17 -0
  53. package/src/assets/icons/icon-dashboard.svg +3 -0
  54. package/src/assets/icons/icon-data-kelistrikan.svg +19 -0
  55. package/src/assets/icons/icon-data-sentral.svg +11 -0
  56. package/src/assets/icons/icon-database.svg +5 -0
  57. package/src/assets/icons/icon-desktop.svg +3 -0
  58. package/src/assets/icons/icon-download.svg +13 -0
  59. package/src/assets/icons/icon-energi-primer.svg +12 -0
  60. package/src/assets/icons/icon-faba-apk2.svg +11 -0
  61. package/src/assets/icons/icon-faba.svg +11 -0
  62. package/src/assets/icons/icon-factory.svg +14 -0
  63. package/src/assets/icons/icon-globe-doc.svg +19 -0
  64. package/src/assets/icons/icon-ikk.svg +10 -0
  65. package/src/assets/icons/icon-kbb.svg +13 -0
  66. package/src/assets/icons/icon-kos.svg +16 -0
  67. package/src/assets/icons/icon-kpi-bod.svg +15 -0
  68. package/src/assets/icons/icon-kss.svg +14 -0
  69. package/src/assets/icons/icon-map.svg +12 -0
  70. package/src/assets/icons/icon-monitoring-harian.svg +13 -0
  71. package/src/assets/icons/icon-notification.svg +4 -0
  72. package/src/assets/icons/icon-overview.svg +17 -0
  73. package/src/assets/icons/icon-pltu.svg +13 -0
  74. package/src/assets/icons/icon-sebaran-sentral.svg +12 -0
  75. package/src/assets/icons/icon-select-data-kelistrikan.svg +19 -0
  76. package/src/assets/icons/icon-select-data-sentral.svg +11 -0
  77. package/src/assets/icons/icon-select-energi-primer.svg +12 -0
  78. package/src/assets/icons/icon-select-faba-apk2.svg +11 -0
  79. package/src/assets/icons/icon-select-ikk.svg +10 -0
  80. package/src/assets/icons/icon-select-kbb.svg +13 -0
  81. package/src/assets/icons/icon-select-kos.svg +16 -0
  82. package/src/assets/icons/icon-select-kpi-bod.svg +15 -0
  83. package/src/assets/icons/icon-select-kss.svg +14 -0
  84. package/src/assets/icons/icon-select-monitoring-harian.svg +13 -0
  85. package/src/assets/icons/icon-select-overview.svg +17 -0
  86. package/src/assets/icons/icon-select-sebaran-sentral.svg +12 -0
  87. package/src/assets/icons/icon-sentral-white.svg +13 -0
  88. package/src/assets/icons/icon-shipping.svg +5 -0
  89. package/src/assets/icons/icon-sort.svg +5 -0
  90. package/src/assets/icons/icon-tree-box.svg +14 -0
  91. package/src/assets/icons/icon-warehouse.svg +12 -0
  92. package/src/assets/icons/pin-green.svg +3 -0
  93. package/src/assets/icons/pin-orange.svg +3 -0
  94. package/src/assets/icons/pin-purple.svg +3 -0
  95. package/src/assets/icons/ship.svg +3 -0
  96. package/src/assets/icons/shipment/icon-antri.svg +15 -0
  97. package/src/assets/icons/shipment/icon-bongkar.svg +4 -0
  98. package/src/assets/icons/shipment/icon-invoice.svg +6 -0
  99. package/src/assets/icons/shipment/icon-loading.svg +8 -0
  100. package/src/assets/icons/shipment/icon-pembayaran.svg +13 -0
  101. package/src/assets/icons/shipment/icon-pengiriman.svg +4 -0
  102. package/src/assets/icons/shipment/icon-sailing.svg +4 -0
  103. package/src/assets/icons/shipment/icon-shipment-completed.svg +6 -0
  104. package/src/assets/icons/shipment/icon-shipment-in-progress.svg +6 -0
  105. package/src/assets/icons/shipment/icon-shipment-over-sla.svg +6 -0
  106. package/src/assets/icons/shipment/icon-spt.svg +4 -0
  107. package/src/assets/icons/shipment/icon-total-shipment.svg +4 -0
  108. package/src/assets/icons/upload_doc_icon.svg +42 -0
  109. package/src/assets/icons/upload_icon_blue.svg +14 -0
  110. package/src/assets/login-bg-day-min.jpg +0 -0
  111. package/src/assets/login-bg-night-min.jpg +0 -0
  112. package/src/assets/login-bg.jpg +0 -0
  113. package/src/assets/login-day.png +0 -0
  114. package/src/assets/login-night.png +0 -0
  115. package/src/assets/lucide-circle-plus-blue.svg +1 -0
  116. package/src/assets/pdf-logo.svg +11 -0
  117. package/src/assets/pemasok-card-bg.svg +6 -0
  118. package/src/assets/success_animation.gif +0 -0
  119. package/src/assets/success_animation.mp4 +0 -0
  120. package/src/assets/success_animation.webm +0 -0
  121. package/src/components/button/BtnAddOutline.vue +14 -0
  122. package/src/components/button/BtnCircle.vue +10 -0
  123. package/src/components/button/BtnOutline.vue +15 -0
  124. package/src/components/button/BtnPrimary.vue +25 -0
  125. package/src/components/button/BtnSecondary.vue +26 -0
  126. package/src/components/detail/AccountDetailTimeline.vue +144 -0
  127. package/src/components/detail/ApprovalInfo.vue +288 -0
  128. package/src/components/detail/DCI2.vue +164 -0
  129. package/src/components/detail/DetailContentHeader.vue +83 -0
  130. package/src/components/detail/DetailContentItem.vue +186 -0
  131. package/src/components/detail/DetailContentItems.vue +388 -0
  132. package/src/components/detail/DetailContentLoading.vue +12 -0
  133. package/src/components/detail/DetailContentTablet.vue +10 -0
  134. package/src/components/detail/DetailSheet.vue +294 -0
  135. package/src/components/detail/DetailTimeline.vue +191 -0
  136. package/src/components/detail/DocApprovalDialog.vue +29 -0
  137. package/src/components/detail/DocViewerContent.vue +991 -0
  138. package/src/components/dialog/ConfirmDialog.vue +96 -0
  139. package/src/components/dialog/DialogBase.vue +53 -0
  140. package/src/components/dialog/DialogSelect.vue +212 -0
  141. package/src/components/dialog/ErrorDialog.vue +63 -0
  142. package/src/components/dialog/FormDialog.vue +141 -0
  143. package/src/components/dialog/FormInputerDialog.vue +91 -0
  144. package/src/components/dialog/InfoDialog.vue +74 -0
  145. package/src/components/dialog/SuccessDialog.vue +51 -0
  146. package/src/components/examples/TestSchemaExample.vue +288 -0
  147. package/src/components/forms/auth/LoginForm.vue +806 -0
  148. package/src/components/forms/auth/PwdScore.vue +68 -0
  149. package/src/components/helper/ApiTester.vue +153 -0
  150. package/src/components/helper/ChangePwd.vue +150 -0
  151. package/src/components/helper/CheckboxElement.vue +43 -0
  152. package/src/components/helper/ConfigSwitcher.vue +54 -0
  153. package/src/components/helper/Copyright.vue +10 -0
  154. package/src/components/helper/ErrorScreen.vue +40 -0
  155. package/src/components/helper/LucideIcon.vue +27 -0
  156. package/src/components/helper/PdfViewer.vue +103 -0
  157. package/src/components/helper/PinInputer.vue +205 -0
  158. package/src/components/helper/PrivacyPolicy.vue +122 -0
  159. package/src/components/layout/PageActivityHeader.vue +48 -0
  160. package/src/components/layout/PageHeader.vue +70 -0
  161. package/src/components/loadings/LoadingDialog.vue +29 -0
  162. package/src/components/loadings/LoadingDialogSpin.vue +25 -0
  163. package/src/components/loadings/LoadingIndicator.vue +38 -0
  164. package/src/components/loadings/LoadingScreen.vue +23 -0
  165. package/src/components/notif/Notif.vue +103 -0
  166. package/src/components/notif/NotifItem.vue +41 -0
  167. package/src/components/pages/Header.vue +431 -0
  168. package/src/components/pages/Leftbar.vue +417 -0
  169. package/src/components/pages/PageActivity.vue +108 -0
  170. package/src/components/pages/PageActivityContent.vue +597 -0
  171. package/src/components/pages/PageContentTable.vue +589 -0
  172. package/src/components/pages/PageTab.vue +84 -0
  173. package/src/components/selector/BaseSelector.vue +1136 -0
  174. package/src/components/selector/ConfigDataSelector.vue +136 -0
  175. package/src/components/settings/SettingsItem.vue +38 -0
  176. package/src/components/tab/TabView.vue +11 -0
  177. package/src/components/tab/TabViewItem.vue +18 -0
  178. package/src/components/tab/TabViewItemBar.vue +9 -0
  179. package/src/components/tables/CellHover.vue +65 -0
  180. package/src/components/tables/DashboardDataTable.vue +707 -0
  181. package/src/components/tables/DataStatusTag.vue +52 -0
  182. package/src/components/tables/DataTable.vue +156 -0
  183. package/src/components/tables/DataTableAccordion.vue +249 -0
  184. package/src/components/tables/DataTableActionRow.vue +64 -0
  185. package/src/components/tables/DataTableCell.vue +272 -0
  186. package/src/components/tables/DataTableHeader.vue +60 -0
  187. package/src/components/tables/DataTableRow.vue +213 -0
  188. package/src/components/tables/ExpandedTable.vue +259 -0
  189. package/src/components/tables/PageTable.vue +73 -0
  190. package/src/components/tables/Pagination.vue +98 -0
  191. package/src/components/tables/dropdown/BaseDropdownTable.vue +140 -0
  192. package/src/components/tables/dropdown/DropdownTableActivity.vue +33 -0
  193. package/src/components/tables/dropdown/DropdownTableAsset.vue +30 -0
  194. package/src/components/tables/dropdown/DropdownTableConfig.vue +30 -0
  195. package/src/components/tables/dropdown/DropdownTableDataKonektor.vue +31 -0
  196. package/src/components/tables/dropdown/DropdownTableDataLabel.vue +30 -0
  197. package/src/components/tables/dropdown/DropdownTableDataSchema.vue +31 -0
  198. package/src/components/tables/dropdown/DropdownTableFabaPemanfaat.vue +30 -0
  199. package/src/components/tables/dropdown/DropdownTableGroup.vue +36 -0
  200. package/src/components/tables/dropdown/DropdownTableHalaman.vue +33 -0
  201. package/src/components/tables/dropdown/DropdownTableLevel.vue +66 -0
  202. package/src/components/tables/dropdown/DropdownTableOrganization.vue +47 -0
  203. package/src/components/tables/dropdown/DropdownTablePengelola.vue +28 -0
  204. package/src/components/tables/dropdown/DropdownTableQueryLayer.vue +29 -0
  205. package/src/components/tables/dropdown/DropdownTableSentral.vue +33 -0
  206. package/src/components/tables/dropdown/DropdownTableWarehouse.vue +30 -0
  207. package/src/components/tables/dropdown/TableDropdown.vue +52 -0
  208. package/src/components/ui/accordion/Accordion.vue +19 -0
  209. package/src/components/ui/accordion/AccordionContent.vue +24 -0
  210. package/src/components/ui/accordion/AccordionItem.vue +24 -0
  211. package/src/components/ui/accordion/AccordionTrigger.vue +42 -0
  212. package/src/components/ui/accordion/index.ts +4 -0
  213. package/src/components/ui/alert-dialog/AlertDialog.vue +14 -0
  214. package/src/components/ui/alert-dialog/AlertDialogAction.vue +20 -0
  215. package/src/components/ui/alert-dialog/AlertDialogCancel.vue +20 -0
  216. package/src/components/ui/alert-dialog/AlertDialogContent.vue +42 -0
  217. package/src/components/ui/alert-dialog/AlertDialogDescription.vue +25 -0
  218. package/src/components/ui/alert-dialog/AlertDialogFooter.vue +21 -0
  219. package/src/components/ui/alert-dialog/AlertDialogHeader.vue +16 -0
  220. package/src/components/ui/alert-dialog/AlertDialogTitle.vue +22 -0
  221. package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +11 -0
  222. package/src/components/ui/alert-dialog/index.ts +9 -0
  223. package/src/components/ui/avatar/Avatar.vue +24 -0
  224. package/src/components/ui/avatar/AvatarFallback.vue +11 -0
  225. package/src/components/ui/avatar/AvatarImage.vue +9 -0
  226. package/src/components/ui/avatar/UsersAvatar.vue +28 -0
  227. package/src/components/ui/avatar/index.ts +24 -0
  228. package/src/components/ui/button/Button.vue +27 -0
  229. package/src/components/ui/button/index.ts +34 -0
  230. package/src/components/ui/calendar/Calendar.vue +325 -0
  231. package/src/components/ui/calendar/index.ts +22 -0
  232. package/src/components/ui/checkbox/Checkbox.vue +33 -0
  233. package/src/components/ui/checkbox/index.ts +1 -0
  234. package/src/components/ui/command/Command.vue +30 -0
  235. package/src/components/ui/command/CommandDialog.vue +21 -0
  236. package/src/components/ui/command/CommandEmpty.vue +20 -0
  237. package/src/components/ui/command/CommandGroup.vue +29 -0
  238. package/src/components/ui/command/CommandInput.vue +33 -0
  239. package/src/components/ui/command/CommandItem.vue +26 -0
  240. package/src/components/ui/command/CommandList.vue +27 -0
  241. package/src/components/ui/command/CommandSeparator.vue +23 -0
  242. package/src/components/ui/command/CommandShortcut.vue +14 -0
  243. package/src/components/ui/command/index.ts +9 -0
  244. package/src/components/ui/context-menu/ContextMenu.vue +15 -0
  245. package/src/components/ui/context-menu/ContextMenuCheckboxItem.vue +40 -0
  246. package/src/components/ui/context-menu/ContextMenuContent.vue +36 -0
  247. package/src/components/ui/context-menu/ContextMenuGroup.vue +11 -0
  248. package/src/components/ui/context-menu/ContextMenuItem.vue +34 -0
  249. package/src/components/ui/context-menu/ContextMenuLabel.vue +25 -0
  250. package/src/components/ui/context-menu/ContextMenuPortal.vue +11 -0
  251. package/src/components/ui/context-menu/ContextMenuRadioGroup.vue +19 -0
  252. package/src/components/ui/context-menu/ContextMenuRadioItem.vue +40 -0
  253. package/src/components/ui/context-menu/ContextMenuSeparator.vue +20 -0
  254. package/src/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
  255. package/src/components/ui/context-menu/ContextMenuSub.vue +19 -0
  256. package/src/components/ui/context-menu/ContextMenuSubContent.vue +35 -0
  257. package/src/components/ui/context-menu/ContextMenuSubTrigger.vue +34 -0
  258. package/src/components/ui/context-menu/ContextMenuTrigger.vue +13 -0
  259. package/src/components/ui/context-menu/index.ts +14 -0
  260. package/src/components/ui/datetime/DatetimeRangeComponent.vue +52 -0
  261. package/src/components/ui/dialog/Dialog.vue +14 -0
  262. package/src/components/ui/dialog/DialogClose.vue +11 -0
  263. package/src/components/ui/dialog/DialogContent.vue +53 -0
  264. package/src/components/ui/dialog/DialogDescription.vue +24 -0
  265. package/src/components/ui/dialog/DialogFooter.vue +19 -0
  266. package/src/components/ui/dialog/DialogHeader.vue +16 -0
  267. package/src/components/ui/dialog/DialogScrollContent.vue +59 -0
  268. package/src/components/ui/dialog/DialogTitle.vue +29 -0
  269. package/src/components/ui/dialog/DialogTrigger.vue +11 -0
  270. package/src/components/ui/dialog/index.ts +9 -0
  271. package/src/components/ui/dropdown-menu/DropdownMenu.vue +14 -0
  272. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +40 -0
  273. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +38 -0
  274. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
  275. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +28 -0
  276. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +24 -0
  277. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +19 -0
  278. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +41 -0
  279. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +22 -0
  280. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  281. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  282. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +30 -0
  283. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +33 -0
  284. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +13 -0
  285. package/src/components/ui/dropdown-menu/index.ts +16 -0
  286. package/src/components/ui/form/FormControl.vue +16 -0
  287. package/src/components/ui/form/FormDescription.vue +20 -0
  288. package/src/components/ui/form/FormItem.vue +25 -0
  289. package/src/components/ui/form/FormLabel.vue +23 -0
  290. package/src/components/ui/form/FormMessage.vue +16 -0
  291. package/src/components/ui/form/index.ts +6 -0
  292. package/src/components/ui/form/useFormField.ts +30 -0
  293. package/src/components/ui/hover-card/HoverCard.vue +14 -0
  294. package/src/components/ui/hover-card/HoverCardContent.vue +41 -0
  295. package/src/components/ui/hover-card/HoverCardTrigger.vue +11 -0
  296. package/src/components/ui/hover-card/index.ts +3 -0
  297. package/src/components/ui/input/Input.vue +24 -0
  298. package/src/components/ui/input/index.ts +1 -0
  299. package/src/components/ui/label/Label.vue +27 -0
  300. package/src/components/ui/label/index.ts +1 -0
  301. package/src/components/ui/pagination/PaginationEllipsis.vue +22 -0
  302. package/src/components/ui/pagination/PaginationFirst.vue +29 -0
  303. package/src/components/ui/pagination/PaginationLast.vue +29 -0
  304. package/src/components/ui/pagination/PaginationNext.vue +29 -0
  305. package/src/components/ui/pagination/PaginationPrev.vue +29 -0
  306. package/src/components/ui/pagination/index.ts +10 -0
  307. package/src/components/ui/pin-input/PinInput.vue +23 -0
  308. package/src/components/ui/pin-input/PinInputGroup.vue +18 -0
  309. package/src/components/ui/pin-input/PinInputInput.vue +18 -0
  310. package/src/components/ui/pin-input/PinInputSeparator.vue +15 -0
  311. package/src/components/ui/pin-input/index.ts +4 -0
  312. package/src/components/ui/popover/Popover.vue +15 -0
  313. package/src/components/ui/popover/PopoverContent.vue +48 -0
  314. package/src/components/ui/popover/PopoverTrigger.vue +11 -0
  315. package/src/components/ui/popover/index.ts +4 -0
  316. package/src/components/ui/preview/PreviewPdf.vue +118 -0
  317. package/src/components/ui/progress/ProgressCircle.vue +27 -0
  318. package/src/components/ui/progress/SemiCircularProgressBar.vue +83 -0
  319. package/src/components/ui/progress/TotalCalories.vue +31 -0
  320. package/src/components/ui/radio-group/RadioGroup.vue +25 -0
  321. package/src/components/ui/radio-group/RadioGroupItem.vue +37 -0
  322. package/src/components/ui/radio-group/index.ts +2 -0
  323. package/src/components/ui/scroll-area/ScrollArea.vue +29 -0
  324. package/src/components/ui/scroll-area/ScrollBar.vue +30 -0
  325. package/src/components/ui/scroll-area/index.ts +2 -0
  326. package/src/components/ui/select/Select.vue +15 -0
  327. package/src/components/ui/select/SelectContent.vue +52 -0
  328. package/src/components/ui/select/SelectGroup.vue +19 -0
  329. package/src/components/ui/select/SelectInline.vue +84 -0
  330. package/src/components/ui/select/SelectItem.vue +44 -0
  331. package/src/components/ui/select/SelectItemText.vue +11 -0
  332. package/src/components/ui/select/SelectLabel.vue +13 -0
  333. package/src/components/ui/select/SelectScrollDownButton.vue +24 -0
  334. package/src/components/ui/select/SelectScrollUpButton.vue +24 -0
  335. package/src/components/ui/select/SelectSeparator.vue +17 -0
  336. package/src/components/ui/select/SelectTrigger.vue +31 -0
  337. package/src/components/ui/select/SelectTriggerCustom.vue +23 -0
  338. package/src/components/ui/select/SelectValue.vue +11 -0
  339. package/src/components/ui/select/index.ts +12 -0
  340. package/src/components/ui/separator/Separator.vue +20 -0
  341. package/src/components/ui/separator/index.ts +1 -0
  342. package/src/components/ui/sheet/Sheet.vue +14 -0
  343. package/src/components/ui/sheet/SheetClose.vue +11 -0
  344. package/src/components/ui/sheet/SheetContent.vue +48 -0
  345. package/src/components/ui/sheet/SheetDescription.vue +22 -0
  346. package/src/components/ui/sheet/SheetFooter.vue +19 -0
  347. package/src/components/ui/sheet/SheetHeader.vue +16 -0
  348. package/src/components/ui/sheet/SheetTitle.vue +22 -0
  349. package/src/components/ui/sheet/SheetTrigger.vue +11 -0
  350. package/src/components/ui/sheet/index.ts +31 -0
  351. package/src/components/ui/skeleton/Skeleton.vue +28 -0
  352. package/src/components/ui/skeleton/index.ts +1 -0
  353. package/src/components/ui/sonner/Sonner.vue +22 -0
  354. package/src/components/ui/sonner/index.ts +1 -0
  355. package/src/components/ui/star/StarRating.vue +19 -0
  356. package/src/components/ui/switch/Switch.vue +37 -0
  357. package/src/components/ui/switch/index.ts +1 -0
  358. package/src/components/ui/table/Table.vue +16 -0
  359. package/src/components/ui/table/TableBody.vue +14 -0
  360. package/src/components/ui/table/TableCaption.vue +14 -0
  361. package/src/components/ui/table/TableCell.vue +21 -0
  362. package/src/components/ui/table/TableEmpty.vue +37 -0
  363. package/src/components/ui/table/TableFooter.vue +14 -0
  364. package/src/components/ui/table/TableHead.vue +14 -0
  365. package/src/components/ui/table/TableHeader.vue +14 -0
  366. package/src/components/ui/table/TableRow.vue +14 -0
  367. package/src/components/ui/table/index.ts +8 -0
  368. package/src/components/ui/tabs/Tabs.vue +15 -0
  369. package/src/components/ui/tabs/TabsContent.vue +22 -0
  370. package/src/components/ui/tabs/TabsList.vue +25 -0
  371. package/src/components/ui/tabs/TabsTrigger.vue +27 -0
  372. package/src/components/ui/tabs/index.ts +4 -0
  373. package/src/components/ui/tags-input/TagsInput.vue +22 -0
  374. package/src/components/ui/tags-input/TagsInputInput.vue +19 -0
  375. package/src/components/ui/tags-input/TagsInputItem.vue +22 -0
  376. package/src/components/ui/tags-input/TagsInputItemDelete.vue +24 -0
  377. package/src/components/ui/tags-input/TagsInputItemText.vue +19 -0
  378. package/src/components/ui/tags-input/index.ts +5 -0
  379. package/src/components/ui/textarea/Textarea.vue +24 -0
  380. package/src/components/ui/textarea/index.ts +1 -0
  381. package/src/components/ui/tooltip/Tooltip.vue +14 -0
  382. package/src/components/ui/tooltip/TooltipContent.vue +31 -0
  383. package/src/components/ui/tooltip/TooltipProvider.vue +11 -0
  384. package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
  385. package/src/components/ui/tooltip/index.ts +4 -0
  386. package/src/composables/useAppConfig.ts +332 -0
  387. package/src/composables/useDarkMode.ts +71 -0
  388. package/src/config/app.config.ts +318 -0
  389. package/src/config/examples/ecommerce.config.ts +132 -0
  390. package/src/config/examples/generic.config.ts +132 -0
  391. package/src/config/menu.config.ts +149 -0
  392. package/src/config/my-app.config.ts +134 -0
  393. package/src/config/test-config.ts +32 -0
  394. package/src/config/theme.config.ts +250 -0
  395. package/src/docs/index.ts +21 -0
  396. package/src/docs.scss +403 -0
  397. package/src/index.d.ts +5 -0
  398. package/src/index.ts +20 -0
  399. package/src/layouts/AuthLayout.vue +68 -0
  400. package/src/layouts/DefaultLayout.vue +119 -0
  401. package/src/layouts/DocsLayout.vue +681 -0
  402. package/src/layouts/FormGlobal.vue +50 -0
  403. package/src/layouts/GlobalDialog.vue +122 -0
  404. package/src/layouts/RakorConfirmDialog.vue +95 -0
  405. package/src/layouts/SettingsLayout.vue +115 -0
  406. package/src/lib/constants.ts +2 -0
  407. package/src/lib/detail.utils.ts +213 -0
  408. package/src/lib/form.utils.ts +1009 -0
  409. package/src/lib/page.flow.utils.ts +81 -0
  410. package/src/lib/page.utils.ts +865 -0
  411. package/src/lib/performance.utils.ts +302 -0
  412. package/src/lib/tablerow.utils.ts +51 -0
  413. package/src/lib/utils.ts +643 -0
  414. package/src/main.scss +717 -0
  415. package/src/main.ts +74 -0
  416. package/src/menu.ts +78 -0
  417. package/src/nestedlist_color.scss +161 -0
  418. package/src/router/index.ts +92 -0
  419. package/src/stores/auth.ts +117 -0
  420. package/src/stores/counter.ts +12 -0
  421. package/src/stores/dialog.ts +168 -0
  422. package/src/stores/form.ts +103 -0
  423. package/src/stores/tabs.ts +52 -0
  424. package/src/tw.scss +419 -0
  425. package/src/types/form.types.ts +348 -0
  426. package/src/types/types.ts +7 -0
  427. package/src/utils/config.utils.ts +149 -0
  428. package/src/views/NotFound.vue +30 -0
  429. package/src/views/PageActivity.vue +15 -0
  430. package/src/views/auth/LoginView.vue +7 -0
  431. package/src/views/auth/OauthCallback.vue +101 -0
  432. package/src/views/dashboard/index.vue +16 -0
  433. package/src/views/settings/AccountSettingsView.vue +70 -0
  434. package/src/views/settings/AuditLogsSettingsView.vue +116 -0
  435. package/src/views/settings/DeviceSettingsView.vue +70 -0
  436. package/src/views/settings/MainSettingsView.vue +12 -0
  437. package/src/views/settings/ProfileSettingsView.vue +104 -0
  438. package/src/vueform/config/informasi-gudang.ts +47 -0
  439. package/src/vueform/config/test-schema.ts +8 -0
  440. package/src/vueform/config/types.ts +768 -0
  441. package/src/vueform/customization/classes.js +46 -0
  442. package/src/vueform/customization/tailwind.classes.js +2117 -0
  443. package/src/vueform/elements/ConfigDataSelectorElement.vue +50 -0
  444. package/src/vueform/elements/DateSelectorElement.vue +323 -0
  445. package/src/vueform/elements/SelectorElement.vue +153 -0
  446. package/src/vueform/schemas/date-selector-test.ts +103 -0
  447. package/src/vueform/schemas/informasi-gudang.ts +160 -0
  448. package/src/vueform/schemas/test-schema.ts +483 -0
  449. package/src/vueform.config.js +77 -0
  450. package/src/vueform.validator.ts +77 -0
@@ -0,0 +1,1009 @@
1
+ import api from "@/api/api";
2
+ import { clearFormSchema, fillFormSchema, intlFormatedToNumber } from "./utils";
3
+ import type { FormReactiveSchema, FormSchemaHooks } from "@/types/form.types";
4
+ import { useFormSheet } from "@/stores/form";
5
+ import { useConfirmDialog, useErrorDialog, useLoadingDialog, useSuccessDialog } from "@/stores/dialog";
6
+ import { InternalServerError } from "./constants";
7
+ import { toast } from "vue-sonner";
8
+ import { nextTick } from "vue";
9
+
10
+ export interface SubmitFormDataOptions {
11
+ endpoint: string;
12
+ form$: any;
13
+ formSchema: FormReactiveSchema | any;
14
+ formHooks?: FormSchemaHooks;
15
+ }
16
+
17
+ interface BaseFormOptions {
18
+ title: string;
19
+ endpoint: string;
20
+ formSchema: FormReactiveSchema;
21
+ formHooks?: FormSchemaHooks;
22
+ formDialogClass?: string;
23
+ pageConfig?: any;
24
+ }
25
+
26
+ export interface AddFormOptions extends BaseFormOptions {}
27
+
28
+ export interface EditFormOptions extends BaseFormOptions {
29
+ item: any;
30
+ }
31
+
32
+ export interface DeleteRestoreFormOptions extends BaseFormOptions {
33
+ index: number;
34
+ allData: any[];
35
+ item: any;
36
+ }
37
+
38
+ // ==========================================
39
+ // CORE INTERFACES FOR GENERIC ADD DATA LIB
40
+ // ==========================================
41
+
42
+ export interface FormStateRefs {
43
+ loadingForm: any;
44
+ formType: any;
45
+ formOpen: any;
46
+ formError: any;
47
+ formEditEl?: any;
48
+ }
49
+
50
+ export interface FormHooksConfig {
51
+ onBeforeMount?: (formSchema: any, formType: "add" | "edit", data?: any) => Promise<boolean>;
52
+ onMounted?: (formEl: any, formSchema: any, formType: "add" | "edit", data?: any) => Promise<boolean>;
53
+ onChange?: (after: any, before: any, formEl: any, formSchema: any, formType: "add" | "edit") => void;
54
+ onBeforeSubmit?: (form$: any) => Promise<boolean>;
55
+ onAfterSubmit?: (response: any) => void;
56
+ }
57
+
58
+ export interface OrganizationAutoFillConfig {
59
+ enabled: boolean;
60
+ fieldName?: string; // default: 'organizationId'
61
+ accessLevelField?: string; // default: 'accessLevel'
62
+ endpoint?: string; // default: '/organization/my'
63
+ }
64
+
65
+ export interface EndpointSpecificConfig {
66
+ [endpoint: string]: {
67
+ onMount?: (formEditEl: any) => void;
68
+ customFields?: Record<string, any>;
69
+ validation?: (formData: any) => Promise<boolean>;
70
+ };
71
+ }
72
+
73
+ // Base interface untuk semua add data options
74
+ export interface AddDataBaseOptions {
75
+ title: string;
76
+ endpoint: string;
77
+ formSchema: FormReactiveSchema | any;
78
+ formHooks?: FormSchemaHooks | FormHooksConfig;
79
+ pageConfig?: any;
80
+
81
+ // Callbacks
82
+ onSuccess?: () => void;
83
+ onError?: (error: string) => void;
84
+
85
+ // Auto-fill configuration
86
+ organizationAutoFill?: OrganizationAutoFillConfig;
87
+
88
+ // Endpoint specific configurations
89
+ endpointConfig?: EndpointSpecificConfig;
90
+
91
+ // Flow specific (untuk cases seperti PageActivityFlow)
92
+ previousData?: any;
93
+ previousDataField?: string;
94
+ }
95
+
96
+ // Interface untuk FormSheet mode (seperti PageActivity.vue)
97
+ export interface AddDataSheetOptions extends AddDataBaseOptions {
98
+ mode: "sheet";
99
+ }
100
+
101
+ // Interface untuk Inline mode (seperti PageActivityNew.vue)
102
+ export interface AddDataInlineOptions extends AddDataBaseOptions {
103
+ mode: "inline";
104
+ formState: FormStateRefs;
105
+ }
106
+
107
+ // Interface untuk Basic mode (seperti Master.vue)
108
+ export interface AddDataBasicOptions extends AddDataBaseOptions {
109
+ mode: "basic";
110
+ formState: FormStateRefs;
111
+ }
112
+
113
+ // Interface untuk Flow mode (seperti PageActivityFlow.vue)
114
+ export interface AddDataFlowOptions extends AddDataBaseOptions {
115
+ mode: "flow";
116
+ formState: FormStateRefs;
117
+ itemData: any; // Data item yang dipilih dari table
118
+ previousDataField: string; // Required untuk flow mode
119
+ }
120
+
121
+ // Union type untuk semua options
122
+ export type AddDataOptions = AddDataSheetOptions | AddDataInlineOptions | AddDataBasicOptions | AddDataFlowOptions;
123
+
124
+ // Legacy interface untuk backward compatibility
125
+ export interface AddDataGenericOptions extends AddDataBaseOptions {
126
+ // Form state refs untuk inline mode
127
+ formState?: FormStateRefs;
128
+
129
+ // Options
130
+ mode?: "sheet" | "inline" | "basic" | "flow";
131
+ endpointSpecificHandlers?: {
132
+ [key: string]: (formEditEl: any) => void;
133
+ };
134
+
135
+ // Auto-fill organization (legacy)
136
+ autoFillOrganization?: boolean;
137
+ }
138
+
139
+ /**
140
+ * Dialog
141
+ *
142
+ */
143
+ const formSheet = useFormSheet();
144
+ const errorDialog = useErrorDialog();
145
+ const successDialog = useSuccessDialog();
146
+ const loadingDialog = useLoadingDialog();
147
+ const confirmDialog = useConfirmDialog();
148
+
149
+ /**
150
+ * Submit form data to API
151
+ * based on vue form schema
152
+ *
153
+ */
154
+ export async function submitFormData({ endpoint, form$, formSchema, formHooks }: SubmitFormDataOptions) {
155
+ /**
156
+ * Run schema hook if
157
+ * schema has onBeforeSubmit hook
158
+ *
159
+ */
160
+ if (formHooks && formHooks.onBeforeSubmit) {
161
+ await nextTick();
162
+ if (!(await formHooks.onBeforeSubmit(form$))) return;
163
+ }
164
+
165
+ const formData = { ...form$.data };
166
+
167
+ /**
168
+ * Transfrom data
169
+ *
170
+ */
171
+ for (const [k, v] of Object.entries(formData)) {
172
+ /**
173
+ * Update media
174
+ *
175
+ */
176
+ if (v && (v as any).mimetype) formData[k] = (v as any).id;
177
+
178
+ if (formSchema.value[k]) {
179
+ const schemaItem = formSchema.value[k];
180
+
181
+ /**
182
+ * Format input on fe is formated internaional number
183
+ * and sent to be as a number
184
+ *
185
+ */
186
+ if (schemaItem.mask?.thousandsSeparator === ",") {
187
+ formData[k] = v ? intlFormatedToNumber(String(v)) : null;
188
+ }
189
+
190
+ /**
191
+ * Format number without sparator (input int)
192
+ *
193
+ */
194
+ if (schemaItem.mask?.thousandsSeparator === "") {
195
+ formData[k] = v ? Number(String(v)) : null;
196
+ }
197
+
198
+ /**
199
+ * Format dialog selector,
200
+ * displayed as object selected item,
201
+ * and sent to be as an id string
202
+ */
203
+ if (['dasi_v2_organization', "dasi_v2_selector_single", "dasi_v2_selector_single_v2"].includes(schemaItem.type)) {
204
+ // Accept object, id string, or single-item array of either
205
+ const rawVal: any = v;
206
+ let val: any = Array.isArray(rawVal) ? rawVal[0] : rawVal;
207
+
208
+ // Fallback: if user didn't touch the field, take id/object from schema default (object or [object])
209
+ if ((!val || (!val.id && typeof val !== 'string')) && schemaItem?.default) {
210
+ const def: any = Array.isArray(schemaItem.default) ? schemaItem.default[0] : schemaItem.default;
211
+ if (def) val = def;
212
+ }
213
+
214
+ // Resolve id
215
+ const resolvedId = typeof val === 'string' ? val : val?.id || null;
216
+
217
+ if (schemaItem.type === "dasi_v2_selector_single_v2" && schemaItem.subItem) {
218
+ formData[k] = {
219
+ id: resolvedId,
220
+ subItemSelectedId: (val as any)?.subItemSelected?.[schemaItem.subItem.submitField || "id"]
221
+ };
222
+ } else {
223
+ formData[k] = resolvedId;
224
+ }
225
+
226
+ // no-op
227
+ }
228
+ }
229
+ }
230
+
231
+ form$.cancelToken = form$?.$vueform?.services?.axios?.CancelToken?.source();
232
+ return await api.post(endpoint, formData, {
233
+ cancelToken: form$.cancelToken.token
234
+ });
235
+ }
236
+
237
+ export async function addFormData(options: AddFormOptions) {
238
+ /**
239
+ * Clear schema
240
+ * and display loading
241
+ *
242
+ */
243
+ clearFormSchema(Object.entries(options.formSchema.value));
244
+ loadingDialog.open();
245
+
246
+ /**
247
+ * Add on before mount and pass edit data,
248
+ * this might change the schema
249
+ *
250
+ */
251
+ if (options.formHooks?.onBeforeMount) {
252
+ try {
253
+ if (!(await options.formHooks.onBeforeMount(options.formSchema, "add"))) {
254
+ loadingDialog.close();
255
+ return;
256
+ }
257
+ } catch (err: any) {
258
+ loadingDialog.close();
259
+ errorDialog.open({
260
+ title: "Tamabah Data Gagal",
261
+ description: err.message || InternalServerError
262
+ });
263
+ return;
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Auto fill organization from
269
+ * auth session
270
+ *
271
+ */
272
+ for (const [_, item] of Object.entries(options.formSchema.value)) {
273
+ if (item.autofill) {
274
+ try {
275
+ const r = await api.get("/organization/my");
276
+ if (!item.accessLevel || (r.data.data.accessLevel && r.data.data.accessLevel.code === item.accessLevel)) {
277
+ item.default = [r.data.data];
278
+ }
279
+ } catch (err) {
280
+ toast.error("Get my organization failed!");
281
+ }
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Render form
287
+ * Hide loading data preparation
288
+ *
289
+ */
290
+ loadingDialog.close();
291
+ return await formSheet.open({
292
+ title: options.title,
293
+ formSchema: options.formSchema,
294
+ loading: false,
295
+ className: options.formDialogClass,
296
+ onChange(after, before, el$) {
297
+ if (options.formHooks?.onChange) {
298
+ options.formHooks?.onChange(after, before, el$, options.formSchema, "add");
299
+ }
300
+ },
301
+ async onMounted(form$) {
302
+ if (options.formHooks?.onMounted) {
303
+ try {
304
+ if (!(await options.formHooks?.onMounted(form$, options.formSchema, "add"))) {
305
+ formSheet.close();
306
+ }
307
+ } catch (err: any) {
308
+ errorDialog
309
+ .open({
310
+ title: "Tamabah Data Gagal",
311
+ description: err.message || InternalServerError
312
+ })
313
+ .then(() => {
314
+ formSheet.close();
315
+ });
316
+ }
317
+ }
318
+ },
319
+ async onSubmit(form$) {
320
+ formSheet.saving = true;
321
+ try {
322
+ const b = await submitFormData({
323
+ form$,
324
+ endpoint: options.endpoint,
325
+ formSchema: options.formSchema,
326
+ formHooks: options.formHooks
327
+ });
328
+ if (!b) return;
329
+ successDialog.open().then(() => {
330
+ formSheet.close(true);
331
+ });
332
+ } catch (err: any) {
333
+ formSheet.formError = err?.response?.data?.[0]?.message || err.message || InternalServerError;
334
+ } finally {
335
+ formSheet.saving = false;
336
+ }
337
+ }
338
+ });
339
+ }
340
+
341
+ export function fieldCapitalFirst(e: any) {
342
+ const val = e.target?.value ?? "";
343
+ if (val.length > 0) {
344
+ let capitalizedString = val[0].toUpperCase() + val.slice(1);
345
+ e.target.value = capitalizedString;
346
+ }
347
+ }
348
+
349
+ export function fieldCapitalize(e: any) {
350
+ const val = e.target?.value ?? "";
351
+ if (val.length > 0) {
352
+ e.target.value = val.toUpperCase();
353
+ }
354
+ }
355
+
356
+ // ==========================================
357
+ // CORE FUNCTIONS FOR GENERIC ADD DATA LIB
358
+ // ==========================================
359
+
360
+ /**
361
+ * Helper function untuk auto-fill organization
362
+ */
363
+ async function handleOrganizationAutoFill(formSchema: any, config: OrganizationAutoFillConfig): Promise<void> {
364
+ if (!config.enabled) return;
365
+
366
+ const fieldName = config.fieldName || "organizationId";
367
+ const accessLevelField = config.accessLevelField || "accessLevel";
368
+ const endpoint = config.endpoint || "/organization/my";
369
+
370
+ if (!formSchema.value[fieldName]?.autofill) return;
371
+
372
+ try {
373
+ const response = await api.get(endpoint);
374
+ const orgData = response.data.data;
375
+
376
+ if (!formSchema.value[fieldName][accessLevelField] || (orgData[accessLevelField] && formSchema.value[fieldName][accessLevelField] === orgData[accessLevelField].code)) {
377
+ formSchema.value[fieldName].default = [orgData];
378
+ }
379
+ } catch (err) {
380
+ toast.error("Get my organization failed!");
381
+ throw err;
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Helper function untuk endpoint specific configuration
387
+ */
388
+ function handleEndpointSpecificConfig(endpoint: string, formEditEl: any, config?: EndpointSpecificConfig): void {
389
+ if (!config || !config[endpoint] || !formEditEl) return;
390
+
391
+ const endpointConfig = config[endpoint];
392
+
393
+ if (endpointConfig.onMount) {
394
+ setTimeout(() => {
395
+ endpointConfig.onMount!(formEditEl.value);
396
+ });
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Helper function untuk setup previous data (flow mode)
402
+ */
403
+ function setupPreviousData(formSchema: any, previousData: any, previousDataField?: string): void {
404
+ if (!previousData || !previousDataField) return;
405
+
406
+ if (formSchema.value[previousDataField]) {
407
+ formSchema.value[previousDataField].default = [previousData];
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Core function - FormSheet Mode (seperti PageActivity.vue)
413
+ */
414
+ async function executeAddDataSheet(options: AddDataSheetOptions): Promise<boolean> {
415
+ const { title, endpoint, formSchema, formHooks, pageConfig, onSuccess } = options;
416
+
417
+ const savePath = pageConfig?.savePath || endpoint;
418
+
419
+ const success = await addFormData({
420
+ title,
421
+ endpoint: savePath,
422
+ formSchema,
423
+ formHooks
424
+ });
425
+
426
+ if (success && onSuccess) {
427
+ onSuccess();
428
+ }
429
+
430
+ return success || false;
431
+ }
432
+
433
+ /**
434
+ * Core function - Basic Mode (seperti Master.vue)
435
+ */
436
+ async function executeAddDataBasic(options: AddDataBasicOptions): Promise<boolean> {
437
+ const { formSchema, formState } = options;
438
+
439
+ // Simple clear schema (Master.vue pattern)
440
+ clearFormSchema(Object.entries(formSchema.value || formSchema));
441
+
442
+ formState.loadingForm.value = false;
443
+ formState.formType.value = "add";
444
+ formState.formOpen.value = true;
445
+ formState.formError.value = null;
446
+
447
+ return true;
448
+ }
449
+
450
+ /**
451
+ * Core function - Inline Mode (seperti PageActivityNew.vue)
452
+ */
453
+ async function executeAddDataInline(options: AddDataInlineOptions): Promise<boolean> {
454
+ const { formSchema, formHooks, formState, organizationAutoFill, endpointConfig, endpoint, onError } = options;
455
+
456
+ // Clear schema dan setup form state
457
+ clearFormSchema(Object.entries(formSchema.value));
458
+
459
+ formState.loadingForm.value = true;
460
+ formState.formType.value = "add";
461
+ formState.formOpen.value = true;
462
+ formState.formError.value = null;
463
+
464
+ try {
465
+ // Call schema onMounted hook
466
+ if (formSchema.value.onMounted) {
467
+ if (!(await formSchema.value.onMounted("add", formSchema))) {
468
+ formState.formOpen.value = false;
469
+ return false;
470
+ }
471
+ }
472
+
473
+ // Call form hooks
474
+ if (formHooks?.onMounted) {
475
+ if (!(await formHooks.onMounted(formState.formEditEl?.value, formSchema, "add"))) {
476
+ formState.formOpen.value = false;
477
+ return false;
478
+ }
479
+ }
480
+
481
+ // Handle endpoint specific configuration
482
+ handleEndpointSpecificConfig(endpoint, formState.formEditEl, endpointConfig);
483
+
484
+ // Handle organization auto-fill
485
+ if (organizationAutoFill?.enabled) {
486
+ await handleOrganizationAutoFill(formSchema, organizationAutoFill);
487
+ }
488
+
489
+ return true;
490
+ } catch (err: any) {
491
+ console.error("Failed to add form");
492
+ onError?.(err.message || InternalServerError);
493
+ formState.formOpen.value = false;
494
+ return false;
495
+ } finally {
496
+ formState.loadingForm.value = false;
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Core function - Flow Mode (seperti PageActivityFlow.vue)
502
+ */
503
+ async function executeAddDataFlow(options: AddDataFlowOptions): Promise<boolean> {
504
+ const { formSchema, formState, itemData, previousDataField, organizationAutoFill, onError } = options;
505
+
506
+ // Clear schema
507
+ clearFormSchema(Object.entries(formSchema.value));
508
+
509
+ // Setup previous data
510
+ setupPreviousData(formSchema, itemData, previousDataField);
511
+
512
+ const needsOrgAutoFill = organizationAutoFill?.enabled;
513
+ formState.loadingForm.value = needsOrgAutoFill || false;
514
+ formState.formType.value = "add";
515
+ formState.formOpen.value = true;
516
+ formState.formError.value = null;
517
+
518
+ try {
519
+ // Handle organization auto-fill
520
+ if (organizationAutoFill?.enabled) {
521
+ await handleOrganizationAutoFill(formSchema, organizationAutoFill);
522
+ }
523
+
524
+ return true;
525
+ } catch (err: any) {
526
+ onError?.(err.message || InternalServerError);
527
+ return false;
528
+ } finally {
529
+ formState.loadingForm.value = false;
530
+ }
531
+ }
532
+
533
+ /**
534
+ * Main function - Generic Add Data
535
+ * Router untuk semua mode add data
536
+ */
537
+ export async function addData(options: AddDataOptions): Promise<boolean> {
538
+ // Validation
539
+ if (!options.formSchema?.value && !options.formSchema) {
540
+ options.onError?.("Form schema tidak ditemukan");
541
+ return false;
542
+ }
543
+
544
+ try {
545
+ switch (options.mode) {
546
+ case "sheet":
547
+ return await executeAddDataSheet(options);
548
+
549
+ case "basic":
550
+ return await executeAddDataBasic(options);
551
+
552
+ case "inline":
553
+ return await executeAddDataInline(options);
554
+
555
+ case "flow":
556
+ return await executeAddDataFlow(options);
557
+
558
+ default:
559
+ throw new Error(`Unsupported mode: ${(options as any).mode}`);
560
+ }
561
+ } catch (error: any) {
562
+ options.onError?.(error.message || InternalServerError);
563
+ return false;
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Legacy function untuk backward compatibility
569
+ * @deprecated Use addData() instead
570
+ */
571
+ export async function addDataGeneric(options: AddDataGenericOptions): Promise<boolean> {
572
+ // Convert legacy options to new format
573
+ const mode = options.mode || "sheet";
574
+
575
+ // Handle legacy autoFillOrganization
576
+ let organizationAutoFill: OrganizationAutoFillConfig | undefined;
577
+ if (options.autoFillOrganization) {
578
+ organizationAutoFill = { enabled: true };
579
+ }
580
+
581
+ // Handle legacy endpointSpecificHandlers
582
+ let endpointConfig: EndpointSpecificConfig | undefined;
583
+ if (options.endpointSpecificHandlers) {
584
+ endpointConfig = {};
585
+ for (const [endpoint, handler] of Object.entries(options.endpointSpecificHandlers)) {
586
+ endpointConfig[endpoint] = { onMount: handler };
587
+ }
588
+ }
589
+
590
+ const newOptions: AddDataOptions = {
591
+ ...options,
592
+ mode: mode as any,
593
+ organizationAutoFill,
594
+ endpointConfig
595
+ } as AddDataOptions;
596
+
597
+ return await addData(newOptions);
598
+ }
599
+
600
+ // ==========================================
601
+ // HELPER FUNCTIONS FOR EASY USAGE
602
+ // ==========================================
603
+
604
+ /**
605
+ * Helper untuk Sheet Mode (PageActivity.vue pattern)
606
+ * Paling simple untuk digunakan
607
+ */
608
+ export async function addDataSheet(options: {
609
+ title: string;
610
+ endpoint: string;
611
+ formSchema: any;
612
+ formHooks?: any;
613
+ pageConfig?: any;
614
+ onSuccess?: () => void;
615
+ onError?: (error: string) => void;
616
+ }): Promise<boolean> {
617
+ return await addData({
618
+ ...options,
619
+ mode: "sheet"
620
+ });
621
+ }
622
+
623
+ /**
624
+ * Helper untuk Inline Mode (PageActivityNew.vue pattern)
625
+ * Dengan auto-fill organization
626
+ */
627
+ export async function addDataInline(options: {
628
+ title: string;
629
+ endpoint: string;
630
+ formSchema: any;
631
+ formHooks?: any;
632
+ pageConfig?: any;
633
+ formState: FormStateRefs;
634
+ onSuccess?: () => void;
635
+ onError?: (error: string) => void;
636
+ endpointHandlers?: Record<string, (formEditEl: any) => void>;
637
+ }): Promise<boolean> {
638
+ // Auto-detect organization auto-fill
639
+ const hasOrgField = options.formSchema.value?.organizationId?.autofill;
640
+
641
+ return await addData({
642
+ ...options,
643
+ mode: "inline",
644
+ organizationAutoFill: hasOrgField ? { enabled: true } : undefined,
645
+ endpointConfig: options.endpointHandlers ? Object.fromEntries(Object.entries(options.endpointHandlers).map(([key, handler]) => [key, { onMount: handler }])) : undefined
646
+ });
647
+ }
648
+
649
+ /**
650
+ * Helper untuk Basic Mode (Master.vue pattern)
651
+ * Paling simple tanpa auto-fill
652
+ */
653
+ export async function addDataBasic(options: {
654
+ formSchema: any;
655
+ formState: FormStateRefs;
656
+ onError?: (error: string) => void;
657
+ customClearFunction?: (schema: any) => void; // For Master.vue custom clearSchema
658
+ }): Promise<boolean> {
659
+ // Handle custom clear function for Master.vue pattern
660
+ if (options.customClearFunction) {
661
+ options.customClearFunction(Object.entries(options.formSchema));
662
+ }
663
+
664
+ return await addData({
665
+ title: "Data",
666
+ endpoint: "",
667
+ ...options,
668
+ mode: "basic"
669
+ });
670
+ }
671
+
672
+ /**
673
+ * Helper untuk Flow Mode (PageActivityFlow.vue pattern)
674
+ * Dengan previous data auto-fill
675
+ */
676
+ export async function addDataFlow(options: {
677
+ title: string;
678
+ endpoint: string;
679
+ formSchema: any;
680
+ formState: FormStateRefs;
681
+ itemData: any;
682
+ previousDataField: string;
683
+ onSuccess?: () => void;
684
+ onError?: (error: string) => void;
685
+ withOrganizationAutoFill?: boolean;
686
+ customClearFunction?: (schema: any) => void; // For PageActivityFlow.vue custom clearSchema
687
+ }): Promise<boolean> {
688
+ // Handle custom clear function for PageActivityFlow.vue pattern
689
+ if (options.customClearFunction) {
690
+ options.customClearFunction(Object.entries(options.formSchema.value));
691
+ }
692
+
693
+ return await addData({
694
+ ...options,
695
+ mode: "flow",
696
+ organizationAutoFill: options.withOrganizationAutoFill ? { enabled: true } : undefined
697
+ });
698
+ }
699
+
700
+ /**
701
+ * Helper untuk create custom endpoint configuration
702
+ */
703
+ export function createEndpointConfig(configs: { [endpoint: string]: (formEditEl: any) => void }): EndpointSpecificConfig {
704
+ return Object.fromEntries(Object.entries(configs).map(([endpoint, handler]) => [endpoint, { onMount: handler }]));
705
+ }
706
+
707
+ /**
708
+ * Helper untuk create organization auto-fill config
709
+ */
710
+ export function createOrgAutoFillConfig(options?: { fieldName?: string; accessLevelField?: string; endpoint?: string }): OrganizationAutoFillConfig {
711
+ return {
712
+ enabled: true,
713
+ fieldName: options?.fieldName || "organizationId",
714
+ accessLevelField: options?.accessLevelField || "accessLevel",
715
+ endpoint: options?.endpoint || "/organization/my"
716
+ };
717
+ }
718
+
719
+ /**
720
+ * Factory function untuk membuat add data function yang sudah dikonfigurasi
721
+ * Berguna untuk halaman yang sering digunakan
722
+ */
723
+ export function createAddDataFunction(baseConfig: Partial<AddDataOptions>) {
724
+ return async (overrides: Partial<AddDataOptions> = {}): Promise<boolean> => {
725
+ const mergedConfig = { ...baseConfig, ...overrides } as AddDataOptions;
726
+ return await addData(mergedConfig);
727
+ };
728
+ }
729
+
730
+ // ==========================================
731
+ // PRESET CONFIGURATIONS FOR COMMON PATTERNS
732
+ // ==========================================
733
+
734
+ /**
735
+ * Preset untuk halaman dengan FormSheet (seperti PageActivity.vue)
736
+ */
737
+ export const SHEET_MODE_PRESET = {
738
+ mode: "sheet" as const
739
+ };
740
+
741
+ /**
742
+ * Preset untuk halaman dengan inline form + auto-fill org (seperti PageActivityNew.vue)
743
+ */
744
+ export const INLINE_WITH_ORG_PRESET = {
745
+ mode: "inline" as const,
746
+ organizationAutoFill: { enabled: true }
747
+ };
748
+
749
+ /**
750
+ * Preset untuk halaman basic (seperti Master.vue)
751
+ */
752
+ export const BASIC_MODE_PRESET = {
753
+ mode: "basic" as const
754
+ };
755
+
756
+ /**
757
+ * Preset untuk halaman flow (seperti PageActivityFlow.vue)
758
+ */
759
+ export const FLOW_MODE_PRESET = {
760
+ mode: "flow" as const,
761
+ organizationAutoFill: { enabled: true }
762
+ };
763
+
764
+ /**
765
+ * -------------------------------------------
766
+ * Edit item
767
+ * @return
768
+ * true: data saved to api
769
+ * false: aborted
770
+ *
771
+ */
772
+ export async function editFormData(options: EditFormOptions) {
773
+ /**
774
+ * Clear schema
775
+ *
776
+ */
777
+ clearFormSchema(Object.entries(options.formSchema.value));
778
+ let editData: any;
779
+
780
+ /**
781
+ * Generate save api url
782
+ *
783
+ */
784
+ const slash = options.endpoint.startsWith("/") ? "" : "/";
785
+ const uri = `${slash}${options.endpoint}/${options.item.id}`;
786
+
787
+ /**
788
+ * Render form with loading
789
+ *
790
+ */
791
+ return await formSheet.open({
792
+ title: options.title,
793
+ formSchema: options.formSchema,
794
+ loading: true,
795
+ className: options.formDialogClass,
796
+ onChange(after, before, el$) {
797
+ if (options.formHooks?.onChange) {
798
+ options.formHooks?.onChange(after, before, el$, options.formSchema, "edit");
799
+ }
800
+ },
801
+ async onDialogOpen() {
802
+ try {
803
+ /**
804
+ * Get edit data from api
805
+ *
806
+ */
807
+ let editUri = uri;
808
+ // Include extras for relational data (e.g., AccessLevel)
809
+ if (options.pageConfig?.extras?.length > 0) {
810
+ editUri += `?extras=${options.pageConfig.extras.join(",")}`;
811
+ }
812
+ const r = await api.get(editUri);
813
+ editData = r.data.data;
814
+
815
+ /**
816
+ * Add on before mount and pass edit data,
817
+ * this might change the schema
818
+ *
819
+ */
820
+ if (options.formHooks?.onBeforeMount) {
821
+ if (!(await options.formHooks.onBeforeMount(options.formSchema, "edit", editData))) {
822
+ return;
823
+ }
824
+ }
825
+
826
+ /**
827
+ * Fill schema with editData from API and then
828
+ * Render form by set loading to false
829
+ *
830
+ */
831
+ fillFormSchema(Object.entries(options.formSchema.value), editData);
832
+ formSheet.loading = false;
833
+ } catch (err: any) {
834
+ errorDialog
835
+ .open({
836
+ title: "Edit Data Gagal",
837
+ description: err.message || InternalServerError
838
+ })
839
+ .then(() => {
840
+ formSheet.close();
841
+ });
842
+ }
843
+ },
844
+ async onMounted(form$) {
845
+ try {
846
+ /**
847
+ * After form rendered
848
+ * run onMounted event
849
+ *
850
+ */
851
+ if (options.formHooks?.onMounted) {
852
+ console.log('q',options.formHooks?.onMounted )
853
+ if (!(await options.formHooks?.onMounted(form$, options.formSchema, "edit", editData))) {
854
+ console.log('On mounted failed, edit canceled');
855
+ formSheet.close();
856
+ }
857
+ }
858
+ } catch (err: any) {
859
+ errorDialog
860
+ .open({
861
+ title: "Edit Data Gagal",
862
+ description: err.message || InternalServerError
863
+ })
864
+ .then(() => {
865
+ formSheet.close();
866
+ });
867
+ }
868
+ },
869
+ async onSubmit(form$) {
870
+ formSheet.saving = true;
871
+ try {
872
+ const b = await submitFormData({
873
+ form$,
874
+ endpoint: `${uri}/edit`,
875
+ formSchema: options.formSchema,
876
+ formHooks: options.formHooks
877
+ });
878
+ if (!b) return;
879
+ successDialog.open().then(() => {
880
+ formSheet.close(true);
881
+ });
882
+ } catch (err: any) {
883
+ formSheet.formError = err?.response?.data?.[0]?.message || err.message || InternalServerError;
884
+ } finally {
885
+ formSheet.saving = false;
886
+ }
887
+ }
888
+ });
889
+
890
+ // loadingForm.value = true;
891
+ // formType.value = "edit";
892
+ // formOpen.value = true;
893
+ // formError.value = null;
894
+ // editId.value = item.id;
895
+ // let editData: any = null;
896
+ // api
897
+ // .get(`${endpoint.value}/${item.id}`)
898
+ // .then(async (r) => {
899
+ // editData = r.data.data;
900
+ // fillFormSchema(Object.entries(formSchema.value || {}), r.data.data);
901
+ // })
902
+ // .catch((err) => {
903
+ // errorDialog.value?.open({
904
+ // title: `Edit ${title.value} Gagal`,
905
+ // description: err.message || "Internal server error. Please try again later.",
906
+ // });
907
+ // })
908
+ // .finally(() => {
909
+ // loadingForm.value = false;
910
+ // if (!formSchema.value) return;
911
+ // setTimeout(async () => {
912
+ // if (formHooks.value && formHooks.value.onMounted) {
913
+ // await formHooks.value.onMounted(formEditEl.value, formSchema, 'edit', editData);
914
+ // }
915
+ // })
916
+ // });
917
+ }
918
+
919
+ /**
920
+ * -------------------------------------------
921
+ * Delete item
922
+ * @return
923
+ * true: data deleted to api
924
+ * false: aborted
925
+ *
926
+ */
927
+ export async function deleteFormData(options: DeleteRestoreFormOptions) {
928
+ const name = options.pageConfig?.dataName ? options.pageConfig.dataName(options.item) : (options.item?.name || options.item?.nama || "data");
929
+ const b = await confirmDialog.open({
930
+ title: `Hapus ${options.title}`,
931
+ description: `Apakah Anda yakin ingin menghapus ${options.title.toLowerCase()} <b class="font-bold text-red-500">${name}?</b> Data terhapus akan dipindah ke dalam folder Deleted`,
932
+ cancelLabel: "Batal",
933
+ actionLabel: `Hapus ${options.title}`,
934
+ actionIcon: "LucideTrash2",
935
+ negative: true
936
+ });
937
+
938
+ /**
939
+ * Aborted by user
940
+ *
941
+ */
942
+ if (!b) return false;
943
+ const deletedItem = options.allData.splice(options.index, 1);
944
+ try {
945
+ api.delete(`${options.endpoint}/${options.item.id}/soft`);
946
+ toast.success(`${options.title} ${name} sukses dihapus`, {
947
+ action: {
948
+ label: "Undo",
949
+ onClick: () => {
950
+ options.allData.splice(options.index, 0, deletedItem[0]);
951
+ api
952
+ .put(`${options.endpoint}/${options.item.id}/restore`)
953
+ .then(() => {
954
+ toast.info(`Aksi hapus ${name} dibatalkan`);
955
+ })
956
+ .catch(err => {
957
+ errorDialog.open({
958
+ title: `Undo Hapus ${options.title} Gagal`,
959
+ description: err.message || "Internal server error. Please try again later."
960
+ });
961
+ });
962
+ }
963
+ }
964
+ });
965
+ } catch (err: any) {
966
+ options.allData.splice(options.index, 0, deletedItem[0]);
967
+ errorDialog.open({
968
+ title: `Hapus ${options.title} Gagal`,
969
+ description: err.message || "Internal server error. Please try again later."
970
+ });
971
+ }
972
+ }
973
+
974
+ /**
975
+ * -------------------------------------------
976
+ * Restore item
977
+ * @return
978
+ * true: data restored to api
979
+ * false: aborted
980
+ *
981
+ */
982
+ export async function restoreFormData(options: DeleteRestoreFormOptions) {
983
+ const name = options.pageConfig?.dataName ? options.pageConfig.dataName(options.item) : (options.item?.name || options.item?.nama || "data");
984
+ const b = await confirmDialog.open({
985
+ title: `Restore ${options.title}`,
986
+ description: `Apakah Anda yakin ingin mengembalikan ${options.title.toLowerCase()} <b class="font-bold text-red-500">${name}?</b> Data akan tampil kembali di semua data`,
987
+ cancelLabel: "Batal",
988
+ actionLabel: `Restore ${options.title}`,
989
+ actionIcon: "LucideUndo2",
990
+ negative: true
991
+ });
992
+
993
+ /**
994
+ * Aborted by user
995
+ *
996
+ */
997
+ if (!b) return false;
998
+ const restoredItem = options.allData.splice(options.index, 1);
999
+ try {
1000
+ api.put(`${options.endpoint}/${options.item.id}/restore`);
1001
+ toast.success(`${options.title} ${name} sukses dikembalikan`);
1002
+ } catch (err: any) {
1003
+ options.allData.splice(options.index, 0, restoredItem[0]);
1004
+ errorDialog.open({
1005
+ title: `Restore ${options.title} Gagal`,
1006
+ description: err.message || "Internal server error. Please try again later."
1007
+ });
1008
+ }
1009
+ }