@dragonmastery/dragoncore-vue 0.0.34 → 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.
- package/dist/ChangePasswordPage-BOMNp35R.js +7 -0
- package/dist/{ChangePasswordPage-CR91NZP4.js → ChangePasswordPage-ITglJw64.js} +2 -2
- package/dist/{ChangePasswordPage-CR91NZP4.js.map → ChangePasswordPage-ITglJw64.js.map} +1 -1
- package/dist/{ConsentRequired-DtUwfpk0.js → ConsentRequired-CD9_9drZ.js} +7 -7
- package/dist/{ConsentRequired-DtUwfpk0.js.map → ConsentRequired-CD9_9drZ.js.map} +1 -1
- package/dist/CreateTeamForm-B9riDuoe.js +12 -0
- package/dist/{CreateTeamForm-ClisfzsU.js → CreateTeamForm-tQemosKP.js} +4 -4
- package/dist/{CreateTeamForm-ClisfzsU.js.map → CreateTeamForm-tQemosKP.js.map} +1 -1
- package/dist/{CreateTeamMemberForm-B3jxlAsC.js → CreateTeamMemberForm-CiKnRKTm.js} +4 -4
- package/dist/{CreateTeamMemberForm-B3jxlAsC.js.map → CreateTeamMemberForm-CiKnRKTm.js.map} +1 -1
- package/dist/CreateTeamMemberForm-OznLRtZ2.js +12 -0
- package/dist/{CreateUserPage-BcCIat_l.js → CreateUserPage-DwMcY1iD.js} +2 -2
- package/dist/{CreateUserPage-BcCIat_l.js.map → CreateUserPage-DwMcY1iD.js.map} +1 -1
- package/dist/CreateUserPage-MTIXjQgC.js +7 -0
- package/dist/CreditBalanceDashboard-9Mn6467S.js +13 -0
- package/dist/{CreditBalanceDashboard-CJr1yOjW.js → CreditBalanceDashboard-BWEpNj7P.js} +2 -2
- package/dist/{CreditBalanceDashboard-CJr1yOjW.js.map → CreditBalanceDashboard-BWEpNj7P.js.map} +1 -1
- package/dist/CreditManagement-C65vEqxp.js +13 -0
- package/dist/{CreditManagement-BbDEviZx.js → CreditManagement-CEAW1uKw.js} +3 -3
- package/dist/{CreditManagement-BbDEviZx.js.map → CreditManagement-CEAW1uKw.js.map} +1 -1
- package/dist/{CreditTransactionHistory-mz-QIKUG.js → CreditTransactionHistory-irDJnMV9.js} +5 -5
- package/dist/{CreditTransactionHistory-mz-QIKUG.js.map → CreditTransactionHistory-irDJnMV9.js.map} +1 -1
- package/dist/{CustomerCreateSupportTicketForm-Cul4aVjB.js → CustomerCreateSupportTicketForm-B6lqDu3-.js} +4 -4
- package/dist/{CustomerCreateSupportTicketForm-Cul4aVjB.js.map → CustomerCreateSupportTicketForm-B6lqDu3-.js.map} +1 -1
- package/dist/CustomerCreateSupportTicketForm-CmWMP0Vs.js +14 -0
- package/dist/{CustomerSupportTicketDetailPage-DflGaKvk.js → CustomerSupportTicketDetailPage-vmpgMU4d.js} +8 -8
- package/dist/{CustomerSupportTicketDetailPage-DflGaKvk.js.map → CustomerSupportTicketDetailPage-vmpgMU4d.js.map} +1 -1
- package/dist/CustomerSupportTicketList-q1nBdbhH.js +64 -0
- package/dist/{CustomerSupportTicketParent-D9FuZjPz.js → CustomerSupportTicketParent-Clov63wF.js} +2 -2
- package/dist/{CustomerSupportTicketParent-D9FuZjPz.js.map → CustomerSupportTicketParent-Clov63wF.js.map} +1 -1
- package/dist/CustomerSupportTicketParent-M9YS9zj9.js +8 -0
- package/dist/CustomerSupportTicketSuccess--ztNfpOC.js +12 -0
- package/dist/{CustomerSupportTicketSuccess-B4WR8Zfn.js → CustomerSupportTicketSuccess-CfSQ5ve3.js} +2 -2
- package/dist/{CustomerSupportTicketSuccess-B4WR8Zfn.js.map → CustomerSupportTicketSuccess-CfSQ5ve3.js.map} +1 -1
- package/dist/{DefaultReferralTeamPage-fS1SlVow.js → DefaultReferralTeamPage-Crc26bES.js} +6 -6
- package/dist/{DefaultReferralTeamPage-fS1SlVow.js.map → DefaultReferralTeamPage-Crc26bES.js.map} +1 -1
- package/dist/{EditTeamForm-B4p-C-8i.js → EditTeamForm-CJlL7tcU.js} +4 -4
- package/dist/{EditTeamForm-B4p-C-8i.js.map → EditTeamForm-CJlL7tcU.js.map} +1 -1
- package/dist/EditTeamForm-CdnmBsNm.js +12 -0
- package/dist/{EditTeamMemberForm-D6vf9hp-.js → EditTeamMemberForm-C0WQvq_7.js} +2 -2
- package/dist/{EditTeamMemberForm-D6vf9hp-.js.map → EditTeamMemberForm-C0WQvq_7.js.map} +1 -1
- package/dist/EditTeamMemberForm-VC3OouUy.js +9 -0
- package/dist/EditUserPage-B0DzlBPq.js +8 -0
- package/dist/{EditUserPage-Dy61CCle.js → EditUserPage-BAlhX8JA.js} +3 -3
- package/dist/{EditUserPage-Dy61CCle.js.map → EditUserPage-BAlhX8JA.js.map} +1 -1
- package/dist/{EnhancedRefreshTokenHandler-s8wUXtB5.js → EnhancedRefreshTokenHandler-bZCCvtpM.js} +2 -2
- package/dist/{EnhancedRefreshTokenHandler-s8wUXtB5.js.map → EnhancedRefreshTokenHandler-bZCCvtpM.js.map} +1 -1
- package/dist/{ForgotPassword-BykH9B9R.js → ForgotPassword-CYHwOPo1.js} +2 -2
- package/dist/{ForgotPassword-BykH9B9R.js.map → ForgotPassword-CYHwOPo1.js.map} +1 -1
- package/dist/ForgotPassword-C_g7r8tQ.js +8 -0
- package/dist/{InlineAttachments-DvqCOd6U.js → InlineAttachments-DHUmSY59.js} +4 -4
- package/dist/{InlineAttachments-DvqCOd6U.js.map → InlineAttachments-DHUmSY59.js.map} +1 -1
- package/dist/{LoginForm-CjF4NSgM.js → LoginForm-SW8Z2SnH.js} +3 -3
- package/dist/{LoginForm-CjF4NSgM.js.map → LoginForm-SW8Z2SnH.js.map} +1 -1
- package/dist/LoginForm-srufyzTf.js +8 -0
- package/dist/Logout-DXBwdbV1.js +8 -0
- package/dist/{Logout-DmpC8Rwh.js → Logout-Dcxar0WO.js} +4 -3
- package/dist/{Logout-DmpC8Rwh.js.map → Logout-Dcxar0WO.js.map} +1 -1
- package/dist/{MfaSetup-DCLKIMaS.js → MfaSetup-BJSFbnKm.js} +2 -2
- package/dist/{MfaSetup-DCLKIMaS.js.map → MfaSetup-BJSFbnKm.js.map} +1 -1
- package/dist/MfaSetup-ByLSlwd5.js +9 -0
- package/dist/MfaVerify-BVzkjS0M.js +9 -0
- package/dist/{MfaVerify-Dm2Yc0Da.js → MfaVerify-DyuEFCCa.js} +3 -3
- package/dist/{MfaVerify-Dm2Yc0Da.js.map → MfaVerify-DyuEFCCa.js.map} +1 -1
- package/dist/{ResetPassword-iVcY7eBY.js → ResetPassword-BSLD7bQQ.js} +2 -2
- package/dist/{ResetPassword-iVcY7eBY.js.map → ResetPassword-BSLD7bQQ.js.map} +1 -1
- package/dist/ResetPassword-CJRPGJF4.js +8 -0
- package/dist/{SavedFiltersPage-Y1T18UAH.js → SavedFiltersPage-DPGwcuZ3.js} +51 -51
- package/dist/{SavedFiltersPage-Y1T18UAH.js.map → SavedFiltersPage-DPGwcuZ3.js.map} +1 -1
- package/dist/Signup-CMDAy5qG.js +10 -0
- package/dist/{Signup-D6vnyS4w.js → Signup-D8qxzAae.js} +5 -5
- package/dist/{Signup-D6vnyS4w.js.map → Signup-D8qxzAae.js.map} +1 -1
- package/dist/{SignupRequirementsPage-BnOkXd7w.js → SignupRequirementsPage-txEGpjmy.js} +6 -6
- package/dist/{SignupRequirementsPage-BnOkXd7w.js.map → SignupRequirementsPage-txEGpjmy.js.map} +1 -1
- package/dist/{StaffCreateSupportTicketForm-B1YioWlS.js → StaffCreateSupportTicketForm-CYanySsY.js} +6 -6
- package/dist/{StaffCreateSupportTicketForm-B1YioWlS.js.map → StaffCreateSupportTicketForm-CYanySsY.js.map} +1 -1
- package/dist/StaffCreateSupportTicketForm-dxtP9z1t.js +14 -0
- package/dist/{StaffSupportTicketDetailPage-CMxsVxjf.js → StaffSupportTicketDetailPage-DA3vRpJw.js} +8 -8
- package/dist/{StaffSupportTicketDetailPage-CMxsVxjf.js.map → StaffSupportTicketDetailPage-DA3vRpJw.js.map} +1 -1
- package/dist/StaffSupportTicketList-B4X77wzv.js +64 -0
- package/dist/StaffSupportTicketParent-CuEupptb.js +8 -0
- package/dist/{StaffSupportTicketParent-CZllER18.js → StaffSupportTicketParent-DFOSKGI1.js} +2 -2
- package/dist/{StaffSupportTicketParent-CZllER18.js.map → StaffSupportTicketParent-DFOSKGI1.js.map} +1 -1
- package/dist/{StaffSupportTicketSuccess-DTMToAq2.js → StaffSupportTicketSuccess-BNvV1hRs.js} +2 -2
- package/dist/{StaffSupportTicketSuccess-DTMToAq2.js.map → StaffSupportTicketSuccess-BNvV1hRs.js.map} +1 -1
- package/dist/StaffSupportTicketSuccess-QSDkFoLP.js +12 -0
- package/dist/{SupportStaffPage--vinFIlV.js → SupportStaffPage-CJRjoBgD.js} +6 -6
- package/dist/{SupportStaffPage--vinFIlV.js.map → SupportStaffPage-CJRjoBgD.js.map} +1 -1
- package/dist/{SupportTicketMaintenancePage-C-BWD49g.js → SupportTicketMaintenancePage-8Dm-QIlz.js} +5 -5
- package/dist/{SupportTicketMaintenancePage-C-BWD49g.js.map → SupportTicketMaintenancePage-8Dm-QIlz.js.map} +1 -1
- package/dist/TeamAttachmentsTab-DcBgmtRU.js +64 -0
- package/dist/TeamHistoryTab-CJHmmx7_.js +6 -0
- package/dist/{TeamHistoryTab-5kNQ_XAq.js → TeamHistoryTab-DsF7t8Nr.js} +3 -3
- package/dist/{TeamHistoryTab-5kNQ_XAq.js.map → TeamHistoryTab-DsF7t8Nr.js.map} +1 -1
- package/dist/{TeamList-P7rVlBuQ.js → TeamList-BOoU9XWg.js} +4 -4
- package/dist/{TeamList-P7rVlBuQ.js.map → TeamList-BOoU9XWg.js.map} +1 -1
- package/dist/TeamList-BeAp59Ic.js +8 -0
- package/dist/{TeamMemberList-DyfXcR6F.js → TeamMemberList-3wgkaznJ.js} +4 -4
- package/dist/{TeamMemberList-DyfXcR6F.js.map → TeamMemberList-3wgkaznJ.js.map} +1 -1
- package/dist/TeamMemberList-txA_1zDI.js +7 -0
- package/dist/TeamMemberParent-Ci8UT_YG.js +10 -0
- package/dist/{TeamMemberParent-2zISixbT.js → TeamMemberParent-zhMS108u.js} +3 -3
- package/dist/{TeamMemberParent-2zISixbT.js.map → TeamMemberParent-zhMS108u.js.map} +1 -1
- package/dist/TeamNotesTab-BW-sNIT_.js +8 -0
- package/dist/{TeamNotesTab-BREl3Vr0.js → TeamNotesTab-Bp0-6tga.js} +5 -5
- package/dist/{TeamNotesTab-BREl3Vr0.js.map → TeamNotesTab-Bp0-6tga.js.map} +1 -1
- package/dist/{TeamParent-D35VUiio.js → TeamParent-CT-UfCvh.js} +3 -3
- package/dist/{TeamParent-D35VUiio.js.map → TeamParent-CT-UfCvh.js.map} +1 -1
- package/dist/TeamParent-ftrZ6TgM.js +11 -0
- package/dist/{TimelineNoteInput-D6AbJMx5.js → TimelineNoteInput-D_On05JJ.js} +2 -2
- package/dist/{TimelineNoteInput-D6AbJMx5.js.map → TimelineNoteInput-D_On05JJ.js.map} +1 -1
- package/dist/{UserListPage-CCl0K7Gk.js → UserListPage-BO6ESqfN.js} +3 -3
- package/dist/{UserListPage-CCl0K7Gk.js.map → UserListPage-BO6ESqfN.js.map} +1 -1
- package/dist/UserListPage-DJovOSHs.js +5 -0
- package/dist/UserProfilePage-BM_M28Wb.js +8 -0
- package/dist/{UserProfilePage-D7FNmca1.js → UserProfilePage-DEfN_eCZ.js} +4 -4
- package/dist/{UserProfilePage-D7FNmca1.js.map → UserProfilePage-DEfN_eCZ.js.map} +1 -1
- package/dist/VerifyEmail-BXXqZxAP.js +10 -0
- package/dist/{VerifyEmail-KCti4rzf.js → VerifyEmail-DDnLh6Eu.js} +5 -5
- package/dist/{VerifyEmail-KCti4rzf.js.map → VerifyEmail-DDnLh6Eu.js.map} +1 -1
- package/dist/{ViewTeam-BbsTsjAy.js → ViewTeam-C-SDshYC.js} +2 -2
- package/dist/{ViewTeam-BbsTsjAy.js.map → ViewTeam-C-SDshYC.js.map} +1 -1
- package/dist/ViewTeam-x_FhmSTc.js +8 -0
- package/dist/{ViewTeamMember-Dsl2GKI1.js → ViewTeamMember-27cPSE4-.js} +2 -2
- package/dist/{ViewTeamMember-Dsl2GKI1.js.map → ViewTeamMember-27cPSE4-.js.map} +1 -1
- package/dist/ViewTeamMember-BAnH7nlP.js +7 -0
- package/dist/{customerSupportTicketRoutes-38JuLJGP.js → customerSupportTicketRoutes-CtugEy49.js} +8 -8
- package/dist/{customerSupportTicketRoutes-38JuLJGP.js.map → customerSupportTicketRoutes-CtugEy49.js.map} +1 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +51 -51
- package/dist/{saved_filter-YIncsdws.js → saved_filter-DAmsAfuP.js} +5 -5
- package/dist/{saved_filter-YIncsdws.js.map → saved_filter-DAmsAfuP.js.map} +1 -1
- package/dist/{src-BXO0PrFd.js → src-D1zivPEG.js} +40 -33
- package/dist/src-D1zivPEG.js.map +1 -0
- package/dist/{staffSupportTicketRoutes-BZrj4aMG.js → staffSupportTicketRoutes-C0JBeFxS.js} +8 -8
- package/dist/{staffSupportTicketRoutes-BZrj4aMG.js.map → staffSupportTicketRoutes-C0JBeFxS.js.map} +1 -1
- package/dist/{teamMetadata-NTjPt89L.js → teamMetadata-BkICmT4w.js} +9 -1
- package/dist/teamMetadata-BkICmT4w.js.map +1 -0
- package/dist/{teamRoutes-Aa9aBVCa.js → teamRoutes-CVXDmndU.js} +11 -11
- package/dist/{teamRoutes-Aa9aBVCa.js.map → teamRoutes-CVXDmndU.js.map} +1 -1
- package/dist/{team_memberRoutes-mO1f-Y4o.js → team_memberRoutes-B3rxZxW2.js} +7 -7
- package/dist/{team_memberRoutes-mO1f-Y4o.js.map → team_memberRoutes-B3rxZxW2.js.map} +1 -1
- package/dist/{useAuthFlowNextStep-zlvxflBZ.js → useAuthFlowNextStep-DYlsa7We.js} +2 -2
- package/dist/{useAuthFlowNextStep-zlvxflBZ.js.map → useAuthFlowNextStep-DYlsa7We.js.map} +1 -1
- package/dist/{useEmailVerificationChannel-DYiMSAES.js → useEmailVerificationChannel-7s9wqRoy.js} +2 -2
- package/dist/{useEmailVerificationChannel-DYiMSAES.js.map → useEmailVerificationChannel-7s9wqRoy.js.map} +1 -1
- package/dist/{useMutation-BXSu7_-s.js → useMutation-Dd1efVil.js} +4 -4
- package/dist/{useMutation-BXSu7_-s.js.map → useMutation-Dd1efVil.js.map} +1 -1
- package/dist/{useQuery-DownvLRA.js → useQuery-CDsWjdHj.js} +4 -4
- package/dist/{useQuery-DownvLRA.js.map → useQuery-CDsWjdHj.js.map} +1 -1
- package/dist/{useQueryCache-CUTrwJWX.js → useQueryCache-D6RxB_yQ.js} +2 -2
- package/dist/{useQueryCache-CUTrwJWX.js.map → useQueryCache-D6RxB_yQ.js.map} +1 -1
- package/dist/{useRpcAuth-BFdprNWb.js → useRpcAuth-BsO0HMzq.js} +3 -3
- package/dist/{useRpcAuth-BFdprNWb.js.map → useRpcAuth-BsO0HMzq.js.map} +1 -1
- package/dist/{userAuthorized-qmzUYDa-.js → userAuthorized-Ds3-sFU4.js} +2 -2
- package/dist/{userAuthorized-qmzUYDa-.js.map → userAuthorized-Ds3-sFU4.js.map} +1 -1
- package/package.json +3 -3
- package/dist/ChangePasswordPage-qLd6YZVO.js +0 -7
- package/dist/CreateTeamForm-DWAeq_Xd.js +0 -12
- package/dist/CreateTeamMemberForm-BYsZNxTq.js +0 -12
- package/dist/CreateUserPage-D0oMJnGd.js +0 -7
- package/dist/CreditBalanceDashboard-D370HlpF.js +0 -13
- package/dist/CreditManagement-B4aHJfOo.js +0 -13
- package/dist/CustomerCreateSupportTicketForm-DCPjvzyF.js +0 -14
- package/dist/CustomerSupportTicketList-BPWQ8WjH.js +0 -64
- package/dist/CustomerSupportTicketParent-C0uMeN09.js +0 -8
- package/dist/CustomerSupportTicketSuccess-Bsp1d0oF.js +0 -12
- package/dist/EditTeamForm-ucwkw2eL.js +0 -12
- package/dist/EditTeamMemberForm-BKbWq88S.js +0 -9
- package/dist/EditUserPage-DCdj6EYd.js +0 -8
- package/dist/ForgotPassword-Xb1yVZ6C.js +0 -8
- package/dist/LoginForm-B5wYdKhY.js +0 -8
- package/dist/Logout-qyH2t-1a.js +0 -8
- package/dist/MfaSetup-DMLXL9fk.js +0 -9
- package/dist/MfaVerify-C4xGQZlQ.js +0 -9
- package/dist/ResetPassword-ulR2HviU.js +0 -8
- package/dist/Signup-D4xILUym.js +0 -10
- package/dist/StaffCreateSupportTicketForm-UkE9YVWE.js +0 -14
- package/dist/StaffSupportTicketList-BlGTtE1R.js +0 -64
- package/dist/StaffSupportTicketParent-D4FKQAmp.js +0 -8
- package/dist/StaffSupportTicketSuccess-CzS9uS2h.js +0 -12
- package/dist/TeamAttachmentsTab-BgtXRohH.js +0 -64
- package/dist/TeamHistoryTab-CBWeRKXM.js +0 -6
- package/dist/TeamList-D3NqS5DL.js +0 -8
- package/dist/TeamMemberList-X2hzYZFT.js +0 -7
- package/dist/TeamMemberParent-DKxE1ziP.js +0 -10
- package/dist/TeamNotesTab-DxMN3WZo.js +0 -8
- package/dist/TeamParent-CuoVw7Yk.js +0 -11
- package/dist/UserListPage-CYkvaHwL.js +0 -5
- package/dist/UserProfilePage-BMmz7SGl.js +0 -8
- package/dist/VerifyEmail-Xd31Com7.js +0 -10
- package/dist/ViewTeam-7YvvwcXd.js +0 -8
- package/dist/ViewTeamMember-bmry5QZ0.js +0 -7
- package/dist/src-BXO0PrFd.js.map +0 -1
- 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":";;;;;;;;;;;;;;;;;;;;;;;;EAoDA,MAAM,QAAQ;EAId,MAAM,OAAO;EAIb,MAAM,QAAQ,KAAwB;EAEtC,MAAM,oBAAoB;AACxB,QAAK,QAAQ;;AAIf,cACQ,MAAM,SACX,WAAW;AACV,OAAI,UAAU,MAAM,MAClB,OAAM,MAAM,WAAW;YACd,CAAC,UAAU,MAAM,MAC1B,OAAM,MAAM,OAAO;KAGvB,EAAE,WAAW,MAAM,CACpB;;uBA5EC,mBAwCS,UAAA;aAxCG;IAAJ,KAAI;IAAQ,OAAM;OACxB,mBAmCM,OAnCN,cAmCM;IAlCJ,mBAAA,+DAAmE;IACnE,mBA2BM,OA3BN,cA2BM,CAxBJ,mBAEK,MAFL,cAEK,CADH,WAAqC,KAAA,QAAA,SAAA,EAAA,QAAA,CAAA,gCAAf,QAAA,MAAK,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,EAE7B,mBAoBS,UAAA;KAnBP,MAAK;KACL,OAAM;KACL,SAAK,cAAU,aAAW,CAAA,UAAA,CAAA;KAC3B,cAAW;sCAEX,mBAaM,OAAA;KAZJ,OAAM;KACN,OAAM;KACN,MAAK;KACL,SAAQ;KACR,QAAO;QAEP,mBAKE,QAAA;KAJA,kBAAe;KACf,mBAAgB;KAChB,gBAAa;KACb,GAAE;;IAMV,mBAAA,mCAAuC;IACvC,mBAEM,OAFN,cAEM,CADJ,WAAa,KAAA,QAAA,UAAA,CAAA,CAAA;OAGjB,mBAEO,QAFP,cAEO,CADL,mBAAiE,UAAA;IAAzD,MAAK;IAAU,SAAK,cAAU,aAAW,CAAA,UAAA,CAAA;MAAE,QAAK,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;AC9B9D,MAAa,KAAK;CAChB,YAAY;CACZ,YAAY,KAAK;CACjB,UAAU,OAAU;CACrB;;;;ACGD,MAAM,YAAY;AAClB,MAAM,aAAa;AAOnB,SAAgB,mBAAmB;CACjC,MAAM,EAAE,MAAM,YAAY,YAAY,UACnC,QAAQ,IAAI,aAAa,mBAAmB,EAC7C;EAAE,UAAU;EAAW,WAAW,KAAK,GAAG;EAAU,CACrD;CAED,MAAM,EAAE,QAAQ,WAAW,aACxB,KAAK,OAAe,IAAI,aAAa,gBAAgB,GAAG,EACzD,EAAE,YAAY,WAAW,CAC1B;CAED,MAAM,EAAE,QAAQ,cAAc,aAC3B,KAAK,OAAe,IAAI,aAAa,mBAAmB,GAAG,EAC5D,EAAE,YAAY,WAAW,CAC1B;CAED,MAAM,SAAS,eAAe,WAAW,SAAS,EAAE,CAAC;CACrD,MAAM,YAAY,eAAe,IAAI,IAAI,OAAO,MAAM,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC;CACxE,MAAM,aAAa,eAAe,OAAO,MAAM,SAAS,WAAW;CAEnE,SAAS,SAAS,UAA2B;AAC3C,SAAO,UAAU,MAAM,IAAI,SAAS;;CAGtC,eAAe,UAAU,QAA8C;AACrE,MAAI,OAAO,MAAM,UAAU,WAAY,QAAO;AAC9C,MAAI,UAAU,MAAM,IAAI,OAAO,GAAG,CAAE,QAAO;AAC3C,MAAI;AACF,SAAM,OAAO,OAAO,GAAG;AACvB,SAAM,SAAS;AACf,UAAO;UACD;AACN,UAAO;;;CAIX,eAAe,YAAY,UAAiC;AAC1D,MAAI;AACF,SAAM,UAAU,SAAS;AACzB,SAAM,SAAS;UACT;;CAKV,eAAe,UAAU,QAA8C;AACrE,MAAI,SAAS,OAAO,GAAG,EAAE;AACvB,SAAM,YAAY,OAAO,GAAG;AAC5B,UAAO;;AAET,SAAO,UAAU,OAAO;;CAG1B,SAAS,cAAc,QAGrB;AACA,SAAO;GACL,MAAM,OAAO;GACb,OAAO,OAAO,WAAW,EAAE;GAC5B;;CAGH,SAAS,mBACP,UACA,SACM;AAOR,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,WAAW;EACZ;;AAGH,MAAa,qBAAqB,OAAO,gBAAgB;;AAKzD,SAAgB,2BAA2B;CACzC,MAAM,WAAW,OAAO,mBAAmB;AAC3C,KAAI,CAAC,SACH,OAAM,IAAI,MACR,iHACD;AAEH,QAAO;;;;;;;;;;;;AClHT,MAAMA,oBAA4C;CAChD,QAAQ,UAAU;CAClB,QAAQ,UAAU;CAClB,MAAM,UAAU;CAChB,SAAS,UAAU;CACnB,MAAM,UAAU;CACjB;;;;AAKD,MAAM,gBAAgB;CAAC;CAAU;CAAS;CAAa;;;;AAKvD,SAAS,oBAAoB,UAA2B;AACtD,QACE,aAAa,UAAU,aACvB,aAAa,UAAU,iBACvB,aAAa,UAAU;;;;;AAO3B,SAAS,oBAAoB,UAA2B;AACtD,QAAO,aAAa,UAAU,YAAY,aAAa,UAAU;;;;;;;;;;;;;;;;;;;AA6CnE,SAAgB,kCACd,QACA,UACqB;CACrB,MAAMC,SAA8B,EAAE;CACtC,MAAM,2BAAW,IAAI,KAAyC;AAG9D,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;EAEjD,MAAM,eAAe,IAAI,MAAM,oBAAoB;EACnD,MAAM,cAAc,IAAI,MAAM,gCAAgC;AAE9D,MAAI,CAAC,gBAAgB,CAAC,YAAa;EAEnC,MAAM,YAAY,eAAe,aAAa,KAAK,cAAc,YAAY,KAAK;EAClF,MAAM,oBAAoB,cAAc,YAAY,KAAK;EACzD,MAAM,cAAc,MAAM,QAAQ,MAAM,GAAG,MAAM,KAAK;AAEtD,MAAI,CAAC,UAAW;EAEhB,MAAM,YAAY,SAAS;AAC3B,MAAI,CAAC,UAAW;EAEhB,MAAM,YAAY,UAAU;EAC5B,MAAM,YAAY,kBAAkB,cAAc,UAAU;EAG5D,IAAIC;AACJ,MAAI,kBACF,YAAW;MAEX,YAAW;AAGb,MAAI,CAAC,SAAS,IAAI,UAAU,CAC1B,UAAS,IAAI,WAAW,EAAE,UAAU,CAAC;EAGvC,MAAM,SAAS,SAAS,IAAI,UAAU;AACtC,SAAO,WAAW;AAGlB,MAAI,oBAAoB,SAAS,EAAE,YAGxB,oBAAoB,SAAS,EAAE;AAExC,OAAI,CAAC,eAAe,YAAY,MAAM,KAAK,IAAI;AAC7C,aAAS,OAAO,UAAU;AAC1B;;AAGF,OAAI;IACF,MAAM,SAAS,KAAK,MAAM,YAAY;AACtC,QAAI,MAAM,QAAQ,OAAO,IAAI,OAAO,SAAS,EAE3C,KAAI,cAAc,SAAS,UAAU,CACnC,QAAO,SAAS,OAAO,KAAK,MAAM,OAAO,EAAE,CAAC;QAE5C,QAAO,SAAS;SAEb;AACL,cAAS,OAAO,UAAU;AAC1B;;YAEK,GAAG;IAEV,MAAM,SAAS,YACZ,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,QAAQ,MAAM,EAAE,SAAS,EAAE;AAC9B,QAAI,OAAO,WAAW,GAAG;AACvB,cAAS,OAAO,UAAU;AAC1B;;AAGF,QAAI,aAAa,UAAU,WAAW,OAAO,WAAW,EACtD,KAAI,cAAc,SAAS,UAAU,CACnC,QAAO,SAAS,CAAC,OAAO,OAAO,GAAI,EAAE,OAAO,OAAO,GAAI,CAAC;aAC/C,cAAc,OACvB,QAAO,SAAS,CAAC,OAAO,IAAK,OAAO,GAAI;QAExC,QAAO,SAAS;aAET,aAAa,UAAU,SAAS;AACzC,cAAS,OAAO,UAAU;AAC1B;eAEI,cAAc,SAAS,UAAU,CACnC,QAAO,SAAS,OAAO,KAAK,MAAM,OAAO,EAAE,CAAC;QAE5C,QAAO,SAAS;;cAQnB,aAAa,UAAU,aAAa,aAAa,UAAU,kBAC5D,YAGA,KAAI,cAAc,SAAS,UAAU,CACnC,QAAO,SAAS,CAAC,OAAO,YAAY,CAAC;MAErC,QAAO,SAAS,CAAC,YAAY;WAEtB,aAAa;AAEtB,OAAI,cAAc,SAAS,UAAU,CACnC,QAAO,QAAQ,OAAO,YAAY;YACzB,cAAc,UACvB,QAAO,QAAQ,gBAAgB,UAAU,gBAAgB;OAEzD,QAAO,QAAQ;AAIjB,OAAI,cAAc,YAAY,aAAa,UAAU,SACnD,QAAO,gBAAgB;;;AAO/B,MAAK,MAAM,CAAC,WAAW,WAAW,SAAS,SAAS,CAClD,KAAI,OAAO,SACT,QAAO,aAAa;AAIxB,QAAO;;;;;;;;;;;;;;;;;;;;;AAsBT,SAAgB,8BACd,QACA,UACwB;CACxB,MAAMC,SAAiC,EAAE;AAEzC,MAAK,MAAM,CAAC,WAAW,WAAW,OAAO,QAAQ,OAAO,EAAE;AAExD,MAAI,CADc,SAAS,WACX;EAEhB,MAAM,WAAW,OAAO;AAExB,MAAI,oBAAoB,SAAS,CAE/B,QAAO,OAAO,UAAU,IAAI,SAAS,MAAM;WAClC,oBAAoB,SAAS,EAEtC;OAAI,OAAO,UAAU,MAAM,QAAQ,OAAO,OAAO,CAC/C,QAAO,OAAO,UAAU,IAAI,SAAS,MAAM,KAAK,UAAU,OAAO,OAAO;QAI1E,QAAO,OAAO,UAAU,IAAI,SAAS,MAAM,OAAO,OAAO,MAAM;;AAInE,QAAO;;;;;;;;;;;AAeT,SAAgB,wBAAwB,OAAmD;CACzF,MAAMC,UAA6B,EAAE;AAErC,QAAO,KAAK,MAAM,CAAC,SAAS,QAAQ;AAClC,MAAI,IAAI,WAAW,OAAO,EAAE;GAC1B,MAAM,QAAQ,MAAM;AACpB,OAAI,UAAU,QAAQ,UAAU,OAC9B,KAAI,MAAM,QAAQ,MAAM,EAAE;IACxB,MAAM,WAAW,MAAM,QAAQ,MAAmB,MAAM,QAAQ,MAAM,OAAU;AAChF,QAAI,SAAS,SAAS,EACpB,SAAQ,OAAO;SAGjB,SAAQ,OAAO,OAAO,MAAM;;GAIlC;AAEF,QAAO;;;;;;;AAQT,SAAgB,sBACd,cACA,SACmC;CACnC,MAAMC,OAA0C,EAAE;AAClD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,CACrD,KAAI,CAAC,IAAI,WAAW,OAAO,IAAI,UAAU,QAAQ,UAAU,OACzD,MAAK,OAAO,MAAM,QAAQ,MAAM,GAC3B,MAAM,QAAQ,MAAmB,KAAK,KAAK,GAC5C,OAAO,MAAM;AAGrB,QAAO;EAAE,GAAG;EAAM,GAAG;EAAS;;;;;;;;;;ACvThC,MAAMC,qBAAmB;AACzB,MAAM,2BAA2B;AAEjC,SAASC,iBAAe,SAAyB;AAC/C,QAAO,GAAGD,qBAAmB;;AAG/B,SAAS,sBAAsB,SAAyB;AACtD,QAAO,GAAG,2BAA2B;;AAGvC,SAAgB,yBACd,SAC0C;AAC1C,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,sBAAsB,QAAQ,CAAC;AACnE,MAAI,CAAC,OAAQ,QAAO;EACpB,MAAM,SAAS,KAAK,MAAM,OAAO;AACjC,SAAO,OAAO,WAAW,YAAY,WAAW,OAAO,SAAS;SAC1D;AACN,SAAO;;;AAIX,SAAgB,yBACd,SACA,SACM;AACN,KAAI;AACF,MAAI,WAAW,OAAO,KAAK,QAAQ,CAAC,SAAS,EAC3C,cAAa,QAAQ,sBAAsB,QAAQ,EAAE,KAAK,UAAU,QAAQ,CAAC;MAE7E,cAAa,WAAW,sBAAsB,QAAQ,CAAC;SAEnD;;;;;;AASV,SAAgB,0BACd,SACA,cAC0C;CAC1C,MAAM,UAAU,wBAAwB,aAAa;AACrD,KAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EAAG,QAAO;AAG5C,KAAI,CADe,aAAa,QAAQC,iBAAe,QAAQ,CAAC,CAC/C,QAAO;CAExB,MAAM,kBAAkB,yBAAyB,QAAQ;AACzD,KAAI,CAAC,mBAAmB,OAAO,KAAK,gBAAgB,CAAC,WAAW,EAAG,QAAO;AAE1E,QAAO,sBAAsB,cAAc,gBAAgB;;;;;;AAO7D,SAAgB,0BACd,SACA,WACA;AACA,SAAQ,OAA2D;AACjE,MAAI,GAAG,SAAS,UAAW,QAAO;EAClC,MAAM,gBAAgB,0BAA0B,SAAS,GAAG,MAAM;AAClE,MAAI,CAAC,cAAe,QAAO;AAC3B,SAAO;GAAE,MAAM;GAAW,OAAO;GAAe;;;;;;AClEpD,MAAM,mBAAmB;AAezB,SAAS,eAAe,SAAyB;AAC/C,QAAO,GAAG,mBAAmB;;AAG/B,SAAS,oBAAoB,SAAgC;AAC3D,KAAI;AACF,SAAO,aAAa,QAAQ,eAAe,QAAQ,CAAC;SAC9C;AACN,SAAO;;;AAIX,SAAS,oBAAoB,SAAiB,UAA+B;AAC3E,KAAI;AACF,MAAI,SACF,cAAa,QAAQ,eAAe,QAAQ,EAAE,SAAS;MAEvD,cAAa,WAAW,eAAe,QAAQ,CAAC;SAE5C;;AAKV,SAAgB,gBACd,QACA;CACA,MAAM,EACJ,SACA,WACA,qBACA,qBACA,mBACE;CAEJ,MAAM,WAAW,iBAAiB;CAClC,MAAM,qBAAqB,IAAI,MAAM;CACrC,MAAM,sBAAsB,IAAmB,oBAAoB,QAAQ,CAAC;CAE5E,MAAM,EAAE,MAAM,SAAS,SAAS,gBAAgB,SAAS,mBAAmB,UAGzE,QAAQ,IAAI,aAAa,iBAAiB,QAAQ,EAAE;EACrD;EACA,WAAW,KAAK,GAAG;EACpB,CAAC;CAEF,MAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,aAKjD,KAAK,UAAU,IAAI,aAAa,kBAAkB,MAAM,EACzD,EAAE,YAAY,mBAAmB,CAClC;CAED,MAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,aAKjD,KAAK,UAAU,IAAI,aAAa,kBAAkB,MAAM,EACzD,EAAE,YAAY,mCAAmC,CAClD;CAED,MAAM,EAAE,QAAQ,cAAc,SAAS,aAAa,aACjD,KAAK,OAAO,IAAI,aAAa,kBAAkB,GAAG,EACnD,EAAE,YAAY,mBAAmB,CAClC;CAED,SAAS,YAAY,QAAkC;AACrD,sBAAoB,OAAO,QAAQ;AACnC,sBAAoB,SAAS,OAAO,GAAG;AACvC,2BAAyB,SAAS,OAAO,QAAQ;AACjD,sBAAoB,QAAQ,OAAO;;CAGrC,SAAS,cAAoB;AAC3B,sBAAoB,EAAE,CAAC;AACvB,sBAAoB,SAAS,KAAK;AAClC,2BAAyB,SAAS,KAAK;AACvC,sBAAoB,QAAQ;;CAG9B,SAAS,gBAAsB;AAC7B,sBAAoB,SAAS,KAAK;AAClC,2BAAyB,SAAS,KAAK;AACvC,sBAAoB,QAAQ;AAC5B,oBAAkB;;CAGpB,eAAe,mBAAmB,MAAkD;EAClF,MAAM,UAAU,qBAAqB;AACrC,MAAI,OAAO,KAAK,QAAQ,CAAC,WAAW,EAClC,QAAO;AAET,MAAI;GACF,MAAM,SAAS,MAAM,aAAa;IAChC;IACA;IACA,YAAY;IACZ;IACD,CAAC;AACF,OAAI,QAAQ;AACV,UAAM,gBAAgB;AACtB,wBAAoB,SAAS,OAAO,GAAG;AACvC,6BAAyB,SAAS,OAAO,QAAQ;AACjD,wBAAoB,QAAQ,OAAO;;AAErC,UAAO,UAAU;UACX;AACN,UAAO;;;CAIX,eAAe,oBAAoB,UAAkB,MAAmD;EACtG,MAAM,UAAU,qBAAqB;AACrC,MAAI;AAMF,UALe,MAAM,aAAa;IAChC,IAAI;IACJ,GAAI,SAAS,UAAa,EAAE,MAAM;IAClC;IACD,CAAC,IACe;UACX;AACN,UAAO;;;CAIX,eAAe,aAAa,UAAkB,MAAkD;AAC9F,MAAI;GACF,MAAM,SAAS,MAAM,aAAa;IAAE,IAAI;IAAU;IAAM,CAAC;AACzD,OAAI,OACF,OAAM,gBAAgB;AAExB,UAAO,UAAU;UACX;AACN,UAAO;;;CAIX,eAAe,aAAa,UAAoC;AAC9D,MAAI;AACF,SAAM,aAAa,SAAS;AAC5B,SAAM,gBAAgB;AACtB,UAAO;UACD;AACN,UAAO;;;AAMX,iBAAgB;EACd,MAAM,UAAU,qBAAqB;AACrC,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,GAAG;AACnC,sBAAmB,QAAQ;AAC3B;;EAEF,MAAM,aAAa,oBAAoB,QAAQ;AAC/C,MAAI,CAAC,YAAY;AACf,sBAAmB,QAAQ;AAC3B;;EAEF,MAAM,UAAU,YACR,QAAQ,QACb,SAAS;AACR,OAAI,CAAC,QAAQ,mBAAmB,MAAO;GACvC,MAAM,SAAS,KAAK,MAAM,MAAM,EAAE,OAAO,WAAW;AACpD,OAAI,OACF,aAAY,OAAO;AAErB,sBAAmB,QAAQ;AAC3B,YAAS;KAEX,EAAE,WAAW,MAAM,CACpB;GACD;CAEF,MAAM,eAAe,eAAe;EAClC,MAAM,KAAK,oBAAoB;AAC/B,MAAI,CAAC,GAAI,QAAO;AAChB,UAAQ,QAAQ,SAAS,EAAE,EAAE,MAAM,MAAM,EAAE,OAAO,GAAG,IAAI;GACzD;AAEF,QAAO;EACL,SAAS,eAAe,QAAQ,SAAS,EAAE,CAAC;EAC5C;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;AChOH,MAAaC,oBAAmD,CAC9D;CACE,MAAM;CACN,MAAM;CACN,iBAAiB,OAAO;CACxB,aAAa,CAAC,kBAAkB;CAChC,MAAM;EACJ,OAAO;EACP,aAAa;EACb,UAAU;GACR,SAAS;GACT,YAAY;IAAC;IAAY;IAAQ;IAAS;IAAc;GACzD;EACF;CACF,CACF;;;;;;;;;;;;;;;;;;;;ECgBD,MAAM,QAAQ;EAKd,MAAM,OAAO;EAKb,MAAM,OAAO,IAAI,GAAG;EACpB,MAAM,QAAQ,IAAI,GAAG;EAErB,SAAS,QAAQ;AACf,QAAK,QAAQ;;EAGf,SAAS,eAAe;GACtB,MAAM,UAAU,KAAK,MAAM,MAAM;AACjC,OAAI,CAAC,SAAS;AACZ,UAAM,QAAQ;AACd;;AAEF,OAAI,QAAQ,SAAS,KAAK;AACxB,UAAM,QAAQ;AACd;;AAEF,SAAM,QAAQ;AACd,QAAK,QAAQ,QAAQ;;AAGvB,cAAY,MAAM,SAAS,SAAS;AAClC,OAAI,MAAM;AACR,SAAK,QAAQ;AACb,UAAM,QAAQ;;IAEhB;;uBArEA,YA0BY,mBAAA;IA1BA,WAAS,QAAA;IAAQ,OAAM;IAAsB,SAAO;;2BAyBvD,CAxBP,mBAwBO,QAAA;KAxBA,UAAM,cAAU,cAAY,CAAA,UAAA,CAAA;KAAE,OAAM;QACzC,mBAcM,OAdN,cAcM;+BAbJ,mBAEQ,SAAA,EAFD,OAAM,SAAO,EAAA,CAClB,mBAA2C,QAAA,EAArC,OAAM,cAAY,EAAC,cAAW,CAAA;oBAEtC,mBAME,SAAA;mEALS,KAAI,QAAA;MACb,MAAK;MACL,aAAY;MACZ,OAAM;MACN,WAAU;kCAJD,KAAA,MAAI,CAAA,CAAA;KAMF,MAAA,SAAA,WAAA,EAAb,mBAEQ,SAFR,cAEQ,CADN,mBAA0D,QAA1D,cAA0D,gBAAf,MAAA,MAAK,EAAA,EAAA,CAAA,CAAA,IAAA,mBAAA,QAAA,KAAA;QAGpD,mBAOM,OAPN,cAOM,CANJ,mBAES,UAAA;KAFD,MAAK;KAAS,OAAM;KAAiB,SAAO;OAAO,WAE3D,EACA,mBAES,UAAA;KAFD,MAAK;KAAS,OAAM;KAAmB,UAAU,QAAA,UAAM,CAAK,KAAA,MAAK,MAAI;uBACxE,QAAA,SAAM,cAAA,OAAA,EAAA,GAAA,aAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECmEnB,MAAM,QAAQ;EASd,MAAM,OAAO;EAKb,MAAM,YAAY,IAAmB,KAAK;EAC1C,MAAM,cAAc,IAAI,GAAG;EAC3B,MAAM,iBAAiB,IAA6B,KAAK;EAEzD,SAAS,QAAQ;AACf,QAAK,QAAQ;;EAGf,SAAS,YAAY,QAA4B;AAC/C,aAAU,QAAQ,OAAO;AACzB,eAAY,QAAQ,OAAO;AAC3B,kBAAe,eAAe,OAAO,OAAO,CAAC;;EAG/C,SAAS,eAAe;AACtB,aAAU,QAAQ;AAClB,eAAY,QAAQ;;EAGtB,eAAe,WAAW,UAAkB;GAC1C,MAAM,OAAO,YAAY,MAAM,MAAM;AACrC,OAAI,CAAC,KAAM;AAEX,OADe,MAAM,MAAM,aAAa,UAAU,KAAK,CAErD,eAAc;;EAIlB,SAAS,aAAa,QAA4B;AAChD,QAAK,UAAU,OAAO;;AAGxB,cAAY,MAAM,SAAS,SAAS;AAClC,OAAI,CAAC,KACH,eAAc;IAEhB;;uBA3IA,YAiFY,mBAAA;IAjFA,WAAS,QAAA;IAAQ,OAAM;IAAyB,SAAO;;2BAgF3D,CA/EN,mBA+EM,OA/EN,cA+EM,CA9EK,QAAA,QAAQ,WAAM,KAAA,CAAW,QAAA,WAAA,WAAA,EAAlC,mBAEI,KAFJ,cAAgF,8FAEhF,IACgB,QAAA,WAAA,WAAA,EAAhB,mBAEM,OAFN,cAEM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CADJ,mBAAmD,QAAA,EAA7C,OAAM,sCAAoC,EAAA,MAAA,GAAA,CAAA,EAAA,CAAA,KAAA,WAAA,EAElD,mBAkEK,MAlEL,cAkEK,EAAA,UAAA,KAAA,EAjEH,mBAgEK,UAAA,MAAA,WA/Dc,QAAA,UAAV,WAAM;yBADf,mBAgEK,MAAA;MA9DF,KAAK,OAAO;MACb,OAAM;SAEU,UAAA,UAAc,OAAO,MAAA,WAAA,EAArC,mBA2BW,UAAA,EAAA,KAAA,GAAA,EAAA;qBA1BT,mBASE,SAAA;;gBARI;OAAJ,KAAI;oEACK,YAAW,QAAA;OACpB,MAAK;OACL,OAAM;OACN,WAAU;OACV,aAAY;OACX,WAAO,CAAA,UAAA,WAAQ,WAAW,OAAO,GAAE,EAAA,CAAA,QAAA,CAAA,EAAA,SACnB,cAAY,CAAA,SAAA,CAAA,CAAA;gDANpB,YAAA,MAAW,CAAA,CAAA;MAQtB,mBAOS,UAAA;OANP,MAAK;OACL,OAAM;OACL,UAAU,QAAA,YAAQ,CAAK,YAAA,MAAY,MAAI;OACvC,UAAK,WAAE,WAAW,OAAO,GAAE;yBAEzB,QAAA,WAAQ,QAAA,OAAA,EAAA,GAAA,aAAA;MAEb,mBAOS,UAAA;OANP,MAAK;OACL,OAAM;OACL,UAAU,QAAA;OACV,SAAO;SACT,YAED,GAAA,aAAA;6BAEF,mBA8BW,UAAA,EAAA,KAAA,GAAA,EAAA,CA7BT,mBAKO,QALP,cAKO,CAAA,gCAJF,OAAO,KAAI,GAAG,KACjB,EAAA,EAAA,mBAEO,QAFP,cAA4D,OACzD,gBAAG,OAAO,KAAK,OAAO,WAAO,EAAA,CAAA,CAAQ,OAAM,GAAG,MACjD,EAAA,CAAA,CAAA,EAEF,mBAsBM,OAtBN,eAsBM,CArBJ,mBASS,UAAA;MARP,MAAK;MACL,OAAM;MACN,OAAM;MACL,UAAK,WAAE,YAAY,OAAM;uCAE1B,mBAEM,OAAA;MAFD,OAAM;MAAU,MAAK;MAAO,QAAO;MAAe,SAAQ;SAC7D,mBAA6K,QAAA;MAAvK,kBAAe;MAAQ,mBAAgB;MAAQ,gBAAa;MAAI,GAAE;qCAG5E,mBAUS,UAAA;MATP,MAAK;MACL,OAAM;MACN,OAAM;MACL,UAAU,QAAA;MACV,UAAK,WAAE,aAAa,OAAM;uCAE3B,mBAEM,OAAA;MAFD,OAAM;MAAU,MAAK;MAAO,QAAO;MAAe,SAAQ;SAC7D,mBAAyM,QAAA;MAAnM,kBAAe;MAAQ,mBAAgB;MAAQ,gBAAa;MAAI,GAAE;;kBAOpF,mBAIM,OAAA,EAJD,OAAM,yBAAuB,EAAA,CAChC,mBAES,UAAA;KAFD,MAAK;KAAS,OAAM;KAAiB,SAAO;OAAO,UAE3D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECoGR,MAAM,QAAQ;EAkBd,MAAM,YAAY,eAAe,MAAM,aAAa,EAAE;EAEtD,SAAS,gBAAgB,QAA4B;AACnD,SAAM,UAAU,OAAO;;EAGzB,MAAM,OAAO;EAMb,MAAM,cAAc,eACZ,MAAM,QAAQ,SAAS,wBAC9B;EAED,MAAM,YAAY,IAAmB,KAAK;EAC1C,MAAM,cAAc,IAAI,GAAG;EAC3B,MAAM,iBAAiB,IAA6B,KAAK;EAEzD,MAAM,eAAe,IAAI,MAAM;EAC/B,MAAM,WAAW,IAAI,GAAG;EACxB,MAAM,eAAe,IAA6B,KAAK;EAEvD,SAAS,QAAQ;AACf,QAAK,QAAQ;;EAGf,SAAS,cAAc,QAA4B;AACjD,SAAM,YAAY,OAAO;AACzB,UAAO;;EAGT,SAAS,YAAY,QAA4B;AAC/C,aAAU,QAAQ,OAAO;AACzB,eAAY,QAAQ,OAAO;AAC3B,kBAAe,eAAe,OAAO,OAAO,CAAC;;EAG/C,SAAS,eAAe;AACtB,aAAU,QAAQ;AAClB,eAAY,QAAQ;;EAGtB,eAAe,WAAW,UAAkB;GAC1C,MAAM,OAAO,YAAY,MAAM,MAAM;AACrC,OAAI,CAAC,KAAM;GACX,MAAM,SAAS,MAAM,MAAM,aAAa,UAAU,KAAK;AACvD,OAAI,QAAQ;AACV,SAAK,UAAU,OAAO;AACtB,kBAAc;;;EAIlB,SAAS,aAAa,QAA4B;AAChD,QAAK,UAAU,OAAO;;EAGxB,SAAS,YAAY;AACnB,OAAI,MAAM,cAAc,YAAY,OAAO;AACzC,iBAAa,QAAQ;AACrB,aAAS,QAAQ;AACjB,mBAAe,aAAa,OAAO,OAAO,CAAC;;;EAI/C,SAAS,aAAa;AACpB,gBAAa,QAAQ;AACrB,YAAS,QAAQ;;EAGnB,eAAe,aAAa;GAC1B,MAAM,OAAO,SAAS,MAAM,MAAM;AAClC,OAAI,CAAC,KAAM;AAEX,OADe,MAAM,MAAM,mBAAmB,KAAK,EACvC;AACV,gBAAY;AACZ,WAAO;;;AAIX,cAAY,MAAM,SAAS,SAAS;AAClC,OAAI,CAAC,MAAM;AACT,kBAAc;AACd,gBAAY;;IAEd;;uBA1RA,YAuKY,mBAAA;IAvKA,WAAS,QAAA;IAAQ,OAAM;IAAkB,SAAO;;2BAsKpD,CArKN,mBAqKM,OArKN,cAqKM;KApKJ,mBAAA,oDAAwD;KAC7C,QAAA,QAAQ,SAAM,KAAA,WAAA,EAAzB,mBA6FM,OAAA,cAAA,CAAA,OAAA,OAAA,OAAA,KA5FJ,mBAEI,KAAA,EAFD,OAAM,yEAAuE,EAAC,kBAEjF,GAAA,GACA,mBAwFK,MAxFL,cAwFK,EAAA,UAAA,KAAA,EAvFH,mBAsFK,UAAA,MAAA,WArFc,QAAA,UAAV,WAAM;0BADf,mBAsFK,MAAA;OApFF,KAAK,OAAO;OACb,OAAM;UAEU,UAAA,UAAc,OAAO,MAAA,WAAA,EAArC,mBA2BW,UAAA,EAAA,KAAA,GAAA,EAAA;sBA1BT,mBASE,SAAA;;iBARI;QAAJ,KAAI;qEACK,YAAW,QAAA;QACpB,MAAK;QACL,OAAM;QACN,WAAU;QACV,aAAY;QACX,WAAO,CAAA,UAAA,WAAQ,WAAW,OAAO,GAAE,EAAA,CAAA,QAAA,CAAA,EAAA,SACnB,cAAY,CAAA,SAAA,CAAA,CAAA;iDANpB,YAAA,MAAW,CAAA,CAAA;OAQtB,mBAOS,UAAA;QANP,MAAK;QACL,OAAM;QACL,UAAU,QAAA,YAAQ,CAAK,YAAA,MAAY,MAAI;QACvC,UAAK,WAAE,WAAW,OAAO,GAAE;0BAEzB,QAAA,WAAQ,QAAA,OAAA,EAAA,GAAA,WAAA;OAEb,mBAOS,UAAA;QANP,MAAK;QACL,OAAM;QACL,UAAU,QAAA;QACV,SAAO;UACT,YAED,GAAA,WAAA;8BAEF,mBAoDW,UAAA,EAAA,KAAA,GAAA,EAAA,CAnDT,mBAUS,UAAA;OATP,MAAK;OACL,OAAK,eAAA,CAAC,iGAA+F,EAAA,iBAC1E,OAAO,OAAO,QAAA,cAAc,IAAE,CAAA,CAAA;OACxD,UAAK,WAAE,cAAc,OAAM;0CAEzB,OAAO,KAAI,GAAG,KACjB,EAAA,EAAA,mBAEO,QAFP,YAA4D,OACzD,gBAAG,OAAO,KAAK,OAAO,WAAO,EAAA,CAAA,CAAQ,OAAM,GAAG,MACjD,EAAA,CAAA,EAAA,IAAA,WAAA,EAEF,mBAuCM,OAvCN,YAuCM;OAtCJ,mBAgBS,UAAA;QAfP,MAAK;QACL,OAAM;QACL,OAAO,QAAA,SAAS,OAAO,GAAE,GAAA,yBAA8B,QAAA,aAAU,sCAAA,WAAoD,UAAA,MAAS;QAC9H,UAAQ,CAAG,QAAA,cAAU,CAAK,QAAA,SAAS,OAAO,GAAE;QAC5C,SAAK,eAAA,WAAO,gBAAgB,OAAM,EAAA,CAAA,OAAA,CAAA;yBAEnC,mBAQM,OAAA;QAPJ,OAAK,eAAA,CAAC,WAAS,EAAA,gBACW,QAAA,SAAS,OAAO,GAAE,EAAA,CAAA,CAAA;QAC3C,MAAM,QAAA,SAAS,OAAO,GAAE,GAAA,iBAAA;QACzB,QAAO;QACP,SAAQ;yCAER,mBAAob,QAAA;QAA9a,kBAAe;QAAQ,mBAAgB;QAAQ,gBAAa;QAAI,GAAE;;OAG5E,mBASS,UAAA;QARP,MAAK;QACL,OAAM;QACN,OAAM;QACL,SAAK,eAAA,WAAO,YAAY,OAAM,EAAA,CAAA,OAAA,CAAA;yCAE/B,mBAEM,OAAA;QAFD,OAAM;QAAU,MAAK;QAAO,QAAO;QAAe,SAAQ;WAC7D,mBAA6K,QAAA;QAAvK,kBAAe;QAAQ,mBAAgB;QAAQ,gBAAa;QAAI,GAAE;;OAG5E,mBAUS,UAAA;QATP,MAAK;QACL,OAAM;QACN,OAAM;QACL,UAAU,QAAA;QACV,SAAK,eAAA,WAAO,aAAa,OAAM,EAAA,CAAA,OAAA,CAAA;yCAEhC,mBAEM,OAAA;QAFD,OAAM;QAAU,MAAK;QAAO,QAAO;QAAe,SAAQ;WAC7D,mBAAyM,QAAA;QAAnM,kBAAe;QAAQ,mBAAgB;QAAQ,gBAAa;QAAI,GAAE;;;uBAWxE,QAAA,WAAA,WAAA,EADd,mBAKI,UAAA,EAAA,KAAA,GAAA,EAAA,CANJ,mBAAA,gBAAoB,EAAA,OAAA,OAAA,OAAA,KACpB,mBAKI,KAAA,EAHF,OAAM,gCAA8B,EACrC,mDAED,GAAA,EAAA;KAEW,QAAA,WAAA,WAAA,EAAX,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CADJ,mBAAmD,QAAA,EAA7C,OAAM,sCAAoC,EAAA,MAAA,GAAA,CAAA,EAAA,CAAA,IAAA,mBAAA,QAAA,KAAA;iCAGlD,mBAA4B,OAAA,EAAvB,OAAM,gBAAc,EAAA,MAAA,GAAA;KAEzB,mBAAA,kDAAsD;KAC3C,aAAA,SAAA,WAAA,EAAX,mBAgCM,OAhCN,aAgCM,CAAA,OAAA,OAAA,OAAA,KA/BJ,mBAEQ,SAAA,EAFD,OAAM,cAAY,EAAA,CACvB,mBAA2C,QAAA,EAArC,OAAM,cAAY,EAAC,cAAW,CAAA,QAEtC,mBA2BM,OA3BN,aA2BM;qBA1BJ,mBASE,SAAA;gBARI;OAAJ,KAAI;oEACK,SAAQ,QAAA;OACjB,MAAK;OACL,aAAY;OACZ,OAAM;OACN,WAAU;OACT,WAAO,CAAA,SAAQ,YAAU,CAAA,QAAA,CAAA,EAAA,SACT,YAAU,CAAA,SAAA,CAAA,CAAA;mCANlB,SAAA,MAAQ,CAAA,CAAA;MAQnB,mBAOS,UAAA;OANP,MAAK;OACL,OAAM;OACL,UAAU,QAAA,YAAQ,CAAK,SAAA,MAAS,MAAI;OACpC,SAAO;yBAEL,QAAA,WAAQ,cAAA,OAAA,EAAA,GAAA,YAAA;MAEb,mBAOS,UAAA;OANP,MAAK;OACL,OAAM;OACL,UAAU,QAAA;OACV,SAAO;SACT,YAED,GAAA,YAAA;2BAGJ,mBAaS,UAAA;;MAXP,MAAK;MACL,OAAM;MACL,UAAQ,CAAG,QAAA,cAAc,QAAA,YAAQ,CAAK,YAAA;MACtC,OAAK,CAAG,YAAA,QAAW,WAAc,MAAA,wBAAuB,CAAA,uDAAwD;MAChH,SAAO;;gCAER,mBAEM,OAAA;OAFD,OAAM;OAAmB,MAAK;OAAO,QAAO;OAAe,SAAQ;UACtE,mBAA6G,QAAA;OAAvG,kBAAe;OAAQ,mBAAgB;OAAQ,gBAAa;OAAI,GAAE;;kDACpE,0BAEN,GAAA;OAAa,YAAA,SAAA,WAAA,EAAb,mBAAyG,QAAzG,aAA+D,UAAK,gBAAG,MAAA,wBAAuB,CAAA,GAAG,KAAC,EAAA,IAAA,mBAAA,QAAA,KAAA;;KAGpG,mBAIM,OAAA,EAJD,OAAM,yBAAuB,EAAA,CAChC,mBAES,UAAA;MAFD,MAAK;MAAS,OAAM;MAAiB,SAAO;QAAO,UAE3D,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC3ER,MAAM,gBAAgB,0BAA0B;EAEhD,MAAM,QAAQ;EAed,MAAM,mBAAmB,IAAI,MAAM;EACnC,MAAM,oBAAoB,IAAI,MAAM;EACpC,MAAM,iBAAiB,IAAyC,KAAK;EAErE,SAAS,oBAAoB;AAC3B,SAAM,aAAa;;EAGrB,SAAS,aAAa,QAAsC;AAC1D,kBAAe,QAAQ;AACvB,qBAAkB,QAAQ;;EAG5B,eAAe,gBAAgB;AAC7B,OAAI,CAAC,eAAe,MAAO;AAC3B,iBAAc,YAAY,eAAe,MAAM,GAAG;AAClD,SAAM,MAAM,aAAa,eAAe,MAAM,GAAG;AACjD,kBAAe,QAAQ;AACvB,qBAAkB,QAAQ;;EAG5B,eAAe,aAAa,QAAsC;AAChE,iBAAc,mBAAmB,OAAO,IAAI,EAAE,MAAM,OAAO,MAAM,CAAC;AAClE,SAAM,cAAc,iBAAiB;;;uBAjIrC,mBA+EM,OA/EN,YA+EM;IA9EJ,mBAAA,uEAA2E;IAEnE,MAAM,gBAAA,WAAA,EADd,mBAeM,OAfN,YAeM,CAXJ,mBAAyF,QAAzF,YAAyF,gBAAjC,MAAM,aAAa,KAAI,EAAA,EAAA,EAC/E,mBASS,UAAA;KARP,MAAK;KACL,OAAM;KACN,cAAW;KACV,SAAO;sCAER,mBAEM,OAAA;KAFD,OAAM;KAAU,MAAK;KAAO,QAAO;KAAe,SAAQ;QAC7D,mBAAiG,QAAA;KAA3F,kBAAe;KAAQ,mBAAgB;KAAQ,gBAAa;KAAI,GAAE;;IAK9E,mBAAA,gDAAoD;IACpD,mBAgBS,UAAA;KAfP,MAAK;KACL,OAAM;KACL,UAAU,MAAM;KAChB,OAAO,MAAM,QAAQ,SAAM,mCAAA;KAC3B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,iBAAA,QAAgB;sCAExB,mBAOM,OAAA;KAPD,OAAM;KAAU,MAAK;KAAO,QAAO;KAAe,SAAQ;QAC7D,mBAKE,QAAA;KAJA,kBAAe;KACf,mBAAgB;KAChB,gBAAa;KACb,GAAE;8BAEA,aAER,GAAA,CAAA,EAAA,EAAA,GAAA,WAAA;IAEA,mBAAA,8BAAkC;IAClC,YAiBgB,uBAAA;iBAhBL,kBAAA;kEAAA,kBAAiB,QAAA;KAC1B,OAAM;KACN,gBAAa;KACb,eAAY;KACZ,mBAAgB;KAChB,wBAAqB;KACpB,iBAAe,MAAM;KACrB,WAAS;KACT,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,eAAA,QAAc;;KAEZ,SAAO,cAIZ,CAHJ,mBAGI,KAAA,MAHD,wCACgC,gBAAG,eAAA,OAAgB,KAAI,GAAG,+BAE7D,EAAA,CAAA,CAAA;;;IAIJ,mBAAA,sDAA0D;IAC1D,YAmBE,sBAAA;KAlBC,WAAS,iBAAA;KACT,SAAS,MAAM;KACf,SAAS,MAAM;KACf,UAAU,MAAM;KAChB,UAAU,MAAM;KAChB,UAAU,MAAM;KAChB,eAAa,MAAM;KACnB,iBAAe,MAAM;KACrB,gBAAc,MAAM;KACpB,wBAAsB,MAAM;KAC5B,iBAAe,MAAM;KACrB,aAAW,MAAA,cAAa,CAAC;KACzB,cAAY,MAAA,cAAa,CAAC;KAC1B,gBAAc,MAAA,cAAa,CAAC,WAAW;KACvC,cAAY,MAAA,cAAa,CAAC;KAC1B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,iBAAA,QAAgB;KACvB,UAAQ;KACR,UAAQ"}
|
|
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-
|
|
2
|
-
import { i as setRefreshTokenHandler, r as getRefreshTokenHandler } from "./EnhancedRefreshTokenHandler-
|
|
3
|
-
import { t as useMutation } from "./useMutation-
|
|
4
|
-
import { t as useQuery } from "./useQuery-
|
|
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-
|
|
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-
|
|
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-
|
|
16
|
-
import { t as staffSupportPaths } from "./staffSupportTicketRoutes-
|
|
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-
|
|
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-
|
|
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, [
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 {
|
|
4848
|
-
//# sourceMappingURL=src-
|
|
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
|