@dragonmastery/dragoncore-vue 0.0.35 → 0.0.36

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 (195) hide show
  1. package/dist/ChangePasswordPage-BOMNp35R.js +7 -0
  2. package/dist/{ChangePasswordPage-CR91NZP4.js → ChangePasswordPage-ITglJw64.js} +2 -2
  3. package/dist/{ChangePasswordPage-CR91NZP4.js.map → ChangePasswordPage-ITglJw64.js.map} +1 -1
  4. package/dist/{ConsentRequired-DtUwfpk0.js → ConsentRequired-CD9_9drZ.js} +7 -7
  5. package/dist/{ConsentRequired-DtUwfpk0.js.map → ConsentRequired-CD9_9drZ.js.map} +1 -1
  6. package/dist/CreateTeamForm-B9riDuoe.js +12 -0
  7. package/dist/{CreateTeamForm-ClisfzsU.js → CreateTeamForm-tQemosKP.js} +4 -4
  8. package/dist/{CreateTeamForm-ClisfzsU.js.map → CreateTeamForm-tQemosKP.js.map} +1 -1
  9. package/dist/{CreateTeamMemberForm-B3jxlAsC.js → CreateTeamMemberForm-CiKnRKTm.js} +4 -4
  10. package/dist/{CreateTeamMemberForm-B3jxlAsC.js.map → CreateTeamMemberForm-CiKnRKTm.js.map} +1 -1
  11. package/dist/CreateTeamMemberForm-OznLRtZ2.js +12 -0
  12. package/dist/{CreateUserPage-BcCIat_l.js → CreateUserPage-DwMcY1iD.js} +2 -2
  13. package/dist/{CreateUserPage-BcCIat_l.js.map → CreateUserPage-DwMcY1iD.js.map} +1 -1
  14. package/dist/CreateUserPage-MTIXjQgC.js +7 -0
  15. package/dist/CreditBalanceDashboard-9Mn6467S.js +13 -0
  16. package/dist/{CreditBalanceDashboard-CJr1yOjW.js → CreditBalanceDashboard-BWEpNj7P.js} +2 -2
  17. package/dist/{CreditBalanceDashboard-CJr1yOjW.js.map → CreditBalanceDashboard-BWEpNj7P.js.map} +1 -1
  18. package/dist/CreditManagement-C65vEqxp.js +13 -0
  19. package/dist/{CreditManagement-BbDEviZx.js → CreditManagement-CEAW1uKw.js} +3 -3
  20. package/dist/{CreditManagement-BbDEviZx.js.map → CreditManagement-CEAW1uKw.js.map} +1 -1
  21. package/dist/{CreditTransactionHistory-mz-QIKUG.js → CreditTransactionHistory-irDJnMV9.js} +5 -5
  22. package/dist/{CreditTransactionHistory-mz-QIKUG.js.map → CreditTransactionHistory-irDJnMV9.js.map} +1 -1
  23. package/dist/{CustomerCreateSupportTicketForm-Cul4aVjB.js → CustomerCreateSupportTicketForm-B6lqDu3-.js} +4 -4
  24. package/dist/{CustomerCreateSupportTicketForm-Cul4aVjB.js.map → CustomerCreateSupportTicketForm-B6lqDu3-.js.map} +1 -1
  25. package/dist/CustomerCreateSupportTicketForm-CmWMP0Vs.js +14 -0
  26. package/dist/{CustomerSupportTicketDetailPage-DflGaKvk.js → CustomerSupportTicketDetailPage-vmpgMU4d.js} +8 -8
  27. package/dist/{CustomerSupportTicketDetailPage-DflGaKvk.js.map → CustomerSupportTicketDetailPage-vmpgMU4d.js.map} +1 -1
  28. package/dist/CustomerSupportTicketList-q1nBdbhH.js +64 -0
  29. package/dist/{CustomerSupportTicketParent-D9FuZjPz.js → CustomerSupportTicketParent-Clov63wF.js} +2 -2
  30. package/dist/{CustomerSupportTicketParent-D9FuZjPz.js.map → CustomerSupportTicketParent-Clov63wF.js.map} +1 -1
  31. package/dist/CustomerSupportTicketParent-M9YS9zj9.js +8 -0
  32. package/dist/CustomerSupportTicketSuccess--ztNfpOC.js +12 -0
  33. package/dist/{CustomerSupportTicketSuccess-B4WR8Zfn.js → CustomerSupportTicketSuccess-CfSQ5ve3.js} +2 -2
  34. package/dist/{CustomerSupportTicketSuccess-B4WR8Zfn.js.map → CustomerSupportTicketSuccess-CfSQ5ve3.js.map} +1 -1
  35. package/dist/{DefaultReferralTeamPage-fS1SlVow.js → DefaultReferralTeamPage-Crc26bES.js} +6 -6
  36. package/dist/{DefaultReferralTeamPage-fS1SlVow.js.map → DefaultReferralTeamPage-Crc26bES.js.map} +1 -1
  37. package/dist/{EditTeamForm-B4p-C-8i.js → EditTeamForm-CJlL7tcU.js} +4 -4
  38. package/dist/{EditTeamForm-B4p-C-8i.js.map → EditTeamForm-CJlL7tcU.js.map} +1 -1
  39. package/dist/EditTeamForm-CdnmBsNm.js +12 -0
  40. package/dist/{EditTeamMemberForm-D6vf9hp-.js → EditTeamMemberForm-C0WQvq_7.js} +2 -2
  41. package/dist/{EditTeamMemberForm-D6vf9hp-.js.map → EditTeamMemberForm-C0WQvq_7.js.map} +1 -1
  42. package/dist/EditTeamMemberForm-VC3OouUy.js +9 -0
  43. package/dist/EditUserPage-B0DzlBPq.js +8 -0
  44. package/dist/{EditUserPage-Dy61CCle.js → EditUserPage-BAlhX8JA.js} +3 -3
  45. package/dist/{EditUserPage-Dy61CCle.js.map → EditUserPage-BAlhX8JA.js.map} +1 -1
  46. package/dist/{EnhancedRefreshTokenHandler-s8wUXtB5.js → EnhancedRefreshTokenHandler-bZCCvtpM.js} +2 -2
  47. package/dist/{EnhancedRefreshTokenHandler-s8wUXtB5.js.map → EnhancedRefreshTokenHandler-bZCCvtpM.js.map} +1 -1
  48. package/dist/{ForgotPassword-BykH9B9R.js → ForgotPassword-CYHwOPo1.js} +2 -2
  49. package/dist/{ForgotPassword-BykH9B9R.js.map → ForgotPassword-CYHwOPo1.js.map} +1 -1
  50. package/dist/ForgotPassword-C_g7r8tQ.js +8 -0
  51. package/dist/{InlineAttachments-DvqCOd6U.js → InlineAttachments-DHUmSY59.js} +4 -4
  52. package/dist/{InlineAttachments-DvqCOd6U.js.map → InlineAttachments-DHUmSY59.js.map} +1 -1
  53. package/dist/{LoginForm-CjF4NSgM.js → LoginForm-SW8Z2SnH.js} +3 -3
  54. package/dist/{LoginForm-CjF4NSgM.js.map → LoginForm-SW8Z2SnH.js.map} +1 -1
  55. package/dist/LoginForm-srufyzTf.js +8 -0
  56. package/dist/Logout-DXBwdbV1.js +8 -0
  57. package/dist/{Logout-DmpC8Rwh.js → Logout-Dcxar0WO.js} +4 -3
  58. package/dist/{Logout-DmpC8Rwh.js.map → Logout-Dcxar0WO.js.map} +1 -1
  59. package/dist/{MfaSetup-DCLKIMaS.js → MfaSetup-BJSFbnKm.js} +2 -2
  60. package/dist/{MfaSetup-DCLKIMaS.js.map → MfaSetup-BJSFbnKm.js.map} +1 -1
  61. package/dist/MfaSetup-ByLSlwd5.js +9 -0
  62. package/dist/MfaVerify-BVzkjS0M.js +9 -0
  63. package/dist/{MfaVerify-Dm2Yc0Da.js → MfaVerify-DyuEFCCa.js} +3 -3
  64. package/dist/{MfaVerify-Dm2Yc0Da.js.map → MfaVerify-DyuEFCCa.js.map} +1 -1
  65. package/dist/{ResetPassword-iVcY7eBY.js → ResetPassword-BSLD7bQQ.js} +2 -2
  66. package/dist/{ResetPassword-iVcY7eBY.js.map → ResetPassword-BSLD7bQQ.js.map} +1 -1
  67. package/dist/ResetPassword-CJRPGJF4.js +8 -0
  68. package/dist/{SavedFiltersPage-Y1T18UAH.js → SavedFiltersPage-DPGwcuZ3.js} +51 -51
  69. package/dist/{SavedFiltersPage-Y1T18UAH.js.map → SavedFiltersPage-DPGwcuZ3.js.map} +1 -1
  70. package/dist/Signup-CMDAy5qG.js +10 -0
  71. package/dist/{Signup-D6vnyS4w.js → Signup-D8qxzAae.js} +5 -5
  72. package/dist/{Signup-D6vnyS4w.js.map → Signup-D8qxzAae.js.map} +1 -1
  73. package/dist/{SignupRequirementsPage-BnOkXd7w.js → SignupRequirementsPage-txEGpjmy.js} +6 -6
  74. package/dist/{SignupRequirementsPage-BnOkXd7w.js.map → SignupRequirementsPage-txEGpjmy.js.map} +1 -1
  75. package/dist/{StaffCreateSupportTicketForm-B1YioWlS.js → StaffCreateSupportTicketForm-CYanySsY.js} +6 -6
  76. package/dist/{StaffCreateSupportTicketForm-B1YioWlS.js.map → StaffCreateSupportTicketForm-CYanySsY.js.map} +1 -1
  77. package/dist/StaffCreateSupportTicketForm-dxtP9z1t.js +14 -0
  78. package/dist/{StaffSupportTicketDetailPage-CMxsVxjf.js → StaffSupportTicketDetailPage-DA3vRpJw.js} +8 -8
  79. package/dist/{StaffSupportTicketDetailPage-CMxsVxjf.js.map → StaffSupportTicketDetailPage-DA3vRpJw.js.map} +1 -1
  80. package/dist/StaffSupportTicketList-B4X77wzv.js +64 -0
  81. package/dist/StaffSupportTicketParent-CuEupptb.js +8 -0
  82. package/dist/{StaffSupportTicketParent-CZllER18.js → StaffSupportTicketParent-DFOSKGI1.js} +2 -2
  83. package/dist/{StaffSupportTicketParent-CZllER18.js.map → StaffSupportTicketParent-DFOSKGI1.js.map} +1 -1
  84. package/dist/{StaffSupportTicketSuccess-DTMToAq2.js → StaffSupportTicketSuccess-BNvV1hRs.js} +2 -2
  85. package/dist/{StaffSupportTicketSuccess-DTMToAq2.js.map → StaffSupportTicketSuccess-BNvV1hRs.js.map} +1 -1
  86. package/dist/StaffSupportTicketSuccess-QSDkFoLP.js +12 -0
  87. package/dist/{SupportStaffPage--vinFIlV.js → SupportStaffPage-CJRjoBgD.js} +6 -6
  88. package/dist/{SupportStaffPage--vinFIlV.js.map → SupportStaffPage-CJRjoBgD.js.map} +1 -1
  89. package/dist/{SupportTicketMaintenancePage-C-BWD49g.js → SupportTicketMaintenancePage-8Dm-QIlz.js} +5 -5
  90. package/dist/{SupportTicketMaintenancePage-C-BWD49g.js.map → SupportTicketMaintenancePage-8Dm-QIlz.js.map} +1 -1
  91. package/dist/TeamAttachmentsTab-DcBgmtRU.js +64 -0
  92. package/dist/TeamHistoryTab-CJHmmx7_.js +6 -0
  93. package/dist/{TeamHistoryTab-5kNQ_XAq.js → TeamHistoryTab-DsF7t8Nr.js} +3 -3
  94. package/dist/{TeamHistoryTab-5kNQ_XAq.js.map → TeamHistoryTab-DsF7t8Nr.js.map} +1 -1
  95. package/dist/{TeamList-P7rVlBuQ.js → TeamList-BOoU9XWg.js} +4 -4
  96. package/dist/{TeamList-P7rVlBuQ.js.map → TeamList-BOoU9XWg.js.map} +1 -1
  97. package/dist/TeamList-BeAp59Ic.js +8 -0
  98. package/dist/{TeamMemberList-DyfXcR6F.js → TeamMemberList-3wgkaznJ.js} +4 -4
  99. package/dist/{TeamMemberList-DyfXcR6F.js.map → TeamMemberList-3wgkaznJ.js.map} +1 -1
  100. package/dist/TeamMemberList-txA_1zDI.js +7 -0
  101. package/dist/TeamMemberParent-Ci8UT_YG.js +10 -0
  102. package/dist/{TeamMemberParent-2zISixbT.js → TeamMemberParent-zhMS108u.js} +3 -3
  103. package/dist/{TeamMemberParent-2zISixbT.js.map → TeamMemberParent-zhMS108u.js.map} +1 -1
  104. package/dist/TeamNotesTab-BW-sNIT_.js +8 -0
  105. package/dist/{TeamNotesTab-BREl3Vr0.js → TeamNotesTab-Bp0-6tga.js} +5 -5
  106. package/dist/{TeamNotesTab-BREl3Vr0.js.map → TeamNotesTab-Bp0-6tga.js.map} +1 -1
  107. package/dist/{TeamParent-D35VUiio.js → TeamParent-CT-UfCvh.js} +3 -3
  108. package/dist/{TeamParent-D35VUiio.js.map → TeamParent-CT-UfCvh.js.map} +1 -1
  109. package/dist/TeamParent-ftrZ6TgM.js +11 -0
  110. package/dist/{TimelineNoteInput-D6AbJMx5.js → TimelineNoteInput-D_On05JJ.js} +2 -2
  111. package/dist/{TimelineNoteInput-D6AbJMx5.js.map → TimelineNoteInput-D_On05JJ.js.map} +1 -1
  112. package/dist/{UserListPage-CCl0K7Gk.js → UserListPage-BO6ESqfN.js} +3 -3
  113. package/dist/{UserListPage-CCl0K7Gk.js.map → UserListPage-BO6ESqfN.js.map} +1 -1
  114. package/dist/UserListPage-DJovOSHs.js +5 -0
  115. package/dist/UserProfilePage-BM_M28Wb.js +8 -0
  116. package/dist/{UserProfilePage-D7FNmca1.js → UserProfilePage-DEfN_eCZ.js} +4 -4
  117. package/dist/{UserProfilePage-D7FNmca1.js.map → UserProfilePage-DEfN_eCZ.js.map} +1 -1
  118. package/dist/VerifyEmail-BXXqZxAP.js +10 -0
  119. package/dist/{VerifyEmail-KCti4rzf.js → VerifyEmail-DDnLh6Eu.js} +5 -5
  120. package/dist/{VerifyEmail-KCti4rzf.js.map → VerifyEmail-DDnLh6Eu.js.map} +1 -1
  121. package/dist/{ViewTeam-BbsTsjAy.js → ViewTeam-C-SDshYC.js} +2 -2
  122. package/dist/{ViewTeam-BbsTsjAy.js.map → ViewTeam-C-SDshYC.js.map} +1 -1
  123. package/dist/ViewTeam-x_FhmSTc.js +8 -0
  124. package/dist/{ViewTeamMember-Dsl2GKI1.js → ViewTeamMember-27cPSE4-.js} +2 -2
  125. package/dist/{ViewTeamMember-Dsl2GKI1.js.map → ViewTeamMember-27cPSE4-.js.map} +1 -1
  126. package/dist/ViewTeamMember-BAnH7nlP.js +7 -0
  127. package/dist/{customerSupportTicketRoutes-38JuLJGP.js → customerSupportTicketRoutes-CtugEy49.js} +8 -8
  128. package/dist/{customerSupportTicketRoutes-38JuLJGP.js.map → customerSupportTicketRoutes-CtugEy49.js.map} +1 -1
  129. package/dist/index.d.ts +26 -1
  130. package/dist/index.js +51 -51
  131. package/dist/{saved_filter-YIncsdws.js → saved_filter-DAmsAfuP.js} +5 -5
  132. package/dist/{saved_filter-YIncsdws.js.map → saved_filter-DAmsAfuP.js.map} +1 -1
  133. package/dist/{src-BXO0PrFd.js → src-D1zivPEG.js} +40 -33
  134. package/dist/src-D1zivPEG.js.map +1 -0
  135. package/dist/{staffSupportTicketRoutes-BZrj4aMG.js → staffSupportTicketRoutes-C0JBeFxS.js} +8 -8
  136. package/dist/{staffSupportTicketRoutes-BZrj4aMG.js.map → staffSupportTicketRoutes-C0JBeFxS.js.map} +1 -1
  137. package/dist/{teamMetadata-NTjPt89L.js → teamMetadata-BkICmT4w.js} +9 -1
  138. package/dist/teamMetadata-BkICmT4w.js.map +1 -0
  139. package/dist/{teamRoutes-Aa9aBVCa.js → teamRoutes-CVXDmndU.js} +11 -11
  140. package/dist/{teamRoutes-Aa9aBVCa.js.map → teamRoutes-CVXDmndU.js.map} +1 -1
  141. package/dist/{team_memberRoutes-mO1f-Y4o.js → team_memberRoutes-B3rxZxW2.js} +7 -7
  142. package/dist/{team_memberRoutes-mO1f-Y4o.js.map → team_memberRoutes-B3rxZxW2.js.map} +1 -1
  143. package/dist/{useAuthFlowNextStep-zlvxflBZ.js → useAuthFlowNextStep-DYlsa7We.js} +2 -2
  144. package/dist/{useAuthFlowNextStep-zlvxflBZ.js.map → useAuthFlowNextStep-DYlsa7We.js.map} +1 -1
  145. package/dist/{useEmailVerificationChannel-DYiMSAES.js → useEmailVerificationChannel-7s9wqRoy.js} +2 -2
  146. package/dist/{useEmailVerificationChannel-DYiMSAES.js.map → useEmailVerificationChannel-7s9wqRoy.js.map} +1 -1
  147. package/dist/{useMutation-BXSu7_-s.js → useMutation-Dd1efVil.js} +4 -4
  148. package/dist/{useMutation-BXSu7_-s.js.map → useMutation-Dd1efVil.js.map} +1 -1
  149. package/dist/{useQuery-DownvLRA.js → useQuery-CDsWjdHj.js} +4 -4
  150. package/dist/{useQuery-DownvLRA.js.map → useQuery-CDsWjdHj.js.map} +1 -1
  151. package/dist/{useQueryCache-CUTrwJWX.js → useQueryCache-D6RxB_yQ.js} +2 -2
  152. package/dist/{useQueryCache-CUTrwJWX.js.map → useQueryCache-D6RxB_yQ.js.map} +1 -1
  153. package/dist/{useRpcAuth-BFdprNWb.js → useRpcAuth-BsO0HMzq.js} +3 -3
  154. package/dist/{useRpcAuth-BFdprNWb.js.map → useRpcAuth-BsO0HMzq.js.map} +1 -1
  155. package/dist/{userAuthorized-qmzUYDa-.js → userAuthorized-Ds3-sFU4.js} +2 -2
  156. package/dist/{userAuthorized-qmzUYDa-.js.map → userAuthorized-Ds3-sFU4.js.map} +1 -1
  157. package/package.json +3 -3
  158. package/dist/ChangePasswordPage-qLd6YZVO.js +0 -7
  159. package/dist/CreateTeamForm-DWAeq_Xd.js +0 -12
  160. package/dist/CreateTeamMemberForm-BYsZNxTq.js +0 -12
  161. package/dist/CreateUserPage-D0oMJnGd.js +0 -7
  162. package/dist/CreditBalanceDashboard-D370HlpF.js +0 -13
  163. package/dist/CreditManagement-B4aHJfOo.js +0 -13
  164. package/dist/CustomerCreateSupportTicketForm-DCPjvzyF.js +0 -14
  165. package/dist/CustomerSupportTicketList-BPWQ8WjH.js +0 -64
  166. package/dist/CustomerSupportTicketParent-C0uMeN09.js +0 -8
  167. package/dist/CustomerSupportTicketSuccess-Bsp1d0oF.js +0 -12
  168. package/dist/EditTeamForm-ucwkw2eL.js +0 -12
  169. package/dist/EditTeamMemberForm-BKbWq88S.js +0 -9
  170. package/dist/EditUserPage-DCdj6EYd.js +0 -8
  171. package/dist/ForgotPassword-Xb1yVZ6C.js +0 -8
  172. package/dist/LoginForm-B5wYdKhY.js +0 -8
  173. package/dist/Logout-qyH2t-1a.js +0 -8
  174. package/dist/MfaSetup-DMLXL9fk.js +0 -9
  175. package/dist/MfaVerify-C4xGQZlQ.js +0 -9
  176. package/dist/ResetPassword-ulR2HviU.js +0 -8
  177. package/dist/Signup-D4xILUym.js +0 -10
  178. package/dist/StaffCreateSupportTicketForm-UkE9YVWE.js +0 -14
  179. package/dist/StaffSupportTicketList-BlGTtE1R.js +0 -64
  180. package/dist/StaffSupportTicketParent-D4FKQAmp.js +0 -8
  181. package/dist/StaffSupportTicketSuccess-CzS9uS2h.js +0 -12
  182. package/dist/TeamAttachmentsTab-BgtXRohH.js +0 -64
  183. package/dist/TeamHistoryTab-CBWeRKXM.js +0 -6
  184. package/dist/TeamList-D3NqS5DL.js +0 -8
  185. package/dist/TeamMemberList-X2hzYZFT.js +0 -7
  186. package/dist/TeamMemberParent-DKxE1ziP.js +0 -10
  187. package/dist/TeamNotesTab-DxMN3WZo.js +0 -8
  188. package/dist/TeamParent-CuoVw7Yk.js +0 -11
  189. package/dist/UserListPage-CYkvaHwL.js +0 -5
  190. package/dist/UserProfilePage-BMmz7SGl.js +0 -8
  191. package/dist/VerifyEmail-Xd31Com7.js +0 -10
  192. package/dist/ViewTeam-7YvvwcXd.js +0 -8
  193. package/dist/ViewTeamMember-bmry5QZ0.js +0 -7
  194. package/dist/src-BXO0PrFd.js.map +0 -1
  195. package/dist/teamMetadata-NTjPt89L.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"saved_filter-YIncsdws.js","names":["DEFAULT_OPERATORS: Record<string, string>","config: FilterConfiguration","operator: string","params: Record<string, string>","filters: FilterQueryParams","base: Record<string, string | string[]>","LAST_USED_PREFIX","getLastUsedKey","savedFilterRoutes: Array<ExtendedRouteRecordRaw>"],"sources":["../src/components/BaseModal.vue","../src/constants/time.ts","../src/slices/saved_filter/usePinnedPresets.ts","../src/utils/filterUrlParser.ts","../src/slices/saved_filter/lastUsedPresetGuard.ts","../src/slices/saved_filter/useSavedFilters.ts","../src/slices/saved_filter/savedFilterRoutes.ts","../src/slices/saved_filter/SaveFilterModal.vue","../src/slices/saved_filter/ManagePresetsModal.vue","../src/slices/saved_filter/PresetsModal.vue","../src/slices/saved_filter/SavedFilterPresets.vue"],"sourcesContent":["<template>\n <dialog ref=\"modal\" class=\"modal\">\n <div class=\"modal-box max-w-md w-full max-h-[90vh] flex flex-col p-0\">\n <!-- Header with title and close button - fixed, not scrollable -->\n <div\n class=\"flex justify-between items-center p-6 pb-4 border-b border-base-300 flex-shrink-0\"\n >\n <h3 class=\"font-bold text-lg\">\n <slot name=\"title\">{{ title }}</slot>\n </h3>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n @click.prevent=\"handleClose\"\n aria-label=\"Close modal\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Content slot - scrollable area -->\n <div class=\"modal-content flex-1 overflow-y-auto p-6\">\n <slot></slot>\n </div>\n </div>\n <form method=\"dialog\" class=\"modal-backdrop\">\n <button type=\"button\" @click.prevent=\"handleClose\">close</button>\n </form>\n </dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\n\ninterface Props {\n isOpen: boolean;\n title?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n});\n\nconst emit = defineEmits<{\n close: [];\n}>();\n\nconst modal = ref<HTMLDialogElement>();\n\nconst handleClose = () => {\n emit('close');\n};\n\n// Watch for modal open/close\nwatch(\n () => props.isOpen,\n (isOpen) => {\n if (isOpen && modal.value) {\n modal.value.showModal();\n } else if (!isOpen && modal.value) {\n modal.value.close();\n }\n },\n { immediate: true },\n);\n</script>\n","/**\n * Time duration constants in milliseconds.\n * Use for staleTime, cache TTL, etc.\n *\n * @example\n * staleTime: 30 * MS.ONE_SECOND\n * staleTime: 5 * MS.ONE_MINUTE\n * staleTime: 24 * MS.ONE_HOUR\n */\nexport const MS = {\n ONE_SECOND: 1000,\n ONE_MINUTE: 60 * 1000,\n ONE_HOUR: 60 * 60 * 1000,\n} as const;\n","/**\n * Composable for pinning presets to favorites (home page + sidebar).\n * Uses API with 24h cache. Max 5 pinned presets.\n *\n * Call usePinnedPresets() once in the layout (InAppLayout) and provide it.\n * Children use useInjectedPinnedPresets() to avoid duplicate fetches.\n */\n\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport type { InjectionKey } from 'vue';\nimport { inject } from 'vue';\nimport { MS } from '../../constants/time';\nimport { useMutation } from '../../composables/useMutation';\nimport { useQuery } from '../../composables/useQuery';\nimport { computed } from 'vue';\n\nconst CACHE_KEY = 'pinned-presets';\nconst MAX_PINNED = 5;\n\nexport type PinnedPreset = Pick<\n SavedFilterReadDto,\n 'id' | 'name' | 'context' | 'route_path' | 'filters'\n>;\n\nexport function usePinnedPresets() {\n const { data: pinnedData, refetch } = useQuery(\n (api) => api.savedFilters.listPinnedPresets(),\n { cacheKey: CACHE_KEY, staleTime: 24 * MS.ONE_HOUR },\n );\n\n const { mutate: addPin } = useMutation(\n (api, id: string) => api.savedFilters.addPinnedPreset(id),\n { invalidate: CACHE_KEY },\n );\n\n const { mutate: removePin } = useMutation(\n (api, id: string) => api.savedFilters.removePinnedPreset(id),\n { invalidate: CACHE_KEY },\n );\n\n const pinned = computed(() => pinnedData.value ?? []);\n const pinnedIds = computed(() => new Set(pinned.value.map((p) => p.id)));\n const canPinMore = computed(() => pinned.value.length < MAX_PINNED);\n\n function isPinned(presetId: string): boolean {\n return pinnedIds.value.has(presetId);\n }\n\n async function pinPreset(preset: SavedFilterReadDto): Promise<boolean> {\n if (pinned.value.length >= MAX_PINNED) return false;\n if (pinnedIds.value.has(preset.id)) return true;\n try {\n await addPin(preset.id);\n await refetch();\n return true;\n } catch {\n return false;\n }\n }\n\n async function unpinPreset(presetId: string): Promise<void> {\n try {\n await removePin(presetId);\n await refetch();\n } catch {\n // Error handled by mutation\n }\n }\n\n async function togglePin(preset: SavedFilterReadDto): Promise<boolean> {\n if (isPinned(preset.id)) {\n await unpinPreset(preset.id);\n return false;\n }\n return pinPreset(preset);\n }\n\n function getPresetLink(preset: PinnedPreset): {\n path: string;\n query: Record<string, string | string[]>;\n } {\n return {\n path: preset.route_path,\n query: preset.filters ?? {},\n };\n }\n\n function updatePinnedPreset(\n presetId: string,\n updates: Partial<PinnedPreset>,\n ): void {\n // API is source of truth. Call refetchPinned when a preset is renamed\n // to refresh the pinned list with updated names.\n void presetId;\n void updates;\n }\n\n return {\n pinned,\n pinnedIds,\n canPinMore,\n isPinned,\n pinPreset,\n unpinPreset,\n togglePin,\n getPresetLink,\n updatePinnedPreset,\n refetchPinned: refetch,\n maxPinned: MAX_PINNED,\n };\n}\n\nexport const PINNED_PRESETS_KEY = Symbol('pinnedPresets') as InjectionKey<\n ReturnType<typeof usePinnedPresets>\n>;\n\n/** Use pinned presets from the layout provider. Call this in child components (Sidebar, AppHome, etc.). */\nexport function useInjectedPinnedPresets() {\n const injected = inject(PINNED_PRESETS_KEY);\n if (!injected) {\n throw new Error(\n 'useInjectedPinnedPresets must be used within a component tree that provides pinned presets (e.g. InAppLayout).',\n );\n }\n return injected;\n}\n","/**\n * Filter URL Parser - Query string serialization/deserialization\n * Uses compact DrizzleORM-style format: flt[field]=value or flt[field][op]=value\n */\n\nimport { OPERATORS } from '@dragonmastery/dragoncore-shared';\n\n/**\n * Default operators for each field type when not specified in URL\n */\nconst DEFAULT_OPERATORS: Record<string, string> = {\n string: OPERATORS.CONTAINS,\n number: OPERATORS.EQUALS,\n date: OPERATORS.EQUALS,\n boolean: OPERATORS.EQUALS,\n enum: OPERATORS.EQUALS,\n};\n\n/**\n * Numeric types that should be converted to numbers\n */\nconst NUMERIC_TYPES = ['number', 'money', 'percentage'];\n\n/**\n * Check if operator requires array values\n */\nfunction requiresArrayValues(operator: string): boolean {\n return (\n operator === OPERATORS.IS_ONE_OF ||\n operator === OPERATORS.IS_NOT_ONE_OF ||\n operator === OPERATORS.BETWEEN\n );\n}\n\n/**\n * Check if operator is a null check (requires no value)\n */\nfunction isNullCheckOperator(operator: string): boolean {\n return operator === OPERATORS.IS_EMPTY || operator === OPERATORS.IS_NOT_EMPTY;\n}\n\n/**\n * Field registry metadata for type inference\n */\nexport interface FieldRegistryMetadata {\n [fieldName: string]: {\n type: 'string' | 'number' | 'date' | 'boolean' | 'enum' | 'money' | 'percentage';\n filterable?: boolean;\n };\n}\n\n/**\n * Filter value object structure\n */\nexport interface FilterValueObject {\n operator: string;\n value?: any;\n values?: any[];\n caseSensitive?: boolean;\n}\n\n/**\n * Filter configuration - flat object mapping field names to filter objects\n */\nexport type FilterConfiguration = Record<string, FilterValueObject>;\n\n/**\n * Deserialize filter configuration from URL query parameters object\n * Parses compact DrizzleORM-style format: flt[field]=value or flt[field][op]=value\n *\n * @param params - URL query parameters object (from Vue Router route.query)\n * @param registry - Field registry metadata for type inference\n * @returns Filter configuration object\n *\n * @example\n * // URL: ?flt[department][eq]=Engineering&flt[id]=4&flt[role][in]=[\"admin\",\"user\"]\n * const filters = deserializeFiltersFromQueryParams(route.query, fieldRegistry);\n * // Result: {\n * // department: { operator: 'eq', value: 'Engineering' },\n * // id: { operator: 'eq', value: 4 },\n * // role: { operator: 'in', values: ['admin', 'user'] }\n * // }\n */\nexport function deserializeFiltersFromQueryParams(\n params: Record<string, string | string[]>,\n registry: FieldRegistryMetadata,\n): FilterConfiguration {\n const config: FilterConfiguration = {};\n const fieldMap = new Map<string, Partial<FilterValueObject>>();\n\n // Parse query params\n for (const [key, value] of Object.entries(params)) {\n // Match flt[field] or flt[field][op]\n const matchDefault = key.match(/^flt\\[([^\\]]+)\\]$/);\n const matchWithOp = key.match(/^flt\\[([^\\]]+)\\]\\[([^\\]]+)\\]$/);\n\n if (!matchDefault && !matchWithOp) continue;\n\n const fieldName = matchDefault ? matchDefault[1] : matchWithOp ? matchWithOp[1] : null;\n const operatorShorthand = matchWithOp ? matchWithOp[2] : null;\n const stringValue = Array.isArray(value) ? value[0] : value;\n\n if (!fieldName) continue;\n\n const fieldMeta = registry[fieldName];\n if (!fieldMeta) continue; // Skip unknown fields\n\n const fieldType = fieldMeta.type;\n const defaultOp = DEFAULT_OPERATORS[fieldType] || OPERATORS.EQUALS;\n\n // Determine operator\n let operator: string;\n if (operatorShorthand) {\n operator = operatorShorthand;\n } else {\n operator = defaultOp;\n }\n\n if (!fieldMap.has(fieldName)) {\n fieldMap.set(fieldName, { operator });\n }\n\n const filter = fieldMap.get(fieldName)!;\n filter.operator = operator;\n\n // Parse value based on operator type\n if (isNullCheckOperator(operator)) {\n // Null checks don't have values\n // Value is already set, nothing more to do\n } else if (requiresArrayValues(operator)) {\n // Array operators: parse JSON array (handles commas/quotes in values)\n if (!stringValue || stringValue.trim() === '') {\n fieldMap.delete(fieldName);\n continue;\n }\n\n try {\n const parsed = JSON.parse(stringValue);\n if (Array.isArray(parsed) && parsed.length > 0) {\n // Convert to appropriate types based on field type\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = parsed.map((v) => Number(v));\n } else {\n filter.values = parsed;\n }\n } else {\n fieldMap.delete(fieldName);\n continue;\n }\n } catch (e) {\n // Invalid JSON, try legacy comma-separated format for backward compatibility\n const values = stringValue\n .split(',')\n .map((v) => v.trim())\n .filter((v) => v.length > 0);\n if (values.length === 0) {\n fieldMap.delete(fieldName);\n continue;\n }\n\n if (operator === OPERATORS.BETWEEN && values.length === 2) {\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = [Number(values[0]!), Number(values[1]!)];\n } else if (fieldType === 'date') {\n filter.values = [values[0]!, values[1]!];\n } else {\n filter.values = values;\n }\n } else if (operator === OPERATORS.BETWEEN) {\n fieldMap.delete(fieldName);\n continue;\n } else {\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = values.map((v) => Number(v));\n } else {\n filter.values = values;\n }\n }\n }\n } else {\n // Single value operators\n // Special case: if operator is in/notIn but we got a single value, convert to array\n if (\n (operator === OPERATORS.IS_ONE_OF || operator === OPERATORS.IS_NOT_ONE_OF) &&\n stringValue\n ) {\n // Convert single value to array for array operators\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = [Number(stringValue)];\n } else {\n filter.values = [stringValue];\n }\n } else if (stringValue) {\n // Regular single value operator\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.value = Number(stringValue);\n } else if (fieldType === 'boolean') {\n filter.value = stringValue === 'true' || stringValue === '1';\n } else {\n filter.value = stringValue;\n }\n\n // String fields: always case-insensitive (contains is default)\n if (fieldType === 'string' && operator === OPERATORS.CONTAINS) {\n filter.caseSensitive = false;\n }\n }\n }\n }\n\n // Convert to FilterConfiguration\n for (const [fieldName, filter] of fieldMap.entries()) {\n if (filter.operator) {\n config[fieldName] = filter as FilterValueObject;\n }\n }\n\n return config;\n}\n\n/**\n * Serialize filter configuration to URL query parameters object\n * Uses compact DrizzleORM-style format: flt[field][op]=value\n *\n * @param config - Filter configuration object\n * @param registry - Field registry metadata for type inference\n * @returns URL query parameters object (can be used with Vue Router)\n *\n * @example\n * const filters = {\n * department: { operator: 'eq', value: 'Engineering' },\n * role: { operator: 'in', values: ['admin', 'user'] }\n * };\n * const params = serializeFiltersToQueryParams(filters, fieldRegistry);\n * // Result: {\n * // 'flt[department][eq]': 'Engineering',\n * // 'flt[role][in]': '[\"admin\",\"user\"]'\n * // }\n */\nexport function serializeFiltersToQueryParams(\n config: FilterConfiguration,\n registry: FieldRegistryMetadata,\n): Record<string, string> {\n const params: Record<string, string> = {};\n\n for (const [fieldName, filter] of Object.entries(config)) {\n const fieldMeta = registry[fieldName];\n if (!fieldMeta) continue;\n\n const operator = filter.operator;\n\n if (isNullCheckOperator(operator)) {\n // Null checks don't need values, just the operator\n params[`flt[${fieldName}][${operator}]`] = '';\n } else if (requiresArrayValues(operator)) {\n // Array operators: use JSON encoding (handles commas/quotes)\n if (filter.values && Array.isArray(filter.values)) {\n params[`flt[${fieldName}][${operator}]`] = JSON.stringify(filter.values);\n }\n } else {\n // Single value: include operator explicitly\n params[`flt[${fieldName}][${operator}]`] = String(filter.value);\n }\n }\n\n return params;\n}\n\n/** Raw filter params format used by useSavedFilters (flt[key]=value) */\nexport type FilterQueryParams = Record<string, string | string[]>;\n\n/**\n * Extract filter query params from route query.\n * Handles Vue Router's LocationQuery type which can have null values.\n * Only extracts flt[...] params (actual filters).\n *\n * @example\n * // URL: ?flt[type][in]=[\"sales\",\"escalation\"]&flt[phase][ne]=Post+Sale\n * // Returns: { 'flt[type][in]': '[\"sales\",\"escalation\"]', 'flt[phase][ne]': 'Post+Sale' }\n */\nexport function extractFiltersFromQuery(query: Record<string, unknown>): FilterQueryParams {\n const filters: FilterQueryParams = {};\n\n Object.keys(query).forEach((key) => {\n if (key.startsWith('flt[')) {\n const value = query[key];\n if (value !== null && value !== undefined) {\n if (Array.isArray(value)) {\n const filtered = value.filter((v): v is string => v !== null && v !== undefined);\n if (filtered.length > 0) {\n filters[key] = filtered;\n }\n } else {\n filters[key] = String(value);\n }\n }\n }\n });\n\n return filters;\n}\n\n/**\n * Build a new query object with filter params replaced (not merged).\n * Strips all flt[...] params from the current query, then adds the new filters.\n * Preserves non-filter params (sort, pagination, etc).\n */\nexport function buildQueryWithFilters(\n currentQuery: Record<string, unknown>,\n filters: FilterQueryParams,\n): Record<string, string | string[]> {\n const base: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(currentQuery)) {\n if (!key.startsWith('flt[') && value !== null && value !== undefined) {\n base[key] = Array.isArray(value)\n ? (value.filter((v): v is string => v != null) as string[])\n : String(value);\n }\n }\n return { ...base, ...filters };\n}\n","/**\n * Router guard helper: redirect to last-used preset filters when navigating with no URL filters.\n * Uses localStorage (no API call) - filters are stored when user applies a preset.\n * Prevents double fetch by applying preset before the list component mounts.\n */\n\nimport { buildQueryWithFilters, extractFiltersFromQuery } from '../../utils/filterUrlParser';\n\nconst LAST_USED_PREFIX = 'lastUsedPreset:';\nconst LAST_USED_FILTERS_PREFIX = 'lastUsedPresetFilters:';\n\nfunction getLastUsedKey(context: string): string {\n return `${LAST_USED_PREFIX}${context}`;\n}\n\nfunction getLastUsedFiltersKey(context: string): string {\n return `${LAST_USED_FILTERS_PREFIX}${context}`;\n}\n\nexport function getLastUsedPresetFilters(\n context: string,\n): Record<string, string | string[]> | null {\n try {\n const stored = localStorage.getItem(getLastUsedFiltersKey(context));\n if (!stored) return null;\n const parsed = JSON.parse(stored) as Record<string, string | string[]>;\n return typeof parsed === 'object' && parsed !== null ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastUsedPresetFilters(\n context: string,\n filters: Record<string, string | string[]> | null,\n): void {\n try {\n if (filters && Object.keys(filters).length > 0) {\n localStorage.setItem(getLastUsedFiltersKey(context), JSON.stringify(filters));\n } else {\n localStorage.removeItem(getLastUsedFiltersKey(context));\n }\n } catch {\n // Ignore\n }\n}\n\n/**\n * If navigating with no filters and we have a last-used preset, returns the query to redirect to.\n * Otherwise returns null (no redirect needed).\n */\nexport function getLastUsedPresetRedirect(\n context: string,\n currentQuery: Record<string, unknown>,\n): Record<string, string | string[]> | null {\n const filters = extractFiltersFromQuery(currentQuery);\n if (Object.keys(filters).length > 0) return null;\n\n const lastUsedId = localStorage.getItem(getLastUsedKey(context));\n if (!lastUsedId) return null;\n\n const lastUsedFilters = getLastUsedPresetFilters(context);\n if (!lastUsedFilters || Object.keys(lastUsedFilters).length === 0) return null;\n\n return buildQueryWithFilters(currentQuery, lastUsedFilters);\n}\n\n/**\n * Creates a Vue Router beforeEnter guard that redirects to last-used preset when navigating with no filters.\n * Use on list routes that have SavedFilterPresets.\n */\nexport function createLastUsedPresetGuard(\n context: string,\n routeName: string,\n) {\n return (to: { name?: unknown; query: Record<string, unknown> }) => {\n if (to.name !== routeName) return undefined;\n const redirectQuery = getLastUsedPresetRedirect(context, to.query);\n if (!redirectQuery) return undefined;\n return { name: routeName, query: redirectQuery };\n };\n}\n","/**\n * Composable for saved filter presets - save, apply, and manage named filter configurations.\n * Works with any data table that provides getFiltersFromTable / applyFiltersToTable adapters.\n */\n\nimport type { DragoncoreApi } from '@dragonmastery/dragoncore-shared';\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { MS } from '../../constants/time';\nimport { useMutation } from '../../composables/useMutation';\nimport { useQuery } from '../../composables/useQuery';\nimport { computed, onMounted, ref, watch } from 'vue';\nimport { setLastUsedPresetFilters } from './lastUsedPresetGuard';\n\nconst LAST_USED_PREFIX = 'lastUsedPreset:';\n\nexport type SavedFiltersConfig = {\n /** Unique context per table type (e.g. \"tracker\", \"followup\") */\n context: string;\n /** Route path for the table (e.g. \"/trackers\", \"/followups\") */\n routePath: string;\n /** Read current filters from the table/URL */\n getFiltersFromTable: () => Record<string, string | string[]>;\n /** Apply filters to the table/URL */\n applyFiltersToTable: (filters: Record<string, string | string[]>) => void;\n /** Called when user explicitly clears all filters - clear last-used preset */\n onClearFilters?: () => void;\n};\n\nfunction getLastUsedKey(context: string): string {\n return `${LAST_USED_PREFIX}${context}`;\n}\n\nfunction getLastUsedPresetId(context: string): string | null {\n try {\n return localStorage.getItem(getLastUsedKey(context));\n } catch {\n return null;\n }\n}\n\nfunction setLastUsedPresetId(context: string, presetId: string | null): void {\n try {\n if (presetId) {\n localStorage.setItem(getLastUsedKey(context), presetId);\n } else {\n localStorage.removeItem(getLastUsedKey(context));\n }\n } catch {\n // Ignore\n }\n}\n\nexport function useSavedFilters<TApi extends DragoncoreApi = DragoncoreApi>(\n config: SavedFiltersConfig,\n) {\n const {\n context,\n routePath,\n getFiltersFromTable,\n applyFiltersToTable,\n onClearFilters,\n } = config;\n\n const cacheKey = `saved-filters:${context}`;\n const hasAppliedLastUsed = ref(false);\n const lastUsedPresetIdRef = ref<string | null>(getLastUsedPresetId(context));\n\n const { data: presets, loading: presetsLoading, refetch: refetchPresets } = useQuery<\n TApi,\n SavedFilterReadDto[]\n >((api) => api.savedFilters.listSavedFilters(context), {\n cacheKey,\n staleTime: 24 * MS.ONE_HOUR,\n });\n\n const { mutate: createPreset, loading: creating } = useMutation<\n TApi,\n { name: string; context: string; route_path: string; filters: Record<string, string | string[]>; sort_by?: string; sort_direction?: 'asc' | 'desc' },\n SavedFilterReadDto\n >(\n (api, input) => api.savedFilters.createSavedFilter(input),\n { invalidate: /^saved-filters:/ },\n );\n\n const { mutate: updatePreset, loading: updating } = useMutation<\n TApi,\n { id: string; name?: string; route_path?: string; filters?: Record<string, string | string[]>; sort_by?: string; sort_direction?: 'asc' | 'desc' },\n SavedFilterReadDto | null\n >(\n (api, input) => api.savedFilters.updateSavedFilter(input),\n { invalidate: /^saved-filters:|^pinned-presets/ },\n );\n\n const { mutate: deletePreset, loading: deleting } = useMutation<TApi, string, boolean>(\n (api, id) => api.savedFilters.deleteSavedFilter(id),\n { invalidate: /^saved-filters:/ },\n );\n\n function applyPreset(preset: SavedFilterReadDto): void {\n applyFiltersToTable(preset.filters);\n setLastUsedPresetId(context, preset.id);\n setLastUsedPresetFilters(context, preset.filters);\n lastUsedPresetIdRef.value = preset.id;\n }\n\n function clearPreset(): void {\n applyFiltersToTable({});\n setLastUsedPresetId(context, null);\n setLastUsedPresetFilters(context, null);\n lastUsedPresetIdRef.value = null;\n }\n\n function clearLastUsed(): void {\n setLastUsedPresetId(context, null);\n setLastUsedPresetFilters(context, null);\n lastUsedPresetIdRef.value = null;\n onClearFilters?.();\n }\n\n async function saveCurrentFilters(name: string): Promise<SavedFilterReadDto | null> {\n const filters = getFiltersFromTable();\n if (Object.keys(filters).length === 0) {\n return null;\n }\n try {\n const result = await createPreset({\n name,\n context,\n route_path: routePath,\n filters,\n });\n if (result) {\n await refetchPresets();\n setLastUsedPresetId(context, result.id);\n setLastUsedPresetFilters(context, result.filters);\n lastUsedPresetIdRef.value = result.id;\n }\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function updatePresetFilters(presetId: string, name?: string): Promise<SavedFilterReadDto | null> {\n const filters = getFiltersFromTable();\n try {\n const result = await updatePreset({\n id: presetId,\n ...(name !== undefined && { name }),\n filters,\n });\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function renamePreset(presetId: string, name: string): Promise<SavedFilterReadDto | null> {\n try {\n const result = await updatePreset({ id: presetId, name });\n if (result) {\n await refetchPresets();\n }\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function removePreset(presetId: string): Promise<boolean> {\n try {\n await deletePreset(presetId);\n await refetchPresets();\n return true;\n } catch {\n return false;\n }\n }\n\n // On mount: if no filters in URL, apply last-used preset when presets load.\n // Note: For routes with lastUsedPresetGuard, the guard redirects before mount so this is often a no-op.\n onMounted(() => {\n const filters = getFiltersFromTable();\n if (Object.keys(filters).length > 0) {\n hasAppliedLastUsed.value = true;\n return;\n }\n const lastUsedId = getLastUsedPresetId(context);\n if (!lastUsedId) {\n hasAppliedLastUsed.value = true;\n return;\n }\n const unwatch = watch(\n () => presets.value,\n (list) => {\n if (!list || hasAppliedLastUsed.value) return;\n const preset = list.find((p) => p.id === lastUsedId);\n if (preset) {\n applyPreset(preset);\n }\n hasAppliedLastUsed.value = true;\n unwatch();\n },\n { immediate: true },\n );\n });\n\n const activePreset = computed(() => {\n const id = lastUsedPresetIdRef.value;\n if (!id) return null;\n return (presets.value ?? []).find((p) => p.id === id) ?? null;\n });\n\n return {\n presets: computed(() => presets.value ?? []),\n presetsLoading,\n creating,\n updating,\n deleting,\n applyPreset,\n clearPreset,\n clearLastUsed,\n activePreset,\n saveCurrentFilters,\n updatePresetFilters,\n renamePreset,\n removePreset,\n };\n}\n","import { userAuthenticated } from '../../middleware/userAuthorized';\nimport type { ExtendedRouteRecordRaw } from '../../types/ExtendedRoute';\n\nexport const savedFilterRoutes: Array<ExtendedRouteRecordRaw> = [\n {\n path: '/saved-filters',\n name: 'SavedFilters',\n component: () => import('./SavedFiltersPage.vue'),\n beforeEnter: [userAuthenticated],\n meta: {\n title: 'Saved Filters',\n description: 'Manage your saved filter presets and favorites',\n side_bar: {\n section: 'Saved Filters',\n visible_to: ['consumer', 'lead', 'staff', 'super_admin'],\n },\n },\n },\n];\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Save Filter Preset\" @close=\"close\">\n <form @submit.prevent=\"handleSubmit\" class=\"space-y-4\">\n <div class=\"form-control\">\n <label class=\"label\">\n <span class=\"label-text\">Preset name</span>\n </label>\n <input\n v-model=\"name\"\n type=\"text\"\n placeholder=\"e.g. My Sales Escalations\"\n class=\"input input-bordered w-full\"\n maxlength=\"100\"\n />\n <label v-if=\"error\" class=\"label\">\n <span class=\"label-text-alt text-error\">{{ error }}</span>\n </label>\n </div>\n <div class=\"flex justify-end gap-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Cancel\n </button>\n <button type=\"submit\" class=\"btn btn-primary\" :disabled=\"saving || !name.trim()\">\n {{ saving ? 'Saving...' : 'Save' }}\n </button>\n </div>\n </form>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport { ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n saving?: boolean;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n save: [name: string];\n}>();\n\nconst name = ref('');\nconst error = ref('');\n\nfunction close() {\n emit('close');\n}\n\nfunction handleSubmit() {\n const trimmed = name.value.trim();\n if (!trimmed) {\n error.value = 'Name is required';\n return;\n }\n if (trimmed.length > 100) {\n error.value = 'Name must be 100 characters or less';\n return;\n }\n error.value = '';\n emit('save', trimmed);\n}\n\nwatch(() => props.isOpen, (open) => {\n if (open) {\n name.value = '';\n error.value = '';\n }\n});\n</script>\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Manage Filter Presets\" @close=\"close\">\n <div class=\"space-y-4\">\n <p v-if=\"presets.length === 0 && !loading\" class=\"text-base-content/70 text-sm\">\n No saved presets yet. Set filters, then use \"Save current filters\" in the Presets menu.\n </p>\n <div v-else-if=\"loading\" class=\"flex justify-center py-4\">\n <span class=\"loading loading-spinner loading-md\" />\n </div>\n <ul v-else class=\"space-y-2\">\n <li\n v-for=\"preset in presets\"\n :key=\"preset.id\"\n class=\"flex items-center gap-2 p-2 rounded-lg bg-base-200\"\n >\n <template v-if=\"editingId === preset.id\">\n <input\n ref=\"renameInputRef\"\n v-model=\"editingName\"\n type=\"text\"\n class=\"input input-sm input-bordered flex-1 min-w-0\"\n maxlength=\"100\"\n placeholder=\"Preset name\"\n @keydown.enter=\"saveRename(preset.id)\"\n @keydown.escape=\"cancelRename\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary shrink-0\"\n :disabled=\"renaming || !editingName.trim()\"\n @click=\"saveRename(preset.id)\"\n >\n {{ renaming ? '...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n :disabled=\"renaming\"\n @click=\"cancelRename\"\n >\n Cancel\n </button>\n </template>\n <template v-else>\n <span class=\"font-medium truncate flex-1 min-w-0\">\n {{ preset.name }}\n <span class=\"text-base-content/60 text-xs font-normal ml-1\">\n ({{ Object.keys(preset.filters || {}).length }})\n </span>\n </span>\n <div class=\"flex gap-1 shrink-0\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n title=\"Rename\"\n @click=\"startRename(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost text-error\"\n title=\"Delete\"\n :disabled=\"deleting\"\n @click=\"handleDelete(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n </div>\n </template>\n </li>\n </ul>\n <div class=\"flex justify-end pt-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Close\n </button>\n </div>\n </div>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { nextTick, ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n presets: SavedFilterReadDto[];\n loading?: boolean;\n deleting?: boolean;\n renaming?: boolean;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n delete: [preset: SavedFilterReadDto];\n}>();\n\nconst editingId = ref<string | null>(null);\nconst editingName = ref('');\nconst renameInputRef = ref<HTMLInputElement | null>(null);\n\nfunction close() {\n emit('close');\n}\n\nfunction startRename(preset: SavedFilterReadDto) {\n editingId.value = preset.id;\n editingName.value = preset.name;\n nextTick(() => renameInputRef.value?.focus());\n}\n\nfunction cancelRename() {\n editingId.value = null;\n editingName.value = '';\n}\n\nasync function saveRename(presetId: string) {\n const name = editingName.value.trim();\n if (!name) return;\n const result = await props.renamePreset(presetId, name);\n if (result) {\n cancelRename();\n }\n}\n\nfunction handleDelete(preset: SavedFilterReadDto) {\n emit('delete', preset);\n}\n\nwatch(() => props.isOpen, (open) => {\n if (!open) {\n cancelRename();\n }\n});\n</script>\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Filter Presets\" @close=\"close\">\n <div class=\"space-y-4\">\n <!-- Preset list: apply (click name), rename, delete -->\n <div v-if=\"presets.length > 0\">\n <p class=\"text-xs font-medium text-base-content/60 uppercase tracking-wide mb-2\">\n Apply preset\n </p>\n <ul class=\"space-y-2\">\n <li\n v-for=\"preset in presets\"\n :key=\"preset.id\"\n class=\"flex items-center gap-2 p-2 rounded-lg bg-base-200\"\n >\n <template v-if=\"editingId === preset.id\">\n <input\n ref=\"renameInputRef\"\n v-model=\"editingName\"\n type=\"text\"\n class=\"input input-sm input-bordered flex-1 min-w-0\"\n maxlength=\"100\"\n placeholder=\"Preset name\"\n @keydown.enter=\"saveRename(preset.id)\"\n @keydown.escape=\"cancelRename\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary shrink-0\"\n :disabled=\"renaming || !editingName.trim()\"\n @click=\"saveRename(preset.id)\"\n >\n {{ renaming ? '...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n :disabled=\"renaming\"\n @click=\"cancelRename\"\n >\n Cancel\n </button>\n </template>\n <template v-else>\n <button\n type=\"button\"\n class=\"flex-1 min-w-0 text-left font-medium truncate rounded px-2 py-1 -mx-2 -my-1 hover:bg-base-300\"\n :class=\"{ 'bg-primary/10': preset.id === activePreset?.id }\"\n @click=\"applyAndClose(preset)\"\n >\n {{ preset.name }}\n <span class=\"text-base-content/60 text-xs font-normal ml-1\">\n ({{ Object.keys(preset.filters || {}).length }})\n </span>\n </button>\n <div class=\"flex gap-1 shrink-0\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :title=\"isPinned(preset.id) ? 'Unpin from favorites' : (canPinMore ? 'Pin to favorites (home + sidebar)' : `Maximum ${maxPinned} pinned`)\"\n :disabled=\"!canPinMore && !isPinned(preset.id)\"\n @click.stop=\"handleTogglePin(preset)\"\n >\n <svg\n class=\"w-4 h-4\"\n :class=\"{ 'text-primary': isPinned(preset.id) }\"\n :fill=\"isPinned(preset.id) ? 'currentColor' : 'none'\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n title=\"Rename\"\n @click.stop=\"startRename(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost text-error\"\n title=\"Delete\"\n :disabled=\"deleting\"\n @click.stop=\"handleDelete(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n </div>\n </template>\n </li>\n </ul>\n </div>\n\n <!-- Empty state -->\n <p\n v-else-if=\"!loading\"\n class=\"text-base-content/70 text-sm\"\n >\n No presets yet. Set filters, then save below.\n </p>\n\n <div v-if=\"loading\" class=\"flex justify-center py-2\">\n <span class=\"loading loading-spinner loading-md\" />\n </div>\n\n <div class=\"divider my-2\" />\n\n <!-- Save current filters: inline form when saving -->\n <div v-if=\"showSaveForm\" class=\"space-y-2\">\n <label class=\"label py-0\">\n <span class=\"label-text\">Preset name</span>\n </label>\n <div class=\"flex gap-2\">\n <input\n ref=\"saveInputRef\"\n v-model=\"saveName\"\n type=\"text\"\n placeholder=\"e.g. My Sales Escalations\"\n class=\"input input-sm input-bordered flex-1\"\n maxlength=\"100\"\n @keydown.enter=\"submitSave\"\n @keydown.escape=\"cancelSave\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n :disabled=\"creating || !saveName.trim()\"\n @click=\"submitSave\"\n >\n {{ creating ? 'Saving...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :disabled=\"creating\"\n @click=\"cancelSave\"\n >\n Cancel\n </button>\n </div>\n </div>\n <button\n v-else\n type=\"button\"\n class=\"btn btn-ghost btn-sm btn-block justify-start gap-2\"\n :disabled=\"!hasFilters || creating || !canSaveMore\"\n :title=\"!canSaveMore ? `Maximum ${MAX_PRESETS_PER_CONTEXT} presets per page. Delete one to save a new preset.` : undefined\"\n @click=\"startSave\"\n >\n <svg class=\"w-4 h-4 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8v8H4V4h8m0 0l4 4-4 4\" />\n </svg>\n Save current filters\n <span v-if=\"!canSaveMore\" class=\"text-base-content/60 text-xs\">(max {{ MAX_PRESETS_PER_CONTEXT }})</span>\n </button>\n\n <div class=\"flex justify-end pt-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Close\n </button>\n </div>\n </div>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport {\n MAX_PRESETS_PER_CONTEXT,\n type SavedFilterReadDto,\n} from '@dragonmastery/dragoncore-shared';\nimport { computed, nextTick, ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n presets: SavedFilterReadDto[];\n loading?: boolean;\n creating?: boolean;\n deleting?: boolean;\n renaming?: boolean;\n hasFilters: boolean;\n activePreset: SavedFilterReadDto | null;\n applyPreset: (preset: SavedFilterReadDto) => void;\n saveCurrentFilters: (name: string) => Promise<SavedFilterReadDto | null>;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n isPinned: (presetId: string) => boolean;\n togglePin: (preset: SavedFilterReadDto) => boolean | Promise<boolean>;\n canPinMore: boolean;\n maxPinned?: number;\n}>();\n\nconst maxPinned = computed(() => props.maxPinned ?? 5);\n\nfunction handleTogglePin(preset: SavedFilterReadDto) {\n props.togglePin(preset);\n}\n\nconst emit = defineEmits<{\n close: [];\n delete: [preset: SavedFilterReadDto];\n rename: [preset: SavedFilterReadDto];\n}>();\n\nconst canSaveMore = computed(\n () => props.presets.length < MAX_PRESETS_PER_CONTEXT,\n);\n\nconst editingId = ref<string | null>(null);\nconst editingName = ref('');\nconst renameInputRef = ref<HTMLInputElement | null>(null);\n\nconst showSaveForm = ref(false);\nconst saveName = ref('');\nconst saveInputRef = ref<HTMLInputElement | null>(null);\n\nfunction close() {\n emit('close');\n}\n\nfunction applyAndClose(preset: SavedFilterReadDto) {\n props.applyPreset(preset);\n close();\n}\n\nfunction startRename(preset: SavedFilterReadDto) {\n editingId.value = preset.id;\n editingName.value = preset.name;\n nextTick(() => renameInputRef.value?.focus());\n}\n\nfunction cancelRename() {\n editingId.value = null;\n editingName.value = '';\n}\n\nasync function saveRename(presetId: string) {\n const name = editingName.value.trim();\n if (!name) return;\n const result = await props.renamePreset(presetId, name);\n if (result) {\n emit('rename', result);\n cancelRename();\n }\n}\n\nfunction handleDelete(preset: SavedFilterReadDto) {\n emit('delete', preset);\n}\n\nfunction startSave() {\n if (props.hasFilters && canSaveMore.value) {\n showSaveForm.value = true;\n saveName.value = '';\n nextTick(() => saveInputRef.value?.focus());\n }\n}\n\nfunction cancelSave() {\n showSaveForm.value = false;\n saveName.value = '';\n}\n\nasync function submitSave() {\n const name = saveName.value.trim();\n if (!name) return;\n const result = await props.saveCurrentFilters(name);\n if (result) {\n cancelSave();\n close();\n }\n}\n\nwatch(() => props.isOpen, (open) => {\n if (!open) {\n cancelRename();\n cancelSave();\n }\n});\n</script>\n","<template>\n <div class=\"flex items-center gap-2 flex-wrap\">\n <!-- Active preset chip: shows when a preset is applied, with clear (×) -->\n <div\n v-if=\"props.activePreset\"\n class=\"badge badge-primary badge-lg gap-1 pr-1\"\n >\n <span class=\"truncate max-w-[8rem] sm:max-w-[12rem]\">{{ props.activePreset.name }}</span>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs btn-circle\"\n aria-label=\"Clear preset\"\n @click=\"handleClearPreset\"\n >\n <svg class=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Presets button: opens modal with everything -->\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :disabled=\"props.presetsLoading\"\n :title=\"props.presets.length ? 'Apply, save, or manage presets' : 'No presets saved'\"\n @click=\"showPresetsModal = true\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\"\n />\n </svg>\n Presets\n </button>\n\n <!-- Delete confirmation modal -->\n <ConfirmDialog\n v-model=\"showDeleteConfirm\"\n title=\"Delete preset?\"\n confirm-text=\"Delete\"\n cancel-text=\"Cancel\"\n processing-text=\"Deleting...\"\n confirm-button-class=\"btn-error\"\n :is-processing=\"props.deleting\"\n @confirm=\"confirmDelete\"\n @cancel=\"presetToDelete = null\"\n >\n <template #message>\n <p>\n Are you sure you want to delete \"{{ presetToDelete?.name }}\"?\n This cannot be undone.\n </p>\n </template>\n </ConfirmDialog>\n\n <!-- Single Presets modal: apply, save, rename, delete -->\n <PresetsModal\n :is-open=\"showPresetsModal\"\n :presets=\"props.presets\"\n :loading=\"props.presetsLoading\"\n :creating=\"props.creating\"\n :deleting=\"props.deleting\"\n :renaming=\"props.renaming\"\n :has-filters=\"props.hasFilters\"\n :active-preset=\"props.activePreset\"\n :apply-preset=\"props.applyPreset\"\n :save-current-filters=\"props.saveCurrentFilters\"\n :rename-preset=\"props.renamePreset\"\n :is-pinned=\"pinnedPresets.isPinned\"\n :toggle-pin=\"pinnedPresets.togglePin\"\n :can-pin-more=\"pinnedPresets.canPinMore.value\"\n :max-pinned=\"pinnedPresets.maxPinned\"\n @close=\"showPresetsModal = false\"\n @delete=\"handleDelete\"\n @rename=\"handleRename\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { ref } from 'vue';\nimport ConfirmDialog from '../../components/ConfirmDialog.vue';\nimport PresetsModal from './PresetsModal.vue';\nimport { useInjectedPinnedPresets } from './usePinnedPresets';\n\nconst pinnedPresets = useInjectedPinnedPresets();\n\nconst props = defineProps<{\n presets: SavedFilterReadDto[];\n presetsLoading: boolean;\n creating: boolean;\n deleting: boolean;\n renaming: boolean;\n hasFilters: boolean;\n activePreset: SavedFilterReadDto | null;\n applyPreset: (preset: SavedFilterReadDto) => void;\n clearPreset: () => void;\n saveCurrentFilters: (name: string) => Promise<SavedFilterReadDto | null>;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n removePreset: (presetId: string) => Promise<boolean>;\n}>();\n\nconst showPresetsModal = ref(false);\nconst showDeleteConfirm = ref(false);\nconst presetToDelete = ref<{ id: string; name: string } | null>(null);\n\nfunction handleClearPreset() {\n props.clearPreset();\n}\n\nfunction handleDelete(preset: { id: string; name: string }) {\n presetToDelete.value = preset;\n showDeleteConfirm.value = true;\n}\n\nasync function confirmDelete() {\n if (!presetToDelete.value) return;\n pinnedPresets.unpinPreset(presetToDelete.value.id);\n await props.removePreset(presetToDelete.value.id);\n presetToDelete.value = null;\n showDeleteConfirm.value = false;\n}\n\nasync function handleRename(preset: { id: string; name: string }) {\n pinnedPresets.updatePinnedPreset(preset.id, { name: preset.name });\n await pinnedPresets.refetchPinned?.();\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"saved_filter-DAmsAfuP.js","names":["DEFAULT_OPERATORS: Record<string, string>","config: FilterConfiguration","operator: string","params: Record<string, string>","filters: FilterQueryParams","base: Record<string, string | string[]>","LAST_USED_PREFIX","getLastUsedKey","savedFilterRoutes: Array<ExtendedRouteRecordRaw>"],"sources":["../src/components/BaseModal.vue","../src/constants/time.ts","../src/slices/saved_filter/usePinnedPresets.ts","../src/utils/filterUrlParser.ts","../src/slices/saved_filter/lastUsedPresetGuard.ts","../src/slices/saved_filter/useSavedFilters.ts","../src/slices/saved_filter/savedFilterRoutes.ts","../src/slices/saved_filter/SaveFilterModal.vue","../src/slices/saved_filter/ManagePresetsModal.vue","../src/slices/saved_filter/PresetsModal.vue","../src/slices/saved_filter/SavedFilterPresets.vue"],"sourcesContent":["<template>\n <dialog ref=\"modal\" class=\"modal\">\n <div class=\"modal-box max-w-md w-full max-h-[90vh] flex flex-col p-0\">\n <!-- Header with title and close button - fixed, not scrollable -->\n <div\n class=\"flex justify-between items-center p-6 pb-4 border-b border-base-300 flex-shrink-0\"\n >\n <h3 class=\"font-bold text-lg\">\n <slot name=\"title\">{{ title }}</slot>\n </h3>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n @click.prevent=\"handleClose\"\n aria-label=\"Close modal\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Content slot - scrollable area -->\n <div class=\"modal-content flex-1 overflow-y-auto p-6\">\n <slot></slot>\n </div>\n </div>\n <form method=\"dialog\" class=\"modal-backdrop\">\n <button type=\"button\" @click.prevent=\"handleClose\">close</button>\n </form>\n </dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\n\ninterface Props {\n isOpen: boolean;\n title?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n});\n\nconst emit = defineEmits<{\n close: [];\n}>();\n\nconst modal = ref<HTMLDialogElement>();\n\nconst handleClose = () => {\n emit('close');\n};\n\n// Watch for modal open/close\nwatch(\n () => props.isOpen,\n (isOpen) => {\n if (isOpen && modal.value) {\n modal.value.showModal();\n } else if (!isOpen && modal.value) {\n modal.value.close();\n }\n },\n { immediate: true },\n);\n</script>\n","/**\n * Time duration constants in milliseconds.\n * Use for staleTime, cache TTL, etc.\n *\n * @example\n * staleTime: 30 * MS.ONE_SECOND\n * staleTime: 5 * MS.ONE_MINUTE\n * staleTime: 24 * MS.ONE_HOUR\n */\nexport const MS = {\n ONE_SECOND: 1000,\n ONE_MINUTE: 60 * 1000,\n ONE_HOUR: 60 * 60 * 1000,\n} as const;\n","/**\n * Composable for pinning presets to favorites (home page + sidebar).\n * Uses API with 24h cache. Max 5 pinned presets.\n *\n * Call usePinnedPresets() once in the layout (InAppLayout) and provide it.\n * Children use useInjectedPinnedPresets() to avoid duplicate fetches.\n */\n\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport type { InjectionKey } from 'vue';\nimport { inject } from 'vue';\nimport { MS } from '../../constants/time';\nimport { useMutation } from '../../composables/useMutation';\nimport { useQuery } from '../../composables/useQuery';\nimport { computed } from 'vue';\n\nconst CACHE_KEY = 'pinned-presets';\nconst MAX_PINNED = 5;\n\nexport type PinnedPreset = Pick<\n SavedFilterReadDto,\n 'id' | 'name' | 'context' | 'route_path' | 'filters'\n>;\n\nexport function usePinnedPresets() {\n const { data: pinnedData, refetch } = useQuery(\n (api) => api.savedFilters.listPinnedPresets(),\n { cacheKey: CACHE_KEY, staleTime: 24 * MS.ONE_HOUR },\n );\n\n const { mutate: addPin } = useMutation(\n (api, id: string) => api.savedFilters.addPinnedPreset(id),\n { invalidate: CACHE_KEY },\n );\n\n const { mutate: removePin } = useMutation(\n (api, id: string) => api.savedFilters.removePinnedPreset(id),\n { invalidate: CACHE_KEY },\n );\n\n const pinned = computed(() => pinnedData.value ?? []);\n const pinnedIds = computed(() => new Set(pinned.value.map((p) => p.id)));\n const canPinMore = computed(() => pinned.value.length < MAX_PINNED);\n\n function isPinned(presetId: string): boolean {\n return pinnedIds.value.has(presetId);\n }\n\n async function pinPreset(preset: SavedFilterReadDto): Promise<boolean> {\n if (pinned.value.length >= MAX_PINNED) return false;\n if (pinnedIds.value.has(preset.id)) return true;\n try {\n await addPin(preset.id);\n await refetch();\n return true;\n } catch {\n return false;\n }\n }\n\n async function unpinPreset(presetId: string): Promise<void> {\n try {\n await removePin(presetId);\n await refetch();\n } catch {\n // Error handled by mutation\n }\n }\n\n async function togglePin(preset: SavedFilterReadDto): Promise<boolean> {\n if (isPinned(preset.id)) {\n await unpinPreset(preset.id);\n return false;\n }\n return pinPreset(preset);\n }\n\n function getPresetLink(preset: PinnedPreset): {\n path: string;\n query: Record<string, string | string[]>;\n } {\n return {\n path: preset.route_path,\n query: preset.filters ?? {},\n };\n }\n\n function updatePinnedPreset(\n presetId: string,\n updates: Partial<PinnedPreset>,\n ): void {\n // API is source of truth. Call refetchPinned when a preset is renamed\n // to refresh the pinned list with updated names.\n void presetId;\n void updates;\n }\n\n return {\n pinned,\n pinnedIds,\n canPinMore,\n isPinned,\n pinPreset,\n unpinPreset,\n togglePin,\n getPresetLink,\n updatePinnedPreset,\n refetchPinned: refetch,\n maxPinned: MAX_PINNED,\n };\n}\n\nexport const PINNED_PRESETS_KEY = Symbol('pinnedPresets') as InjectionKey<\n ReturnType<typeof usePinnedPresets>\n>;\n\n/** Use pinned presets from the layout provider. Call this in child components (Sidebar, AppHome, etc.). */\nexport function useInjectedPinnedPresets() {\n const injected = inject(PINNED_PRESETS_KEY);\n if (!injected) {\n throw new Error(\n 'useInjectedPinnedPresets must be used within a component tree that provides pinned presets (e.g. InAppLayout).',\n );\n }\n return injected;\n}\n","/**\n * Filter URL Parser - Query string serialization/deserialization\n * Uses compact DrizzleORM-style format: flt[field]=value or flt[field][op]=value\n */\n\nimport { OPERATORS } from '@dragonmastery/dragoncore-shared';\n\n/**\n * Default operators for each field type when not specified in URL\n */\nconst DEFAULT_OPERATORS: Record<string, string> = {\n string: OPERATORS.CONTAINS,\n number: OPERATORS.EQUALS,\n date: OPERATORS.EQUALS,\n boolean: OPERATORS.EQUALS,\n enum: OPERATORS.EQUALS,\n};\n\n/**\n * Numeric types that should be converted to numbers\n */\nconst NUMERIC_TYPES = ['number', 'money', 'percentage'];\n\n/**\n * Check if operator requires array values\n */\nfunction requiresArrayValues(operator: string): boolean {\n return (\n operator === OPERATORS.IS_ONE_OF ||\n operator === OPERATORS.IS_NOT_ONE_OF ||\n operator === OPERATORS.BETWEEN\n );\n}\n\n/**\n * Check if operator is a null check (requires no value)\n */\nfunction isNullCheckOperator(operator: string): boolean {\n return operator === OPERATORS.IS_EMPTY || operator === OPERATORS.IS_NOT_EMPTY;\n}\n\n/**\n * Field registry metadata for type inference\n */\nexport interface FieldRegistryMetadata {\n [fieldName: string]: {\n type: 'string' | 'number' | 'date' | 'boolean' | 'enum' | 'money' | 'percentage';\n filterable?: boolean;\n };\n}\n\n/**\n * Filter value object structure\n */\nexport interface FilterValueObject {\n operator: string;\n value?: any;\n values?: any[];\n caseSensitive?: boolean;\n}\n\n/**\n * Filter configuration - flat object mapping field names to filter objects\n */\nexport type FilterConfiguration = Record<string, FilterValueObject>;\n\n/**\n * Deserialize filter configuration from URL query parameters object\n * Parses compact DrizzleORM-style format: flt[field]=value or flt[field][op]=value\n *\n * @param params - URL query parameters object (from Vue Router route.query)\n * @param registry - Field registry metadata for type inference\n * @returns Filter configuration object\n *\n * @example\n * // URL: ?flt[department][eq]=Engineering&flt[id]=4&flt[role][in]=[\"admin\",\"user\"]\n * const filters = deserializeFiltersFromQueryParams(route.query, fieldRegistry);\n * // Result: {\n * // department: { operator: 'eq', value: 'Engineering' },\n * // id: { operator: 'eq', value: 4 },\n * // role: { operator: 'in', values: ['admin', 'user'] }\n * // }\n */\nexport function deserializeFiltersFromQueryParams(\n params: Record<string, string | string[]>,\n registry: FieldRegistryMetadata,\n): FilterConfiguration {\n const config: FilterConfiguration = {};\n const fieldMap = new Map<string, Partial<FilterValueObject>>();\n\n // Parse query params\n for (const [key, value] of Object.entries(params)) {\n // Match flt[field] or flt[field][op]\n const matchDefault = key.match(/^flt\\[([^\\]]+)\\]$/);\n const matchWithOp = key.match(/^flt\\[([^\\]]+)\\]\\[([^\\]]+)\\]$/);\n\n if (!matchDefault && !matchWithOp) continue;\n\n const fieldName = matchDefault ? matchDefault[1] : matchWithOp ? matchWithOp[1] : null;\n const operatorShorthand = matchWithOp ? matchWithOp[2] : null;\n const stringValue = Array.isArray(value) ? value[0] : value;\n\n if (!fieldName) continue;\n\n const fieldMeta = registry[fieldName];\n if (!fieldMeta) continue; // Skip unknown fields\n\n const fieldType = fieldMeta.type;\n const defaultOp = DEFAULT_OPERATORS[fieldType] || OPERATORS.EQUALS;\n\n // Determine operator\n let operator: string;\n if (operatorShorthand) {\n operator = operatorShorthand;\n } else {\n operator = defaultOp;\n }\n\n if (!fieldMap.has(fieldName)) {\n fieldMap.set(fieldName, { operator });\n }\n\n const filter = fieldMap.get(fieldName)!;\n filter.operator = operator;\n\n // Parse value based on operator type\n if (isNullCheckOperator(operator)) {\n // Null checks don't have values\n // Value is already set, nothing more to do\n } else if (requiresArrayValues(operator)) {\n // Array operators: parse JSON array (handles commas/quotes in values)\n if (!stringValue || stringValue.trim() === '') {\n fieldMap.delete(fieldName);\n continue;\n }\n\n try {\n const parsed = JSON.parse(stringValue);\n if (Array.isArray(parsed) && parsed.length > 0) {\n // Convert to appropriate types based on field type\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = parsed.map((v) => Number(v));\n } else {\n filter.values = parsed;\n }\n } else {\n fieldMap.delete(fieldName);\n continue;\n }\n } catch (e) {\n // Invalid JSON, try legacy comma-separated format for backward compatibility\n const values = stringValue\n .split(',')\n .map((v) => v.trim())\n .filter((v) => v.length > 0);\n if (values.length === 0) {\n fieldMap.delete(fieldName);\n continue;\n }\n\n if (operator === OPERATORS.BETWEEN && values.length === 2) {\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = [Number(values[0]!), Number(values[1]!)];\n } else if (fieldType === 'date') {\n filter.values = [values[0]!, values[1]!];\n } else {\n filter.values = values;\n }\n } else if (operator === OPERATORS.BETWEEN) {\n fieldMap.delete(fieldName);\n continue;\n } else {\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = values.map((v) => Number(v));\n } else {\n filter.values = values;\n }\n }\n }\n } else {\n // Single value operators\n // Special case: if operator is in/notIn but we got a single value, convert to array\n if (\n (operator === OPERATORS.IS_ONE_OF || operator === OPERATORS.IS_NOT_ONE_OF) &&\n stringValue\n ) {\n // Convert single value to array for array operators\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.values = [Number(stringValue)];\n } else {\n filter.values = [stringValue];\n }\n } else if (stringValue) {\n // Regular single value operator\n if (NUMERIC_TYPES.includes(fieldType)) {\n filter.value = Number(stringValue);\n } else if (fieldType === 'boolean') {\n filter.value = stringValue === 'true' || stringValue === '1';\n } else {\n filter.value = stringValue;\n }\n\n // String fields: always case-insensitive (contains is default)\n if (fieldType === 'string' && operator === OPERATORS.CONTAINS) {\n filter.caseSensitive = false;\n }\n }\n }\n }\n\n // Convert to FilterConfiguration\n for (const [fieldName, filter] of fieldMap.entries()) {\n if (filter.operator) {\n config[fieldName] = filter as FilterValueObject;\n }\n }\n\n return config;\n}\n\n/**\n * Serialize filter configuration to URL query parameters object\n * Uses compact DrizzleORM-style format: flt[field][op]=value\n *\n * @param config - Filter configuration object\n * @param registry - Field registry metadata for type inference\n * @returns URL query parameters object (can be used with Vue Router)\n *\n * @example\n * const filters = {\n * department: { operator: 'eq', value: 'Engineering' },\n * role: { operator: 'in', values: ['admin', 'user'] }\n * };\n * const params = serializeFiltersToQueryParams(filters, fieldRegistry);\n * // Result: {\n * // 'flt[department][eq]': 'Engineering',\n * // 'flt[role][in]': '[\"admin\",\"user\"]'\n * // }\n */\nexport function serializeFiltersToQueryParams(\n config: FilterConfiguration,\n registry: FieldRegistryMetadata,\n): Record<string, string> {\n const params: Record<string, string> = {};\n\n for (const [fieldName, filter] of Object.entries(config)) {\n const fieldMeta = registry[fieldName];\n if (!fieldMeta) continue;\n\n const operator = filter.operator;\n\n if (isNullCheckOperator(operator)) {\n // Null checks don't need values, just the operator\n params[`flt[${fieldName}][${operator}]`] = '';\n } else if (requiresArrayValues(operator)) {\n // Array operators: use JSON encoding (handles commas/quotes)\n if (filter.values && Array.isArray(filter.values)) {\n params[`flt[${fieldName}][${operator}]`] = JSON.stringify(filter.values);\n }\n } else {\n // Single value: include operator explicitly\n params[`flt[${fieldName}][${operator}]`] = String(filter.value);\n }\n }\n\n return params;\n}\n\n/** Raw filter params format used by useSavedFilters (flt[key]=value) */\nexport type FilterQueryParams = Record<string, string | string[]>;\n\n/**\n * Extract filter query params from route query.\n * Handles Vue Router's LocationQuery type which can have null values.\n * Only extracts flt[...] params (actual filters).\n *\n * @example\n * // URL: ?flt[type][in]=[\"sales\",\"escalation\"]&flt[phase][ne]=Post+Sale\n * // Returns: { 'flt[type][in]': '[\"sales\",\"escalation\"]', 'flt[phase][ne]': 'Post+Sale' }\n */\nexport function extractFiltersFromQuery(query: Record<string, unknown>): FilterQueryParams {\n const filters: FilterQueryParams = {};\n\n Object.keys(query).forEach((key) => {\n if (key.startsWith('flt[')) {\n const value = query[key];\n if (value !== null && value !== undefined) {\n if (Array.isArray(value)) {\n const filtered = value.filter((v): v is string => v !== null && v !== undefined);\n if (filtered.length > 0) {\n filters[key] = filtered;\n }\n } else {\n filters[key] = String(value);\n }\n }\n }\n });\n\n return filters;\n}\n\n/**\n * Build a new query object with filter params replaced (not merged).\n * Strips all flt[...] params from the current query, then adds the new filters.\n * Preserves non-filter params (sort, pagination, etc).\n */\nexport function buildQueryWithFilters(\n currentQuery: Record<string, unknown>,\n filters: FilterQueryParams,\n): Record<string, string | string[]> {\n const base: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(currentQuery)) {\n if (!key.startsWith('flt[') && value !== null && value !== undefined) {\n base[key] = Array.isArray(value)\n ? (value.filter((v): v is string => v != null) as string[])\n : String(value);\n }\n }\n return { ...base, ...filters };\n}\n","/**\n * Router guard helper: redirect to last-used preset filters when navigating with no URL filters.\n * Uses localStorage (no API call) - filters are stored when user applies a preset.\n * Prevents double fetch by applying preset before the list component mounts.\n */\n\nimport { buildQueryWithFilters, extractFiltersFromQuery } from '../../utils/filterUrlParser';\n\nconst LAST_USED_PREFIX = 'lastUsedPreset:';\nconst LAST_USED_FILTERS_PREFIX = 'lastUsedPresetFilters:';\n\nfunction getLastUsedKey(context: string): string {\n return `${LAST_USED_PREFIX}${context}`;\n}\n\nfunction getLastUsedFiltersKey(context: string): string {\n return `${LAST_USED_FILTERS_PREFIX}${context}`;\n}\n\nexport function getLastUsedPresetFilters(\n context: string,\n): Record<string, string | string[]> | null {\n try {\n const stored = localStorage.getItem(getLastUsedFiltersKey(context));\n if (!stored) return null;\n const parsed = JSON.parse(stored) as Record<string, string | string[]>;\n return typeof parsed === 'object' && parsed !== null ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastUsedPresetFilters(\n context: string,\n filters: Record<string, string | string[]> | null,\n): void {\n try {\n if (filters && Object.keys(filters).length > 0) {\n localStorage.setItem(getLastUsedFiltersKey(context), JSON.stringify(filters));\n } else {\n localStorage.removeItem(getLastUsedFiltersKey(context));\n }\n } catch {\n // Ignore\n }\n}\n\n/**\n * If navigating with no filters and we have a last-used preset, returns the query to redirect to.\n * Otherwise returns null (no redirect needed).\n */\nexport function getLastUsedPresetRedirect(\n context: string,\n currentQuery: Record<string, unknown>,\n): Record<string, string | string[]> | null {\n const filters = extractFiltersFromQuery(currentQuery);\n if (Object.keys(filters).length > 0) return null;\n\n const lastUsedId = localStorage.getItem(getLastUsedKey(context));\n if (!lastUsedId) return null;\n\n const lastUsedFilters = getLastUsedPresetFilters(context);\n if (!lastUsedFilters || Object.keys(lastUsedFilters).length === 0) return null;\n\n return buildQueryWithFilters(currentQuery, lastUsedFilters);\n}\n\n/**\n * Creates a Vue Router beforeEnter guard that redirects to last-used preset when navigating with no filters.\n * Use on list routes that have SavedFilterPresets.\n */\nexport function createLastUsedPresetGuard(\n context: string,\n routeName: string,\n) {\n return (to: { name?: unknown; query: Record<string, unknown> }) => {\n if (to.name !== routeName) return undefined;\n const redirectQuery = getLastUsedPresetRedirect(context, to.query);\n if (!redirectQuery) return undefined;\n return { name: routeName, query: redirectQuery };\n };\n}\n","/**\n * Composable for saved filter presets - save, apply, and manage named filter configurations.\n * Works with any data table that provides getFiltersFromTable / applyFiltersToTable adapters.\n */\n\nimport type { DragoncoreApi } from '@dragonmastery/dragoncore-shared';\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { MS } from '../../constants/time';\nimport { useMutation } from '../../composables/useMutation';\nimport { useQuery } from '../../composables/useQuery';\nimport { computed, onMounted, ref, watch } from 'vue';\nimport { setLastUsedPresetFilters } from './lastUsedPresetGuard';\n\nconst LAST_USED_PREFIX = 'lastUsedPreset:';\n\nexport type SavedFiltersConfig = {\n /** Unique context per table type (e.g. \"tracker\", \"followup\") */\n context: string;\n /** Route path for the table (e.g. \"/trackers\", \"/followups\") */\n routePath: string;\n /** Read current filters from the table/URL */\n getFiltersFromTable: () => Record<string, string | string[]>;\n /** Apply filters to the table/URL */\n applyFiltersToTable: (filters: Record<string, string | string[]>) => void;\n /** Called when user explicitly clears all filters - clear last-used preset */\n onClearFilters?: () => void;\n};\n\nfunction getLastUsedKey(context: string): string {\n return `${LAST_USED_PREFIX}${context}`;\n}\n\nfunction getLastUsedPresetId(context: string): string | null {\n try {\n return localStorage.getItem(getLastUsedKey(context));\n } catch {\n return null;\n }\n}\n\nfunction setLastUsedPresetId(context: string, presetId: string | null): void {\n try {\n if (presetId) {\n localStorage.setItem(getLastUsedKey(context), presetId);\n } else {\n localStorage.removeItem(getLastUsedKey(context));\n }\n } catch {\n // Ignore\n }\n}\n\nexport function useSavedFilters<TApi extends DragoncoreApi = DragoncoreApi>(\n config: SavedFiltersConfig,\n) {\n const {\n context,\n routePath,\n getFiltersFromTable,\n applyFiltersToTable,\n onClearFilters,\n } = config;\n\n const cacheKey = `saved-filters:${context}`;\n const hasAppliedLastUsed = ref(false);\n const lastUsedPresetIdRef = ref<string | null>(getLastUsedPresetId(context));\n\n const { data: presets, loading: presetsLoading, refetch: refetchPresets } = useQuery<\n TApi,\n SavedFilterReadDto[]\n >((api) => api.savedFilters.listSavedFilters(context), {\n cacheKey,\n staleTime: 24 * MS.ONE_HOUR,\n });\n\n const { mutate: createPreset, loading: creating } = useMutation<\n TApi,\n { name: string; context: string; route_path: string; filters: Record<string, string | string[]>; sort_by?: string; sort_direction?: 'asc' | 'desc' },\n SavedFilterReadDto\n >(\n (api, input) => api.savedFilters.createSavedFilter(input),\n { invalidate: /^saved-filters:/ },\n );\n\n const { mutate: updatePreset, loading: updating } = useMutation<\n TApi,\n { id: string; name?: string; route_path?: string; filters?: Record<string, string | string[]>; sort_by?: string; sort_direction?: 'asc' | 'desc' },\n SavedFilterReadDto | null\n >(\n (api, input) => api.savedFilters.updateSavedFilter(input),\n { invalidate: /^saved-filters:|^pinned-presets/ },\n );\n\n const { mutate: deletePreset, loading: deleting } = useMutation<TApi, string, boolean>(\n (api, id) => api.savedFilters.deleteSavedFilter(id),\n { invalidate: /^saved-filters:/ },\n );\n\n function applyPreset(preset: SavedFilterReadDto): void {\n applyFiltersToTable(preset.filters);\n setLastUsedPresetId(context, preset.id);\n setLastUsedPresetFilters(context, preset.filters);\n lastUsedPresetIdRef.value = preset.id;\n }\n\n function clearPreset(): void {\n applyFiltersToTable({});\n setLastUsedPresetId(context, null);\n setLastUsedPresetFilters(context, null);\n lastUsedPresetIdRef.value = null;\n }\n\n function clearLastUsed(): void {\n setLastUsedPresetId(context, null);\n setLastUsedPresetFilters(context, null);\n lastUsedPresetIdRef.value = null;\n onClearFilters?.();\n }\n\n async function saveCurrentFilters(name: string): Promise<SavedFilterReadDto | null> {\n const filters = getFiltersFromTable();\n if (Object.keys(filters).length === 0) {\n return null;\n }\n try {\n const result = await createPreset({\n name,\n context,\n route_path: routePath,\n filters,\n });\n if (result) {\n await refetchPresets();\n setLastUsedPresetId(context, result.id);\n setLastUsedPresetFilters(context, result.filters);\n lastUsedPresetIdRef.value = result.id;\n }\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function updatePresetFilters(presetId: string, name?: string): Promise<SavedFilterReadDto | null> {\n const filters = getFiltersFromTable();\n try {\n const result = await updatePreset({\n id: presetId,\n ...(name !== undefined && { name }),\n filters,\n });\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function renamePreset(presetId: string, name: string): Promise<SavedFilterReadDto | null> {\n try {\n const result = await updatePreset({ id: presetId, name });\n if (result) {\n await refetchPresets();\n }\n return result ?? null;\n } catch {\n return null;\n }\n }\n\n async function removePreset(presetId: string): Promise<boolean> {\n try {\n await deletePreset(presetId);\n await refetchPresets();\n return true;\n } catch {\n return false;\n }\n }\n\n // On mount: if no filters in URL, apply last-used preset when presets load.\n // Note: For routes with lastUsedPresetGuard, the guard redirects before mount so this is often a no-op.\n onMounted(() => {\n const filters = getFiltersFromTable();\n if (Object.keys(filters).length > 0) {\n hasAppliedLastUsed.value = true;\n return;\n }\n const lastUsedId = getLastUsedPresetId(context);\n if (!lastUsedId) {\n hasAppliedLastUsed.value = true;\n return;\n }\n const unwatch = watch(\n () => presets.value,\n (list) => {\n if (!list || hasAppliedLastUsed.value) return;\n const preset = list.find((p) => p.id === lastUsedId);\n if (preset) {\n applyPreset(preset);\n }\n hasAppliedLastUsed.value = true;\n unwatch();\n },\n { immediate: true },\n );\n });\n\n const activePreset = computed(() => {\n const id = lastUsedPresetIdRef.value;\n if (!id) return null;\n return (presets.value ?? []).find((p) => p.id === id) ?? null;\n });\n\n return {\n presets: computed(() => presets.value ?? []),\n presetsLoading,\n creating,\n updating,\n deleting,\n applyPreset,\n clearPreset,\n clearLastUsed,\n activePreset,\n saveCurrentFilters,\n updatePresetFilters,\n renamePreset,\n removePreset,\n };\n}\n","import { userAuthenticated } from '../../middleware/userAuthorized';\nimport type { ExtendedRouteRecordRaw } from '../../types/ExtendedRoute';\n\nexport const savedFilterRoutes: Array<ExtendedRouteRecordRaw> = [\n {\n path: '/saved-filters',\n name: 'SavedFilters',\n component: () => import('./SavedFiltersPage.vue'),\n beforeEnter: [userAuthenticated],\n meta: {\n title: 'Saved Filters',\n description: 'Manage your saved filter presets and favorites',\n side_bar: {\n section: 'Saved Filters',\n visible_to: ['consumer', 'lead', 'staff', 'super_admin'],\n },\n },\n },\n];\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Save Filter Preset\" @close=\"close\">\n <form @submit.prevent=\"handleSubmit\" class=\"space-y-4\">\n <div class=\"form-control\">\n <label class=\"label\">\n <span class=\"label-text\">Preset name</span>\n </label>\n <input\n v-model=\"name\"\n type=\"text\"\n placeholder=\"e.g. My Sales Escalations\"\n class=\"input input-bordered w-full\"\n maxlength=\"100\"\n />\n <label v-if=\"error\" class=\"label\">\n <span class=\"label-text-alt text-error\">{{ error }}</span>\n </label>\n </div>\n <div class=\"flex justify-end gap-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Cancel\n </button>\n <button type=\"submit\" class=\"btn btn-primary\" :disabled=\"saving || !name.trim()\">\n {{ saving ? 'Saving...' : 'Save' }}\n </button>\n </div>\n </form>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport { ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n saving?: boolean;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n save: [name: string];\n}>();\n\nconst name = ref('');\nconst error = ref('');\n\nfunction close() {\n emit('close');\n}\n\nfunction handleSubmit() {\n const trimmed = name.value.trim();\n if (!trimmed) {\n error.value = 'Name is required';\n return;\n }\n if (trimmed.length > 100) {\n error.value = 'Name must be 100 characters or less';\n return;\n }\n error.value = '';\n emit('save', trimmed);\n}\n\nwatch(() => props.isOpen, (open) => {\n if (open) {\n name.value = '';\n error.value = '';\n }\n});\n</script>\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Manage Filter Presets\" @close=\"close\">\n <div class=\"space-y-4\">\n <p v-if=\"presets.length === 0 && !loading\" class=\"text-base-content/70 text-sm\">\n No saved presets yet. Set filters, then use \"Save current filters\" in the Presets menu.\n </p>\n <div v-else-if=\"loading\" class=\"flex justify-center py-4\">\n <span class=\"loading loading-spinner loading-md\" />\n </div>\n <ul v-else class=\"space-y-2\">\n <li\n v-for=\"preset in presets\"\n :key=\"preset.id\"\n class=\"flex items-center gap-2 p-2 rounded-lg bg-base-200\"\n >\n <template v-if=\"editingId === preset.id\">\n <input\n ref=\"renameInputRef\"\n v-model=\"editingName\"\n type=\"text\"\n class=\"input input-sm input-bordered flex-1 min-w-0\"\n maxlength=\"100\"\n placeholder=\"Preset name\"\n @keydown.enter=\"saveRename(preset.id)\"\n @keydown.escape=\"cancelRename\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary shrink-0\"\n :disabled=\"renaming || !editingName.trim()\"\n @click=\"saveRename(preset.id)\"\n >\n {{ renaming ? '...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n :disabled=\"renaming\"\n @click=\"cancelRename\"\n >\n Cancel\n </button>\n </template>\n <template v-else>\n <span class=\"font-medium truncate flex-1 min-w-0\">\n {{ preset.name }}\n <span class=\"text-base-content/60 text-xs font-normal ml-1\">\n ({{ Object.keys(preset.filters || {}).length }})\n </span>\n </span>\n <div class=\"flex gap-1 shrink-0\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n title=\"Rename\"\n @click=\"startRename(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost text-error\"\n title=\"Delete\"\n :disabled=\"deleting\"\n @click=\"handleDelete(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n </div>\n </template>\n </li>\n </ul>\n <div class=\"flex justify-end pt-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Close\n </button>\n </div>\n </div>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { nextTick, ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n presets: SavedFilterReadDto[];\n loading?: boolean;\n deleting?: boolean;\n renaming?: boolean;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n delete: [preset: SavedFilterReadDto];\n}>();\n\nconst editingId = ref<string | null>(null);\nconst editingName = ref('');\nconst renameInputRef = ref<HTMLInputElement | null>(null);\n\nfunction close() {\n emit('close');\n}\n\nfunction startRename(preset: SavedFilterReadDto) {\n editingId.value = preset.id;\n editingName.value = preset.name;\n nextTick(() => renameInputRef.value?.focus());\n}\n\nfunction cancelRename() {\n editingId.value = null;\n editingName.value = '';\n}\n\nasync function saveRename(presetId: string) {\n const name = editingName.value.trim();\n if (!name) return;\n const result = await props.renamePreset(presetId, name);\n if (result) {\n cancelRename();\n }\n}\n\nfunction handleDelete(preset: SavedFilterReadDto) {\n emit('delete', preset);\n}\n\nwatch(() => props.isOpen, (open) => {\n if (!open) {\n cancelRename();\n }\n});\n</script>\n","<template>\n <BaseModal :is-open=\"isOpen\" title=\"Filter Presets\" @close=\"close\">\n <div class=\"space-y-4\">\n <!-- Preset list: apply (click name), rename, delete -->\n <div v-if=\"presets.length > 0\">\n <p class=\"text-xs font-medium text-base-content/60 uppercase tracking-wide mb-2\">\n Apply preset\n </p>\n <ul class=\"space-y-2\">\n <li\n v-for=\"preset in presets\"\n :key=\"preset.id\"\n class=\"flex items-center gap-2 p-2 rounded-lg bg-base-200\"\n >\n <template v-if=\"editingId === preset.id\">\n <input\n ref=\"renameInputRef\"\n v-model=\"editingName\"\n type=\"text\"\n class=\"input input-sm input-bordered flex-1 min-w-0\"\n maxlength=\"100\"\n placeholder=\"Preset name\"\n @keydown.enter=\"saveRename(preset.id)\"\n @keydown.escape=\"cancelRename\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary shrink-0\"\n :disabled=\"renaming || !editingName.trim()\"\n @click=\"saveRename(preset.id)\"\n >\n {{ renaming ? '...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n :disabled=\"renaming\"\n @click=\"cancelRename\"\n >\n Cancel\n </button>\n </template>\n <template v-else>\n <button\n type=\"button\"\n class=\"flex-1 min-w-0 text-left font-medium truncate rounded px-2 py-1 -mx-2 -my-1 hover:bg-base-300\"\n :class=\"{ 'bg-primary/10': preset.id === activePreset?.id }\"\n @click=\"applyAndClose(preset)\"\n >\n {{ preset.name }}\n <span class=\"text-base-content/60 text-xs font-normal ml-1\">\n ({{ Object.keys(preset.filters || {}).length }})\n </span>\n </button>\n <div class=\"flex gap-1 shrink-0\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :title=\"isPinned(preset.id) ? 'Unpin from favorites' : (canPinMore ? 'Pin to favorites (home + sidebar)' : `Maximum ${maxPinned} pinned`)\"\n :disabled=\"!canPinMore && !isPinned(preset.id)\"\n @click.stop=\"handleTogglePin(preset)\"\n >\n <svg\n class=\"w-4 h-4\"\n :class=\"{ 'text-primary': isPinned(preset.id) }\"\n :fill=\"isPinned(preset.id) ? 'currentColor' : 'none'\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n title=\"Rename\"\n @click.stop=\"startRename(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost text-error\"\n title=\"Delete\"\n :disabled=\"deleting\"\n @click.stop=\"handleDelete(preset)\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n </div>\n </template>\n </li>\n </ul>\n </div>\n\n <!-- Empty state -->\n <p\n v-else-if=\"!loading\"\n class=\"text-base-content/70 text-sm\"\n >\n No presets yet. Set filters, then save below.\n </p>\n\n <div v-if=\"loading\" class=\"flex justify-center py-2\">\n <span class=\"loading loading-spinner loading-md\" />\n </div>\n\n <div class=\"divider my-2\" />\n\n <!-- Save current filters: inline form when saving -->\n <div v-if=\"showSaveForm\" class=\"space-y-2\">\n <label class=\"label py-0\">\n <span class=\"label-text\">Preset name</span>\n </label>\n <div class=\"flex gap-2\">\n <input\n ref=\"saveInputRef\"\n v-model=\"saveName\"\n type=\"text\"\n placeholder=\"e.g. My Sales Escalations\"\n class=\"input input-sm input-bordered flex-1\"\n maxlength=\"100\"\n @keydown.enter=\"submitSave\"\n @keydown.escape=\"cancelSave\"\n />\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n :disabled=\"creating || !saveName.trim()\"\n @click=\"submitSave\"\n >\n {{ creating ? 'Saving...' : 'Save' }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :disabled=\"creating\"\n @click=\"cancelSave\"\n >\n Cancel\n </button>\n </div>\n </div>\n <button\n v-else\n type=\"button\"\n class=\"btn btn-ghost btn-sm btn-block justify-start gap-2\"\n :disabled=\"!hasFilters || creating || !canSaveMore\"\n :title=\"!canSaveMore ? `Maximum ${MAX_PRESETS_PER_CONTEXT} presets per page. Delete one to save a new preset.` : undefined\"\n @click=\"startSave\"\n >\n <svg class=\"w-4 h-4 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8v8H4V4h8m0 0l4 4-4 4\" />\n </svg>\n Save current filters\n <span v-if=\"!canSaveMore\" class=\"text-base-content/60 text-xs\">(max {{ MAX_PRESETS_PER_CONTEXT }})</span>\n </button>\n\n <div class=\"flex justify-end pt-2\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"close\">\n Close\n </button>\n </div>\n </div>\n </BaseModal>\n</template>\n\n<script setup lang=\"ts\">\nimport BaseModal from '../../components/BaseModal.vue';\nimport {\n MAX_PRESETS_PER_CONTEXT,\n type SavedFilterReadDto,\n} from '@dragonmastery/dragoncore-shared';\nimport { computed, nextTick, ref, watch } from 'vue';\n\nconst props = defineProps<{\n isOpen: boolean;\n presets: SavedFilterReadDto[];\n loading?: boolean;\n creating?: boolean;\n deleting?: boolean;\n renaming?: boolean;\n hasFilters: boolean;\n activePreset: SavedFilterReadDto | null;\n applyPreset: (preset: SavedFilterReadDto) => void;\n saveCurrentFilters: (name: string) => Promise<SavedFilterReadDto | null>;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n isPinned: (presetId: string) => boolean;\n togglePin: (preset: SavedFilterReadDto) => boolean | Promise<boolean>;\n canPinMore: boolean;\n maxPinned?: number;\n}>();\n\nconst maxPinned = computed(() => props.maxPinned ?? 5);\n\nfunction handleTogglePin(preset: SavedFilterReadDto) {\n props.togglePin(preset);\n}\n\nconst emit = defineEmits<{\n close: [];\n delete: [preset: SavedFilterReadDto];\n rename: [preset: SavedFilterReadDto];\n}>();\n\nconst canSaveMore = computed(\n () => props.presets.length < MAX_PRESETS_PER_CONTEXT,\n);\n\nconst editingId = ref<string | null>(null);\nconst editingName = ref('');\nconst renameInputRef = ref<HTMLInputElement | null>(null);\n\nconst showSaveForm = ref(false);\nconst saveName = ref('');\nconst saveInputRef = ref<HTMLInputElement | null>(null);\n\nfunction close() {\n emit('close');\n}\n\nfunction applyAndClose(preset: SavedFilterReadDto) {\n props.applyPreset(preset);\n close();\n}\n\nfunction startRename(preset: SavedFilterReadDto) {\n editingId.value = preset.id;\n editingName.value = preset.name;\n nextTick(() => renameInputRef.value?.focus());\n}\n\nfunction cancelRename() {\n editingId.value = null;\n editingName.value = '';\n}\n\nasync function saveRename(presetId: string) {\n const name = editingName.value.trim();\n if (!name) return;\n const result = await props.renamePreset(presetId, name);\n if (result) {\n emit('rename', result);\n cancelRename();\n }\n}\n\nfunction handleDelete(preset: SavedFilterReadDto) {\n emit('delete', preset);\n}\n\nfunction startSave() {\n if (props.hasFilters && canSaveMore.value) {\n showSaveForm.value = true;\n saveName.value = '';\n nextTick(() => saveInputRef.value?.focus());\n }\n}\n\nfunction cancelSave() {\n showSaveForm.value = false;\n saveName.value = '';\n}\n\nasync function submitSave() {\n const name = saveName.value.trim();\n if (!name) return;\n const result = await props.saveCurrentFilters(name);\n if (result) {\n cancelSave();\n close();\n }\n}\n\nwatch(() => props.isOpen, (open) => {\n if (!open) {\n cancelRename();\n cancelSave();\n }\n});\n</script>\n","<template>\n <div class=\"flex items-center gap-2 flex-wrap\">\n <!-- Active preset chip: shows when a preset is applied, with clear (×) -->\n <div\n v-if=\"props.activePreset\"\n class=\"badge badge-primary badge-lg gap-1 pr-1\"\n >\n <span class=\"truncate max-w-[8rem] sm:max-w-[12rem]\">{{ props.activePreset.name }}</span>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs btn-circle\"\n aria-label=\"Clear preset\"\n @click=\"handleClearPreset\"\n >\n <svg class=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Presets button: opens modal with everything -->\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost\"\n :disabled=\"props.presetsLoading\"\n :title=\"props.presets.length ? 'Apply, save, or manage presets' : 'No presets saved'\"\n @click=\"showPresetsModal = true\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\"\n />\n </svg>\n Presets\n </button>\n\n <!-- Delete confirmation modal -->\n <ConfirmDialog\n v-model=\"showDeleteConfirm\"\n title=\"Delete preset?\"\n confirm-text=\"Delete\"\n cancel-text=\"Cancel\"\n processing-text=\"Deleting...\"\n confirm-button-class=\"btn-error\"\n :is-processing=\"props.deleting\"\n @confirm=\"confirmDelete\"\n @cancel=\"presetToDelete = null\"\n >\n <template #message>\n <p>\n Are you sure you want to delete \"{{ presetToDelete?.name }}\"?\n This cannot be undone.\n </p>\n </template>\n </ConfirmDialog>\n\n <!-- Single Presets modal: apply, save, rename, delete -->\n <PresetsModal\n :is-open=\"showPresetsModal\"\n :presets=\"props.presets\"\n :loading=\"props.presetsLoading\"\n :creating=\"props.creating\"\n :deleting=\"props.deleting\"\n :renaming=\"props.renaming\"\n :has-filters=\"props.hasFilters\"\n :active-preset=\"props.activePreset\"\n :apply-preset=\"props.applyPreset\"\n :save-current-filters=\"props.saveCurrentFilters\"\n :rename-preset=\"props.renamePreset\"\n :is-pinned=\"pinnedPresets.isPinned\"\n :toggle-pin=\"pinnedPresets.togglePin\"\n :can-pin-more=\"pinnedPresets.canPinMore.value\"\n :max-pinned=\"pinnedPresets.maxPinned\"\n @close=\"showPresetsModal = false\"\n @delete=\"handleDelete\"\n @rename=\"handleRename\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { SavedFilterReadDto } from '@dragonmastery/dragoncore-shared';\nimport { ref } from 'vue';\nimport ConfirmDialog from '../../components/ConfirmDialog.vue';\nimport PresetsModal from './PresetsModal.vue';\nimport { useInjectedPinnedPresets } from './usePinnedPresets';\n\nconst pinnedPresets = useInjectedPinnedPresets();\n\nconst props = defineProps<{\n presets: SavedFilterReadDto[];\n presetsLoading: boolean;\n creating: boolean;\n deleting: boolean;\n renaming: boolean;\n hasFilters: boolean;\n activePreset: SavedFilterReadDto | null;\n applyPreset: (preset: SavedFilterReadDto) => void;\n clearPreset: () => void;\n saveCurrentFilters: (name: string) => Promise<SavedFilterReadDto | null>;\n renamePreset: (presetId: string, name: string) => Promise<SavedFilterReadDto | null>;\n removePreset: (presetId: string) => Promise<boolean>;\n}>();\n\nconst showPresetsModal = ref(false);\nconst showDeleteConfirm = ref(false);\nconst presetToDelete = ref<{ id: string; name: string } | null>(null);\n\nfunction handleClearPreset() {\n props.clearPreset();\n}\n\nfunction handleDelete(preset: { id: string; name: string }) {\n presetToDelete.value = preset;\n showDeleteConfirm.value = true;\n}\n\nasync function confirmDelete() {\n if (!presetToDelete.value) return;\n pinnedPresets.unpinPreset(presetToDelete.value.id);\n await props.removePreset(presetToDelete.value.id);\n presetToDelete.value = null;\n showDeleteConfirm.value = false;\n}\n\nasync function handleRename(preset: { id: string; name: string }) {\n pinnedPresets.updatePinnedPreset(preset.id, { name: preset.name });\n await pinnedPresets.refetchPinned?.();\n}\n</script>\n"],"mappings":"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"}
@@ -1,23 +1,23 @@
1
- import { d as useEnv, i as setRouter, o as useUserSessionStore, r as executeWithAuth } from "./useRpcAuth-BFdprNWb.js";
2
- import { i as setRefreshTokenHandler, r as getRefreshTokenHandler } from "./EnhancedRefreshTokenHandler-s8wUXtB5.js";
3
- import { t as useMutation } from "./useMutation-BXSu7_-s.js";
4
- import { t as useQuery } from "./useQuery-DownvLRA.js";
1
+ import { d as useEnv, i as setRouter, o as useUserSessionStore, r as executeWithAuth } from "./useRpcAuth-BsO0HMzq.js";
2
+ import { i as setRefreshTokenHandler, r as getRefreshTokenHandler } from "./EnhancedRefreshTokenHandler-bZCCvtpM.js";
3
+ import { t as useMutation } from "./useMutation-Dd1efVil.js";
4
+ import { t as useQuery } from "./useQuery-CDsWjdHj.js";
5
5
  import { t as AppLink_default } from "./AppLink-FcNGKgvG.js";
6
- import { a as useSavedFilters, c as buildQueryWithFilters, f as PINNED_PRESETS_KEY, m as usePinnedPresets, p as useInjectedPinnedPresets, t as SavedFilterPresets_default, u as extractFiltersFromQuery } from "./saved_filter-YIncsdws.js";
6
+ import { a as useSavedFilters, c as buildQueryWithFilters, f as PINNED_PRESETS_KEY, m as usePinnedPresets, p as useInjectedPinnedPresets, t as SavedFilterPresets_default, u as extractFiltersFromQuery } from "./saved_filter-DAmsAfuP.js";
7
7
  import { t as ConfirmDialog_default } from "./ConfirmDialog-DjthOYU6.js";
8
8
  import { n as export_helper_default } from "./TeamMembersTab-BigqpBDH.js";
9
9
  import { a as withReturnUrl, n as getBackLinkFromRoute, r as getValidReturnUrl } from "./useReturnUrl-DnezAxBA.js";
10
- import { r as SIGNUP_EXTENSIBILITY_KEYS } from "./Signup-D6vnyS4w.js";
10
+ import { r as SIGNUP_EXTENSIBILITY_KEYS } from "./Signup-D8qxzAae.js";
11
11
  import { t as BREADCRUMB_KEY } from "./useBreadcrumbs-CPWXm0hm.js";
12
12
  import { t as ZiniaContainer_default } from "./ZiniaContainer-BPIfQOc7.js";
13
13
  import { i as formatUserDate, t as formatSystemTimestamp } from "./convertToLocalDateTime-BKBxm2Rc.js";
14
14
  import { t as extractRpcErrorMessage } from "./extractRpcErrorMessage-Df8-CJGV.js";
15
- import { c as userAuthenticated, l as userIsSuperAdmin, o as leadOrStaffOnly } from "./userAuthorized-qmzUYDa-.js";
16
- import { t as staffSupportPaths } from "./staffSupportTicketRoutes-BZrj4aMG.js";
15
+ import { c as userAuthenticated, l as userIsSuperAdmin, o as leadOrStaffOnly } from "./userAuthorized-Ds3-sFU4.js";
16
+ import { t as staffSupportPaths } from "./staffSupportTicketRoutes-C0JBeFxS.js";
17
17
  import { a as SupportTicketTypeBadge_default, c as formatStaffCreditValue, i as SupportTicketApprovalBadge_default, o as SupportTicketPriorityBadge_default, s as formatCustomerCreditValue } from "./TimelineSystemEvent-D5fkhkZT.js";
18
18
  import { t as formatTicketDisplayId } from "./displayIdFormatter-Ca4Al9iB.js";
19
19
  import { t as SupportTicketDevLifecycleBadge_default } from "./SupportTicketDevLifecycleBadge-D8-Cv1Np.js";
20
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, isRef, nextTick, normalizeClass, onMounted, openBlock, provide, readonly, ref, renderList, renderSlot, resolveComponent, toDisplayString, unref, vModelCheckbox, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
20
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, inject, isRef, nextTick, normalizeClass, onMounted, openBlock, provide, readonly, ref, renderList, renderSlot, resolveComponent, toDisplayString, unref, vModelCheckbox, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
21
21
  import { RouterView, useRoute, useRouter } from "vue-router";
22
22
  import { toast } from "vue3-toastify";
23
23
  import { CompleteSupportTicketSchema, CustomerSupportTicketReadSchema, OPERATORS, SUPPORT_TICKET_APPROVAL_FILTER_OPTIONS, SUPPORT_TICKET_DEV_LIFECYCLE_FILTER_OPTIONS, SUPPORT_TICKET_PRIORITY_FILTER_OPTIONS, SUPPORT_TICKET_STATUS_FILTER_OPTIONS, SUPPORT_TICKET_TYPE_FILTER_OPTIONS, StaffSupportTicketFiltersSchema, StaffSupportTicketReadSchema, SupportTicketDevLifecycleUpdateEnum, TeamFiltersSchema, TeamMemberFiltersSchema, supportTicketPriorityToNumber } from "@dragonmastery/dragoncore-shared";
@@ -2341,7 +2341,7 @@ const userRoutes = [{
2341
2341
  {
2342
2342
  path: "profile",
2343
2343
  name: "Profile",
2344
- component: () => import("./UserProfilePage-BMmz7SGl.js"),
2344
+ component: () => import("./UserProfilePage-BM_M28Wb.js"),
2345
2345
  meta: {
2346
2346
  title: "Profile",
2347
2347
  description: "Profile page for Category 5 App"
@@ -2350,7 +2350,7 @@ const userRoutes = [{
2350
2350
  {
2351
2351
  path: "password",
2352
2352
  name: "Password",
2353
- component: () => import("./ChangePasswordPage-qLd6YZVO.js"),
2353
+ component: () => import("./ChangePasswordPage-BOMNp35R.js"),
2354
2354
  meta: {
2355
2355
  title: "Password",
2356
2356
  description: "Password page for Category 5 App"
@@ -2447,6 +2447,10 @@ const teamMemberFiltersSchemaWithMetadata = withMetadata(TeamMemberFiltersSchema
2447
2447
  }
2448
2448
  });
2449
2449
 
2450
+ //#endregion
2451
+ //#region src/slices/support_ticket/supportTicketListUi.ts
2452
+ const SUPPORT_TICKET_LIST_UI_CONFIG = Symbol("supportTicketListUiConfig");
2453
+
2450
2454
  //#endregion
2451
2455
  //#region src/slices/support_ticket/customer/components/SupportTicketTimeline.vue
2452
2456
  const _hoisted_1$12 = { class: "mt-8" };
@@ -3858,6 +3862,8 @@ const _hoisted_5$1 = ["value"];
3858
3862
  const _sfc_main$3 = /* @__PURE__ */ defineComponent({
3859
3863
  __name: "StaffSupportTicketList",
3860
3864
  setup(__props) {
3865
+ const listUiConfig = inject(SUPPORT_TICKET_LIST_UI_CONFIG, void 0);
3866
+ const showCustomerViewLink = computed(() => listUiConfig?.showCustomerViewLink !== false);
3861
3867
  const route = useRoute();
3862
3868
  const router = useRouter();
3863
3869
  const savedFilters = useSavedFilters({
@@ -4060,13 +4066,14 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
4060
4066
  "save-current-filters",
4061
4067
  "rename-preset",
4062
4068
  "remove-preset"
4063
- ]), _cache[0] || (_cache[0] = createElementVNode("h1", { class: "text-xl sm:text-2xl font-bold" }, "Manage Support Tickets", -1))]), createElementVNode("div", _hoisted_3$1, [createVNode(_component_router_link, {
4069
+ ]), _cache[0] || (_cache[0] = createElementVNode("h1", { class: "text-xl sm:text-2xl font-bold" }, "Manage Support Tickets", -1))]), createElementVNode("div", _hoisted_3$1, [showCustomerViewLink.value ? (openBlock(), createBlock(_component_router_link, {
4070
+ key: 0,
4064
4071
  to: { name: "CustomerSupportTicketList" },
4065
4072
  class: "btn btn-outline btn-sm sm:btn-md"
4066
4073
  }, {
4067
4074
  default: withCtx(() => [..._cache[1] || (_cache[1] = [createTextVNode(" Customer View ", -1)])]),
4068
4075
  _: 1
4069
- }), createVNode(_component_router_link, {
4076
+ })) : createCommentVNode("v-if", true), createVNode(_component_router_link, {
4070
4077
  to: { name: unref(staffSupportPaths).staff_create.name },
4071
4078
  class: "btn btn-primary btn-sm sm:btn-md"
4072
4079
  }, {
@@ -4508,7 +4515,7 @@ const baseRoutes = [
4508
4515
  {
4509
4516
  path: authPaths.login.path,
4510
4517
  name: authPaths.login.name,
4511
- component: () => import("./LoginForm-B5wYdKhY.js"),
4518
+ component: () => import("./LoginForm-srufyzTf.js"),
4512
4519
  meta: {
4513
4520
  title: "Login",
4514
4521
  description: "Login page for Category 5 App"
@@ -4518,7 +4525,7 @@ const baseRoutes = [
4518
4525
  {
4519
4526
  path: authPaths.forgot_password.path,
4520
4527
  name: authPaths.forgot_password.name,
4521
- component: () => import("./ForgotPassword-Xb1yVZ6C.js"),
4528
+ component: () => import("./ForgotPassword-C_g7r8tQ.js"),
4522
4529
  meta: {
4523
4530
  title: "Forgot Password",
4524
4531
  description: "Forgot Password page for Category 5 App"
@@ -4528,7 +4535,7 @@ const baseRoutes = [
4528
4535
  {
4529
4536
  path: authPaths.reset_password.path,
4530
4537
  name: authPaths.reset_password.name,
4531
- component: () => import("./ResetPassword-ulR2HviU.js"),
4538
+ component: () => import("./ResetPassword-CJRPGJF4.js"),
4532
4539
  meta: {
4533
4540
  title: "Reset Password",
4534
4541
  description: "Reset Password page for Category 5 App"
@@ -4538,7 +4545,7 @@ const baseRoutes = [
4538
4545
  {
4539
4546
  path: authPaths.logout.path,
4540
4547
  name: authPaths.logout.name,
4541
- component: () => import("./Logout-qyH2t-1a.js"),
4548
+ component: () => import("./Logout-DXBwdbV1.js"),
4542
4549
  meta: {
4543
4550
  title: "Logout",
4544
4551
  description: "Logout page for Category 5 App"
@@ -4547,7 +4554,7 @@ const baseRoutes = [
4547
4554
  {
4548
4555
  path: authPaths.mfa_setup.path,
4549
4556
  name: authPaths.mfa_setup.name,
4550
- component: () => import("./MfaSetup-DMLXL9fk.js"),
4557
+ component: () => import("./MfaSetup-ByLSlwd5.js"),
4551
4558
  meta: {
4552
4559
  title: "Set Up Two-Factor Authentication",
4553
4560
  description: "Enable MFA for your account"
@@ -4556,7 +4563,7 @@ const baseRoutes = [
4556
4563
  {
4557
4564
  path: authPaths.mfa_verify.path,
4558
4565
  name: authPaths.mfa_verify.name,
4559
- component: () => import("./MfaVerify-C4xGQZlQ.js"),
4566
+ component: () => import("./MfaVerify-BVzkjS0M.js"),
4560
4567
  meta: {
4561
4568
  title: "Verify Two-Factor Authentication",
4562
4569
  description: "Enter your MFA code to complete sign in"
@@ -4565,7 +4572,7 @@ const baseRoutes = [
4565
4572
  {
4566
4573
  path: authPaths.verify_email.path,
4567
4574
  name: authPaths.verify_email.name,
4568
- component: () => import("./VerifyEmail-Xd31Com7.js"),
4575
+ component: () => import("./VerifyEmail-BXXqZxAP.js"),
4569
4576
  meta: {
4570
4577
  title: "Verify Email",
4571
4578
  description: "Verify your email address"
@@ -4582,7 +4589,7 @@ const baseRoutes = [
4582
4589
  {
4583
4590
  path: authPaths.consent_required.path,
4584
4591
  name: authPaths.consent_required.name,
4585
- component: () => import("./ConsentRequired-DtUwfpk0.js"),
4592
+ component: () => import("./ConsentRequired-CD9_9drZ.js"),
4586
4593
  meta: {
4587
4594
  title: "Consent Required",
4588
4595
  description: "Accept updated terms to continue"
@@ -4592,7 +4599,7 @@ const baseRoutes = [
4592
4599
  if (allowUserSignup) baseRoutes.splice(1, 0, {
4593
4600
  path: authPaths.register.path,
4594
4601
  name: authPaths.register.name,
4595
- component: () => import("./Signup-D4xILUym.js"),
4602
+ component: () => import("./Signup-CMDAy5qG.js"),
4596
4603
  meta: {
4597
4604
  title: "Register",
4598
4605
  description: "Register page for Category 5 App"
@@ -4698,7 +4705,7 @@ const adminRoutes = [{
4698
4705
  {
4699
4706
  path: "create-user",
4700
4707
  name: "CreateUser",
4701
- component: () => import("./CreateUserPage-D0oMJnGd.js"),
4708
+ component: () => import("./CreateUserPage-MTIXjQgC.js"),
4702
4709
  meta: {
4703
4710
  title: "Create User",
4704
4711
  description: "Create User page for Category 5 App",
@@ -4711,7 +4718,7 @@ const adminRoutes = [{
4711
4718
  {
4712
4719
  path: "support-staff",
4713
4720
  name: "SupportStaff",
4714
- component: () => import("./SupportStaffPage--vinFIlV.js"),
4721
+ component: () => import("./SupportStaffPage-CJRjoBgD.js"),
4715
4722
  meta: {
4716
4723
  title: "Support Staff",
4717
4724
  description: "Manage users who can triage support tickets",
@@ -4724,7 +4731,7 @@ const adminRoutes = [{
4724
4731
  {
4725
4732
  path: "users",
4726
4733
  name: "UserManagement",
4727
- component: () => import("./UserListPage-CYkvaHwL.js"),
4734
+ component: () => import("./UserListPage-DJovOSHs.js"),
4728
4735
  meta: {
4729
4736
  title: "User Management",
4730
4737
  description: "View and manage all users",
@@ -4737,7 +4744,7 @@ const adminRoutes = [{
4737
4744
  {
4738
4745
  path: "users/:id/edit",
4739
4746
  name: "EditUser",
4740
- component: () => import("./EditUserPage-DCdj6EYd.js"),
4747
+ component: () => import("./EditUserPage-B0DzlBPq.js"),
4741
4748
  meta: {
4742
4749
  title: "Edit User",
4743
4750
  description: "Edit user role",
@@ -4760,7 +4767,7 @@ const adminRoutes = [{
4760
4767
  {
4761
4768
  path: "credit-management",
4762
4769
  name: "CreditManagement",
4763
- component: () => import("./CreditManagement-B4aHJfOo.js"),
4770
+ component: () => import("./CreditManagement-C65vEqxp.js"),
4764
4771
  meta: {
4765
4772
  title: "Credit Management",
4766
4773
  description: "Manage customer credits and allocations",
@@ -4773,7 +4780,7 @@ const adminRoutes = [{
4773
4780
  {
4774
4781
  path: "support-ticket-maintenance",
4775
4782
  name: "SupportTicketMaintenance",
4776
- component: () => import("./SupportTicketMaintenancePage-C-BWD49g.js"),
4783
+ component: () => import("./SupportTicketMaintenancePage-8Dm-QIlz.js"),
4777
4784
  meta: {
4778
4785
  title: "Support Ticket Maintenance",
4779
4786
  description: "Admin utilities for fixing support ticket data",
@@ -4786,7 +4793,7 @@ const adminRoutes = [{
4786
4793
  {
4787
4794
  path: "signup-requirements",
4788
4795
  name: "SignupRequirements",
4789
- component: () => import("./SignupRequirementsPage-BnOkXd7w.js"),
4796
+ component: () => import("./SignupRequirementsPage-txEGpjmy.js"),
4790
4797
  meta: {
4791
4798
  title: "Signup Requirements",
4792
4799
  description: "Configure consent checkboxes shown on signup and consent-required flows",
@@ -4799,7 +4806,7 @@ const adminRoutes = [{
4799
4806
  {
4800
4807
  path: "default-referral-team",
4801
4808
  name: "DefaultReferralTeam",
4802
- component: () => import("./DefaultReferralTeamPage-fS1SlVow.js"),
4809
+ component: () => import("./DefaultReferralTeamPage-Crc26bES.js"),
4803
4810
  meta: {
4804
4811
  title: "Default Referral Team",
4805
4812
  description: "Set the default team for unknown referral tags",
@@ -4827,7 +4834,7 @@ const creditRoutes = [{
4827
4834
  children: [{
4828
4835
  path: creditPaths.credit_balance.path,
4829
4836
  name: creditPaths.credit_balance.name,
4830
- component: () => import("./CreditBalanceDashboard-D370HlpF.js"),
4837
+ component: () => import("./CreditBalanceDashboard-9Mn6467S.js"),
4831
4838
  meta: {
4832
4839
  title: "Credit Balance",
4833
4840
  description: "View your current credit balance and history.",
@@ -4844,5 +4851,5 @@ const creditRoutes = [{
4844
4851
  }];
4845
4852
 
4846
4853
  //#endregion
4847
- export { DragoncoreVue as $, userAlreadyLoggedIn as A, Auth_default as B, customerSupportTicketRowSchemaWithMetadata as C, teamFiltersSchemaWithMetadata as D, teamMemberFiltersSchemaWithMetadata as E, FieldGroup_default as F, useBuildTag as G, UnverifiedEmailBanner_default as H, FieldDisplay_default as I, Navbar_default as J, RightSidebar_default as K, Legal_default as L, SummarySection_default as M, KeyValueEditor_default as N, TeamAttachmentsTab_default as O, FileManager_default as P, AppTabNavigation_default as Q, InApp_default as R, CustomerSupportTicketList_default as S, SupportTicketTimeline_default as T, useEmailVerificationGuard as U, Admin_default as V, Sidebar_default as W, InputModal_default as X, LoginButton_default as Y, AppHeader_default as Z, ConvertToCustomerWorkflow_default as _, authPaths as a, ApproveRejectActions_default as b, useSupportTicketStatus as c, SupportTicketAttachments_default as d, CreditBalanceWidget_default as f, ConvertToInternalWorkflow_default as g, ReactivateInternalTaskWorkflow_default as h, SocialLoginButtons_default as i, timezones as j, userRoutes as k, useSupportTicketPermissions as l, adminSupportTicketRowSchemaWithMetadata as m, creditRoutes as n, authRoutes as o, StaffSupportTicketList_default as p, NotFound_default as q, adminRoutes as r, getAuthRoutes as s, creditPaths as t, adminSupportTicketFiltersSchemaWithMetadata as u, CompleteSupportTicketForm_default as v, SupportTicketStatusBadge_default as w, CustomerCreditBalance_default as x, CancelInternalTaskWorkflow_default as y, Default_default as z };
4848
- //# sourceMappingURL=src-BXO0PrFd.js.map
4854
+ export { AppTabNavigation_default as $, userRoutes as A, Default_default as B, customerSupportTicketRowSchemaWithMetadata as C, teamMemberFiltersSchemaWithMetadata as D, SUPPORT_TICKET_LIST_UI_CONFIG as E, FileManager_default as F, Sidebar_default as G, Admin_default as H, FieldGroup_default as I, NotFound_default as J, useBuildTag as K, FieldDisplay_default as L, timezones as M, SummarySection_default as N, teamFiltersSchemaWithMetadata as O, KeyValueEditor_default as P, AppHeader_default as Q, Legal_default as R, CustomerSupportTicketList_default as S, SupportTicketTimeline_default as T, UnverifiedEmailBanner_default as U, Auth_default as V, useEmailVerificationGuard as W, LoginButton_default as X, Navbar_default as Y, InputModal_default as Z, ConvertToCustomerWorkflow_default as _, authPaths as a, ApproveRejectActions_default as b, useSupportTicketStatus as c, SupportTicketAttachments_default as d, DragoncoreVue as et, CreditBalanceWidget_default as f, ConvertToInternalWorkflow_default as g, ReactivateInternalTaskWorkflow_default as h, SocialLoginButtons_default as i, userAlreadyLoggedIn as j, TeamAttachmentsTab_default as k, useSupportTicketPermissions as l, adminSupportTicketRowSchemaWithMetadata as m, creditRoutes as n, authRoutes as o, StaffSupportTicketList_default as p, RightSidebar_default as q, adminRoutes as r, getAuthRoutes as s, creditPaths as t, adminSupportTicketFiltersSchemaWithMetadata as u, CompleteSupportTicketForm_default as v, SupportTicketStatusBadge_default as w, CustomerCreditBalance_default as x, CancelInternalTaskWorkflow_default as y, InApp_default as z };
4855
+ //# sourceMappingURL=src-D1zivPEG.js.map