@8wave/ai-elements 0.115.0-beta.52 → 0.115.0-beta.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/_chunks/Agent-Bz23Ejuh.js +705 -0
  2. package/dist/_chunks/Agent-Bz23Ejuh.js.map +1 -0
  3. package/dist/_chunks/{PkChatbotFilePreview-DcqwX9nI.js → PkChatbotFilePreview-CyaNjBrA.js} +2 -2
  4. package/dist/_chunks/{PkChatbotFilePreview-DcqwX9nI.js.map → PkChatbotFilePreview-CyaNjBrA.js.map} +1 -1
  5. package/dist/_chunks/{PkHeldImage-BtaPh0Jr.js → PkHeldImage-CtqqMvpW.js} +2 -2
  6. package/dist/_chunks/{PkHeldImage-BtaPh0Jr.js.map → PkHeldImage-CtqqMvpW.js.map} +1 -1
  7. package/dist/_chunks/{PkLazyImg-Cx2e4KmY.js → PkLazyImg-Ci06XyhW.js} +2 -2
  8. package/dist/_chunks/{PkLazyImg-Cx2e4KmY.js.map → PkLazyImg-Ci06XyhW.js.map} +1 -1
  9. package/dist/_chunks/{PkStreamingMarkdown-B_qmgO9_.js → PkStreamingMarkdown-DbSttKVa.js} +3 -3
  10. package/dist/_chunks/{PkStreamingMarkdown-B_qmgO9_.js.map → PkStreamingMarkdown-DbSttKVa.js.map} +1 -1
  11. package/dist/_chunks/{PkToolEditSpreadsheet-BSxYLcys.js → PkToolEditSpreadsheet-BrYSJlT4.js} +3 -3
  12. package/dist/_chunks/{PkToolEditSpreadsheet-BSxYLcys.js.map → PkToolEditSpreadsheet-BrYSJlT4.js.map} +1 -1
  13. package/dist/_chunks/{PkToolRequestGeolocation-YW0ilIxN.js → PkToolRequestGeolocation-D4rIR3LN.js} +3 -3
  14. package/dist/_chunks/{PkToolRequestGeolocation-YW0ilIxN.js.map → PkToolRequestGeolocation-D4rIR3LN.js.map} +1 -1
  15. package/dist/_chunks/{PkToolRequestOAuthConnection-Cx4aFL5g.js → PkToolRequestOAuthConnection-epwcNb5F.js} +3 -3
  16. package/dist/_chunks/{PkToolRequestOAuthConnection-Cx4aFL5g.js.map → PkToolRequestOAuthConnection-epwcNb5F.js.map} +1 -1
  17. package/dist/_chunks/{PkToolShowArtifact-Bgj02cPe.js → PkToolShowArtifact-BGUn1sMi.js} +3 -3
  18. package/dist/_chunks/{PkToolShowArtifact-Bgj02cPe.js.map → PkToolShowArtifact-BGUn1sMi.js.map} +1 -1
  19. package/dist/_chunks/{PkToolShowCalendarEvent-BLSTS6zf.js → PkToolShowCalendarEvent-DwxqgAUr.js} +3 -3
  20. package/dist/_chunks/PkToolShowCalendarEvent-DwxqgAUr.js.map +1 -0
  21. package/dist/_chunks/{PkToolShowComparison-DdT-C7iJ.js → PkToolShowComparison-hDhhVvwp.js} +2 -2
  22. package/dist/_chunks/{PkToolShowComparison-DdT-C7iJ.js.map → PkToolShowComparison-hDhhVvwp.js.map} +1 -1
  23. package/dist/_chunks/{PkToolShowContactForm-Die8UpNv.js → PkToolShowContactForm-ChaAOt5I.js} +4 -4
  24. package/dist/_chunks/{PkToolShowContactForm-Die8UpNv.js.map → PkToolShowContactForm-ChaAOt5I.js.map} +1 -1
  25. package/dist/_chunks/{PkToolShowDiagram-Ct-dFEmS.js → PkToolShowDiagram-CyNPq6j7.js} +2 -2
  26. package/dist/_chunks/{PkToolShowDiagram-Ct-dFEmS.js.map → PkToolShowDiagram-CyNPq6j7.js.map} +1 -1
  27. package/dist/_chunks/{PkToolShowEmail-BvH4Czk2.js → PkToolShowEmail-BM16pMjW.js} +2 -2
  28. package/dist/_chunks/{PkToolShowEmail-BvH4Czk2.js.map → PkToolShowEmail-BM16pMjW.js.map} +1 -1
  29. package/dist/_chunks/{PkToolShowForm-Dmq95u6b.js → PkToolShowForm-BpTuRgHg.js} +8 -8
  30. package/dist/_chunks/PkToolShowForm-BpTuRgHg.js.map +1 -0
  31. package/dist/_chunks/{PkToolShowImageGallery-CKuyTxih.js → PkToolShowImageGallery-CgjP34RE.js} +4 -4
  32. package/dist/_chunks/{PkToolShowImageGallery-CKuyTxih.js.map → PkToolShowImageGallery-CgjP34RE.js.map} +1 -1
  33. package/dist/_chunks/{PkToolShowLocation-DLYMzcrZ.js → PkToolShowLocation-rK5fcW4y.js} +2 -2
  34. package/dist/_chunks/{PkToolShowLocation-DLYMzcrZ.js.map → PkToolShowLocation-rK5fcW4y.js.map} +1 -1
  35. package/dist/_chunks/{PkToolShowMessage-BGcIhbEe.js → PkToolShowMessage-DgT-JkYg.js} +2 -2
  36. package/dist/_chunks/{PkToolShowMessage-BGcIhbEe.js.map → PkToolShowMessage-DgT-JkYg.js.map} +1 -1
  37. package/dist/_chunks/PkToolShowProductList-BIeg8NR-.js +72 -0
  38. package/dist/_chunks/PkToolShowProductList-BIeg8NR-.js.map +1 -0
  39. package/dist/_chunks/{PkToolShowQrCode-DDT92XTk.js → PkToolShowQrCode-C2hZDGqM.js} +2 -2
  40. package/dist/_chunks/{PkToolShowQrCode-DDT92XTk.js.map → PkToolShowQrCode-C2hZDGqM.js.map} +1 -1
  41. package/dist/_chunks/{PkToolShowSources-MJRFeqMA.js → PkToolShowSources-B9nZyCAn.js} +4 -4
  42. package/dist/_chunks/{PkToolShowSources-MJRFeqMA.js.map → PkToolShowSources-B9nZyCAn.js.map} +1 -1
  43. package/dist/_chunks/{PkToolShowSuggestedReply-DPVS3C74.js → PkToolShowSuggestedReply-D6g3UYqI.js} +3 -3
  44. package/dist/_chunks/{PkToolShowSuggestedReply-DPVS3C74.js.map → PkToolShowSuggestedReply-D6g3UYqI.js.map} +1 -1
  45. package/dist/_chunks/{PkToolShowVideo-DnvvRE7H.js → PkToolShowVideo-B6GG8PJm.js} +4 -4
  46. package/dist/_chunks/{PkToolShowVideo-DnvvRE7H.js.map → PkToolShowVideo-B6GG8PJm.js.map} +1 -1
  47. package/dist/_chunks/{PkToolShowWeather-DrxYD77R.js → PkToolShowWeather-C80WsCYi.js} +2 -2
  48. package/dist/_chunks/{PkToolShowWeather-DrxYD77R.js.map → PkToolShowWeather-C80WsCYi.js.map} +1 -1
  49. package/dist/_chunks/{PkToolShowWebPages-CYbiGa7e.js → PkToolShowWebPages-BkUh-IyZ.js} +11 -11
  50. package/dist/_chunks/PkToolShowWebPages-BkUh-IyZ.js.map +1 -0
  51. package/dist/_chunks/{VvCheckbox.es-VDzdPrIO.js → VvCheckbox.es-UTRUhwdC.js} +2 -2
  52. package/dist/_chunks/{VvCheckbox.es-VDzdPrIO.js.map → VvCheckbox.es-UTRUhwdC.js.map} +1 -1
  53. package/dist/_chunks/{VvCheckboxGroup.es-D3Q0u-Xo.js → VvCheckboxGroup.es-Cj7KLXHq.js} +2 -2
  54. package/dist/_chunks/{VvCheckboxGroup.es-D3Q0u-Xo.js.map → VvCheckboxGroup.es-Cj7KLXHq.js.map} +1 -1
  55. package/dist/_chunks/{VvCombobox.es-CcgeeuW6.js → VvCombobox.es-DptfdnAe.js} +2 -2
  56. package/dist/_chunks/{VvCombobox.es-CcgeeuW6.js.map → VvCombobox.es-DptfdnAe.js.map} +1 -1
  57. package/dist/_chunks/{VvInputText.es-C5Y-NpdS.js → VvInputText.es-DqLQDq9I.js} +2 -2
  58. package/dist/_chunks/{VvInputText.es-C5Y-NpdS.js.map → VvInputText.es-DqLQDq9I.js.map} +1 -1
  59. package/dist/_chunks/{VvRadio.es-CgueGQnO.js → VvRadio.es-D7Ws1in6.js} +2 -2
  60. package/dist/_chunks/{VvRadio.es-CgueGQnO.js.map → VvRadio.es-D7Ws1in6.js.map} +1 -1
  61. package/dist/_chunks/{VvRadioGroup.es-CoyUKzWp.js → VvRadioGroup.es-BDgpsR9Z.js} +2 -2
  62. package/dist/_chunks/{VvRadioGroup.es-CoyUKzWp.js.map → VvRadioGroup.es-BDgpsR9Z.js.map} +1 -1
  63. package/dist/_chunks/{VvSelect.es-DJWvclS9.js → VvSelect.es-DWbNpZKw.js} +2 -2
  64. package/dist/_chunks/{VvSelect.es-DJWvclS9.js.map → VvSelect.es-DWbNpZKw.js.map} +1 -1
  65. package/dist/_chunks/{VvTextarea.es-zXk1Uruf.js → VvTextarea.es-5UD9_C3G.js} +2 -2
  66. package/dist/_chunks/{VvTextarea.es-zXk1Uruf.js.map → VvTextarea.es-5UD9_C3G.js.map} +1 -1
  67. package/dist/_chunks/{chatImagePolicy-C5eH4Cpq.js → chatImagePolicy-Cnmsgd96.js} +2 -2
  68. package/dist/_chunks/{chatImagePolicy-C5eH4Cpq.js.map → chatImagePolicy-Cnmsgd96.js.map} +1 -1
  69. package/dist/_chunks/{index.es-_UjFDhTh.js → index.es-B9zAw2XU.js} +2 -2
  70. package/dist/_chunks/{index.es-_UjFDhTh.js.map → index.es-B9zAw2XU.js.map} +1 -1
  71. package/dist/_chunks/{index.es-BVC277zB.js → index.es-D9VqgSyV.js} +10 -10
  72. package/dist/_chunks/{index.es-BVC277zB.js.map → index.es-D9VqgSyV.js.map} +1 -1
  73. package/dist/_chunks/{markdown-qIVVfGoX.js → markdown-25UY48qE.js} +2 -2
  74. package/dist/_chunks/{markdown-qIVVfGoX.js.map → markdown-25UY48qE.js.map} +1 -1
  75. package/dist/ai-elements.es.js +939 -785
  76. package/dist/ai-elements.es.js.map +1 -1
  77. package/dist-vue/PkChatbot.js +1 -1
  78. package/dist-vue/PkChatbotAuth.js +1 -1
  79. package/dist-vue/PkChatbotEmptyState.js +1 -1
  80. package/dist-vue/PkChatbotFeedbackForm.js +1 -1
  81. package/dist-vue/PkChatbotInput.js +1 -1
  82. package/dist-vue/PkChatbotMessages.js +1 -1
  83. package/dist-vue/PkChatbotStepPayload.js +1 -1
  84. package/dist-vue/PkChatbotStepToolDetail.js +1 -1
  85. package/dist-vue/PkChatbotSteps.js +1 -1
  86. package/dist-vue/PkChatbotViewChat.js +1 -1
  87. package/dist-vue/PkChatbotViewConversations.js +1 -1
  88. package/dist-vue/PkChatbotViewFiles.js +1 -1
  89. package/dist-vue/PkChatbotViewProfile.js +1 -1
  90. package/dist-vue/_chunks/Agent-Ci7XnQ12.js +742 -0
  91. package/dist-vue/_chunks/Agent-Ci7XnQ12.js.map +1 -0
  92. package/dist-vue/_chunks/{Document-DmBTgjd4.js → Document-Bhlc3wdt.js} +10 -10
  93. package/dist-vue/_chunks/{Document-DmBTgjd4.js.map → Document-Bhlc3wdt.js.map} +1 -1
  94. package/dist-vue/_chunks/{PkChatbot-W9tO1H9i.js → PkChatbot-C05Rv5zO.js} +8 -8
  95. package/dist-vue/_chunks/{PkChatbot-W9tO1H9i.js.map → PkChatbot-C05Rv5zO.js.map} +1 -1
  96. package/dist-vue/_chunks/{PkChatbotAuth-C2TpCnWH.js → PkChatbotAuth-DD5RF7kY.js} +3 -3
  97. package/dist-vue/_chunks/PkChatbotAuth-DD5RF7kY.js.map +1 -0
  98. package/dist-vue/_chunks/{PkChatbotEmptyState-BY3f3T0T.js → PkChatbotEmptyState-B5qeL1kv.js} +2 -2
  99. package/dist-vue/_chunks/{PkChatbotEmptyState-BY3f3T0T.js.map → PkChatbotEmptyState-B5qeL1kv.js.map} +1 -1
  100. package/dist-vue/_chunks/{PkChatbotFeedbackForm-h4mjmVTG.js → PkChatbotFeedbackForm-BJ_Omuq2.js} +2 -2
  101. package/dist-vue/_chunks/{PkChatbotFeedbackForm-h4mjmVTG.js.map → PkChatbotFeedbackForm-BJ_Omuq2.js.map} +1 -1
  102. package/dist-vue/_chunks/{PkChatbotInput-C5l6QDQY.js → PkChatbotInput-BLzTQmvy.js} +2 -2
  103. package/dist-vue/_chunks/{PkChatbotInput-C5l6QDQY.js.map → PkChatbotInput-BLzTQmvy.js.map} +1 -1
  104. package/dist-vue/_chunks/{PkChatbotMessages-3RZER9PO.js → PkChatbotMessages-CxTz0W0d.js} +22 -22
  105. package/dist-vue/_chunks/PkChatbotMessages-CxTz0W0d.js.map +1 -0
  106. package/dist-vue/_chunks/{PkChatbotStepPayload-C-xnhmzZ.js → PkChatbotStepPayload-B04aqOGu.js} +2 -2
  107. package/dist-vue/_chunks/{PkChatbotStepPayload-C-xnhmzZ.js.map → PkChatbotStepPayload-B04aqOGu.js.map} +1 -1
  108. package/dist-vue/_chunks/{PkChatbotStepToolDetail-Cko1vU0N.js → PkChatbotStepToolDetail-yII_Dk3p.js} +3 -3
  109. package/dist-vue/_chunks/{PkChatbotStepToolDetail-Cko1vU0N.js.map → PkChatbotStepToolDetail-yII_Dk3p.js.map} +1 -1
  110. package/dist-vue/_chunks/{PkChatbotSteps-BkZ3Kq2M.js → PkChatbotSteps-DYiCeWOd.js} +5 -5
  111. package/dist-vue/_chunks/{PkChatbotSteps-BkZ3Kq2M.js.map → PkChatbotSteps-DYiCeWOd.js.map} +1 -1
  112. package/dist-vue/_chunks/{PkChatbotViewChat-BFImSy1X.js → PkChatbotViewChat-s-Vx4U1E.js} +7 -7
  113. package/dist-vue/_chunks/PkChatbotViewChat-s-Vx4U1E.js.map +1 -0
  114. package/dist-vue/_chunks/PkChatbotViewConversations-D7XHDBGS.js +195 -0
  115. package/dist-vue/_chunks/PkChatbotViewConversations-D7XHDBGS.js.map +1 -0
  116. package/dist-vue/_chunks/{PkChatbotViewFiles-CMQdbZN6.js → PkChatbotViewFiles-t07w-VNZ.js} +36 -36
  117. package/dist-vue/_chunks/PkChatbotViewFiles-t07w-VNZ.js.map +1 -0
  118. package/dist-vue/_chunks/{PkChatbotViewProfile-CDCy1LEX.js → PkChatbotViewProfile-DJT5AEkZ.js} +2 -2
  119. package/dist-vue/_chunks/{PkChatbotViewProfile-CDCy1LEX.js.map → PkChatbotViewProfile-DJT5AEkZ.js.map} +1 -1
  120. package/dist-vue/_chunks/{PkStreamingMarkdown-DJG-aPx2.js → PkStreamingMarkdown-ALhm02o3.js} +3 -3
  121. package/dist-vue/_chunks/{PkStreamingMarkdown-DJG-aPx2.js.map → PkStreamingMarkdown-ALhm02o3.js.map} +1 -1
  122. package/dist-vue/_chunks/{PkToolEditSpreadsheet-BHh7NUdR.js → PkToolEditSpreadsheet-DU3RBd6q.js} +2 -2
  123. package/dist-vue/_chunks/{PkToolEditSpreadsheet-BHh7NUdR.js.map → PkToolEditSpreadsheet-DU3RBd6q.js.map} +1 -1
  124. package/dist-vue/_chunks/{PkToolRequestGeolocation-Ccbhljmn.js → PkToolRequestGeolocation-CE4zQofM.js} +2 -2
  125. package/dist-vue/_chunks/{PkToolRequestGeolocation-Ccbhljmn.js.map → PkToolRequestGeolocation-CE4zQofM.js.map} +1 -1
  126. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-BXf5ZRzR.js → PkToolRequestOAuthConnection-CAk5s541.js} +2 -2
  127. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-BXf5ZRzR.js.map → PkToolRequestOAuthConnection-CAk5s541.js.map} +1 -1
  128. package/dist-vue/_chunks/{PkToolShowArtifact-BsfbvfVC.js → PkToolShowArtifact-CA1sKasD.js} +2 -2
  129. package/dist-vue/_chunks/{PkToolShowArtifact-BsfbvfVC.js.map → PkToolShowArtifact-CA1sKasD.js.map} +1 -1
  130. package/dist-vue/_chunks/{PkToolShowCalendarEvent-yttlTHiX.js → PkToolShowCalendarEvent-Cb3lmDQZ.js} +2 -2
  131. package/dist-vue/_chunks/PkToolShowCalendarEvent-Cb3lmDQZ.js.map +1 -0
  132. package/dist-vue/_chunks/{PkToolShowContactForm-C-YbtBlG.js → PkToolShowContactForm-C0QHEj5k.js} +3 -3
  133. package/dist-vue/_chunks/{PkToolShowContactForm-C-YbtBlG.js.map → PkToolShowContactForm-C0QHEj5k.js.map} +1 -1
  134. package/dist-vue/_chunks/{PkToolShowDiagram-CIHVrQ3e.js → PkToolShowDiagram-CQUd_reA.js} +2 -2
  135. package/dist-vue/_chunks/{PkToolShowDiagram-CIHVrQ3e.js.map → PkToolShowDiagram-CQUd_reA.js.map} +1 -1
  136. package/dist-vue/_chunks/{PkToolShowForm-BwYJhEVO.js → PkToolShowForm-B_ezmfuo.js} +8 -8
  137. package/dist-vue/_chunks/PkToolShowForm-B_ezmfuo.js.map +1 -0
  138. package/dist-vue/_chunks/{PkToolShowImageGallery-1A9zyOVn.js → PkToolShowImageGallery-B8gmmHvk.js} +2 -2
  139. package/dist-vue/_chunks/{PkToolShowImageGallery-1A9zyOVn.js.map → PkToolShowImageGallery-B8gmmHvk.js.map} +1 -1
  140. package/dist-vue/_chunks/PkToolShowProductList-BMvt5mKe.js +72 -0
  141. package/dist-vue/_chunks/PkToolShowProductList-BMvt5mKe.js.map +1 -0
  142. package/dist-vue/_chunks/{PkToolShowSources-BQpdJE_m.js → PkToolShowSources-DEmjN0Ou.js} +3 -3
  143. package/dist-vue/_chunks/{PkToolShowSources-BQpdJE_m.js.map → PkToolShowSources-DEmjN0Ou.js.map} +1 -1
  144. package/dist-vue/_chunks/{PkToolShowSuggestedReply-D3jLsbKJ.js → PkToolShowSuggestedReply-BE6gBA-2.js} +2 -2
  145. package/dist-vue/_chunks/{PkToolShowSuggestedReply-D3jLsbKJ.js.map → PkToolShowSuggestedReply-BE6gBA-2.js.map} +1 -1
  146. package/dist-vue/_chunks/{PkToolShowVideo-DUdkb3qb.js → PkToolShowVideo-ZPDVzjPX.js} +2 -2
  147. package/dist-vue/_chunks/{PkToolShowVideo-DUdkb3qb.js.map → PkToolShowVideo-ZPDVzjPX.js.map} +1 -1
  148. package/dist-vue/_chunks/{PkToolShowWebPages-BeeBiv9R.js → PkToolShowWebPages-dI4WMr7F.js} +8 -8
  149. package/dist-vue/_chunks/PkToolShowWebPages-dI4WMr7F.js.map +1 -0
  150. package/dist-vue/_chunks/{createChatbotApiClient-CDrs7NwO.js → createChatbotApiClient-IlTQndxL.js} +2 -2
  151. package/dist-vue/_chunks/{createChatbotApiClient-CDrs7NwO.js.map → createChatbotApiClient-IlTQndxL.js.map} +1 -1
  152. package/dist-vue/_chunks/{index.es-D7kQZyxD.js → index.es-VzNLOQUv.js} +2 -2
  153. package/dist-vue/_chunks/{index.es-D7kQZyxD.js.map → index.es-VzNLOQUv.js.map} +1 -1
  154. package/dist-vue/_chunks/{useChatbotStore-D6YNk8Rx.js → useChatbotStore-CtJ3bwuy.js} +3 -3
  155. package/dist-vue/_chunks/{useChatbotStore-D6YNk8Rx.js.map → useChatbotStore-CtJ3bwuy.js.map} +1 -1
  156. package/dist-vue/_chunks/{useDialogConfirm-KWz0ohCQ.js → useDialogConfirm-BxhvsnRr.js} +9 -8
  157. package/dist-vue/_chunks/useDialogConfirm-BxhvsnRr.js.map +1 -0
  158. package/dist-vue/_chunks/{utils-roi6YVNC.js → utils-BzypADaU.js} +2 -2
  159. package/dist-vue/_chunks/{utils-roi6YVNC.js.map → utils-BzypADaU.js.map} +1 -1
  160. package/dist-vue/api.js +1 -1
  161. package/dist-vue/apps/web-component/src/components/EmbeddedChatWidget.ce.d.ts +4 -4
  162. package/dist-vue/apps/web-component/src/composables/useChatbotAgent.d.ts +5 -4
  163. package/dist-vue/apps/web-component/src/composables/useChatbotProfileProvider.d.ts +1 -1
  164. package/dist-vue/composables.js +169 -24
  165. package/dist-vue/composables.js.map +1 -1
  166. package/dist-vue/index.js +3477 -3384
  167. package/dist-vue/index.js.map +1 -1
  168. package/dist-vue/packages/auth/src/email-brand.d.ts +11 -0
  169. package/dist-vue/packages/components/src/PkEditorMarkdown.d.ts +1 -1
  170. package/dist-vue/packages/components/src/chat/PkChatbotMessages.d.ts +1 -1
  171. package/dist-vue/packages/components/src/table/PkTableEmpty.d.ts +1 -1
  172. package/dist-vue/packages/composable/src/chatbot/useChatbotStore.d.ts +6 -6
  173. package/dist-vue/packages/composable/src/index.d.ts +1 -0
  174. package/dist-vue/packages/composable/src/useBranding.d.ts +89 -0
  175. package/dist-vue/packages/composable/src/useDialogConfirm.d.ts +2 -1
  176. package/dist-vue/packages/composable/src/useSettingsStore.d.ts +8 -3
  177. package/dist-vue/packages/models/src/schema/Agent.d.ts +20 -14
  178. package/dist-vue/packages/models/src/schema/Branding.d.ts +625 -0
  179. package/dist-vue/packages/models/src/schema/Platform.d.ts +8 -0
  180. package/dist-vue/packages/models/src/schema/PwaManifest.d.ts +38 -0
  181. package/dist-vue/packages/models/src/schema/ReasoningChat.d.ts +2 -2
  182. package/dist-vue/packages/models/src/schema/SubAgent.d.ts +2 -2
  183. package/dist-vue/packages/models/src/schema/index.d.ts +2 -0
  184. package/dist-vue/style.css +1 -1
  185. package/package.json +1 -1
  186. package/dist/_chunks/Agent-CJbRpoZG.js +0 -577
  187. package/dist/_chunks/Agent-CJbRpoZG.js.map +0 -1
  188. package/dist/_chunks/PkToolShowCalendarEvent-BLSTS6zf.js.map +0 -1
  189. package/dist/_chunks/PkToolShowForm-Dmq95u6b.js.map +0 -1
  190. package/dist/_chunks/PkToolShowProductList-DjS9nvXe.js +0 -72
  191. package/dist/_chunks/PkToolShowProductList-DjS9nvXe.js.map +0 -1
  192. package/dist/_chunks/PkToolShowWebPages-CYbiGa7e.js.map +0 -1
  193. package/dist-vue/_chunks/Agent---jwXeaB.js +0 -558
  194. package/dist-vue/_chunks/Agent---jwXeaB.js.map +0 -1
  195. package/dist-vue/_chunks/PkChatbotAuth-C2TpCnWH.js.map +0 -1
  196. package/dist-vue/_chunks/PkChatbotMessages-3RZER9PO.js.map +0 -1
  197. package/dist-vue/_chunks/PkChatbotViewChat-BFImSy1X.js.map +0 -1
  198. package/dist-vue/_chunks/PkChatbotViewConversations-C6T4ZxxX.js +0 -195
  199. package/dist-vue/_chunks/PkChatbotViewConversations-C6T4ZxxX.js.map +0 -1
  200. package/dist-vue/_chunks/PkChatbotViewFiles-CMQdbZN6.js.map +0 -1
  201. package/dist-vue/_chunks/PkToolShowCalendarEvent-yttlTHiX.js.map +0 -1
  202. package/dist-vue/_chunks/PkToolShowForm-BwYJhEVO.js.map +0 -1
  203. package/dist-vue/_chunks/PkToolShowProductList-D61i6AMs.js +0 -72
  204. package/dist-vue/_chunks/PkToolShowProductList-D61i6AMs.js.map +0 -1
  205. package/dist-vue/_chunks/PkToolShowWebPages-BeeBiv9R.js.map +0 -1
  206. package/dist-vue/_chunks/useDialogConfirm-KWz0ohCQ.js.map +0 -1
@@ -1,195 +0,0 @@
1
- import { n as e } from "./useChatbotStore-D6YNk8Rx.js";
2
- import "./src-DT8FLE4_.js";
3
- import { t } from "./markdown-CCMpGUA7.js";
4
- import { n } from "./message-RohfrdWS.js";
5
- import { t as r } from "./useDialogConfirm-KWz0ohCQ.js";
6
- import { t as i } from "./PkRelativeTime--1cIphlA.js";
7
- import { t as a } from "./chatbotProfileContext-CgnFhNPn.js";
8
- import { VvButton as o, VvButtonGroup as s, VvDropdown as c, VvDropdownAction as l, VvIcon as ee, VvInputText as u } from "@volverjs/ui-vue/components";
9
- import { Fragment as d, computed as f, createBlock as te, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createTextVNode as g, createVNode as _, defineComponent as v, inject as y, isRef as ne, mergeProps as re, normalizeClass as b, openBlock as x, ref as S, renderList as C, toDisplayString as w, unref as T, withCtx as E, withModifiers as D } from "vue";
10
- import { useI18n as ie } from "vue-i18n";
11
- import { storeToRefs as ae } from "pinia";
12
- //#region ../../packages/composable/src/chatbot/useConversationActions.ts
13
- function O(e) {
14
- return t(e.title) || t(n(e.messages?.find((e) => e.role === "user"))) || "";
15
- }
16
- function k(e) {
17
- let n = S(null), i = S(""), a = (e, r = "") => {
18
- n.value = e.id, i.value = t(e.title) || r;
19
- }, o = async (t) => {
20
- let r = i.value.trim();
21
- if (n.value = null, r && r.length <= 255) try {
22
- await e.renameChatTitle(t, r);
23
- } catch {}
24
- }, s = () => {
25
- n.value = null;
26
- }, c = (e, t) => {
27
- e.key === "Enter" ? (e.preventDefault(), o(t)) : e.key === "Escape" && (e.preventDefault(), s());
28
- }, { openDialogConfirm: l } = r();
29
- return {
30
- editingId: n,
31
- editingTitle: i,
32
- startEdit: a,
33
- confirmEdit: o,
34
- cancelEdit: s,
35
- onRenameKeydown: c,
36
- requestDelete: async (t) => {
37
- try {
38
- if (!await l()) return;
39
- await e.deleteChat(t);
40
- } catch {}
41
- }
42
- };
43
- }
44
- //#endregion
45
- //#region ../../packages/components/src/chat/PkChatbotViewConversations.vue?vue&type=script&setup=true&lang.ts
46
- var oe = { class: "flex flex-col flex-1 min-h-0 relative" }, se = {
47
- key: 0,
48
- class: "u-pick-list__list u-pick-list__list--fill"
49
- }, ce = { class: "u-pick-list__entry u-pick-list__entry--roomy" }, le = { class: "flex flex-col gap-6 flex-1 min-w-0" }, ue = {
50
- key: 1,
51
- class: "flex flex-col flex-1 items-center justify-center gap-12 p-24 text-center"
52
- }, de = { class: "w-64 h-64 rounded-full bg-surface-1 border border-surface-3 flex items-center justify-center" }, fe = { class: "flex flex-col gap-4" }, A = { class: "text-16 font-semibold text-word-1" }, j = { class: "text-14 text-word-3 leading-relaxed" }, M = {
53
- key: 2,
54
- class: "u-pick-list__list u-pick-list__list--fill overflow-y-auto pb-64 light-scrollbar"
55
- }, N = {
56
- key: 0,
57
- class: "flex flex-1 items-center gap-8 min-w-0 px-md py-12"
58
- }, P = ["aria-current", "onClick"], F = { class: "min-w-0 flex-1" }, I = { class: "flex items-center gap-8" }, L = { class: "u-pick-list__label font-medium flex-1" }, R = { class: "text-12 text-word-4 line-clamp-2" }, z = { class: "u-pick-list__actions" }, B = {
59
- key: 3,
60
- class: "absolute bottom-0 left-0 right-0 flex flex-col items-center gap-4 px-16 pb-16 pt-32 pointer-events-none",
61
- style: { background: "linear-gradient(to top, var(--color-surface) 55%, transparent)" }
62
- }, V = /* @__PURE__ */ v({
63
- __name: "PkChatbotViewConversations",
64
- props: { agentId: {} },
65
- setup(v) {
66
- let O = v, { t: V } = ie({ useScope: "global" }), H = e(O.agentId), { conversations: U, isLoadingConversations: pe, localChatId: W } = ae(H), { navigate: me, startNewChat: G, renameChatTitle: he, deleteChat: ge } = H, { editingId: K, editingTitle: q, startEdit: _e, confirmEdit: ve, cancelEdit: ye, onRenameKeydown: be, requestDelete: xe } = k({
67
- renameChatTitle: he,
68
- deleteChat: ge
69
- }), J = (e) => {
70
- K.value || (W.value = e, me("chat"));
71
- }, Y = (e) => W.value === e.id, X = (e, r) => t(n(e.filter((e) => e.role === r).slice(-1)[0]) || ""), Se = (e) => {
72
- _e(e, X(e.messages, "assistant"));
73
- }, { openDialogConfirm: Ce } = r(), Z = y(a, void 0), Q = f(() => !!Z?.eraseConversations && !(Z.isExternalAuth?.value ?? !1)), $ = S(!1), we = async () => {
74
- let e = Z?.eraseConversations;
75
- if (e && Q.value && await Ce({
76
- title: V("confirmTitle.deleteMyConversations"),
77
- questionLabel: V("message.deleteMyConversationsConfirm")
78
- })) {
79
- $.value = !0;
80
- try {
81
- await e(), U.value = [], G();
82
- } catch {
83
- H.loadConversations(O.agentId);
84
- } finally {
85
- $.value = !1;
86
- }
87
- }
88
- };
89
- return (e, n) => {
90
- let r = ee, a = o, f = u, v = s, y = l, S = c;
91
- return x(), m("div", oe, [T(pe) && T(U).length === 0 ? (x(), m("div", se, [(x(), m(d, null, C(5, (e) => h("div", {
92
- key: e,
93
- class: "u-pick-list__row u-pick-list__row--skeleton"
94
- }, [h("div", ce, [h("div", le, [
95
- h("div", { class: b(["vv-skeleton h-16 rounded", e % 2 ? "w-192" : "w-128"]) }, [...n[5] ||= [h("div", { class: "vv-skeleton__item" }, null, -1)]], 2),
96
- n[6] ||= h("div", { class: "vv-skeleton h-12 rounded" }, [h("div", { class: "vv-skeleton__item" })], -1),
97
- n[7] ||= h("div", { class: "vv-skeleton h-12 rounded w-160" }, [h("div", { class: "vv-skeleton__item" })], -1)
98
- ])])])), 64))])) : T(U).length === 0 ? (x(), m("div", ue, [
99
- h("div", de, [_(r, {
100
- name: "ri:chat-3-line",
101
- class: "w-28 h-28 text-word-4"
102
- })]),
103
- h("div", fe, [h("strong", A, w(T(V)("message.noConversations")), 1), h("span", j, w(T(V)("message.noConversationsHint")), 1)]),
104
- _(a, {
105
- modifiers: "primary rounded",
106
- icon: "ri:add-line",
107
- class: "mt-8",
108
- label: T(V)("action.startNewChat"),
109
- onClick: n[0] ||= (e) => T(G)()
110
- }, null, 8, ["label"])
111
- ])) : (x(), m("ul", M, [(x(!0), m(d, null, C(T(U), (e) => (x(), m("li", {
112
- key: e.id,
113
- class: b(["u-pick-list__row", { "u-pick-list__row--current": Y(e) }])
114
- }, [T(K) === e.id ? (x(), m("div", N, [_(f, {
115
- modelValue: T(q),
116
- "onUpdate:modelValue": n[1] ||= (e) => ne(q) ? q.value = e : null,
117
- class: "flex-1 mb-0",
118
- modifiers: "compact",
119
- autofocus: "",
120
- "select-on-focus": "",
121
- maxlength: 255,
122
- placeholder: T(V)("placeholder.insert"),
123
- onKeydown: (t) => T(be)(t, e.id)
124
- }, null, 8, [
125
- "modelValue",
126
- "placeholder",
127
- "onKeydown"
128
- ]), _(v, { modifiers: "compact" }, {
129
- default: E(() => [_(a, {
130
- icon: "ri:save-line",
131
- title: T(V)("action.save"),
132
- modifiers: "action-quiet-small",
133
- onClick: (t) => T(ve)(e.id)
134
- }, null, 8, ["title", "onClick"]), _(a, {
135
- icon: "ri:close-line",
136
- title: T(V)("action.cancel"),
137
- modifiers: "action-quiet-small",
138
- onClick: n[2] ||= (e) => T(ye)()
139
- }, null, 8, ["title"])]),
140
- _: 2
141
- }, 1024)])) : (x(), m(d, { key: 1 }, [h("button", {
142
- type: "button",
143
- class: "u-pick-list__entry u-pick-list__entry--roomy leading-relaxed",
144
- "aria-current": Y(e) ? "true" : void 0,
145
- onClick: (t) => J(e.id)
146
- }, [h("div", F, [h("div", I, [h("strong", L, w(T(t)(e.title) || X(e.messages, "assistant")), 1), _(i, {
147
- class: "text-word-4 text-smaller shrink-0",
148
- date: e.lastMessageAt
149
- }, null, 8, ["date"])]), h("span", R, w(T(t)(e.summary) || X(e.messages, "user")), 1)])], 8, P), h("div", z, [_(S, re({ ref_for: !0 }, {
150
- placement: "bottom-end",
151
- modifiers: "menu",
152
- flip: !0,
153
- offset: 3,
154
- strategy: "fixed"
155
- }), {
156
- items: E(() => [_(y, { onClick: (t) => Se(e) }, {
157
- default: E(() => [_(r, { name: "ri:pencil-line" }), g(" " + w(T(V)("action.renameChat")), 1)]),
158
- _: 1
159
- }, 8, ["onClick"]), _(y, { onClick: (t) => T(xe)(e.id) }, {
160
- default: E(() => [_(r, { name: "ri:delete-bin-line" }), g(" " + w(T(V)("action.delete")), 1)]),
161
- _: 1
162
- }, 8, ["onClick"])]),
163
- default: E(() => [_(a, {
164
- icon: "ri:more-2-fill",
165
- title: T(V)("action.moreActions"),
166
- modifiers: "action-quiet-small"
167
- }, null, 8, ["title"])]),
168
- _: 2
169
- }, 1040)])], 64))], 2))), 128))])), T(U).length > 0 ? (x(), m("div", B, [_(a, {
170
- class: "text-14 pointer-events-auto",
171
- modifiers: "primary rounded",
172
- icon: "ri:add-line",
173
- label: T(V)("action.startNewChat"),
174
- onClick: n[3] ||= D((e) => T(G)(), ["stop"])
175
- }, null, 8, ["label"]), Q.value ? (x(), te(a, {
176
- key: 0,
177
- class: "text-12 pointer-events-auto",
178
- modifiers: "action-quiet-danger",
179
- icon: "ri:delete-bin-line",
180
- loading: $.value,
181
- disabled: $.value,
182
- label: T(V)("action.deleteMyConversations"),
183
- onClick: n[4] ||= D((e) => we(), ["stop"])
184
- }, null, 8, [
185
- "loading",
186
- "disabled",
187
- "label"
188
- ])) : p("", !0)])) : p("", !0)]);
189
- };
190
- }
191
- });
192
- //#endregion
193
- export { O as n, k as r, V as t };
194
-
195
- //# sourceMappingURL=PkChatbotViewConversations-C6T4ZxxX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PkChatbotViewConversations-C6T4ZxxX.js","names":["__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","__unplugin_components_4","__unplugin_components_5","_openBlock","_createElementBlock","_unref","_Fragment","_renderList","_createElementVNode","_normalizeClass","_createVNode","_toDisplayString","_isRef","_withCtx","PkRelativeTime","_mergeProps","_createTextVNode","_withModifiers","_createBlock","_createCommentVNode","_sfc_main","useChatbotStore","useDialogConfirm","PkRelativeTime_default","ChatbotProfileContextKey","getConversationPreview","stripMarkdown","conversation","getTextPart","message","useConversationActions","editingId","ref","editingTitle","startEdit","fallbackTitle","confirmEdit","trimmed","actions","id","cancelEdit","onRenameKeydown","event","openDialogConfirm","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","PkChatbotViewConversations_default","defineComponent","props","__props","$t","useI18n","store","storeToRefs","startEditConversation","handleDelete","openConversation","navigate","isCurrentConversation","localChatId","getLastMessage","messages","m","role","profile","inject","canEraseConversations","computed","isErasingConversations","handleEraseAll","eraseConversations","startNewChat","_component_VvIcon","VvIcon","_component_VvButton","VvButton","_component_VvInputText","VvInputText","_component_VvButtonGroup","VvButtonGroup","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","openBlock","createElementBlock","unref","isLoadingConversations","conversations","Fragment","renderList","createElementVNode","i","normalizeClass","_cache","createVNode","toDisplayString","isRef","$event","withCtx","mergeProps","createTextVNode","withModifiers","createBlock","createCommentVNode"],"sources":["../../../../packages/composable/src/chatbot/useConversationActions.ts","../../../../packages/components/src/chat/PkChatbotViewConversations.vue","../../../../packages/components/src/chat/PkChatbotViewConversations.vue"],"sourcesContent":["import { ref } from 'vue'\nimport type { Chat as Conversation } from 'models'\nimport { getTextPart, stripMarkdown } from 'utils'\nimport { useDialogConfirm } from '../useDialogConfirm'\n\n/**\n * Single-line preview for a conversation: explicit title, otherwise the\n * first user message. Used as list label and as search haystack.\n */\nexport function getConversationPreview(conversation: Conversation): string {\n return (\n stripMarkdown(conversation.title) ||\n stripMarkdown(\n getTextPart(\n // The list endpoint isn't Zod-parsed: don't trust the\n // declared types at runtime\n conversation.messages?.find(\n (message) => message.role === 'user',\n ),\n ),\n ) ||\n ''\n )\n}\n\n/**\n * Inline-rename and delete-with-confirm state shared by the conversation\n * lists (PkChatbotViewConversations, PkChatSidebar). Renames are optimistic:\n * on failure the next conversations load reconciles with the server state.\n */\nexport function useConversationActions(actions: {\n renameChatTitle: (chatId: string, title: string) => Promise<unknown>\n deleteChat: (chatId: string) => Promise<unknown>\n}) {\n const editingId = ref<string | null>(null)\n const editingTitle = ref('')\n\n const startEdit = (conversation: Conversation, fallbackTitle = '') => {\n editingId.value = conversation.id\n editingTitle.value = stripMarkdown(conversation.title) || fallbackTitle\n }\n\n const confirmEdit = async (id: string) => {\n const trimmed = editingTitle.value.trim()\n editingId.value = null\n if (trimmed && trimmed.length <= 255) {\n try {\n await actions.renameChatTitle(id, trimmed)\n } catch {\n // Revert optimistically: reload will pick up server state\n }\n }\n }\n\n const cancelEdit = () => {\n editingId.value = null\n }\n\n const onRenameKeydown = (event: KeyboardEvent, id: string) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n confirmEdit(id)\n } else if (event.key === 'Escape') {\n event.preventDefault()\n cancelEdit()\n }\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n const requestDelete = async (id: string) => {\n try {\n const proceed = await openDialogConfirm()\n if (!proceed) {\n return\n }\n await actions.deleteChat(id)\n } catch {\n // Silently fail: next load will reconcile\n }\n }\n\n return {\n editingId,\n editingTitle,\n startEdit,\n confirmEdit,\n cancelEdit,\n onRenameKeydown,\n requestDelete,\n }\n}\n","<script setup lang=\"ts\">\n import { computed, inject, ref } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import {\n useChatbotStore,\n useConversationActions,\n useDialogConfirm,\n } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { ChatbotProfileContextKey } from './chatbotProfileContext'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, isLoadingConversations, localChatId } =\n storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const {\n editingId,\n editingTitle,\n startEdit: startEditConversation,\n confirmEdit,\n cancelEdit,\n onRenameKeydown,\n requestDelete: handleDelete,\n } = useConversationActions({ renameChatTitle, deleteChat })\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n startEditConversation(\n conversation,\n getLastMessage(conversation.messages, 'assistant'),\n )\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n\n // GDPR B.3 — bulk \"delete my conversations\", available to anonymous\n // sessions too (the host wires the endpoint through the profile context).\n // Hidden when the host application owns the session (external token or\n // host-session mode): the endpoint erases ALL conversations of the\n // session's user platform-wide, an account-scoped action that belongs to\n // the host, not to an embedded widget. Same gating as sign-out and\n // manage-profile in PkChatbotViewProfile.\n const profile = inject(ChatbotProfileContextKey, undefined)\n const canEraseConversations = computed(\n () =>\n !!profile?.eraseConversations &&\n !(profile.isExternalAuth?.value ?? false),\n )\n const isErasingConversations = ref(false)\n const handleEraseAll = async () => {\n const eraseConversations = profile?.eraseConversations\n if (!eraseConversations || !canEraseConversations.value) {\n return\n }\n const proceed = await openDialogConfirm({\n title: $t('confirmTitle.deleteMyConversations'),\n questionLabel: $t('message.deleteMyConversationsConfirm'),\n })\n if (!proceed) {\n return\n }\n isErasingConversations.value = true\n try {\n await eraseConversations()\n conversations.value = []\n startNewChat()\n } catch {\n // Same policy as single delete: fail silently and reconcile\n // with the server state\n store.loadConversations(props.agentId)\n } finally {\n isErasingConversations.value = false\n }\n }\n</script>\n\n<template>\n <div class=\"flex flex-col flex-1 min-h-0 relative\">\n <!-- Loading skeleton -->\n <div\n v-if=\"isLoadingConversations && conversations.length === 0\"\n class=\"u-pick-list__list u-pick-list__list--fill\">\n <div\n v-for=\"i in 5\"\n :key=\"i\"\n class=\"u-pick-list__row u-pick-list__row--skeleton\">\n <div class=\"u-pick-list__entry u-pick-list__entry--roomy\">\n <div class=\"flex flex-col gap-6 flex-1 min-w-0\">\n <div\n class=\"vv-skeleton h-16 rounded\"\n :class=\"i % 2 ? 'w-192' : 'w-128'\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded w-160\">\n <div class=\"vv-skeleton__item\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"conversations.length === 0\"\n class=\"flex flex-col flex-1 items-center justify-center gap-12 p-24 text-center\">\n <div\n class=\"w-64 h-64 rounded-full bg-surface-1 border border-surface-3 flex items-center justify-center\">\n <VvIcon name=\"ri:chat-3-line\" class=\"w-28 h-28 text-word-4\" />\n </div>\n <div class=\"flex flex-col gap-4\">\n <strong class=\"text-16 font-semibold text-word-1\">\n {{ $t('message.noConversations') }}\n </strong>\n <span class=\"text-14 text-word-3 leading-relaxed\">\n {{ $t('message.noConversationsHint') }}\n </span>\n </div>\n <VvButton\n modifiers=\"primary rounded\"\n icon=\"ri:add-line\"\n class=\"mt-8\"\n :label=\"$t('action.startNewChat')\"\n @click=\"startNewChat()\" />\n </div>\n\n <!-- Conversation list. The row is a container, not a button: the menu\n and the rename field are siblings of the entry, because a button\n cannot legally contain other controls (Firefox and Safari drop\n them from the accessibility tree). -->\n <ul\n v-else\n class=\"u-pick-list__list u-pick-list__list--fill overflow-y-auto pb-64 light-scrollbar\">\n <li\n v-for=\"conversation in conversations\"\n :key=\"conversation.id\"\n class=\"u-pick-list__row\"\n :class=\"{\n 'u-pick-list__row--current':\n isCurrentConversation(conversation),\n }\">\n <div\n v-if=\"editingId === conversation.id\"\n class=\"flex flex-1 items-center gap-8 min-w-0 px-md py-12\">\n <VvInputText\n v-model=\"editingTitle\"\n class=\"flex-1 mb-0\"\n modifiers=\"compact\"\n autofocus\n select-on-focus\n :maxlength=\"255\"\n :placeholder=\"$t('placeholder.insert')\"\n @keydown=\"onRenameKeydown($event, conversation.id)\" />\n <VvButtonGroup modifiers=\"compact\">\n <VvButton\n icon=\"ri:save-line\"\n :title=\"$t('action.save')\"\n modifiers=\"action-quiet-small\"\n @click=\"confirmEdit(conversation.id)\" />\n <VvButton\n icon=\"ri:close-line\"\n :title=\"$t('action.cancel')\"\n modifiers=\"action-quiet-small\"\n @click=\"cancelEdit()\" />\n </VvButtonGroup>\n </div>\n <template v-else>\n <button\n type=\"button\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy leading-relaxed\"\n :aria-current=\"\n isCurrentConversation(conversation)\n ? 'true'\n : undefined\n \"\n @click=\"openConversation(conversation.id)\">\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-8\">\n <strong\n class=\"u-pick-list__label font-medium flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n </div>\n <span class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(\n conversation.messages,\n 'user',\n )\n }}\n </span>\n </div>\n </button>\n <div class=\"u-pick-list__actions\">\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"handleDelete(conversation.id)\">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </li>\n </ul>\n\n <!-- Sticky \"new chat\" CTA (hidden on empty state, which has its own CTA) -->\n <div\n v-if=\"conversations.length > 0\"\n class=\"absolute bottom-0 left-0 right-0 flex flex-col items-center gap-4 px-16 pb-16 pt-32 pointer-events-none\"\n :style=\"{\n background:\n 'linear-gradient(to top, var(--color-surface) 55%, transparent)',\n }\">\n <VvButton\n class=\"text-14 pointer-events-auto\"\n modifiers=\"primary rounded\"\n icon=\"ri:add-line\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n <VvButton\n v-if=\"canEraseConversations\"\n class=\"text-12 pointer-events-auto\"\n modifiers=\"action-quiet-danger\"\n icon=\"ri:delete-bin-line\"\n :loading=\"isErasingConversations\"\n :disabled=\"isErasingConversations\"\n :label=\"$t('action.deleteMyConversations')\"\n @click.stop=\"handleEraseAll()\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, inject, ref } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import {\n useChatbotStore,\n useConversationActions,\n useDialogConfirm,\n } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { ChatbotProfileContextKey } from './chatbotProfileContext'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, isLoadingConversations, localChatId } =\n storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const {\n editingId,\n editingTitle,\n startEdit: startEditConversation,\n confirmEdit,\n cancelEdit,\n onRenameKeydown,\n requestDelete: handleDelete,\n } = useConversationActions({ renameChatTitle, deleteChat })\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n startEditConversation(\n conversation,\n getLastMessage(conversation.messages, 'assistant'),\n )\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n\n // GDPR B.3 — bulk \"delete my conversations\", available to anonymous\n // sessions too (the host wires the endpoint through the profile context).\n // Hidden when the host application owns the session (external token or\n // host-session mode): the endpoint erases ALL conversations of the\n // session's user platform-wide, an account-scoped action that belongs to\n // the host, not to an embedded widget. Same gating as sign-out and\n // manage-profile in PkChatbotViewProfile.\n const profile = inject(ChatbotProfileContextKey, undefined)\n const canEraseConversations = computed(\n () =>\n !!profile?.eraseConversations &&\n !(profile.isExternalAuth?.value ?? false),\n )\n const isErasingConversations = ref(false)\n const handleEraseAll = async () => {\n const eraseConversations = profile?.eraseConversations\n if (!eraseConversations || !canEraseConversations.value) {\n return\n }\n const proceed = await openDialogConfirm({\n title: $t('confirmTitle.deleteMyConversations'),\n questionLabel: $t('message.deleteMyConversationsConfirm'),\n })\n if (!proceed) {\n return\n }\n isErasingConversations.value = true\n try {\n await eraseConversations()\n conversations.value = []\n startNewChat()\n } catch {\n // Same policy as single delete: fail silently and reconcile\n // with the server state\n store.loadConversations(props.agentId)\n } finally {\n isErasingConversations.value = false\n }\n }\n</script>\n\n<template>\n <div class=\"flex flex-col flex-1 min-h-0 relative\">\n <!-- Loading skeleton -->\n <div\n v-if=\"isLoadingConversations && conversations.length === 0\"\n class=\"u-pick-list__list u-pick-list__list--fill\">\n <div\n v-for=\"i in 5\"\n :key=\"i\"\n class=\"u-pick-list__row u-pick-list__row--skeleton\">\n <div class=\"u-pick-list__entry u-pick-list__entry--roomy\">\n <div class=\"flex flex-col gap-6 flex-1 min-w-0\">\n <div\n class=\"vv-skeleton h-16 rounded\"\n :class=\"i % 2 ? 'w-192' : 'w-128'\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded w-160\">\n <div class=\"vv-skeleton__item\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"conversations.length === 0\"\n class=\"flex flex-col flex-1 items-center justify-center gap-12 p-24 text-center\">\n <div\n class=\"w-64 h-64 rounded-full bg-surface-1 border border-surface-3 flex items-center justify-center\">\n <VvIcon name=\"ri:chat-3-line\" class=\"w-28 h-28 text-word-4\" />\n </div>\n <div class=\"flex flex-col gap-4\">\n <strong class=\"text-16 font-semibold text-word-1\">\n {{ $t('message.noConversations') }}\n </strong>\n <span class=\"text-14 text-word-3 leading-relaxed\">\n {{ $t('message.noConversationsHint') }}\n </span>\n </div>\n <VvButton\n modifiers=\"primary rounded\"\n icon=\"ri:add-line\"\n class=\"mt-8\"\n :label=\"$t('action.startNewChat')\"\n @click=\"startNewChat()\" />\n </div>\n\n <!-- Conversation list. The row is a container, not a button: the menu\n and the rename field are siblings of the entry, because a button\n cannot legally contain other controls (Firefox and Safari drop\n them from the accessibility tree). -->\n <ul\n v-else\n class=\"u-pick-list__list u-pick-list__list--fill overflow-y-auto pb-64 light-scrollbar\">\n <li\n v-for=\"conversation in conversations\"\n :key=\"conversation.id\"\n class=\"u-pick-list__row\"\n :class=\"{\n 'u-pick-list__row--current':\n isCurrentConversation(conversation),\n }\">\n <div\n v-if=\"editingId === conversation.id\"\n class=\"flex flex-1 items-center gap-8 min-w-0 px-md py-12\">\n <VvInputText\n v-model=\"editingTitle\"\n class=\"flex-1 mb-0\"\n modifiers=\"compact\"\n autofocus\n select-on-focus\n :maxlength=\"255\"\n :placeholder=\"$t('placeholder.insert')\"\n @keydown=\"onRenameKeydown($event, conversation.id)\" />\n <VvButtonGroup modifiers=\"compact\">\n <VvButton\n icon=\"ri:save-line\"\n :title=\"$t('action.save')\"\n modifiers=\"action-quiet-small\"\n @click=\"confirmEdit(conversation.id)\" />\n <VvButton\n icon=\"ri:close-line\"\n :title=\"$t('action.cancel')\"\n modifiers=\"action-quiet-small\"\n @click=\"cancelEdit()\" />\n </VvButtonGroup>\n </div>\n <template v-else>\n <button\n type=\"button\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy leading-relaxed\"\n :aria-current=\"\n isCurrentConversation(conversation)\n ? 'true'\n : undefined\n \"\n @click=\"openConversation(conversation.id)\">\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-8\">\n <strong\n class=\"u-pick-list__label font-medium flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n </div>\n <span class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(\n conversation.messages,\n 'user',\n )\n }}\n </span>\n </div>\n </button>\n <div class=\"u-pick-list__actions\">\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"handleDelete(conversation.id)\">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </li>\n </ul>\n\n <!-- Sticky \"new chat\" CTA (hidden on empty state, which has its own CTA) -->\n <div\n v-if=\"conversations.length > 0\"\n class=\"absolute bottom-0 left-0 right-0 flex flex-col items-center gap-4 px-16 pb-16 pt-32 pointer-events-none\"\n :style=\"{\n background:\n 'linear-gradient(to top, var(--color-surface) 55%, transparent)',\n }\">\n <VvButton\n class=\"text-14 pointer-events-auto\"\n modifiers=\"primary rounded\"\n icon=\"ri:add-line\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n <VvButton\n v-if=\"canEraseConversations\"\n class=\"text-12 pointer-events-auto\"\n modifiers=\"action-quiet-danger\"\n icon=\"ri:delete-bin-line\"\n :loading=\"isErasingConversations\"\n :disabled=\"isErasingConversations\"\n :label=\"$t('action.deleteMyConversations')\"\n @click.stop=\"handleEraseAll()\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PkChatbotViewFiles-CMQdbZN6.js","names":["__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_unref","_Fragment","_renderList","_createElementVNode","_normalizeClass","_createVNode","_toDisplayString","_createBlock","_sfc_main","isImageMime","fileIconForMime","isInlineViewable","useChatbotStore","useDialogConfirm","useImageFallback","useFileRow","useI18n","thumbUrl","urls","file","canShowImage","inline","download","iso","locale","useUserFileKind","isSpreadsheet","t","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","PkChatbotViewFiles_default","defineComponent","props","__props","$t","store","storeToRefs","deletingId","ref","handleExclude","openDialogConfirm","removeConfirm","_component_VvIcon","VvIcon","_component_VvButton","VvButton","openBlock","createElementBlock","unref","isLoadingChatFiles","chatFiles","Fragment","renderList","createElementVNode","i","_cache","normalizeClass","createVNode","toDisplayString","openFile","showThumb","onThumbError","createBlock","formatDate","kindNote","removeLabel"],"sources":["../../../../packages/composable/src/useFileRow.ts","../../../../packages/components/src/chat/PkChatbotViewFiles.vue","../../../../packages/components/src/chat/PkChatbotViewFiles.vue"],"sourcesContent":["import { useI18n } from 'vue-i18n'\nimport { isImageMime, isInlineViewable } from 'models'\nimport { useImageFallback } from './useImageFallback'\n\n/** Minimal shape a file-list row needs for the shared display helpers. */\nexport interface FileRowLike {\n documentId: string\n mimeType: string | null\n}\n\n/**\n * Shared display logic for the user-files list rows, used by both the in-app\n * table (PjUserFilesTable) and the embedded widget (PkChatbotViewFiles). The two\n * surfaces differ only in how they build URLs (authenticated store vs widget API\n * client), so the URL builders are injected.\n *\n * - `view(id, inline)` → opens/downloads the original file.\n * - `preview(id)` → small resized blob for the row thumbnail.\n */\nexport function useFileRow(urls: {\n view: (documentId: string, inline: boolean) => string\n preview: (documentId: string) => string\n}) {\n const { locale } = useI18n({ useScope: 'global' })\n\n // Image rows show a thumbnail; if it fails to load (auth/redirect, or the\n // preview isn't generated yet) we fall back to the file-type icon.\n const { canShowImage, onImageError } = useImageFallback()\n const thumbUrl = (file: FileRowLike): string =>\n urls.preview(file.documentId)\n const showThumb = (file: FileRowLike): boolean =>\n isImageMime(file.mimeType) && canShowImage(thumbUrl(file))\n const onThumbError = (file: FileRowLike): void => {\n onImageError(thumbUrl(file))\n }\n\n // Name click previews images/PDF inline; an explicit download forces an\n // attachment (inline=false → download SAS).\n const openFile = (file: FileRowLike, download = false): void => {\n const inline = !download && isInlineViewable(file.mimeType)\n window.open(urls.view(file.documentId, inline), '_blank', 'noopener')\n }\n\n const formatDate = (iso: string): string =>\n new Date(iso).toLocaleDateString(locale.value, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n\n return { showThumb, thumbUrl, onThumbError, openFile, formatDate }\n}\n\n/** What tells a spreadsheet row apart from a KB document. */\nexport interface FileKindLike {\n kind?: 'document' | 'spreadsheet'\n sourceAttachmentId?: string | null\n}\n\n/**\n * The wording that depends on what a \"My files\" row is. A KB document is a\n * copy of the upload: removing it only takes it out of the assistant's reach.\n * A spreadsheet is the chat attachment itself and never enters the KB: its row\n * says so, and removing it deletes it from its chat with every version the\n * assistant wrote of it.\n */\nexport function useUserFileKind() {\n const { t } = useI18n({ useScope: 'global' })\n\n const isSpreadsheet = (file: FileKindLike): boolean =>\n file.kind === 'spreadsheet'\n\n /** A short note for the row; undefined for a KB document. */\n const kindNote = (file: FileKindLike): string | undefined => {\n if (!isSpreadsheet(file)) {\n return undefined\n }\n return file.sourceAttachmentId\n ? t('userFiles.spreadsheetVersion')\n : t('userFiles.spreadsheetInChatOnly')\n }\n\n const removeLabel = (file: FileKindLike): string =>\n isSpreadsheet(file)\n ? t('userFiles.deleteSpreadsheet')\n : t('userFiles.exclude')\n\n /** The options of the confirmation dialog before removing the file. */\n const removeConfirm = (file: FileKindLike) =>\n isSpreadsheet(file)\n ? {\n title: t('confirmTitle.deleteSpreadsheet'),\n questionLabel: t('userFiles.deleteSpreadsheetConfirm'),\n }\n : {\n title: t('confirmTitle.excludeUserFile'),\n questionLabel: t('userFiles.excludeConfirm'),\n }\n\n return { isSpreadsheet, kindNote, removeLabel, removeConfirm }\n}\n","<script setup lang=\"ts\">\n import { ref } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import { fileIconForMime } from 'models'\n import {\n useChatbotStore,\n useDialogConfirm,\n useFileRow,\n useUserFileKind,\n type ChatbotFile,\n } from 'composables'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n const { openDialogConfirm } = useDialogConfirm()\n\n const store = useChatbotStore(props.agentId)\n const { chatFiles, isLoadingChatFiles } = storeToRefs(store)\n const { showThumb, thumbUrl, onThumbError, openFile, formatDate } =\n useFileRow({\n view: store.getChatFileUrl,\n preview: store.getChatFilePreviewUrl,\n })\n const { kindNote, removeLabel, removeConfirm } = useUserFileKind()\n\n const deletingId = ref<string | null>(null)\n\n const handleExclude = async (file: ChatbotFile) => {\n const proceed = await openDialogConfirm(removeConfirm(file))\n if (!proceed) {\n return\n }\n deletingId.value = file.documentId\n try {\n await store.deleteChatFile(file.documentId)\n } catch {\n // surfaced by the host's error handling\n } finally {\n deletingId.value = null\n }\n }\n</script>\n\n<template>\n <div class=\"flex flex-col flex-1 min-h-0 relative\">\n <!-- Loading skeleton, shaped like the rows it replaces -->\n <div\n v-if=\"isLoadingChatFiles && chatFiles.length === 0\"\n class=\"u-pick-list__list u-pick-list__list--fill\">\n <div\n v-for=\"i in 4\"\n :key=\"i\"\n class=\"u-pick-list__row u-pick-list__row--skeleton\">\n <div class=\"u-pick-list__entry u-pick-list__entry--roomy\">\n <div class=\"vv-skeleton w-36 h-36 shrink-0 rounded-md\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"flex flex-col gap-6 flex-1 min-w-0\">\n <div\n class=\"vv-skeleton h-14 rounded\"\n :class=\"i % 2 ? 'w-192' : 'w-128'\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded w-96\">\n <div class=\"vv-skeleton__item\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"chatFiles.length === 0\"\n class=\"flex flex-col flex-1 items-center justify-center gap-12 p-24 text-center\">\n <div\n class=\"w-64 h-64 rounded-full bg-surface-1 border border-surface-3 flex items-center justify-center\">\n <VvIcon\n name=\"ri:folder-open-line\"\n class=\"w-28 h-28 text-word-4\" />\n </div>\n <span class=\"text-14 text-word-3 leading-relaxed\">\n {{ $t('userFiles.chatFilesEmpty') }}\n </span>\n </div>\n\n <!-- File list -->\n <ul\n v-else\n class=\"pk-chatbot-files u-pick-list__list u-pick-list__list--fill overflow-y-auto light-scrollbar\">\n <li\n v-for=\"file in chatFiles\"\n :key=\"file.documentId\"\n class=\"u-pick-list__row\">\n <button\n type=\"button\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy\"\n :title=\"$t('userFiles.open')\"\n @click=\"openFile(file)\">\n <span class=\"pk-chatbot-files__icon\">\n <img\n v-if=\"showThumb(file)\"\n :src=\"thumbUrl(file)\"\n loading=\"lazy\"\n decoding=\"async\"\n alt=\"\"\n class=\"pk-chatbot-files__thumb\"\n @error=\"onThumbError(file)\" />\n <VvIcon v-else :name=\"fileIconForMime(file.mimeType)\" />\n </span>\n <span class=\"flex flex-col min-w-0 flex-1\">\n <span class=\"u-pick-list__label\">\n {{ file.name || $t('userFiles.untitled') }}\n </span>\n <span class=\"text-12 text-word-3\">\n {{\n [formatDate(file.createdAt), kindNote(file)]\n .filter(Boolean)\n .join(' · ')\n }}\n </span>\n </span>\n </button>\n <div class=\"u-pick-list__actions pk-chatbot-files__actions\">\n <VvButton\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :title=\"$t('action.download')\"\n @click=\"openFile(file, true)\" />\n <VvButton\n modifiers=\"action-quiet-small\"\n icon=\"ri:delete-bin-line\"\n :title=\"removeLabel(file)\"\n :loading=\"deletingId === file.documentId\"\n :disabled=\"deletingId === file.documentId\"\n @click=\"handleExclude(file)\" />\n </div>\n </li>\n </ul>\n </div>\n</template>\n\n<style lang=\"scss\">\n // The frame, the rows and the label come from `u-pick-list`; what is left\n // here is the file tile and the pair of row actions.\n .pk-chatbot-files {\n list-style: none;\n margin: 0;\n padding: 0;\n\n // The box exists to clip a thumbnail and to keep the labels of rows\n // with and without one on the same left edge: with a file icon in it\n // there is nothing to draw, so it stays transparent.\n &__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--spacing-36);\n height: var(--spacing-36);\n flex-shrink: 0;\n border-radius: var(--rounded-md);\n color: var(--color-word-3);\n overflow: hidden;\n\n svg {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n\n &__thumb {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &__actions {\n gap: var(--spacing-2);\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { ref } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import { fileIconForMime } from 'models'\n import {\n useChatbotStore,\n useDialogConfirm,\n useFileRow,\n useUserFileKind,\n type ChatbotFile,\n } from 'composables'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n const { openDialogConfirm } = useDialogConfirm()\n\n const store = useChatbotStore(props.agentId)\n const { chatFiles, isLoadingChatFiles } = storeToRefs(store)\n const { showThumb, thumbUrl, onThumbError, openFile, formatDate } =\n useFileRow({\n view: store.getChatFileUrl,\n preview: store.getChatFilePreviewUrl,\n })\n const { kindNote, removeLabel, removeConfirm } = useUserFileKind()\n\n const deletingId = ref<string | null>(null)\n\n const handleExclude = async (file: ChatbotFile) => {\n const proceed = await openDialogConfirm(removeConfirm(file))\n if (!proceed) {\n return\n }\n deletingId.value = file.documentId\n try {\n await store.deleteChatFile(file.documentId)\n } catch {\n // surfaced by the host's error handling\n } finally {\n deletingId.value = null\n }\n }\n</script>\n\n<template>\n <div class=\"flex flex-col flex-1 min-h-0 relative\">\n <!-- Loading skeleton, shaped like the rows it replaces -->\n <div\n v-if=\"isLoadingChatFiles && chatFiles.length === 0\"\n class=\"u-pick-list__list u-pick-list__list--fill\">\n <div\n v-for=\"i in 4\"\n :key=\"i\"\n class=\"u-pick-list__row u-pick-list__row--skeleton\">\n <div class=\"u-pick-list__entry u-pick-list__entry--roomy\">\n <div class=\"vv-skeleton w-36 h-36 shrink-0 rounded-md\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"flex flex-col gap-6 flex-1 min-w-0\">\n <div\n class=\"vv-skeleton h-14 rounded\"\n :class=\"i % 2 ? 'w-192' : 'w-128'\">\n <div class=\"vv-skeleton__item\" />\n </div>\n <div class=\"vv-skeleton h-12 rounded w-96\">\n <div class=\"vv-skeleton__item\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"chatFiles.length === 0\"\n class=\"flex flex-col flex-1 items-center justify-center gap-12 p-24 text-center\">\n <div\n class=\"w-64 h-64 rounded-full bg-surface-1 border border-surface-3 flex items-center justify-center\">\n <VvIcon\n name=\"ri:folder-open-line\"\n class=\"w-28 h-28 text-word-4\" />\n </div>\n <span class=\"text-14 text-word-3 leading-relaxed\">\n {{ $t('userFiles.chatFilesEmpty') }}\n </span>\n </div>\n\n <!-- File list -->\n <ul\n v-else\n class=\"pk-chatbot-files u-pick-list__list u-pick-list__list--fill overflow-y-auto light-scrollbar\">\n <li\n v-for=\"file in chatFiles\"\n :key=\"file.documentId\"\n class=\"u-pick-list__row\">\n <button\n type=\"button\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy\"\n :title=\"$t('userFiles.open')\"\n @click=\"openFile(file)\">\n <span class=\"pk-chatbot-files__icon\">\n <img\n v-if=\"showThumb(file)\"\n :src=\"thumbUrl(file)\"\n loading=\"lazy\"\n decoding=\"async\"\n alt=\"\"\n class=\"pk-chatbot-files__thumb\"\n @error=\"onThumbError(file)\" />\n <VvIcon v-else :name=\"fileIconForMime(file.mimeType)\" />\n </span>\n <span class=\"flex flex-col min-w-0 flex-1\">\n <span class=\"u-pick-list__label\">\n {{ file.name || $t('userFiles.untitled') }}\n </span>\n <span class=\"text-12 text-word-3\">\n {{\n [formatDate(file.createdAt), kindNote(file)]\n .filter(Boolean)\n .join(' · ')\n }}\n </span>\n </span>\n </button>\n <div class=\"u-pick-list__actions pk-chatbot-files__actions\">\n <VvButton\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :title=\"$t('action.download')\"\n @click=\"openFile(file, true)\" />\n <VvButton\n modifiers=\"action-quiet-small\"\n icon=\"ri:delete-bin-line\"\n :title=\"removeLabel(file)\"\n :loading=\"deletingId === file.documentId\"\n :disabled=\"deletingId === file.documentId\"\n @click=\"handleExclude(file)\" />\n </div>\n </li>\n </ul>\n </div>\n</template>\n\n<style lang=\"scss\">\n // The frame, the rows and the label come from `u-pick-list`; what is left\n // here is the file tile and the pair of row actions.\n .pk-chatbot-files {\n list-style: none;\n margin: 0;\n padding: 0;\n\n // The box exists to clip a thumbnail and to keep the labels of rows\n // with and without one on the same left edge: with a file icon in it\n // there is nothing to draw, so it stays transparent.\n &__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--spacing-36);\n height: var(--spacing-36);\n flex-shrink: 0;\n border-radius: var(--rounded-md);\n color: var(--color-word-3);\n overflow: hidden;\n\n svg {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n\n &__thumb {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &__actions {\n gap: var(--spacing-2);\n }\n }\n</style>\n"],"mappings":";;;;;;;;;AAmBA,SAAgBmB,EAAW,GAGxB;CACC,IAAM,EAAE,cAAWC,EAAQ,EAAE,UAAU,SAAS,CAAC,GAI3C,EAAE,iBAAc,oBAAiBF,EAAiB,GAClDG,KAAY,MACdC,EAAK,QAAQC,EAAK,UAAU;CAqBhC,OAAO;EAAE,YApBU,MACfV,EAAYU,EAAK,QAAQ,KAAKC,EAAaH,EAASE,CAAI,CAAC;EAmBzC;EAAU,eAlBR,MAA4B;GAC9C,EAAaF,EAASE,CAAI,CAAC;EAC/B;EAgB4C,WAZ1B,GAAmB,IAAW,OAAgB;GAC5D,IAAME,IAAS,CAACC,KAAYX,EAAiBQ,EAAK,QAAQ;GAC1D,OAAO,KAAKD,EAAK,KAAKC,EAAK,YAAYE,CAAM,GAAG,UAAU,UAAU;EACxE;EASsD,aAPlC,MAChB,IAAI,KAAKE,CAAG,CAAC,CAAC,mBAAmBC,EAAO,OAAO;GAC3C,MAAM;GACN,OAAO;GACP,KAAK;EACT,CAAC;CAE4D;AACrE;AAeA,SAAgBC,IAAkB;CAC9B,IAAM,EAAE,SAAMT,EAAQ,EAAE,UAAU,SAAS,CAAC,GAEtCU,KAAiB,MACnBP,EAAK,SAAS;CA6BlB,OAAO;EAAE;EAAe,WA1BN,MAA2C;GACzD,IAAKO,EAAcP,CAAI,GAGvB,OAAOA,EAAK,qBACNQ,EAAE,8BAA8B,IAChCA,EAAE,iCAAiC;EAC7C;EAmBkC,cAjBb,MACjBD,EAAcP,CAAI,IACZQ,EAAE,6BAA6B,IAC/BA,EAAE,mBAAmB;EAcgB,gBAXxB,MACnBD,EAAcP,CAAI,IACZ;GACI,OAAOQ,EAAE,gCAAgC;GACzC,eAAeA,EAAE,oCAAoC;EACzD,IACA;GACI,OAAOA,EAAE,8BAA8B;GACvC,eAAeA,EAAE,0BAA0B;EAC/C;CAEmD;AACjE;;;;;;;;;;;;;;;;ECvFI,IAAMkB,IAAQC,GAER,EAAE,GAAGC,MAAO/B,EAAQ,EAAE,UAAU,SAAS,CAAC,GAC1C,EAAE,yBAAsBH,EAAiB,GAEzCmC,IAAQpC,EAAgBiC,EAAM,OAAO,GACrC,EAAE,cAAW,0BAAuBI,EAAYD,CAAK,GACrD,EAAE,cAAW,aAAU,iBAAc,aAAU,kBACjDjC,EAAW;GACP,MAAMiC,EAAM;GACZ,SAASA,EAAM;EACnB,CAAC,GACC,EAAE,aAAU,gBAAa,qBAAkBvB,EAAgB,GAE3DyB,IAAaC,EAAmB,IAAI,GAEpCC,IAAgB,OAAO,MAAsB;GAE/C,IAAK,MADiBC,EAAkBC,EAAcnC,CAAI,CAAC,GAI3D;MAAW,QAAQA,EAAK;IACxB,IAAI;KACA,MAAM6B,EAAM,eAAe7B,EAAK,UAAU;IAC9C,QAAQ,CAER,UAAU;KACN,EAAW,QAAQ;IACvB;GAPwB;EAQ5B;;;GAIA,OAAArB,EAAA,GAAAC,EA+FM,OA/FN6B,GA+FM,CA5FQ5B,EAAA8D,CAAA,KAAsB9D,EAAA+D,CAAA,CAAS,CAAC,WAAM,KADhDjE,EAAA,GAAAC,EAuBM,OAvBN8B,GAuBM,EApBF/B,EAAA,GAAAC,EAmBME,GAAA,MAAAC,EAlBU,IAAL,MADXC,EAmBM,OAAA;IAjBD,KAAKgE;IACN,OAAM;GACNhE,GAAAA,CAAAA,EAcM,OAdN2B,GAcM,CAbF,AAAAsC,EAAA,OAAAjE,EAEM,OAAA,EAFD,OAAM,4CAA2C,GAAA,CAClDA,EAAiC,OAAA,EAA5B,OAAM,oBAAmB,CAAA,CAAA,GAAA,EAAA,GAElCA,EASM,OATN4B,GASM,CARF5B,EAIM,OAAA,EAHF,OAAKC,EAAA,CAAC,4BACE+D,IAAC,IAAA,UAAA,OAAA,CAAA,EAAA,GAAA,CAAA,GAAA,AAAAC,EAAA,OAAA,CACTjE,EAAiC,OAAA,EAA5B,OAAM,oBAAmB,GAAA,MAAA,EAAA,CAAA,CAAA,GAAA,CAAA,GAElC,AAAAiE,EAAA,OAAAjE,EAEM,OAAA,EAFD,OAAM,gCAA+B,GAAA,CACtCA,EAAiC,OAAA,EAA5B,OAAM,oBAAmB,CAAA,CAAA,GAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CASnCH,GAAAA,EAAAA,EAAAA,CAAAA,KAAAA,EAAA+D,CAAA,CAAS,CAAC,WAAM,KAD/BjE,EAAA,GAAAC,EAYM,OAZNiC,GAYM,CATF7B,EAKM,OALN8B,GAKM,CAHF5B,EAEoCkD,GAAA;IADhC,MAAK;IACL,OAAM;GAEdpD,CAAAA,CAAAA,CAAAA,GAAAA,EAEO,QAFP+B,GAEO5B,EADAN,EAAA+C,CAAA,CAAE,CAAA,0BAAA,CAAA,GAAA,CAAA,CAAA,CAAA,MAKbjD,EAAA,GAAAC,EAmDK,MAnDLoC,GAmDK,EAhDDrC,EAAA,EAAA,GAAAC,EA+CKE,GAAA,MAAAC,EA9CcF,EAAA+D,CAAA,IAAR,OADXjE,EAAA,GAAAC,EA+CK,MAAA;IA7CA,KAAKoB,EAAK;IACX,OAAM;GACNhB,GAAAA,CAAAA,EA4BS,UAAA;IA3BL,MAAK;IACL,OAAM;IACL,OAAOH,EAAA+C,CAAA,CAAE,CAAA,gBAAA;IACT,UAAK,MAAE/C,EAAAwE,CAAA,CAAQ,CAACrD,CAAI;GACrBhB,GAAAA,CAAAA,EAUO,QAVPkC,GAUO,CAROrC,EAAAyE,CAAA,CAAS,CAACtD,CAAI,KADxBrB,EAAA,GAAAC,EAOkC,OAAA;;IAL7B,KAAKC,EAAAiB,CAAA,CAAQ,CAACE,CAAI;IACnB,SAAQ;IACR,UAAS;IACT,KAAI;IACJ,OAAM;IACL,UAAK,MAAEnB,EAAA0E,CAAA,CAAY,CAACvD,CAAI;GAC7BrB,GAAAA,MAAAA,IAAAA,CAAAA,MAAAA,EAAA,GAAAS,EAAwDgD,GAAA;;IAAxC,MAAMvD,EAAAU,CAAA,CAAe,CAACS,EAAK,QAAQ;GAEvDhB,GAAAA,MAAAA,GAAAA,CAAAA,MAAAA,CAAAA,EAAAA,CAAAA,GAAAA,EAWO,QAXPoC,GAWO,CAVHpC,EAEO,QAFPqC,GAEOlC,EADAa,EAAK,QAAQnB,EAAA+C,CAAA,CAAE,CAAA,oBAAA,CAAA,GAAA,CAAA,GAEtB5C,EAMO,QANPsC,GAMOnC,EAAA,CAJEN,EAAA4E,CAAA,CAAU,CAACzD,EAAK,SAAS,GAAGnB,EAAA6E,CAAA,CAAQ,CAAC1D,CAAI,CAAA,CAAA,CAAwC,OAAO,OAAO,CAAA,CAAuC,KAAI,KAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,GAAAiB,CAAA,GAO3JjC,EAaM,OAbNuC,GAaM,CAZFrC,EAIoCoD,GAAA;IAHhC,WAAU;IACV,MAAK;IACJ,OAAOzD,EAAA+C,CAAA,CAAE,CAAA,iBAAA;IACT,UAAK,MAAE/C,EAAAwE,CAAA,CAAQ,CAACrD,GAAI,EAAA;GACzBd,GAAAA,MAAAA,GAAAA,CAAAA,SAAAA,SAAAA,CAAAA,GAAAA,EAMmCoD,GAAA;IAL/B,WAAU;IACV,MAAK;IACJ,OAAOzD,EAAA8E,CAAA,CAAW,CAAC3D,CAAI;IACvB,SAAS+B,EAAA,UAAe/B,EAAK;IAC7B,UAAU+B,EAAA,UAAe/B,EAAK;IAC9B,UAAK,MAAEiC,EAAcjC,CAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PkToolShowCalendarEvent-yttlTHiX.js","names":["$t","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","__unplugin_components_4","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_withCtx","_unref","_normalizeProps","_guardReactiveProps","_createTextVNode","_createCommentVNode","_sfc_main","__exportAll","isSameSite","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","PkToolShowCalendarEvent_vue_vue_type_script_setup_true_lang_default","props","__props","useClipboard","useI18n","toolPart","computed","dateDisplay","input","start","startDate","end","endDate","startDay","endDay","allDay","d","calendarStart","calendarDay","calendarMonth","toIcsDateTime","iso","escapeIcs","str","generateIcs","ics","title","location","additionalInfo","blob","url","a","openGoogleCalendar","params","openOutlook","copyEvent","lines","copy","_component_VvIcon","VvIcon","_component_VvButton","VvButton","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","_component_VvButtonGroup","VvButtonGroup","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","_ctx","withCtx","unref","copied","normalizeProps","guardReactiveProps","_cache","createTextVNode","createCommentVNode","PkToolShowCalendarEvent_exports","PkToolShowCalendarEvent_default"],"sources":["../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue","../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center select-none\">\n <div\n class=\"bg-brand px-8 py-2 text-white text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center select-none\">\n <div\n class=\"bg-brand px-8 py-2 text-white text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PkToolShowForm-BwYJhEVO.js","names":["_useModel","__unplugin_components_0","__unplugin_components_1","_openBlock","_createBlock","_withCtx","_createElementBlock","_Fragment","_renderList","_renderSlot","_mergeProps","_createTextVNode","_toDisplayString","_sfc_main","_useModel","__unplugin_components_0","__unplugin_components_1","_openBlock","_createBlock","_withCtx","_createElementBlock","_Fragment","_renderList","_renderSlot","_mergeProps","_createTextVNode","_toDisplayString","_sfc_main","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_unref","_normalizeClass","_createCommentVNode","_normalizeStyle","_Fragment","_createBlock","PkStreamingMarkdown","PkEditorCheckboxButtons","_createSlots","_renderList","_withCtx","PkEditorRadioButtons","_withKeys","_withModifiers","_createVNode","_sfc_main","__exportAll","isVoiceRenderAck","PkStreamingMarkdown_default","formStepOptions","formAnswerSlots","PkEditorRadioButtons_default","defineComponent","\"modelValue\"","\"modelModifiers\"","props","__props","modelValue","useModel","uid","useId","groupName","computed","radioModifiers","_component_VvRadio","VvRadio","_component_VvRadioGroup","VvRadioGroup","openBlock","createBlock","_cache","$event","withCtx","createElementBlock","Fragment","renderList","option","renderSlot","_ctx","mergeProps","createTextVNode","toDisplayString","PkEditorCheckboxButtons_default","_component_VvCheckbox","VvCheckbox","_component_VvCheckboxGroup","VvCheckboxGroup","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","PkToolShowForm_vue_vue_type_script_setup_true_lang_default","__emit","emit","$t","$d","useI18n","toolPart","isLegacy","isRenderAck","isInteractive","isAutoSubmitStep","step","currentStep","steps","isLegacyAutoSubmit","isSelfSubmitting","input","o","hasFailed","currentStepIndex","ref","canGoBack","canGoNext","isMultiStep","progress","answers","reactive","customAnswer","scalarValue","val","activeCheckboxValue","outputAnswers","output","list","normalizedOutput","out","value","radioOptions","goNext","submitCustomAnswer","submitForm","goBack","finalAnswers","index","onRadioChange","getSummaryValue","_component_VvInputText","VvInputText","_component_VvButton","VvButton","_component_VvIcon","VvIcon","createElementVNode","unref","normalizeClass","createCommentVNode","normalizeStyle","createSlots","withKeys","withModifiers","createVNode","PkToolShowForm_exports","PkToolShowForm_default"],"sources":["../../../../packages/components/src/PkEditorRadioButtons.vue","../../../../packages/components/src/PkEditorRadioButtons.vue","../../../../packages/components/src/PkEditorCheckboxButtons.vue","../../../../packages/components/src/PkEditorCheckboxButtons.vue","../../../../packages/components/src/chat/PkToolShowForm.vue","../../../../packages/components/src/chat/PkToolShowForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n import { computed, useId } from 'vue'\n\n const props = defineProps<{\n name: string\n label?: string\n hintLabel?: string\n invalid?: boolean\n invalidLabel?: string | string[]\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n modifiers?: string | string[]\n /**\n * Render the options as one segmented control (a recessed track with\n * the chosen option raised) instead of a row of boxed cards. Suits a\n * choice between a few short named states, such as a level or a mode.\n */\n segmented?: boolean\n }>()\n\n const modelValue = defineModel<\n string | number | boolean | symbol | unknown[] | undefined\n >({ default: undefined })\n\n // Native radios group by their name attribute across the whole document, so\n // two instances sharing one name become a single group: the browser unchecks\n // the other instance's inputs and Vue never puts them back, because its own\n // model did not change. It happened with \"theme\", offered by the profile\n // menu and the agent settings panel at the same time, and it can happen to\n // any two tool forms with the same step id. Scope the name to the instance.\n const uid = useId()\n const groupName = computed(() => `${props.name}-${uid}`)\n\n const radioModifiers = computed(() => {\n const toReturn = props.modifiers\n ? Array.isArray(props.modifiers)\n ? props.modifiers\n : [props.modifiers]\n : []\n return [...toReturn, props.segmented ? 'segment' : 'button']\n })\n</script>\n\n<template>\n <VvRadioGroup\n v-model=\"modelValue\"\n :name=\"groupName\"\n :label\n :hint-label=\"hintLabel\"\n :invalid\n :invalid-label=\"invalidLabel\"\n :modifiers=\"segmented ? 'segmented' : 'buttons'\">\n <VvRadio\n v-for=\"(option, key) in options\"\n :key\n :name=\"groupName\"\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n :modifiers=\"radioModifiers\">\n <slot :name=\"option.value\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvRadio>\n </VvRadioGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n import { computed, useId } from 'vue'\n\n const props = defineProps<{\n name: string\n label?: string\n hintLabel?: string\n invalid?: boolean\n invalidLabel?: string | string[]\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n modifiers?: string | string[]\n /**\n * Render the options as one segmented control (a recessed track with\n * the chosen option raised) instead of a row of boxed cards. Suits a\n * choice between a few short named states, such as a level or a mode.\n */\n segmented?: boolean\n }>()\n\n const modelValue = defineModel<\n string | number | boolean | symbol | unknown[] | undefined\n >({ default: undefined })\n\n // Native radios group by their name attribute across the whole document, so\n // two instances sharing one name become a single group: the browser unchecks\n // the other instance's inputs and Vue never puts them back, because its own\n // model did not change. It happened with \"theme\", offered by the profile\n // menu and the agent settings panel at the same time, and it can happen to\n // any two tool forms with the same step id. Scope the name to the instance.\n const uid = useId()\n const groupName = computed(() => `${props.name}-${uid}`)\n\n const radioModifiers = computed(() => {\n const toReturn = props.modifiers\n ? Array.isArray(props.modifiers)\n ? props.modifiers\n : [props.modifiers]\n : []\n return [...toReturn, props.segmented ? 'segment' : 'button']\n })\n</script>\n\n<template>\n <VvRadioGroup\n v-model=\"modelValue\"\n :name=\"groupName\"\n :label\n :hint-label=\"hintLabel\"\n :invalid\n :invalid-label=\"invalidLabel\"\n :modifiers=\"segmented ? 'segmented' : 'buttons'\">\n <VvRadio\n v-for=\"(option, key) in options\"\n :key\n :name=\"groupName\"\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n :modifiers=\"radioModifiers\">\n <slot :name=\"option.value\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvRadio>\n </VvRadioGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n\n defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n }>()\n\n const modelValue = defineModel<unknown[] | undefined>({\n default: undefined,\n })\n</script>\n\n<template>\n <VvCheckboxGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvCheckbox\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n modifiers=\"button\">\n <slot :name=\"String(option.value)\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvCheckbox>\n </VvCheckboxGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n\n defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n }>()\n\n const modelValue = defineModel<unknown[] | undefined>({\n default: undefined,\n })\n</script>\n\n<template>\n <VvCheckboxGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvCheckbox\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n modifiers=\"button\">\n <slot :name=\"String(option.value)\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvCheckbox>\n </VvCheckboxGroup>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { isVoiceRenderAck } from 'models'\n import { formAnswerSlots, formStepOptions } from './utils'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkEditorRadioButtons from '../PkEditorRadioButtons.vue'\n import PkEditorCheckboxButtons from '../PkEditorCheckboxButtons.vue'\n\n // --- Types ---\n\n interface FormOption {\n label: string\n description?: string\n }\n\n interface FormStep {\n id: string\n question: string\n message?: string\n type?: 'text' | 'number' | 'date'\n options?: FormOption[]\n multiSelect?: boolean\n allowFreeformInput?: boolean\n placeholder?: string\n }\n\n interface FormAnswer {\n id: string\n value: string | string[] | number | null\n }\n\n interface ToolPartShape {\n state?: 'input-available' | 'output-available' | 'output-error'\n toolCallId?: string\n // AI SDK v5 encodes the tool name in `type` (e.g. 'tool-showMultipleChoice').\n // `toolName` is kept for backward compatibility but is normally absent.\n type?: string\n toolName?: string\n input?: {\n title?: string\n steps?: FormStep[]\n // Legacy showMultipleChoice fields\n question?: string\n options?: (string | FormOption)[]\n }\n // The web card submits `{ answers: [...] }`; the platform channels\n // (Teams modal) submit a flat record keyed by step id.\n output?: string | { answers: FormAnswer[] } | Record<string, unknown>\n }\n\n type AnswerValue = string | string[] | number | null\n\n // --- Props & Emits ---\n\n const props = defineProps<{\n part: unknown\n allowCustomAnswer?: boolean\n /**\n * Answered during a call. Nothing in the part says so (the answer went\n * to the agent as speech, not to the tool call), so the surface that\n * sent it is the only one that knows, and without it the same form\n * could be submitted again and again.\n */\n answered?: boolean\n }>()\n\n const emit = defineEmits<{\n select: [answer: string | { answers: FormAnswer[] }]\n }>()\n\n const { t: $t, d: $d } = useI18n({ useScope: 'global' })\n\n // --- Parsed tool part ---\n\n const toolPart = computed(\n () => JSON.parse(JSON.stringify(props.part)) as ToolPartShape,\n )\n\n const isLegacy = computed(\n () =>\n toolPart.value.toolName === 'showMultipleChoice' ||\n toolPart.value.type === 'tool-showMultipleChoice',\n )\n\n /**\n * A form drawn during a CALL is already \"answered\" as far as the tool loop\n * is concerned: the turn could not wait for it, so the backend closed it\n * with a note saying the widget was drawn (see `isVoiceRenderAck`). That\n * note is not an answer, and the caller still has to give one.\n */\n const isRenderAck = computed(() => isVoiceRenderAck(toolPart.value.output))\n\n const isInteractive = computed(\n () =>\n !props.answered &&\n (toolPart.value.state === 'input-available' || isRenderAck.value),\n )\n\n /** Single-step with no custom-answer and no freeform → auto-submit on option pick */\n const isAutoSubmitStep = computed(() => {\n const step = currentStep.value\n if (!step) {\n return false\n }\n return (\n steps.value.length === 1 &&\n !step.allowFreeformInput &&\n !props.allowCustomAnswer\n )\n })\n\n /** Legacy tool should auto-submit on option pick regardless of allowCustomAnswer */\n const isLegacyAutoSubmit = computed(\n () =>\n isLegacy.value &&\n steps.value.length === 1 &&\n !currentStep.value?.multiSelect,\n )\n\n /**\n * True only for the steps that send themselves as soon as an option is\n * picked: the single case where the footer button would be redundant.\n * Every other shape needs it, single-step forms included: with\n * `allowFreeformInput` (or `allowCustomAnswer`) the radio pick no longer\n * auto-submits, so without the footer the user was left with a chosen\n * option and no way to send it.\n */\n const isSelfSubmitting = computed(\n () =>\n Boolean(currentStep.value?.options) &&\n !currentStep.value?.multiSelect &&\n (isAutoSubmitStep.value || isLegacyAutoSubmit.value),\n )\n\n // --- Steps ---\n\n const steps = computed<FormStep[]>(() => {\n const input = toolPart.value.input\n if (input?.steps?.length) {\n return input.steps\n }\n // Legacy showMultipleChoice → normalize into a single step\n if (input?.question && input?.options) {\n return [\n {\n id: 'legacy',\n question: input.question,\n options: input.options.map((o) =>\n typeof o === 'string' ? { label: o } : o,\n ),\n },\n ]\n }\n return []\n })\n\n /**\n * The reason the card has nothing to draw. A call the SDK rejected keeps\n * `state: 'output-error'` and moves the arguments it could not validate to\n * `rawInput`, so `input` is empty and there are no steps: without this the\n * component rendered NOTHING, and the user was left with a question that\n * had been announced and never appeared.\n */\n const hasFailed = computed(\n () => toolPart.value.state === 'output-error' && !steps.value.length,\n )\n\n // --- Navigation state ---\n\n const currentStepIndex = ref(0)\n const currentStep = computed(() => steps.value[currentStepIndex.value])\n const canGoBack = computed(() => currentStepIndex.value > 0)\n const canGoNext = computed(\n () => currentStepIndex.value < steps.value.length - 1,\n )\n const isMultiStep = computed(() => steps.value.length > 1)\n\n const progress = computed(() => {\n if (!isMultiStep.value) {\n return null\n }\n return Math.round(\n ((currentStepIndex.value + 1) / steps.value.length) * 100,\n )\n })\n\n // --- Answers ---\n\n /**\n * One slot PER STEP, keyed by position and not by step id: the ids come\n * from the model and nothing enforces they are unique, and keyed by id two\n * steps sharing one collapsed onto a single answer. See `formAnswerSlots`.\n */\n const answers = reactive<Record<number, AnswerValue>>({})\n const customAnswer = ref('')\n\n // The freeform field belongs to the step showing it: text left behind\n // (unsubmitted, or arriving from a late input update) must not follow the\n // user to the next or previous question.\n watch(currentStepIndex, () => {\n customAnswer.value = ''\n })\n\n // Single scalar answer shared by radio buttons and freeform text/number/date inputs.\n const scalarValue = computed<string | number | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStepIndex.value]\n : undefined\n if (val == null || Array.isArray(val)) {\n return undefined\n }\n return val\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStepIndex.value] = val ?? null\n }\n },\n })\n\n const activeCheckboxValue = computed<unknown[] | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStepIndex.value]\n : undefined\n return Array.isArray(val) ? val : []\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStepIndex.value] = (val as string[]) ?? []\n }\n },\n })\n\n // --- Initialize answers from existing output ---\n\n /** The `{ answers: [...] }` list, when the output carries one. */\n function outputAnswers(output: ToolPartShape['output']) {\n if (!output || typeof output === 'string') {\n return undefined\n }\n const list = (output as { answers?: unknown }).answers\n return Array.isArray(list) ? (list as FormAnswer[]) : undefined\n }\n\n watch(\n () => toolPart.value.output,\n (output) => {\n if (!output || isVoiceRenderAck(output)) {\n return\n }\n // Every shape an answered form comes back in (the web card's list,\n // a legacy plain string, the flat record a platform channel posts)\n // lands on the same per-position slots: see `formAnswerSlots`.\n Object.assign(\n answers,\n formAnswerSlots(steps.value, output) as Record<\n number,\n AnswerValue\n >,\n )\n },\n { immediate: true },\n )\n\n // --- Restore custom answer from output when it doesn't match any option ---\n\n const normalizedOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || isVoiceRenderAck(out)) {\n return undefined\n }\n if (typeof out === 'string') {\n return out\n }\n const list = outputAnswers(out)\n if (list?.length === 1) {\n const val = list[0].value\n return Array.isArray(val) ? val.join(', ') : String(val)\n }\n return undefined\n })\n\n watch(\n normalizedOutput,\n (value) => {\n if (!value || !currentStep.value) {\n return\n }\n const optionLabels = (currentStep.value.options ?? []).map(\n (o) => o.label,\n )\n if (!optionLabels.includes(value)) {\n customAnswer.value = value\n }\n },\n { immediate: true },\n )\n\n // --- Option mapping for radio/checkbox components ---\n\n const radioOptions = computed(() => formStepOptions(currentStep.value))\n\n // --- Navigation & Submission ---\n\n /** Footer button, and Enter on a pure freeform step. */\n function goNext() {\n // A typed freeform answer wins over the picked option: it is the more\n // recent intent, and the footer button is now the visible way to send\n // it (the freeform field only submits on Enter).\n if (customAnswer.value.trim()) {\n submitCustomAnswer()\n return\n }\n if (canGoNext.value) {\n currentStepIndex.value++\n } else {\n submitForm()\n }\n }\n\n function goBack() {\n if (canGoBack.value) {\n currentStepIndex.value--\n }\n }\n\n function submitForm() {\n if (!isInteractive.value) {\n return\n }\n\n const finalAnswers: FormAnswer[] = steps.value.map((step, index) => ({\n id: step.id,\n value: answers[index] ?? null,\n }))\n\n // Legacy backward compatibility: single-step, single-select → return plain string\n if (\n isLegacyAutoSubmit.value &&\n !currentStep.value?.allowFreeformInput\n ) {\n const val = finalAnswers[0].value\n emit('select', Array.isArray(val) ? val[0] : (val as string))\n } else {\n emit('select', { answers: finalAnswers })\n }\n }\n\n /** Enter inside the freeform field shown alongside the options. */\n function submitCustomAnswer() {\n const value = customAnswer.value.trim()\n if (!value) {\n return\n }\n\n answers[currentStepIndex.value] = value\n // Cleared before navigating: `goNext()` reads it back to route a typed\n // answer here, so leaving it set would recurse.\n customAnswer.value = ''\n if (steps.value.length === 1) {\n submitForm()\n } else {\n goNext()\n }\n }\n\n function onRadioChange() {\n if (!isInteractive.value) {\n return\n }\n if (isAutoSubmitStep.value || isLegacyAutoSubmit.value) {\n submitForm()\n }\n }\n\n // --- Summary helpers ---\n\n function getSummaryValue(step: FormStep, index: number) {\n const val = answers[index]\n if (val == null) {\n return '—'\n }\n if (Array.isArray(val)) {\n return val.join(', ')\n }\n if (step.type === 'date') {\n return $d(new Date(val), 'short')\n }\n return val\n }\n</script>\n\n<template>\n <div\n v-if=\"hasFailed\"\n class=\"text-12 text-danger flex items-center gap-6 py-8\">\n <span class=\"i-vv-alert-circle text-16 shrink-0\" />\n <span>{{ $t('message.formRenderError') }}</span>\n </div>\n <div\n v-else-if=\"steps.length\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden flex flex-col bg-surface\">\n <!-- Header -->\n <div\n v-if=\"toolPart.input?.title || (isInteractive && steps.length > 1)\"\n class=\"text-12 border-b border-surface-3 text-word-3 bg-surface-1\">\n <div\n v-if=\"toolPart.input?.title\"\n class=\"px-sm py-10 font-bold\"\n :class=\"{\n 'border-b border-surface-3':\n isInteractive && steps.length > 1,\n }\">\n {{ toolPart.input?.title }}\n </div>\n <!-- Progress for multi-step -->\n <div\n v-if=\"isInteractive && steps.length > 1\"\n class=\"flex flex-col gap-4 p-sm\">\n <div class=\"flex justify-between text-10 text-word-3\">\n <span>\n {{\n $t('showForm.step', {\n current: currentStepIndex + 1,\n total: steps.length,\n })\n }}\n </span>\n <span>{{ progress }}%</span>\n </div>\n <div class=\"h-4 bg-surface-3 rounded-full overflow-hidden\">\n <div\n class=\"h-full bg-word-4 transition-all duration-300\"\n :style=\"{ width: `${progress}%` }\"></div>\n </div>\n </div>\n </div>\n\n <!-- Input Available State -->\n <template v-if=\"isInteractive\">\n <!-- Current Step Content -->\n <div class=\"px-sm py-16 flex flex-col gap-12\">\n <div class=\"leading-normal text-12\">\n <strong class=\"font-semibold\">\n {{ currentStep.question }}\n </strong>\n <PkStreamingMarkdown\n v-if=\"currentStep.message\"\n :markdown=\"currentStep.message\"\n class=\"text-word-2 mt-4\" />\n </div>\n\n <!-- Checkbox list for multi-select -->\n <PkEditorCheckboxButtons\n v-if=\"currentStep.options && currentStep.multiSelect\"\n v-model=\"activeCheckboxValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n class=\"mb-0\"\n vertical>\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorCheckboxButtons>\n\n <!-- Radio buttons for single-select -->\n <PkEditorRadioButtons\n v-else-if=\"currentStep.options && !currentStep.multiSelect\"\n v-model=\"scalarValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n vertical\n class=\"mb-0\"\n @update:model-value=\"onRadioChange\">\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorRadioButtons>\n\n <!-- Pure Freeform Input (text, number, date) -->\n <div\n v-else-if=\"!currentStep.options\"\n class=\"flex flex-col gap-6 w-full\">\n <VvInputText\n :key=\"currentStep.id\"\n v-model=\"scalarValue\"\n :placeholder=\"\n currentStep.placeholder || $t('placeholder.insert')\n \"\n :type=\"currentStep.type\"\n class=\"w-full\"\n :name=\"currentStep.id\"\n modifiers=\"compact\"\n :disabled=\"!isInteractive\"\n @keyup.enter=\"goNext\" />\n </div>\n </div>\n\n <!-- Custom footer freeform input (shown alongside options when allowFreeformInput) -->\n <div\n v-if=\"currentStep.allowFreeformInput && currentStep.options\"\n class=\"px-sm pb-sm border-t border-surface-3\">\n <form\n class=\"flex gap-xs pt-sm\"\n @submit.prevent=\"submitCustomAnswer\">\n <VvInputText\n :key=\"`${currentStep.id}-custom`\"\n v-model=\"customAnswer\"\n class=\"flex-1\"\n :name=\"`${currentStep.id}-custom`\"\n modifiers=\"compact\"\n :disabled=\"!isInteractive\"\n :placeholder=\"\n currentStep.placeholder ||\n $t('showForm.otherPlaceholder')\n \" />\n </form>\n </div>\n\n <!-- Footer navigation: shown for every step that does not submit\n itself on option pick (see `isSelfSubmitting`). -->\n <div\n v-if=\"!isSelfSubmitting\"\n class=\"px-sm py-10 bg-surface border-t border-surface-3 flex justify-between gap-12\">\n <VvButton\n v-if=\"canGoBack\"\n modifiers=\"action-quiet\"\n icon=\"ri:arrow-left-s-line\"\n :label=\"$t('action.back')\"\n @click.stop=\"goBack\" />\n <div v-else></div>\n\n <VvButton\n :modifiers=\"canGoNext ? 'action-quiet' : 'action-primary'\"\n :icon=\"\n canGoNext\n ? 'ri:arrow-right-s-line'\n : 'ri:send-plane-2-line'\n \"\n icon-position=\"right\"\n :label=\"canGoNext ? $t('action.next') : $t('action.submit')\"\n @click.stop=\"goNext\" />\n </div>\n </template>\n\n <!-- Output Available State (Multi-step Summary) -->\n <template v-else>\n <div class=\"px-sm py-12 bg-surface space-y-10\">\n <ul class=\"flex flex-col gap-8\">\n <li\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n class=\"leading-normal\">\n <div class=\"text-12 text-word-3\">\n {{ step.question }}\n </div>\n <span class=\"text-12 text-word-2 font-semibold\">\n {{ getSummaryValue(step, index) }}\n </span>\n </li>\n </ul>\n </div>\n <div\n class=\"px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div class=\"flex flex-col\">\n <span class=\"font-medium text-12 text-word-1 leading-tight\">\n {{ $t('showForm.completed') }}\n </span>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { isVoiceRenderAck } from 'models'\n import { formAnswerSlots, formStepOptions } from './utils'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkEditorRadioButtons from '../PkEditorRadioButtons.vue'\n import PkEditorCheckboxButtons from '../PkEditorCheckboxButtons.vue'\n\n // --- Types ---\n\n interface FormOption {\n label: string\n description?: string\n }\n\n interface FormStep {\n id: string\n question: string\n message?: string\n type?: 'text' | 'number' | 'date'\n options?: FormOption[]\n multiSelect?: boolean\n allowFreeformInput?: boolean\n placeholder?: string\n }\n\n interface FormAnswer {\n id: string\n value: string | string[] | number | null\n }\n\n interface ToolPartShape {\n state?: 'input-available' | 'output-available' | 'output-error'\n toolCallId?: string\n // AI SDK v5 encodes the tool name in `type` (e.g. 'tool-showMultipleChoice').\n // `toolName` is kept for backward compatibility but is normally absent.\n type?: string\n toolName?: string\n input?: {\n title?: string\n steps?: FormStep[]\n // Legacy showMultipleChoice fields\n question?: string\n options?: (string | FormOption)[]\n }\n // The web card submits `{ answers: [...] }`; the platform channels\n // (Teams modal) submit a flat record keyed by step id.\n output?: string | { answers: FormAnswer[] } | Record<string, unknown>\n }\n\n type AnswerValue = string | string[] | number | null\n\n // --- Props & Emits ---\n\n const props = defineProps<{\n part: unknown\n allowCustomAnswer?: boolean\n /**\n * Answered during a call. Nothing in the part says so (the answer went\n * to the agent as speech, not to the tool call), so the surface that\n * sent it is the only one that knows, and without it the same form\n * could be submitted again and again.\n */\n answered?: boolean\n }>()\n\n const emit = defineEmits<{\n select: [answer: string | { answers: FormAnswer[] }]\n }>()\n\n const { t: $t, d: $d } = useI18n({ useScope: 'global' })\n\n // --- Parsed tool part ---\n\n const toolPart = computed(\n () => JSON.parse(JSON.stringify(props.part)) as ToolPartShape,\n )\n\n const isLegacy = computed(\n () =>\n toolPart.value.toolName === 'showMultipleChoice' ||\n toolPart.value.type === 'tool-showMultipleChoice',\n )\n\n /**\n * A form drawn during a CALL is already \"answered\" as far as the tool loop\n * is concerned: the turn could not wait for it, so the backend closed it\n * with a note saying the widget was drawn (see `isVoiceRenderAck`). That\n * note is not an answer, and the caller still has to give one.\n */\n const isRenderAck = computed(() => isVoiceRenderAck(toolPart.value.output))\n\n const isInteractive = computed(\n () =>\n !props.answered &&\n (toolPart.value.state === 'input-available' || isRenderAck.value),\n )\n\n /** Single-step with no custom-answer and no freeform → auto-submit on option pick */\n const isAutoSubmitStep = computed(() => {\n const step = currentStep.value\n if (!step) {\n return false\n }\n return (\n steps.value.length === 1 &&\n !step.allowFreeformInput &&\n !props.allowCustomAnswer\n )\n })\n\n /** Legacy tool should auto-submit on option pick regardless of allowCustomAnswer */\n const isLegacyAutoSubmit = computed(\n () =>\n isLegacy.value &&\n steps.value.length === 1 &&\n !currentStep.value?.multiSelect,\n )\n\n /**\n * True only for the steps that send themselves as soon as an option is\n * picked: the single case where the footer button would be redundant.\n * Every other shape needs it, single-step forms included: with\n * `allowFreeformInput` (or `allowCustomAnswer`) the radio pick no longer\n * auto-submits, so without the footer the user was left with a chosen\n * option and no way to send it.\n */\n const isSelfSubmitting = computed(\n () =>\n Boolean(currentStep.value?.options) &&\n !currentStep.value?.multiSelect &&\n (isAutoSubmitStep.value || isLegacyAutoSubmit.value),\n )\n\n // --- Steps ---\n\n const steps = computed<FormStep[]>(() => {\n const input = toolPart.value.input\n if (input?.steps?.length) {\n return input.steps\n }\n // Legacy showMultipleChoice → normalize into a single step\n if (input?.question && input?.options) {\n return [\n {\n id: 'legacy',\n question: input.question,\n options: input.options.map((o) =>\n typeof o === 'string' ? { label: o } : o,\n ),\n },\n ]\n }\n return []\n })\n\n /**\n * The reason the card has nothing to draw. A call the SDK rejected keeps\n * `state: 'output-error'` and moves the arguments it could not validate to\n * `rawInput`, so `input` is empty and there are no steps: without this the\n * component rendered NOTHING, and the user was left with a question that\n * had been announced and never appeared.\n */\n const hasFailed = computed(\n () => toolPart.value.state === 'output-error' && !steps.value.length,\n )\n\n // --- Navigation state ---\n\n const currentStepIndex = ref(0)\n const currentStep = computed(() => steps.value[currentStepIndex.value])\n const canGoBack = computed(() => currentStepIndex.value > 0)\n const canGoNext = computed(\n () => currentStepIndex.value < steps.value.length - 1,\n )\n const isMultiStep = computed(() => steps.value.length > 1)\n\n const progress = computed(() => {\n if (!isMultiStep.value) {\n return null\n }\n return Math.round(\n ((currentStepIndex.value + 1) / steps.value.length) * 100,\n )\n })\n\n // --- Answers ---\n\n /**\n * One slot PER STEP, keyed by position and not by step id: the ids come\n * from the model and nothing enforces they are unique, and keyed by id two\n * steps sharing one collapsed onto a single answer. See `formAnswerSlots`.\n */\n const answers = reactive<Record<number, AnswerValue>>({})\n const customAnswer = ref('')\n\n // The freeform field belongs to the step showing it: text left behind\n // (unsubmitted, or arriving from a late input update) must not follow the\n // user to the next or previous question.\n watch(currentStepIndex, () => {\n customAnswer.value = ''\n })\n\n // Single scalar answer shared by radio buttons and freeform text/number/date inputs.\n const scalarValue = computed<string | number | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStepIndex.value]\n : undefined\n if (val == null || Array.isArray(val)) {\n return undefined\n }\n return val\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStepIndex.value] = val ?? null\n }\n },\n })\n\n const activeCheckboxValue = computed<unknown[] | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStepIndex.value]\n : undefined\n return Array.isArray(val) ? val : []\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStepIndex.value] = (val as string[]) ?? []\n }\n },\n })\n\n // --- Initialize answers from existing output ---\n\n /** The `{ answers: [...] }` list, when the output carries one. */\n function outputAnswers(output: ToolPartShape['output']) {\n if (!output || typeof output === 'string') {\n return undefined\n }\n const list = (output as { answers?: unknown }).answers\n return Array.isArray(list) ? (list as FormAnswer[]) : undefined\n }\n\n watch(\n () => toolPart.value.output,\n (output) => {\n if (!output || isVoiceRenderAck(output)) {\n return\n }\n // Every shape an answered form comes back in (the web card's list,\n // a legacy plain string, the flat record a platform channel posts)\n // lands on the same per-position slots: see `formAnswerSlots`.\n Object.assign(\n answers,\n formAnswerSlots(steps.value, output) as Record<\n number,\n AnswerValue\n >,\n )\n },\n { immediate: true },\n )\n\n // --- Restore custom answer from output when it doesn't match any option ---\n\n const normalizedOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || isVoiceRenderAck(out)) {\n return undefined\n }\n if (typeof out === 'string') {\n return out\n }\n const list = outputAnswers(out)\n if (list?.length === 1) {\n const val = list[0].value\n return Array.isArray(val) ? val.join(', ') : String(val)\n }\n return undefined\n })\n\n watch(\n normalizedOutput,\n (value) => {\n if (!value || !currentStep.value) {\n return\n }\n const optionLabels = (currentStep.value.options ?? []).map(\n (o) => o.label,\n )\n if (!optionLabels.includes(value)) {\n customAnswer.value = value\n }\n },\n { immediate: true },\n )\n\n // --- Option mapping for radio/checkbox components ---\n\n const radioOptions = computed(() => formStepOptions(currentStep.value))\n\n // --- Navigation & Submission ---\n\n /** Footer button, and Enter on a pure freeform step. */\n function goNext() {\n // A typed freeform answer wins over the picked option: it is the more\n // recent intent, and the footer button is now the visible way to send\n // it (the freeform field only submits on Enter).\n if (customAnswer.value.trim()) {\n submitCustomAnswer()\n return\n }\n if (canGoNext.value) {\n currentStepIndex.value++\n } else {\n submitForm()\n }\n }\n\n function goBack() {\n if (canGoBack.value) {\n currentStepIndex.value--\n }\n }\n\n function submitForm() {\n if (!isInteractive.value) {\n return\n }\n\n const finalAnswers: FormAnswer[] = steps.value.map((step, index) => ({\n id: step.id,\n value: answers[index] ?? null,\n }))\n\n // Legacy backward compatibility: single-step, single-select → return plain string\n if (\n isLegacyAutoSubmit.value &&\n !currentStep.value?.allowFreeformInput\n ) {\n const val = finalAnswers[0].value\n emit('select', Array.isArray(val) ? val[0] : (val as string))\n } else {\n emit('select', { answers: finalAnswers })\n }\n }\n\n /** Enter inside the freeform field shown alongside the options. */\n function submitCustomAnswer() {\n const value = customAnswer.value.trim()\n if (!value) {\n return\n }\n\n answers[currentStepIndex.value] = value\n // Cleared before navigating: `goNext()` reads it back to route a typed\n // answer here, so leaving it set would recurse.\n customAnswer.value = ''\n if (steps.value.length === 1) {\n submitForm()\n } else {\n goNext()\n }\n }\n\n function onRadioChange() {\n if (!isInteractive.value) {\n return\n }\n if (isAutoSubmitStep.value || isLegacyAutoSubmit.value) {\n submitForm()\n }\n }\n\n // --- Summary helpers ---\n\n function getSummaryValue(step: FormStep, index: number) {\n const val = answers[index]\n if (val == null) {\n return '—'\n }\n if (Array.isArray(val)) {\n return val.join(', ')\n }\n if (step.type === 'date') {\n return $d(new Date(val), 'short')\n }\n return val\n }\n</script>\n\n<template>\n <div\n v-if=\"hasFailed\"\n class=\"text-12 text-danger flex items-center gap-6 py-8\">\n <span class=\"i-vv-alert-circle text-16 shrink-0\" />\n <span>{{ $t('message.formRenderError') }}</span>\n </div>\n <div\n v-else-if=\"steps.length\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden flex flex-col bg-surface\">\n <!-- Header -->\n <div\n v-if=\"toolPart.input?.title || (isInteractive && steps.length > 1)\"\n class=\"text-12 border-b border-surface-3 text-word-3 bg-surface-1\">\n <div\n v-if=\"toolPart.input?.title\"\n class=\"px-sm py-10 font-bold\"\n :class=\"{\n 'border-b border-surface-3':\n isInteractive && steps.length > 1,\n }\">\n {{ toolPart.input?.title }}\n </div>\n <!-- Progress for multi-step -->\n <div\n v-if=\"isInteractive && steps.length > 1\"\n class=\"flex flex-col gap-4 p-sm\">\n <div class=\"flex justify-between text-10 text-word-3\">\n <span>\n {{\n $t('showForm.step', {\n current: currentStepIndex + 1,\n total: steps.length,\n })\n }}\n </span>\n <span>{{ progress }}%</span>\n </div>\n <div class=\"h-4 bg-surface-3 rounded-full overflow-hidden\">\n <div\n class=\"h-full bg-word-4 transition-all duration-300\"\n :style=\"{ width: `${progress}%` }\"></div>\n </div>\n </div>\n </div>\n\n <!-- Input Available State -->\n <template v-if=\"isInteractive\">\n <!-- Current Step Content -->\n <div class=\"px-sm py-16 flex flex-col gap-12\">\n <div class=\"leading-normal text-12\">\n <strong class=\"font-semibold\">\n {{ currentStep.question }}\n </strong>\n <PkStreamingMarkdown\n v-if=\"currentStep.message\"\n :markdown=\"currentStep.message\"\n class=\"text-word-2 mt-4\" />\n </div>\n\n <!-- Checkbox list for multi-select -->\n <PkEditorCheckboxButtons\n v-if=\"currentStep.options && currentStep.multiSelect\"\n v-model=\"activeCheckboxValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n class=\"mb-0\"\n vertical>\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorCheckboxButtons>\n\n <!-- Radio buttons for single-select -->\n <PkEditorRadioButtons\n v-else-if=\"currentStep.options && !currentStep.multiSelect\"\n v-model=\"scalarValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n vertical\n class=\"mb-0\"\n @update:model-value=\"onRadioChange\">\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorRadioButtons>\n\n <!-- Pure Freeform Input (text, number, date) -->\n <div\n v-else-if=\"!currentStep.options\"\n class=\"flex flex-col gap-6 w-full\">\n <VvInputText\n :key=\"currentStep.id\"\n v-model=\"scalarValue\"\n :placeholder=\"\n currentStep.placeholder || $t('placeholder.insert')\n \"\n :type=\"currentStep.type\"\n class=\"w-full\"\n :name=\"currentStep.id\"\n modifiers=\"compact\"\n :disabled=\"!isInteractive\"\n @keyup.enter=\"goNext\" />\n </div>\n </div>\n\n <!-- Custom footer freeform input (shown alongside options when allowFreeformInput) -->\n <div\n v-if=\"currentStep.allowFreeformInput && currentStep.options\"\n class=\"px-sm pb-sm border-t border-surface-3\">\n <form\n class=\"flex gap-xs pt-sm\"\n @submit.prevent=\"submitCustomAnswer\">\n <VvInputText\n :key=\"`${currentStep.id}-custom`\"\n v-model=\"customAnswer\"\n class=\"flex-1\"\n :name=\"`${currentStep.id}-custom`\"\n modifiers=\"compact\"\n :disabled=\"!isInteractive\"\n :placeholder=\"\n currentStep.placeholder ||\n $t('showForm.otherPlaceholder')\n \" />\n </form>\n </div>\n\n <!-- Footer navigation: shown for every step that does not submit\n itself on option pick (see `isSelfSubmitting`). -->\n <div\n v-if=\"!isSelfSubmitting\"\n class=\"px-sm py-10 bg-surface border-t border-surface-3 flex justify-between gap-12\">\n <VvButton\n v-if=\"canGoBack\"\n modifiers=\"action-quiet\"\n icon=\"ri:arrow-left-s-line\"\n :label=\"$t('action.back')\"\n @click.stop=\"goBack\" />\n <div v-else></div>\n\n <VvButton\n :modifiers=\"canGoNext ? 'action-quiet' : 'action-primary'\"\n :icon=\"\n canGoNext\n ? 'ri:arrow-right-s-line'\n : 'ri:send-plane-2-line'\n \"\n icon-position=\"right\"\n :label=\"canGoNext ? $t('action.next') : $t('action.submit')\"\n @click.stop=\"goNext\" />\n </div>\n </template>\n\n <!-- Output Available State (Multi-step Summary) -->\n <template v-else>\n <div class=\"px-sm py-12 bg-surface space-y-10\">\n <ul class=\"flex flex-col gap-8\">\n <li\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n class=\"leading-normal\">\n <div class=\"text-12 text-word-3\">\n {{ step.question }}\n </div>\n <span class=\"text-12 text-word-2 font-semibold\">\n {{ getSummaryValue(step, index) }}\n </span>\n </li>\n </ul>\n </div>\n <div\n class=\"px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div class=\"flex flex-col\">\n <span class=\"font-medium text-12 text-word-1 leading-tight\">\n {{ $t('showForm.completed') }}\n </span>\n </div>\n </div>\n </template>\n </div>\n</template>\n"],"mappings":"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"}