@orbe-agro/client-core 5.6.259 → 5.6.261

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 (98) hide show
  1. package/dist/@ecme/assets/styles/app.css +23 -3
  2. package/dist/@ecme/assets/styles/tailwind/index.css +25 -3
  3. package/dist/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.js +2 -1
  4. package/dist/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.js.map +1 -1
  5. package/dist/@ecme/components/template/Footer.js +1 -1
  6. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.js +121 -0
  7. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.js.map +1 -0
  8. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js +47 -18
  9. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js.map +1 -1
  10. package/dist/@ecme/components/template/OrbeAiWidget/useResizablePanel.js +45 -31
  11. package/dist/@ecme/components/template/OrbeAiWidget/useResizablePanel.js.map +1 -1
  12. package/dist/@ecme/components/ui/Dropdown/DropdownMenu.js +5 -1
  13. package/dist/@ecme/components/ui/Dropdown/DropdownMenu.js.map +1 -1
  14. package/dist/@ecme/index.js +4 -1
  15. package/dist/@ecme/services/AiService.js +22 -0
  16. package/dist/@ecme/services/AiService.js.map +1 -1
  17. package/dist/@ecme/services/index.js +4 -1
  18. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistory.js +9 -23
  19. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistory.js.map +1 -1
  20. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.js +6 -16
  21. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.js.map +1 -1
  22. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.js +10 -7
  23. package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.js.map +1 -1
  24. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js +6 -4
  25. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js.map +1 -1
  26. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.js +83 -0
  27. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.js.map +1 -0
  28. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js +3 -2
  29. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js.map +1 -1
  30. package/dist/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.js +37 -0
  31. package/dist/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.js.map +1 -0
  32. package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js +25 -1
  33. package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js.map +1 -1
  34. package/dist/@ecme/views/concepts/ai/Chat/utils.js +16 -1
  35. package/dist/@ecme/views/concepts/ai/Chat/utils.js.map +1 -1
  36. package/dist/@types/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.d.ts.map +1 -1
  37. package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.d.ts +14 -0
  38. package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.d.ts.map +1 -0
  39. package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.d.ts.map +1 -1
  40. package/dist/@types/@ecme/components/template/OrbeAiWidget/useResizablePanel.d.ts +12 -5
  41. package/dist/@types/@ecme/components/template/OrbeAiWidget/useResizablePanel.d.ts.map +1 -1
  42. package/dist/@types/@ecme/components/ui/Dropdown/DropdownMenu.d.ts +2 -0
  43. package/dist/@types/@ecme/components/ui/Dropdown/DropdownMenu.d.ts.map +1 -1
  44. package/dist/@types/@ecme/services/AiService.d.ts +5 -0
  45. package/dist/@types/@ecme/services/AiService.d.ts.map +1 -1
  46. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistory.d.ts +3 -1
  47. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistory.d.ts.map +1 -1
  48. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.d.ts +1 -1
  49. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.d.ts.map +1 -1
  50. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.d.ts +5 -1
  51. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.d.ts.map +1 -1
  52. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts +8 -1
  53. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts.map +1 -1
  54. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.d.ts +12 -0
  55. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.d.ts.map +1 -0
  56. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts.map +1 -1
  57. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.d.ts +12 -0
  58. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.d.ts.map +1 -0
  59. package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts +4 -0
  60. package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts.map +1 -1
  61. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts +24 -0
  62. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts.map +1 -1
  63. package/dist/@types/@ecme/views/concepts/ai/Chat/utils.d.ts +13 -0
  64. package/dist/@types/@ecme/views/concepts/ai/Chat/utils.d.ts.map +1 -1
  65. package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts +8 -0
  66. package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts.map +1 -1
  67. package/dist/@types/base/configs/endpoints.config/transportadora/contratoFrete.d.ts +8 -0
  68. package/dist/@types/base/configs/endpoints.config/transportadora/contratoFrete.d.ts.map +1 -1
  69. package/dist/@types/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.d.ts +2 -0
  70. package/dist/@types/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.d.ts.map +1 -1
  71. package/dist/base/assets/styles/init.css +23 -4
  72. package/dist/base/configs/endpoints.config/transportadora/contratoFrete.js +3 -1
  73. package/dist/base/configs/endpoints.config/transportadora/contratoFrete.js.map +1 -1
  74. package/dist/base/index.js +3 -1
  75. package/dist/base/services/index.js +3 -1
  76. package/dist/base/services/modules/index.js +3 -1
  77. package/dist/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.js +14 -0
  78. package/dist/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.js.map +1 -1
  79. package/dist/base/services/modules/transportadora/index.js +3 -1
  80. package/lib/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.tsx +4 -1
  81. package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.tsx +140 -0
  82. package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx +48 -16
  83. package/lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts +72 -37
  84. package/lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx +7 -1
  85. package/lib/@ecme/services/AiService.ts +24 -0
  86. package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx +11 -27
  87. package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx +7 -13
  88. package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx +17 -8
  89. package/lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx +17 -4
  90. package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.tsx +128 -0
  91. package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts +3 -2
  92. package/lib/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.ts +68 -0
  93. package/lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts +44 -1
  94. package/lib/@ecme/views/concepts/ai/Chat/types.ts +28 -0
  95. package/lib/@ecme/views/concepts/ai/Chat/utils.ts +33 -0
  96. package/lib/base/configs/endpoints.config/transportadora/contratoFrete.ts +2 -0
  97. package/lib/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.ts +14 -0
  98. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useResizablePanel.js","sources":["../../../../../lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts"],"sourcesContent":["import { useCallback, useState } from 'react'\nimport type { PointerEvent as ReactPointerEvent } from 'react'\n\nexport type Rect = { top: number; left: number; width: number; height: number }\n\nexport type ResizeDirection =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\nconst MIN = { width: 360, height: 420 }\nconst DEFAULT = { width: 480, height: 720 }\nconst MARGIN = 12 // distância mínima das bordas do viewport\nconst ANCHOR = { right: 24, bottomOffset: 92 } // canto inferior-direito, acima do FAB\n\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(Math.max(value, min), max)\n\n/** Retângulo inicial: ancorado no canto inferior-direito, logo acima do FAB. */\nconst getDefaultRect = (): Rect => {\n const width = Math.min(DEFAULT.width, window.innerWidth - MARGIN * 2)\n const height = Math.min(DEFAULT.height, window.innerHeight - MARGIN * 2)\n return {\n width,\n height,\n left: Math.max(MARGIN, window.innerWidth - width - ANCHOR.right),\n top: Math.max(MARGIN, window.innerHeight - height - ANCHOR.bottomOffset),\n }\n}\n\n/**\n * Painel redimensionável por qualquer borda/canto. O painel é posicionado\n * livremente (`fixed` com top/left/width/height); cada direção move sua borda\n * mantendo a borda oposta fixa, com limites de mínimo e do viewport.\n */\nconst useResizablePanel = () => {\n const [rect, setRect] = useState<Rect>(getDefaultRect)\n\n const startResize = useCallback(\n (event: ReactPointerEvent, direction: ResizeDirection) => {\n event.preventDefault()\n event.stopPropagation()\n\n const startX = event.clientX\n const startY = event.clientY\n const start = rect\n const right = start.left + start.width\n const bottom = start.top + start.height\n\n const previousUserSelect = document.body.style.userSelect\n document.body.style.userSelect = 'none'\n\n const handleMove = (moveEvent: PointerEvent) => {\n const dx = moveEvent.clientX - startX\n const dy = moveEvent.clientY - startY\n const next: Rect = { ...start }\n\n if (direction.includes('right')) {\n next.width = clamp(\n start.width + dx,\n MIN.width,\n window.innerWidth - start.left - MARGIN,\n )\n }\n if (direction.includes('left')) {\n next.width = clamp(start.width - dx, MIN.width, right - MARGIN)\n next.left = right - next.width\n }\n if (direction.includes('bottom')) {\n next.height = clamp(\n start.height + dy,\n MIN.height,\n window.innerHeight - start.top - MARGIN,\n )\n }\n if (direction.includes('top')) {\n next.height = clamp(\n start.height - dy,\n MIN.height,\n bottom - MARGIN,\n )\n next.top = bottom - next.height\n }\n\n setRect(next)\n }\n\n const stopResize = () => {\n document.body.style.userSelect = previousUserSelect\n window.removeEventListener('pointermove', handleMove)\n window.removeEventListener('pointerup', stopResize)\n }\n\n window.addEventListener('pointermove', handleMove)\n window.addEventListener('pointerup', stopResize)\n },\n [rect],\n )\n\n return { rect, startResize }\n}\n\nexport default useResizablePanel\n"],"names":[],"mappings":";AAeA,MAAM,MAAM,EAAE,OAAO,KAAK,QAAQ,IAAA;AAClC,MAAM,UAAU,EAAE,OAAO,KAAK,QAAQ,IAAA;AACtC,MAAM,SAAS;AACf,MAAM,SAAS,EAAE,OAAO,IAAI,cAAc,GAAA;AAE1C,MAAM,QAAQ,CAAC,OAAe,KAAa,QACvC,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAGtC,MAAM,iBAAiB,MAAY;AAC/B,QAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,OAAO,aAAa,SAAS,CAAC;AACpE,QAAM,SAAS,KAAK,IAAI,QAAQ,QAAQ,OAAO,cAAc,SAAS,CAAC;AACvE,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,MAAM,KAAK,IAAI,QAAQ,OAAO,aAAa,QAAQ,OAAO,KAAK;AAAA,IAC/D,KAAK,KAAK,IAAI,QAAQ,OAAO,cAAc,SAAS,OAAO,YAAY;AAAA,EAAA;AAE/E;AAOA,MAAM,oBAAoB,MAAM;AAC5B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAe,cAAc;AAErD,QAAM,cAAc;AAAA,IAChB,CAAC,OAA0B,cAA+B;AACtD,YAAM,eAAA;AACN,YAAM,gBAAA;AAEN,YAAM,SAAS,MAAM;AACrB,YAAM,SAAS,MAAM;AACrB,YAAM,QAAQ;AACd,YAAM,QAAQ,MAAM,OAAO,MAAM;AACjC,YAAM,SAAS,MAAM,MAAM,MAAM;AAEjC,YAAM,qBAAqB,SAAS,KAAK,MAAM;AAC/C,eAAS,KAAK,MAAM,aAAa;AAEjC,YAAM,aAAa,CAAC,cAA4B;AAC5C,cAAM,KAAK,UAAU,UAAU;AAC/B,cAAM,KAAK,UAAU,UAAU;AAC/B,cAAM,OAAa,EAAE,GAAG,MAAA;AAExB,YAAI,UAAU,SAAS,OAAO,GAAG;AAC7B,eAAK,QAAQ;AAAA,YACT,MAAM,QAAQ;AAAA,YACd,IAAI;AAAA,YACJ,OAAO,aAAa,MAAM,OAAO;AAAA,UAAA;AAAA,QAEzC;AACA,YAAI,UAAU,SAAS,MAAM,GAAG;AAC5B,eAAK,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,OAAO,QAAQ,MAAM;AAC9D,eAAK,OAAO,QAAQ,KAAK;AAAA,QAC7B;AACA,YAAI,UAAU,SAAS,QAAQ,GAAG;AAC9B,eAAK,SAAS;AAAA,YACV,MAAM,SAAS;AAAA,YACf,IAAI;AAAA,YACJ,OAAO,cAAc,MAAM,MAAM;AAAA,UAAA;AAAA,QAEzC;AACA,YAAI,UAAU,SAAS,KAAK,GAAG;AAC3B,eAAK,SAAS;AAAA,YACV,MAAM,SAAS;AAAA,YACf,IAAI;AAAA,YACJ,SAAS;AAAA,UAAA;AAEb,eAAK,MAAM,SAAS,KAAK;AAAA,QAC7B;AAEA,gBAAQ,IAAI;AAAA,MAChB;AAEA,YAAM,aAAa,MAAM;AACrB,iBAAS,KAAK,MAAM,aAAa;AACjC,eAAO,oBAAoB,eAAe,UAAU;AACpD,eAAO,oBAAoB,aAAa,UAAU;AAAA,MACtD;AAEA,aAAO,iBAAiB,eAAe,UAAU;AACjD,aAAO,iBAAiB,aAAa,UAAU;AAAA,IACnD;AAAA,IACA,CAAC,IAAI;AAAA,EAAA;AAGT,SAAO,EAAE,MAAM,YAAA;AACnB;"}
1
+ {"version":3,"file":"useResizablePanel.js","sources":["../../../../../lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport type { PointerEvent as ReactPointerEvent } from 'react'\n\n/**\n * `right`/`bottom` são offsets a partir das bordas direita/inferior do\n * viewport — a mesma referência do botão (FAB, `bottom-6 right-6`). Assim,\n * resolução e zoom movem painel e botão juntos.\n */\nexport type Rect = { right: number; bottom: number; width: number; height: number }\n\nexport type ResizeDirection =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\nconst MIN = { width: 360, height: 420 }\nconst DEFAULT = { width: 480, height: 720 }\nexport const MARGIN = 12 // distância mínima das bordas do viewport\n\n/**\n * Canto inferior-direito do painel, logo acima do FAB:\n * right = `right-6` (24); bottom = `bottom-6` (24) + `h-14` (56) + `gap-3` (12).\n * Se as classes do botão no OrbeAiWidget mudarem, ajustar aqui.\n */\nconst ANCHOR = { right: 24, bottom: 92 }\n\n/** Em telas menores que o MIN o máximo vence: o painel nunca sai da tela. */\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(Math.max(value, min), max)\n\n/** Área útil do `fixed`: o viewport sem a barra de rolagem, igual ao `100%` do CSS. */\nconst getViewport = () => ({\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n})\n\n/**\n * Painel redimensionável por qualquer borda/canto, ancorado no botão. Cada\n * direção move sua borda mantendo a oposta fixa. O tamanho nunca é alterado\n * por mudança de viewport: quem limita é o max-width/max-height do painel.\n */\nconst useResizablePanel = () => {\n const [rect, setRect] = useState<Rect>({ ...ANCHOR, ...DEFAULT })\n\n /** Recola o painel acima do botão, mantendo o tamanho escolhido. */\n const anchor = useCallback(() => {\n setRect((prev) =>\n prev.right === ANCHOR.right && prev.bottom === ANCHOR.bottom\n ? prev\n : { ...prev, ...ANCHOR },\n )\n }, [])\n\n // Resolução e zoom disparam `resize`: o painel volta para cima do botão.\n useEffect(() => {\n window.addEventListener('resize', anchor)\n return () => window.removeEventListener('resize', anchor)\n }, [anchor])\n\n const startResize = useCallback(\n (event: ReactPointerEvent, direction: ResizeDirection) => {\n event.preventDefault()\n event.stopPropagation()\n\n const startX = event.clientX\n const startY = event.clientY\n const viewport = getViewport()\n // Parte do tamanho RENDERIZADO: se o CSS está limitando o painel, o\n // valor guardado é maior que o visível e o arrasto teria zona morta.\n const start: Rect = {\n ...rect,\n width: Math.min(rect.width, viewport.width - rect.right - MARGIN),\n height: Math.min(\n rect.height,\n viewport.height - rect.bottom - MARGIN,\n ),\n }\n\n const previousUserSelect = document.body.style.userSelect\n document.body.style.userSelect = 'none'\n\n const handleMove = (moveEvent: PointerEvent) => {\n const dx = moveEvent.clientX - startX\n const dy = moveEvent.clientY - startY\n const next: Rect = { ...start }\n\n // Esquerda/topo: a borda ancorada fica fixa, só o tamanho muda.\n if (direction.includes('left')) {\n next.width = clamp(\n start.width - dx,\n MIN.width,\n viewport.width - start.right - MARGIN,\n )\n }\n if (direction.includes('top')) {\n next.height = clamp(\n start.height - dy,\n MIN.height,\n viewport.height - start.bottom - MARGIN,\n )\n }\n // Direita/baixo: a borda oposta fica fixa, então o offset anda junto.\n if (direction.includes('right')) {\n next.width = clamp(\n start.width + dx,\n MIN.width,\n start.width + start.right - MARGIN,\n )\n next.right = start.right - (next.width - start.width)\n }\n if (direction.includes('bottom')) {\n next.height = clamp(\n start.height + dy,\n MIN.height,\n start.height + start.bottom - MARGIN,\n )\n next.bottom = start.bottom - (next.height - start.height)\n }\n\n setRect(next)\n }\n\n const stopResize = () => {\n document.body.style.userSelect = previousUserSelect\n window.removeEventListener('pointermove', handleMove)\n window.removeEventListener('pointerup', stopResize)\n }\n\n window.addEventListener('pointermove', handleMove)\n window.addEventListener('pointerup', stopResize)\n },\n [rect],\n )\n\n return { rect, startResize, anchor }\n}\n\nexport default useResizablePanel\n"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ const DropdownMenu = (props) => {
15
15
  disabled,
16
16
  toggleClassName,
17
17
  menuClass,
18
+ floatingClass,
18
19
  placement,
19
20
  trigger = "click",
20
21
  onOpen,
@@ -216,7 +217,10 @@ const DropdownMenu = (props) => {
216
217
  ref: refs.setFloating,
217
218
  style: floatingStyles,
218
219
  ...getFloatingProps(),
219
- className: "outline-none z-30",
220
+ className: classNames(
221
+ "outline-none z-30",
222
+ floatingClass
223
+ ),
220
224
  children: /* @__PURE__ */ jsx(
221
225
  "ul",
222
226
  {
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.js","sources":["../../../../../lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx"],"sourcesContent":["import {\n useState,\n useRef,\n useContext,\n useEffect,\n useImperativeHandle,\n} from 'react'\nimport DropdownToggle from './DropdownToggle'\nimport DropdownSubItem from './DropdownSubItem'\nimport MenuContext from './context/menuContext'\nimport classNames from '../utils/classNames'\nimport { useConfig } from '../ConfigProvider'\nimport {\n autoUpdate,\n flip,\n FloatingFocusManager,\n FloatingList,\n FloatingNode,\n FloatingPortal,\n safePolygon,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListItem,\n useListNavigation,\n useMergeRefs,\n useRole,\n useTypeahead,\n useTransitionStyles,\n} from '@floating-ui/react'\nimport type { CommonProps } from '../@types/common'\nimport type { DropdownToggleSharedProps } from './DropdownToggle'\nimport type { DropdownSubItemSharedProps } from './DropdownSubItem'\nimport type { Placement } from '@floating-ui/react'\nimport type { HTMLProps, FocusEvent, MouseEvent, ReactNode, Ref } from 'react'\n\nexport interface DropdownMenuProps\n extends CommonProps,\n DropdownToggleSharedProps,\n DropdownSubItemSharedProps {\n activeKey?: string\n title?: string | ReactNode\n menuClass?: string\n trigger?: 'click' | 'hover' | 'context'\n placement?: Placement\n onOpen?: (bool: boolean) => void\n ref?: Ref<HTMLElement | DropdownMenuRef>\n}\n\nexport type DropdownMenuRef = {\n handleDropdownOpen: () => void\n handleDropdownClose: () => void\n}\n\nconst DropdownMenu = (props: DropdownMenuProps & HTMLProps<HTMLElement>) => {\n const {\n children,\n title,\n renderTitle,\n disabled,\n toggleClassName,\n menuClass,\n placement,\n trigger = 'click',\n onOpen,\n ref,\n ...rest\n } = props\n\n const [isOpen, setIsOpen] = useState(false)\n const [hasFocusInside, setHasFocusInside] = useState(false)\n const [activeIndex, setActiveIndex] = useState<number | null>(null)\n\n const elementsRef = useRef<Array<HTMLElement | null>>([])\n const labelsRef = useRef<Array<string | null>>([])\n\n const { direction } = useConfig()\n\n const parent = useContext(MenuContext)\n\n const tree = useFloatingTree()\n const nodeId = useFloatingNodeId()\n const parentId = useFloatingParentNodeId()\n const item = useListItem()\n\n const isNested = parentId != null\n\n const handleOpen = (open: boolean) => {\n if (disabled) {\n return\n }\n setIsOpen(open)\n onOpen?.(open)\n }\n\n const getDefaultPlacement = () => {\n return direction === 'ltr' ? 'bottom-start' : 'bottom-end'\n }\n\n const getNestedDefaultPlacement = () => {\n return direction === 'ltr' ? 'right-start' : 'left-start'\n }\n\n const { floatingStyles, refs, context } = useFloating<HTMLElement>({\n nodeId,\n open: isOpen,\n onOpenChange: (open) => {\n handleOpen(open)\n },\n placement:\n placement ||\n (isNested ? getNestedDefaultPlacement() : getDefaultPlacement()),\n middleware: [flip(), shift()],\n whileElementsMounted: autoUpdate,\n })\n\n const { isMounted, styles } = useTransitionStyles(context, {\n common: ({ side }) => ({\n transformOrigin: {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n }[side],\n }),\n initial: {\n transform: 'translateY(-5%)',\n opacity: 0,\n },\n duration: 200,\n open: {\n opacity: 1,\n transform: 'translateY(0%)',\n },\n close: {\n opacity: 0,\n transform: 'translateY(-5%)',\n },\n })\n\n const hover = useHover(context, {\n enabled: isNested || trigger === 'hover',\n delay: { open: 75 },\n handleClose: safePolygon({ blockPointerEvents: true }),\n })\n\n const click = useClick(context, {\n event: 'mousedown',\n toggle: !isNested,\n ignoreMouse: isNested,\n })\n\n const role = useRole(context, { role: 'menu' })\n\n const dismiss = useDismiss(context, { bubbles: true })\n\n const listNavigation = useListNavigation(context, {\n listRef: elementsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n })\n const typeahead = useTypeahead(context, {\n listRef: labelsRef,\n onMatch: isOpen ? setActiveIndex : undefined,\n activeIndex,\n })\n\n const { getReferenceProps, getFloatingProps, getItemProps } =\n useInteractions([\n hover,\n role,\n dismiss,\n listNavigation,\n typeahead,\n ...(trigger === 'click' ? [click] : []),\n ])\n\n useEffect(() => {\n if (!tree) return\n\n function handleTreeClick() {\n setIsOpen(false)\n onOpen?.(false)\n }\n\n function onSubMenuOpen(event: { nodeId: string; parentId: string }) {\n if (event.nodeId !== nodeId && event.parentId === parentId) {\n setIsOpen(false)\n onOpen?.(false)\n }\n }\n\n tree.events.on('click', handleTreeClick)\n tree.events.on('menuopen', onSubMenuOpen)\n\n return () => {\n tree.events.off('click', handleTreeClick)\n tree.events.off('menuopen', onSubMenuOpen)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [tree, nodeId, parentId])\n\n useEffect(() => {\n if (isOpen && tree) {\n tree.events.emit('menuopen', { parentId, nodeId })\n }\n }, [tree, isOpen, nodeId, parentId])\n\n const toggleRef = useMergeRefs([refs.setReference, item.ref, ref])\n\n useImperativeHandle(ref, () => {\n return {\n handleDropdownOpen: () => {\n setIsOpen(true)\n onOpen?.(true)\n },\n handleDropdownClose: () => {\n setIsOpen(false)\n onOpen?.(false)\n },\n }\n }, [onOpen])\n\n const toggleProps = {\n ...getReferenceProps(\n parent.getItemProps({\n ...rest,\n onFocus(event: FocusEvent<HTMLElement>) {\n rest.onFocus?.(event)\n setHasFocusInside(false)\n parent.setHasFocusInside(true)\n },\n }),\n ),\n ...(trigger === 'context'\n ? {\n onContextMenu: (e: MouseEvent<HTMLElement>) => {\n e.preventDefault()\n handleOpen(true)\n },\n }\n : {}),\n }\n\n return (\n <FloatingNode id={nodeId}>\n {!isNested ? (\n <DropdownToggle\n ref={toggleRef}\n role={'menuitem'}\n data-open={isOpen ? '' : undefined}\n data-focus-inside={hasFocusInside ? '' : undefined}\n className={classNames(toggleClassName)}\n disabled={disabled}\n placement={placement}\n renderTitle={renderTitle}\n {...toggleProps}\n >\n {title}\n </DropdownToggle>\n ) : (\n <li\n ref={toggleRef}\n tabIndex={parent.activeIndex === item.index ? 0 : -1}\n data-open={isOpen ? '' : undefined}\n data-nested={''}\n data-focus-inside={hasFocusInside ? '' : undefined}\n className={classNames(toggleClassName, 'outline-none')}\n {...toggleProps}\n >\n <DropdownSubItem>\n {renderTitle ? renderTitle : title}\n </DropdownSubItem>\n </li>\n )}\n <MenuContext.Provider\n value={{\n activeIndex,\n setActiveIndex,\n getItemProps,\n setHasFocusInside,\n isOpen,\n }}\n >\n <FloatingList elementsRef={elementsRef} labelsRef={labelsRef}>\n {isMounted && (\n <FloatingPortal>\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={isNested ? -1 : 0}\n returnFocus={!isNested}\n >\n <div\n ref={refs.setFloating}\n style={floatingStyles}\n {...getFloatingProps()}\n className=\"outline-none z-30\"\n >\n <ul\n className={classNames(\n 'dropdown-menu min-w-[160px]',\n menuClass,\n )}\n style={styles}\n >\n {children}\n </ul>\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n )}\n </FloatingList>\n </MenuContext.Provider>\n </FloatingNode>\n )\n}\n\nexport default DropdownMenu\n"],"names":["DropdownSubItem"],"mappings":"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"}
1
+ {"version":3,"file":"DropdownMenu.js","sources":["../../../../../lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx"],"sourcesContent":["import {\n useState,\n useRef,\n useContext,\n useEffect,\n useImperativeHandle,\n} from 'react'\nimport DropdownToggle from './DropdownToggle'\nimport DropdownSubItem from './DropdownSubItem'\nimport MenuContext from './context/menuContext'\nimport classNames from '../utils/classNames'\nimport { useConfig } from '../ConfigProvider'\nimport {\n autoUpdate,\n flip,\n FloatingFocusManager,\n FloatingList,\n FloatingNode,\n FloatingPortal,\n safePolygon,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListItem,\n useListNavigation,\n useMergeRefs,\n useRole,\n useTypeahead,\n useTransitionStyles,\n} from '@floating-ui/react'\nimport type { CommonProps } from '../@types/common'\nimport type { DropdownToggleSharedProps } from './DropdownToggle'\nimport type { DropdownSubItemSharedProps } from './DropdownSubItem'\nimport type { Placement } from '@floating-ui/react'\nimport type { HTMLProps, FocusEvent, MouseEvent, ReactNode, Ref } from 'react'\n\nexport interface DropdownMenuProps\n extends CommonProps,\n DropdownToggleSharedProps,\n DropdownSubItemSharedProps {\n activeKey?: string\n title?: string | ReactNode\n menuClass?: string\n /** Classes do wrapper flutuante (portal). Útil para subir o z-index acima de painéis fixos. */\n floatingClass?: string\n trigger?: 'click' | 'hover' | 'context'\n placement?: Placement\n onOpen?: (bool: boolean) => void\n ref?: Ref<HTMLElement | DropdownMenuRef>\n}\n\nexport type DropdownMenuRef = {\n handleDropdownOpen: () => void\n handleDropdownClose: () => void\n}\n\nconst DropdownMenu = (props: DropdownMenuProps & HTMLProps<HTMLElement>) => {\n const {\n children,\n title,\n renderTitle,\n disabled,\n toggleClassName,\n menuClass,\n floatingClass,\n placement,\n trigger = 'click',\n onOpen,\n ref,\n ...rest\n } = props\n\n const [isOpen, setIsOpen] = useState(false)\n const [hasFocusInside, setHasFocusInside] = useState(false)\n const [activeIndex, setActiveIndex] = useState<number | null>(null)\n\n const elementsRef = useRef<Array<HTMLElement | null>>([])\n const labelsRef = useRef<Array<string | null>>([])\n\n const { direction } = useConfig()\n\n const parent = useContext(MenuContext)\n\n const tree = useFloatingTree()\n const nodeId = useFloatingNodeId()\n const parentId = useFloatingParentNodeId()\n const item = useListItem()\n\n const isNested = parentId != null\n\n const handleOpen = (open: boolean) => {\n if (disabled) {\n return\n }\n setIsOpen(open)\n onOpen?.(open)\n }\n\n const getDefaultPlacement = () => {\n return direction === 'ltr' ? 'bottom-start' : 'bottom-end'\n }\n\n const getNestedDefaultPlacement = () => {\n return direction === 'ltr' ? 'right-start' : 'left-start'\n }\n\n const { floatingStyles, refs, context } = useFloating<HTMLElement>({\n nodeId,\n open: isOpen,\n onOpenChange: (open) => {\n handleOpen(open)\n },\n placement:\n placement ||\n (isNested ? getNestedDefaultPlacement() : getDefaultPlacement()),\n middleware: [flip(), shift()],\n whileElementsMounted: autoUpdate,\n })\n\n const { isMounted, styles } = useTransitionStyles(context, {\n common: ({ side }) => ({\n transformOrigin: {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n }[side],\n }),\n initial: {\n transform: 'translateY(-5%)',\n opacity: 0,\n },\n duration: 200,\n open: {\n opacity: 1,\n transform: 'translateY(0%)',\n },\n close: {\n opacity: 0,\n transform: 'translateY(-5%)',\n },\n })\n\n const hover = useHover(context, {\n enabled: isNested || trigger === 'hover',\n delay: { open: 75 },\n handleClose: safePolygon({ blockPointerEvents: true }),\n })\n\n const click = useClick(context, {\n event: 'mousedown',\n toggle: !isNested,\n ignoreMouse: isNested,\n })\n\n const role = useRole(context, { role: 'menu' })\n\n const dismiss = useDismiss(context, { bubbles: true })\n\n const listNavigation = useListNavigation(context, {\n listRef: elementsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n })\n const typeahead = useTypeahead(context, {\n listRef: labelsRef,\n onMatch: isOpen ? setActiveIndex : undefined,\n activeIndex,\n })\n\n const { getReferenceProps, getFloatingProps, getItemProps } =\n useInteractions([\n hover,\n role,\n dismiss,\n listNavigation,\n typeahead,\n ...(trigger === 'click' ? [click] : []),\n ])\n\n useEffect(() => {\n if (!tree) return\n\n function handleTreeClick() {\n setIsOpen(false)\n onOpen?.(false)\n }\n\n function onSubMenuOpen(event: { nodeId: string; parentId: string }) {\n if (event.nodeId !== nodeId && event.parentId === parentId) {\n setIsOpen(false)\n onOpen?.(false)\n }\n }\n\n tree.events.on('click', handleTreeClick)\n tree.events.on('menuopen', onSubMenuOpen)\n\n return () => {\n tree.events.off('click', handleTreeClick)\n tree.events.off('menuopen', onSubMenuOpen)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [tree, nodeId, parentId])\n\n useEffect(() => {\n if (isOpen && tree) {\n tree.events.emit('menuopen', { parentId, nodeId })\n }\n }, [tree, isOpen, nodeId, parentId])\n\n const toggleRef = useMergeRefs([refs.setReference, item.ref, ref])\n\n useImperativeHandle(ref, () => {\n return {\n handleDropdownOpen: () => {\n setIsOpen(true)\n onOpen?.(true)\n },\n handleDropdownClose: () => {\n setIsOpen(false)\n onOpen?.(false)\n },\n }\n }, [onOpen])\n\n const toggleProps = {\n ...getReferenceProps(\n parent.getItemProps({\n ...rest,\n onFocus(event: FocusEvent<HTMLElement>) {\n rest.onFocus?.(event)\n setHasFocusInside(false)\n parent.setHasFocusInside(true)\n },\n }),\n ),\n ...(trigger === 'context'\n ? {\n onContextMenu: (e: MouseEvent<HTMLElement>) => {\n e.preventDefault()\n handleOpen(true)\n },\n }\n : {}),\n }\n\n return (\n <FloatingNode id={nodeId}>\n {!isNested ? (\n <DropdownToggle\n ref={toggleRef}\n role={'menuitem'}\n data-open={isOpen ? '' : undefined}\n data-focus-inside={hasFocusInside ? '' : undefined}\n className={classNames(toggleClassName)}\n disabled={disabled}\n placement={placement}\n renderTitle={renderTitle}\n {...toggleProps}\n >\n {title}\n </DropdownToggle>\n ) : (\n <li\n ref={toggleRef}\n tabIndex={parent.activeIndex === item.index ? 0 : -1}\n data-open={isOpen ? '' : undefined}\n data-nested={''}\n data-focus-inside={hasFocusInside ? '' : undefined}\n className={classNames(toggleClassName, 'outline-none')}\n {...toggleProps}\n >\n <DropdownSubItem>\n {renderTitle ? renderTitle : title}\n </DropdownSubItem>\n </li>\n )}\n <MenuContext.Provider\n value={{\n activeIndex,\n setActiveIndex,\n getItemProps,\n setHasFocusInside,\n isOpen,\n }}\n >\n <FloatingList elementsRef={elementsRef} labelsRef={labelsRef}>\n {isMounted && (\n <FloatingPortal>\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={isNested ? -1 : 0}\n returnFocus={!isNested}\n >\n <div\n ref={refs.setFloating}\n style={floatingStyles}\n {...getFloatingProps()}\n className={classNames(\n 'outline-none z-30',\n floatingClass,\n )}\n >\n <ul\n className={classNames(\n 'dropdown-menu min-w-[160px]',\n menuClass,\n )}\n style={styles}\n >\n {children}\n </ul>\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n )}\n </FloatingList>\n </MenuContext.Provider>\n </FloatingNode>\n )\n}\n\nexport default DropdownMenu\n"],"names":["DropdownSubItem"],"mappings":"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"}
@@ -10,7 +10,7 @@ import "./auth/index.js";
10
10
  import "./assets/index.js";
11
11
  import "./locales/index.js";
12
12
  import { ADMIN, USER } from "./constants/roles.constant.js";
13
- import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./services/AiService.js";
13
+ import { AI_API_URL, apiDeleteConversation, apiGetChatHistory, apiGetConversations, apiGetImages, apiPostImages, apiRenameConversation, resumeChat, streamChat } from "./services/AiService.js";
14
14
  import { APP_NAME, REDIRECT_URL_KEY } from "./constants/app.constant.js";
15
15
  import { AUTH_PREFIX_PATH, CONCEPTS_PREFIX_PATH, DASHBOARDS_PREFIX_PATH, GUIDE_PREFIX_PATH, PAGES_PREFIX_PATH, ROOT, UI_COMPONENTS_PREFIX_PATH } from "./constants/route.constant.js";
16
16
  import { default as default2 } from "./components/shared/AbbreviateNumber.js";
@@ -374,6 +374,7 @@ export {
374
374
  default102 as UsersAvatarGroup,
375
375
  default103 as Views,
376
376
  default104 as acronym,
377
+ apiDeleteConversation,
377
378
  apiForgotPassword,
378
379
  apiGetAnalyticDashboard,
379
380
  apiGetArticleList,
@@ -383,6 +384,7 @@ export {
383
384
  apiGetContactDetails,
384
385
  apiGetContacts,
385
386
  apiGetConversation,
387
+ apiGetConversations,
386
388
  apiGetCustomer,
387
389
  apiGetCustomerLog,
388
390
  apiGetCustomersList,
@@ -421,6 +423,7 @@ export {
421
423
  apiGoogleOauthSignIn,
422
424
  apiPostImages,
423
425
  apiPostProject,
426
+ apiRenameConversation,
424
427
  apiResetPassword,
425
428
  apiSignIn,
426
429
  apiSignOut,
@@ -23,6 +23,25 @@ async function apiGetChatHistory(conversationId) {
23
23
  params: conversationId ? { conversation_id: conversationId } : void 0
24
24
  });
25
25
  }
26
+ async function apiGetConversations() {
27
+ return aiRequest({
28
+ url: "/ai/chat/conversations",
29
+ method: "get"
30
+ });
31
+ }
32
+ async function apiRenameConversation(conversationId, title) {
33
+ return aiRequest({
34
+ url: `/ai/chat/conversations/${encodeURIComponent(conversationId)}`,
35
+ method: "patch",
36
+ data: { title }
37
+ });
38
+ }
39
+ async function apiDeleteConversation(conversationId) {
40
+ return aiRequest({
41
+ url: `/ai/chat/conversations/${encodeURIComponent(conversationId)}`,
42
+ method: "delete"
43
+ });
44
+ }
26
45
  async function streamChat({
27
46
  prompt,
28
47
  conversationId,
@@ -87,9 +106,12 @@ async function apiPostImages(data) {
87
106
  }
88
107
  export {
89
108
  AI_API_URL,
109
+ apiDeleteConversation,
90
110
  apiGetChatHistory,
111
+ apiGetConversations,
91
112
  apiGetImages,
92
113
  apiPostImages,
114
+ apiRenameConversation,
93
115
  resumeChat,
94
116
  streamChat
95
117
  };
@@ -1 +1 @@
1
- {"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import { authHeaders } from './aiAuthHeaders'\nimport ApiService from './ApiService'\nimport { readSse } from './sseParser'\nimport type { ChatEvent } from '@/views/concepts/ai/Chat/types'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst AI_DEV_URL = 'http://localhost:8000'\nconst AI_BUILD_URL = 'https://orbe-ai.apps.qas.orbeagro.com.br'\n\n/**\n * Host da API de IA.\n *\n * O /ai/* nao vive no gateway do resto da aplicacao, entao nao pode usar o\n * baseURL do AxiosBase (API_URL). A resolucao e por origin em runtime, e nao\n * por import.meta.env.MODE, porque o MODE e congelado na build da lib como\n * \"production\" e nao reflete o dev do MFE consumidor.\n */\nfunction getAiApiUrl() {\n const origin = globalThis?.location?.origin ?? ''\n\n if (origin.includes('localhost') || origin.includes('127.0.0.1')) {\n return AI_DEV_URL\n }\n\n // QAS e PRD compartilham a mesma URL por enquanto. Quando houver uma URL\n // de PRD, o split entra aqui: if (origin.includes('.prd.')) return AI_PRD_URL\n return AI_BUILD_URL\n}\n\nexport const AI_API_URL = getAiApiUrl()\n\n/**\n * Toda chamada de IA sai pelo AI_API_URL (o baseURL por requisicao vence o da\n * instancia do AxiosBase) e fica fora do loading global — o chat mostra o\n * proprio balaozinho de \"digitando\".\n */\nconst aiRequest = <T>(config: AxiosRequestConfig) =>\n ApiService.fetchDataWithAxios<T>({\n ...config,\n baseURL: AI_API_URL,\n skipGlobalLoading: true,\n })\n\nexport async function apiGetChatHistory<T>(conversationId?: string) {\n return aiRequest<T>({\n url: '/ai/chat/history',\n method: 'get',\n params: conversationId ? { conversation_id: conversationId } : undefined,\n })\n}\n\nexport type StreamChatParams = {\n prompt: string\n /** Identifica a conversa; o backend usa como thread da memoria. */\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Resposta a pausa atual do agente. Ha duas, e um endpoint so:\n * - `approved` responde ao `approval_required` (true aprova, false nega).\n * - `dados` responde ao `input_required`; `null` = o usuario fechou o\n * formulario sem preencher.\n */\nexport type ResumeChatParams = {\n approved?: boolean\n dados?: Record<string, unknown> | null\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Envia a mensagem e consome a resposta em streaming (SSE).\n *\n * Usa `fetch`, e nao o Axios, porque o Axios no browser so resolve a Promise\n * com a resposta inteira — nao ha como ler o corpo enquanto ele chega.\n */\nexport async function streamChat({\n prompt,\n conversationId,\n signal,\n onEvent,\n}: StreamChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/stream',\n { prompt, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/**\n * Retoma uma conversa parada numa pausa (aprovacao ou coleta de dados).\n *\n * Devolve o mesmo tipo de stream do `streamChat`, e a resposta continua na\n * MESMA mensagem do chat — o backend so volta do ponto onde parou.\n *\n * O `JSON.stringify` descarta chaves `undefined`, entao o backend recebe apenas\n * o campo da pausa que esta sendo respondida.\n */\nexport async function resumeChat({\n approved,\n dados,\n conversationId,\n signal,\n onEvent,\n}: ResumeChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/resume',\n { approved, dados, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/** POST + leitura do SSE, comum ao envio e a retomada. */\nasync function postarEConsumir(\n caminho: string,\n corpo: Record<string, unknown>,\n onEvent: (evento: ChatEvent) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const resposta = await fetch(`${AI_API_URL}${caminho}`, {\n method: 'POST',\n headers: {\n ...authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(corpo),\n signal,\n })\n\n if (!resposta.ok || !resposta.body) {\n throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`)\n }\n\n await readSse(resposta.body, ({ event, data }) => {\n try {\n onEvent({ type: event, data: JSON.parse(data) } as ChatEvent)\n } catch (error) {\n // Evento malformado nao pode derrubar o stream inteiro.\n console.debug('Evento SSE ignorado:', event, error)\n }\n })\n}\n\nexport async function apiGetImages<T, U extends Record<string, unknown>>(\n params: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'get',\n params,\n })\n}\n\nexport async function apiPostImages<T, U extends Record<string, unknown>>(\n data: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'post',\n data,\n })\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,aAAa;AACnB,MAAM,eAAe;AAUrB,SAAS,cAAc;AACnB,QAAM,SAAS,YAAY,UAAU,UAAU;AAE/C,MAAI,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;AAC9D,WAAO;AAAA,EACX;AAIA,SAAO;AACX;AAEO,MAAM,aAAa,YAAA;AAO1B,MAAM,YAAY,CAAI,WAClB,WAAW,mBAAsB;AAAA,EAC7B,GAAG;AAAA,EACH,SAAS;AAAA,EACT,mBAAmB;AACvB,CAAC;AAEL,eAAsB,kBAAqB,gBAAyB;AAChE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,iBAAiB,EAAE,iBAAiB,mBAAmB;AAAA,EAAA,CAClE;AACL;AA8BA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,QAAQ,iBAAiB,eAAA;AAAA,IAC3B;AAAA,IACA;AAAA,EAAA;AAER;AAWA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,UAAU,OAAO,iBAAiB,eAAA;AAAA,IACpC;AAAA,IACA;AAAA,EAAA;AAER;AAGA,eAAe,gBACX,SACA,OACA,SACA,QACa;AACb,QAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,OAAO,IAAI;AAAA,IACpD,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,GAAG,YAAA;AAAA,MACH,gBAAgB;AAAA,IAAA;AAAA,IAEpB,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B;AAAA,EAAA,CACH;AAED,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAChC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,GAAG;AAAA,EACvE;AAEA,QAAM,QAAQ,SAAS,MAAM,CAAC,EAAE,OAAO,WAAW;AAC9C,QAAI;AACA,cAAQ,EAAE,MAAM,OAAO,MAAM,KAAK,MAAM,IAAI,GAAgB;AAAA,IAChE,SAAS,OAAO;AAEZ,cAAQ,MAAM,wBAAwB,OAAO,KAAK;AAAA,IACtD;AAAA,EACJ,CAAC;AACL;AAEA,eAAsB,aAClB,QACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;AAEA,eAAsB,cAClB,MACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;"}
1
+ {"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import { authHeaders } from './aiAuthHeaders'\nimport ApiService from './ApiService'\nimport { readSse } from './sseParser'\nimport type { ChatEvent } from '@/views/concepts/ai/Chat/types'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst AI_DEV_URL = 'http://localhost:8000'\nconst AI_BUILD_URL = 'https://orbe-ai.apps.qas.orbeagro.com.br'\n\n/**\n * Host da API de IA.\n *\n * O /ai/* nao vive no gateway do resto da aplicacao, entao nao pode usar o\n * baseURL do AxiosBase (API_URL). A resolucao e por origin em runtime, e nao\n * por import.meta.env.MODE, porque o MODE e congelado na build da lib como\n * \"production\" e nao reflete o dev do MFE consumidor.\n */\nfunction getAiApiUrl() {\n const origin = globalThis?.location?.origin ?? ''\n\n if (origin.includes('localhost') || origin.includes('127.0.0.1')) {\n return AI_DEV_URL\n }\n\n // QAS e PRD compartilham a mesma URL por enquanto. Quando houver uma URL\n // de PRD, o split entra aqui: if (origin.includes('.prd.')) return AI_PRD_URL\n return AI_BUILD_URL\n}\n\nexport const AI_API_URL = getAiApiUrl()\n\n/**\n * Toda chamada de IA sai pelo AI_API_URL (o baseURL por requisicao vence o da\n * instancia do AxiosBase) e fica fora do loading global — o chat mostra o\n * proprio balaozinho de \"digitando\".\n */\nconst aiRequest = <T>(config: AxiosRequestConfig) =>\n ApiService.fetchDataWithAxios<T>({\n ...config,\n baseURL: AI_API_URL,\n skipGlobalLoading: true,\n })\n\nexport async function apiGetChatHistory<T>(conversationId?: string) {\n return aiRequest<T>({\n url: '/ai/chat/history',\n method: 'get',\n params: conversationId ? { conversation_id: conversationId } : undefined,\n })\n}\n\n/** Conversas do usuário (só o resumo), a mais recente primeiro. */\nexport async function apiGetConversations<T>() {\n return aiRequest<T>({\n url: '/ai/chat/conversations',\n method: 'get',\n })\n}\n\nexport async function apiRenameConversation(conversationId: string, title: string) {\n return aiRequest<void>({\n url: `/ai/chat/conversations/${encodeURIComponent(conversationId)}`,\n method: 'patch',\n data: { title },\n })\n}\n\n/** Apaga a conversa e toda a memória dela no backend. */\nexport async function apiDeleteConversation(conversationId: string) {\n return aiRequest<void>({\n url: `/ai/chat/conversations/${encodeURIComponent(conversationId)}`,\n method: 'delete',\n })\n}\n\nexport type StreamChatParams = {\n prompt: string\n /** Identifica a conversa; o backend usa como thread da memoria. */\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Resposta a pausa atual do agente. Ha duas, e um endpoint so:\n * - `approved` responde ao `approval_required` (true aprova, false nega).\n * - `dados` responde ao `input_required`; `null` = o usuario fechou o\n * formulario sem preencher.\n */\nexport type ResumeChatParams = {\n approved?: boolean\n dados?: Record<string, unknown> | null\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Envia a mensagem e consome a resposta em streaming (SSE).\n *\n * Usa `fetch`, e nao o Axios, porque o Axios no browser so resolve a Promise\n * com a resposta inteira — nao ha como ler o corpo enquanto ele chega.\n */\nexport async function streamChat({\n prompt,\n conversationId,\n signal,\n onEvent,\n}: StreamChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/stream',\n { prompt, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/**\n * Retoma uma conversa parada numa pausa (aprovacao ou coleta de dados).\n *\n * Devolve o mesmo tipo de stream do `streamChat`, e a resposta continua na\n * MESMA mensagem do chat — o backend so volta do ponto onde parou.\n *\n * O `JSON.stringify` descarta chaves `undefined`, entao o backend recebe apenas\n * o campo da pausa que esta sendo respondida.\n */\nexport async function resumeChat({\n approved,\n dados,\n conversationId,\n signal,\n onEvent,\n}: ResumeChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/resume',\n { approved, dados, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/** POST + leitura do SSE, comum ao envio e a retomada. */\nasync function postarEConsumir(\n caminho: string,\n corpo: Record<string, unknown>,\n onEvent: (evento: ChatEvent) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const resposta = await fetch(`${AI_API_URL}${caminho}`, {\n method: 'POST',\n headers: {\n ...authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(corpo),\n signal,\n })\n\n if (!resposta.ok || !resposta.body) {\n throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`)\n }\n\n await readSse(resposta.body, ({ event, data }) => {\n try {\n onEvent({ type: event, data: JSON.parse(data) } as ChatEvent)\n } catch (error) {\n // Evento malformado nao pode derrubar o stream inteiro.\n console.debug('Evento SSE ignorado:', event, error)\n }\n })\n}\n\nexport async function apiGetImages<T, U extends Record<string, unknown>>(\n params: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'get',\n params,\n })\n}\n\nexport async function apiPostImages<T, U extends Record<string, unknown>>(\n data: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'post',\n data,\n })\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,aAAa;AACnB,MAAM,eAAe;AAUrB,SAAS,cAAc;AACnB,QAAM,SAAS,YAAY,UAAU,UAAU;AAE/C,MAAI,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;AAC9D,WAAO;AAAA,EACX;AAIA,SAAO;AACX;AAEO,MAAM,aAAa,YAAA;AAO1B,MAAM,YAAY,CAAI,WAClB,WAAW,mBAAsB;AAAA,EAC7B,GAAG;AAAA,EACH,SAAS;AAAA,EACT,mBAAmB;AACvB,CAAC;AAEL,eAAsB,kBAAqB,gBAAyB;AAChE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,iBAAiB,EAAE,iBAAiB,mBAAmB;AAAA,EAAA,CAClE;AACL;AAGA,eAAsB,sBAAyB;AAC3C,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,EAAA,CACX;AACL;AAEA,eAAsB,sBAAsB,gBAAwB,OAAe;AAC/E,SAAO,UAAgB;AAAA,IACnB,KAAK,0BAA0B,mBAAmB,cAAc,CAAC;AAAA,IACjE,QAAQ;AAAA,IACR,MAAM,EAAE,MAAA;AAAA,EAAM,CACjB;AACL;AAGA,eAAsB,sBAAsB,gBAAwB;AAChE,SAAO,UAAgB;AAAA,IACnB,KAAK,0BAA0B,mBAAmB,cAAc,CAAC;AAAA,IACjE,QAAQ;AAAA,EAAA,CACX;AACL;AA8BA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,QAAQ,iBAAiB,eAAA;AAAA,IAC3B;AAAA,IACA;AAAA,EAAA;AAER;AAWA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,UAAU,OAAO,iBAAiB,eAAA;AAAA,IACpC;AAAA,IACA;AAAA,EAAA;AAER;AAGA,eAAe,gBACX,SACA,OACA,SACA,QACa;AACb,QAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,OAAO,IAAI;AAAA,IACpD,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,GAAG,YAAA;AAAA,MACH,gBAAgB;AAAA,IAAA;AAAA,IAEpB,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B;AAAA,EAAA,CACH;AAED,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAChC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,GAAG;AAAA,EACvE;AAEA,QAAM,QAAQ,SAAS,MAAM,CAAC,EAAE,OAAO,WAAW;AAC9C,QAAI;AACA,cAAQ,EAAE,MAAM,OAAO,MAAM,KAAK,MAAM,IAAI,GAAgB;AAAA,IAChE,SAAS,OAAO;AAEZ,cAAQ,MAAM,wBAAwB,OAAO,KAAK;AAAA,IACtD;AAAA,EACJ,CAAC;AACL;AAEA,eAAsB,aAClB,QACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;AAEA,eAAsB,cAClB,MACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;"}
@@ -1,6 +1,6 @@
1
1
  import { default as default2 } from "./ApiService.js";
2
2
  import { apiGetPricingPlans, apiGetRolesPermissionsRoles, apiGetRolesPermissionsUsers, apiGetSettingsBilling, apiGetSettingsIntergration, apiGetSettingsNotification, apiGetSettingsProfile } from "./AccontsService.js";
3
- import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./AiService.js";
3
+ import { AI_API_URL, apiDeleteConversation, apiGetChatHistory, apiGetConversations, apiGetImages, apiPostImages, apiRenameConversation, resumeChat, streamChat } from "./AiService.js";
4
4
  import { apiForgotPassword, apiResetPassword, apiSignIn, apiSignOut, apiSignUp } from "./AuthService.js";
5
5
  import { apiGetCalendar } from "./CalendarService.js";
6
6
  import { apiGetChats, apiGetContactDetails, apiGetContacts, apiGetConversation } from "./ChatService.js";
@@ -18,6 +18,7 @@ import { apiGetProject, apiGetProjectMembers, apiGetProjectTask, apiGetProjectTa
18
18
  export {
19
19
  AI_API_URL,
20
20
  default2 as ApiService,
21
+ apiDeleteConversation,
21
22
  apiForgotPassword,
22
23
  apiGetAnalyticDashboard,
23
24
  apiGetArticleList,
@@ -27,6 +28,7 @@ export {
27
28
  apiGetContactDetails,
28
29
  apiGetContacts,
29
30
  apiGetConversation,
31
+ apiGetConversations,
30
32
  apiGetCustomer,
31
33
  apiGetCustomerLog,
32
34
  apiGetCustomersList,
@@ -65,6 +67,7 @@ export {
65
67
  apiGoogleOauthSignIn,
66
68
  apiPostImages,
67
69
  apiPostProject,
70
+ apiRenameConversation,
68
71
  apiResetPassword,
69
72
  apiSignIn,
70
73
  apiSignOut,
@@ -3,36 +3,22 @@ import { Fragment } from "react";
3
3
  import "../../../../../components/ui/ScrollBar/index.js";
4
4
  import ChatHistoryItem from "./ChatHistoryItem.js";
5
5
  import { usGenerativeChatStore } from "../store/generativeChatStore.js";
6
- import { apiGetChatHistory } from "../../../../../services/AiService.js";
7
- import useSWR from "swr";
6
+ import useChatConversations from "../hooks/useChatConversations.js";
8
7
  import ScrollBar from "../../../../../components/ui/ScrollBar/ScrollBar.js";
9
- const ChatHistory = ({ queryText = "", onClick }) => {
8
+ const ChatHistory = ({
9
+ queryText = "",
10
+ onClick,
11
+ dropdownFloatingClass
12
+ }) => {
10
13
  const {
11
14
  chatHistory,
12
- setChatHistory,
13
15
  setRenameDialog,
14
16
  setSelectedConversation,
15
17
  selectedConversation
16
18
  } = usGenerativeChatStore();
17
- useSWR(
18
- ["/api/ai/chat/history"],
19
- () => apiGetChatHistory(),
20
- {
21
- revalidateOnFocus: false,
22
- revalidateIfStale: false,
23
- revalidateOnReconnect: false,
24
- onSuccess: (data) => {
25
- setChatHistory(data);
26
- }
27
- }
28
- );
19
+ const { remover } = useChatConversations();
29
20
  const handleDelete = (id) => {
30
- setChatHistory(chatHistory.filter((item) => item.id !== id));
31
- setSelectedConversation("");
32
- };
33
- const handleArchive = (id) => {
34
- setChatHistory(chatHistory.filter((item) => item.id !== id));
35
- setSelectedConversation("");
21
+ remover(id);
36
22
  };
37
23
  const handleRename = (id, title) => {
38
24
  setRenameDialog({
@@ -58,8 +44,8 @@ const ChatHistory = ({ queryText = "", onClick }) => {
58
44
  title: item.title,
59
45
  conversation: item.lastConversation,
60
46
  active: selectedConversation === item.id,
47
+ dropdownFloatingClass,
61
48
  onDelete: () => handleDelete(item.id),
62
- onArchive: () => handleArchive(item.id),
63
49
  onRename: () => handleRename(item.id, item.title),
64
50
  onClick: () => handleClick(item.id)
65
51
  },
@@ -1 +1 @@
1
- {"version":3,"file":"ChatHistory.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx"],"sourcesContent":["import { Fragment } from 'react'\nimport ScrollBar from '@/components/ui/ScrollBar'\nimport ChatHistoryItem from './ChatHistoryItem'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { apiGetChatHistory } from '@/services/AiService'\n\nimport useSWR from 'swr'\nimport type { GetChatHistoryResponse } from '../types'\n\ntype ChatHistoryProps = {\n queryText?: string\n onClick?: () => void\n}\n\nconst ChatHistory = ({ queryText = '', onClick }: ChatHistoryProps) => {\n const {\n chatHistory,\n setChatHistory,\n setRenameDialog,\n setSelectedConversation,\n selectedConversation,\n } = usGenerativeChatStore()\n\n useSWR(\n ['/api/ai/chat/history'],\n () => apiGetChatHistory<GetChatHistoryResponse>(),\n {\n revalidateOnFocus: false,\n revalidateIfStale: false,\n revalidateOnReconnect: false,\n onSuccess: (data) => {\n setChatHistory(data)\n },\n },\n )\n\n const handleDelete = (id: string) => {\n setChatHistory(chatHistory.filter((item) => item.id !== id))\n setSelectedConversation('')\n }\n\n const handleArchive = (id: string) => {\n setChatHistory(chatHistory.filter((item) => item.id !== id))\n setSelectedConversation('')\n }\n\n const handleRename = (id: string, title: string) => {\n setRenameDialog({\n id,\n title,\n open: true,\n })\n }\n\n const handleClick = (id: string) => {\n setSelectedConversation(id)\n onClick?.()\n }\n\n return (\n <ScrollBar className=\"h-full\">\n <div className=\"flex flex-col gap-2 py-2 px-3\">\n {chatHistory\n .filter((item) =>\n item.title\n .toLowerCase()\n .includes(queryText.toLowerCase()),\n )\n .map((item) => {\n if (!item.enable) {\n return <Fragment key={item.id} />\n }\n return (\n <ChatHistoryItem\n key={item.id}\n data-testid={item.id}\n title={item.title}\n conversation={item.lastConversation}\n active={selectedConversation === item.id}\n onDelete={() => handleDelete(item.id)}\n onArchive={() => handleArchive(item.id)}\n onRename={() =>\n handleRename(item.id, item.title)\n }\n onClick={() => handleClick(item.id)}\n />\n )\n })}\n </div>\n </ScrollBar>\n )\n}\n\nexport default ChatHistory\n"],"names":[],"mappings":";;;;;;;;AAcA,MAAM,cAAc,CAAC,EAAE,YAAY,IAAI,cAAgC;AACnE,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA,sBAAA;AAEJ;AAAA,IACI,CAAC,sBAAsB;AAAA,IACvB,MAAM,kBAAA;AAAA,IACN;AAAA,MACI,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB,uBAAuB;AAAA,MACvB,WAAW,CAAC,SAAS;AACjB,uBAAe,IAAI;AAAA,MACvB;AAAA,IAAA;AAAA,EACJ;AAGJ,QAAM,eAAe,CAAC,OAAe;AACjC,mBAAe,YAAY,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AAC3D,4BAAwB,EAAE;AAAA,EAC9B;AAEA,QAAM,gBAAgB,CAAC,OAAe;AAClC,mBAAe,YAAY,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AAC3D,4BAAwB,EAAE;AAAA,EAC9B;AAEA,QAAM,eAAe,CAAC,IAAY,UAAkB;AAChD,oBAAgB;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IAAA,CACT;AAAA,EACL;AAEA,QAAM,cAAc,CAAC,OAAe;AAChC,4BAAwB,EAAE;AAC1B,cAAA;AAAA,EACJ;AAEA,SACI,oBAAC,aAAU,WAAU,UACjB,8BAAC,OAAA,EAAI,WAAU,iCACV,UAAA,YACI;AAAA,IAAO,CAAC,SACL,KAAK,MACA,cACA,SAAS,UAAU,YAAA,CAAa;AAAA,EAAA,EAExC,IAAI,CAAC,SAAS;AACX,QAAI,CAAC,KAAK,QAAQ;AACd,aAAO,oBAAC,UAAA,IAAc,KAAK,EAAI;AAAA,IACnC;AACA,WACI;AAAA,MAAC;AAAA,MAAA;AAAA,QAEG,eAAa,KAAK;AAAA,QAClB,OAAO,KAAK;AAAA,QACZ,cAAc,KAAK;AAAA,QACnB,QAAQ,yBAAyB,KAAK;AAAA,QACtC,UAAU,MAAM,aAAa,KAAK,EAAE;AAAA,QACpC,WAAW,MAAM,cAAc,KAAK,EAAE;AAAA,QACtC,UAAU,MACN,aAAa,KAAK,IAAI,KAAK,KAAK;AAAA,QAEpC,SAAS,MAAM,YAAY,KAAK,EAAE;AAAA,MAAA;AAAA,MAV7B,KAAK;AAAA,IAAA;AAAA,EAatB,CAAC,GACT,GACJ;AAER;"}
1
+ {"version":3,"file":"ChatHistory.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx"],"sourcesContent":["import { Fragment } from 'react'\nimport ScrollBar from '@/components/ui/ScrollBar'\nimport ChatHistoryItem from './ChatHistoryItem'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport useChatConversations from '../hooks/useChatConversations'\n\ntype ChatHistoryProps = {\n queryText?: string\n onClick?: () => void\n /** Repassado ao menu de cada item (ex.: subir o z-index dentro do widget). */\n dropdownFloatingClass?: string\n}\n\nconst ChatHistory = ({\n queryText = '',\n onClick,\n dropdownFloatingClass,\n}: ChatHistoryProps) => {\n const {\n chatHistory,\n setRenameDialog,\n setSelectedConversation,\n selectedConversation,\n } = usGenerativeChatStore()\n const { remover } = useChatConversations()\n\n const handleDelete = (id: string) => {\n remover(id)\n }\n\n const handleRename = (id: string, title: string) => {\n setRenameDialog({\n id,\n title,\n open: true,\n })\n }\n\n const handleClick = (id: string) => {\n setSelectedConversation(id)\n onClick?.()\n }\n\n return (\n <ScrollBar className=\"h-full\">\n <div className=\"flex flex-col gap-2 py-2 px-3\">\n {chatHistory\n .filter((item) =>\n item.title\n .toLowerCase()\n .includes(queryText.toLowerCase()),\n )\n .map((item) => {\n if (!item.enable) {\n return <Fragment key={item.id} />\n }\n return (\n <ChatHistoryItem\n key={item.id}\n data-testid={item.id}\n title={item.title}\n conversation={item.lastConversation}\n active={selectedConversation === item.id}\n dropdownFloatingClass={dropdownFloatingClass}\n onDelete={() => handleDelete(item.id)}\n onRename={() =>\n handleRename(item.id, item.title)\n }\n onClick={() => handleClick(item.id)}\n />\n )\n })}\n </div>\n </ScrollBar>\n )\n}\n\nexport default ChatHistory\n"],"names":[],"mappings":";;;;;;;AAaA,MAAM,cAAc,CAAC;AAAA,EACjB,YAAY;AAAA,EACZ;AAAA,EACA;AACJ,MAAwB;AACpB,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA,sBAAA;AACJ,QAAM,EAAE,QAAA,IAAY,qBAAA;AAEpB,QAAM,eAAe,CAAC,OAAe;AACjC,YAAQ,EAAE;AAAA,EACd;AAEA,QAAM,eAAe,CAAC,IAAY,UAAkB;AAChD,oBAAgB;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IAAA,CACT;AAAA,EACL;AAEA,QAAM,cAAc,CAAC,OAAe;AAChC,4BAAwB,EAAE;AAC1B,cAAA;AAAA,EACJ;AAEA,SACI,oBAAC,aAAU,WAAU,UACjB,8BAAC,OAAA,EAAI,WAAU,iCACV,UAAA,YACI;AAAA,IAAO,CAAC,SACL,KAAK,MACA,cACA,SAAS,UAAU,YAAA,CAAa;AAAA,EAAA,EAExC,IAAI,CAAC,SAAS;AACX,QAAI,CAAC,KAAK,QAAQ;AACd,aAAO,oBAAC,UAAA,IAAc,KAAK,EAAI;AAAA,IACnC;AACA,WACI;AAAA,MAAC;AAAA,MAAA;AAAA,QAEG,eAAa,KAAK;AAAA,QAClB,OAAO,KAAK;AAAA,QACZ,cAAc,KAAK;AAAA,QACnB,QAAQ,yBAAyB,KAAK;AAAA,QACtC;AAAA,QACA,UAAU,MAAM,aAAa,KAAK,EAAE;AAAA,QACpC,UAAU,MACN,aAAa,KAAK,IAAI,KAAK,KAAK;AAAA,QAEpC,SAAS,MAAM,YAAY,KAAK,EAAE;AAAA,MAAA;AAAA,MAV7B,KAAK;AAAA,IAAA;AAAA,EAatB,CAAC,GACT,GACJ;AAER;"}
@@ -2,7 +2,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useState, useRef } from "react";
3
3
  import { Dropdown } from "../../../../../components/ui/Dropdown/index.js";
4
4
  import classNames from "classnames";
5
- import { TbPencil, TbArchive, TbTrash, TbDots } from "react-icons/tb";
5
+ import { TbPencil, TbTrash, TbDots } from "react-icons/tb";
6
6
  const ChatHistoryItem = (props) => {
7
7
  const [dropdownOpen, setDropdownOpen] = useState(false);
8
8
  const dropdownRef = useRef(null);
@@ -11,9 +11,9 @@ const ChatHistoryItem = (props) => {
11
11
  conversation,
12
12
  active,
13
13
  onRename,
14
- onArchive,
15
14
  onDelete,
16
15
  onClick,
16
+ dropdownFloatingClass,
17
17
  ...rest
18
18
  } = props;
19
19
  const handleCallback = (e, callback) => {
@@ -50,6 +50,7 @@ const ChatHistoryItem = (props) => {
50
50
  {
51
51
  ref: dropdownRef,
52
52
  placement: "bottom-end",
53
+ floatingClass: dropdownFloatingClass,
53
54
  renderTitle: /* @__PURE__ */ jsx(
54
55
  "div",
55
56
  {
@@ -75,18 +76,7 @@ const ChatHistoryItem = (props) => {
75
76
  onClick: (e) => handleCallback(e, onRename),
76
77
  children: [
77
78
  /* @__PURE__ */ jsx(TbPencil, { className: "text-xl" }),
78
- /* @__PURE__ */ jsx("span", { children: "Rename" })
79
- ]
80
- }
81
- ),
82
- /* @__PURE__ */ jsxs(
83
- Dropdown.Item,
84
- {
85
- eventKey: "rename",
86
- onClick: (e) => handleCallback(e, onArchive),
87
- children: [
88
- /* @__PURE__ */ jsx(TbArchive, { className: "text-xl" }),
89
- /* @__PURE__ */ jsx("span", { children: "Archive" })
79
+ /* @__PURE__ */ jsx("span", { children: "Renomear" })
90
80
  ]
91
81
  }
92
82
  ),
@@ -94,11 +84,11 @@ const ChatHistoryItem = (props) => {
94
84
  Dropdown.Item,
95
85
  {
96
86
  className: "text-error",
97
- eventKey: "rename",
87
+ eventKey: "delete",
98
88
  onClick: (e) => handleCallback(e, onDelete),
99
89
  children: [
100
90
  /* @__PURE__ */ jsx(TbTrash, { className: "text-xl text-error" }),
101
- /* @__PURE__ */ jsx("span", { className: "text-error", children: "Deleted" })
91
+ /* @__PURE__ */ jsx("span", { className: "text-error", children: "Excluir" })
102
92
  ]
103
93
  }
104
94
  )
@@ -1 +1 @@
1
- {"version":3,"file":"ChatHistoryItem.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx"],"sourcesContent":["import { useState, useRef } from 'react'\nimport Dropdown from '@/components/ui/Dropdown'\nimport classNames from 'classnames'\nimport { TbDots, TbArchive, TbPencil, TbTrash } from 'react-icons/tb'\nimport type { DropdownRef } from '@/components/ui/Dropdown'\n\nimport type { MouseEvent, SyntheticEvent } from 'react'\n\ntype ChatHistoryItemProps = {\n title: string\n conversation: string\n active?: boolean\n onDelete?: () => void\n onArchive?: () => void\n onRename?: () => void\n onClick?: () => void\n}\n\nconst ChatHistoryItem = (props: ChatHistoryItemProps) => {\n const [dropdownOpen, setDropdownOpen] = useState(false)\n\n const dropdownRef = useRef<DropdownRef>(null)\n\n const {\n title,\n conversation,\n active,\n onRename,\n onArchive,\n onDelete,\n onClick,\n ...rest\n } = props\n\n const handleCallback = (\n e: SyntheticEvent<Element, Event>,\n callback?: () => void,\n ) => {\n e.stopPropagation()\n callback?.()\n }\n\n const handleDropdownToggleClick = (e: MouseEvent) => {\n e.stopPropagation()\n dropdownRef.current?.handleDropdownOpen()\n }\n\n return (\n <div\n className={classNames(\n 'rounded-xl p-3 px-5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer group relative',\n (dropdownOpen || active) && 'bg-gray-100 dark:bg-gray-700',\n )}\n onClick={onClick}\n {...rest}\n >\n <div>\n <div className=\"heading-text font-bold truncate\">{title}</div>\n <div className=\"truncate\">{conversation}</div>\n </div>\n <div\n className={classNames(\n 'rounded-xl absolute bottom-0 top-0 to-transparent ltr:right-0 ltr:bg-gradient-to-l rtl:left-0 rtl:bg-gradient-to-r group-hover:from-gray-100 dark:group-hover:from-gray-700 w-8 from-0% group-hover:w-20 group-hover:from-60% flex items-center justify-end',\n dropdownOpen &&\n 'from-gray-100 dark:from-gray-700 w-20 from-60%',\n )}\n >\n <Dropdown\n ref={dropdownRef}\n placement=\"bottom-end\"\n renderTitle={\n <div\n className={classNames(\n 'p-2 opacity-0 group-hover:opacity-100',\n dropdownOpen && 'opacity-100',\n )}\n >\n <TbDots\n className=\"text-xl\"\n onClick={handleDropdownToggleClick}\n />\n </div>\n }\n onOpen={(bool) => setDropdownOpen(bool)}\n >\n <Dropdown.Item\n eventKey=\"rename\"\n onClick={(e) => handleCallback(e, onRename)}\n >\n <TbPencil className=\"text-xl\" />\n <span>Rename</span>\n </Dropdown.Item>\n <Dropdown.Item\n eventKey=\"rename\"\n onClick={(e) => handleCallback(e, onArchive)}\n >\n <TbArchive className=\"text-xl\" />\n <span>Archive</span>\n </Dropdown.Item>\n <Dropdown.Item\n className=\"text-error\"\n eventKey=\"rename\"\n onClick={(e) => handleCallback(e, onDelete)}\n >\n <TbTrash className=\"text-xl text-error\" />\n <span className=\"text-error\">Deleted</span>\n </Dropdown.Item>\n </Dropdown>\n </div>\n </div>\n )\n}\n\nexport default ChatHistoryItem\n"],"names":[],"mappings":";;;;;AAkBA,MAAM,kBAAkB,CAAC,UAAgC;AACrD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,QAAM,cAAc,OAAoB,IAAI;AAE5C,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,IACH;AAEJ,QAAM,iBAAiB,CACnB,GACA,aACC;AACD,MAAE,gBAAA;AACF,eAAA;AAAA,EACJ;AAEA,QAAM,4BAA4B,CAAC,MAAkB;AACjD,MAAE,gBAAA;AACF,gBAAY,SAAS,mBAAA;AAAA,EACzB;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,QACP;AAAA,SACC,gBAAgB,WAAW;AAAA,MAAA;AAAA,MAEhC;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,qBAAC,OAAA,EACG,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,WAAU,mCAAmC,UAAA,OAAM;AAAA,UACxD,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,aAAA,CAAa;AAAA,QAAA,GAC5C;AAAA,QACA;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,WAAW;AAAA,cACP;AAAA,cACA,gBACI;AAAA,YAAA;AAAA,YAGR,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,KAAK;AAAA,gBACL,WAAU;AAAA,gBACV,aACI;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACG,WAAW;AAAA,sBACP;AAAA,sBACA,gBAAgB;AAAA,oBAAA;AAAA,oBAGpB,UAAA;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACG,WAAU;AAAA,wBACV,SAAS;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACb;AAAA,gBAAA;AAAA,gBAGR,QAAQ,CAAC,SAAS,gBAAgB,IAAI;AAAA,gBAEtC,UAAA;AAAA,kBAAA;AAAA,oBAAC,SAAS;AAAA,oBAAT;AAAA,sBACG,UAAS;AAAA,sBACT,SAAS,CAAC,MAAM,eAAe,GAAG,QAAQ;AAAA,sBAE1C,UAAA;AAAA,wBAAA,oBAAC,UAAA,EAAS,WAAU,UAAA,CAAU;AAAA,wBAC9B,oBAAC,UAAK,UAAA,SAAA,CAAM;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAAA;AAAA,kBAEhB;AAAA,oBAAC,SAAS;AAAA,oBAAT;AAAA,sBACG,UAAS;AAAA,sBACT,SAAS,CAAC,MAAM,eAAe,GAAG,SAAS;AAAA,sBAE3C,UAAA;AAAA,wBAAA,oBAAC,WAAA,EAAU,WAAU,UAAA,CAAU;AAAA,wBAC/B,oBAAC,UAAK,UAAA,UAAA,CAAO;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAAA;AAAA,kBAEjB;AAAA,oBAAC,SAAS;AAAA,oBAAT;AAAA,sBACG,WAAU;AAAA,sBACV,UAAS;AAAA,sBACT,SAAS,CAAC,MAAM,eAAe,GAAG,QAAQ;AAAA,sBAE1C,UAAA;AAAA,wBAAA,oBAAC,SAAA,EAAQ,WAAU,qBAAA,CAAqB;AAAA,wBACxC,oBAAC,QAAA,EAAK,WAAU,cAAa,UAAA,UAAA,CAAO;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACxC;AAAA,cAAA;AAAA,YAAA;AAAA,UACJ;AAAA,QAAA;AAAA,MACJ;AAAA,IAAA;AAAA,EAAA;AAGZ;"}
1
+ {"version":3,"file":"ChatHistoryItem.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx"],"sourcesContent":["import { useState, useRef } from 'react'\nimport Dropdown from '@/components/ui/Dropdown'\nimport classNames from 'classnames'\nimport { TbDots, TbPencil, TbTrash } from 'react-icons/tb'\nimport type { DropdownRef } from '@/components/ui/Dropdown'\n\nimport type { MouseEvent, SyntheticEvent } from 'react'\n\ntype ChatHistoryItemProps = {\n title: string\n conversation: string\n active?: boolean\n onDelete?: () => void\n onRename?: () => void\n onClick?: () => void\n dropdownFloatingClass?: string\n}\n\nconst ChatHistoryItem = (props: ChatHistoryItemProps) => {\n const [dropdownOpen, setDropdownOpen] = useState(false)\n\n const dropdownRef = useRef<DropdownRef>(null)\n\n const {\n title,\n conversation,\n active,\n onRename,\n onDelete,\n onClick,\n dropdownFloatingClass,\n ...rest\n } = props\n\n const handleCallback = (\n e: SyntheticEvent<Element, Event>,\n callback?: () => void,\n ) => {\n e.stopPropagation()\n callback?.()\n }\n\n const handleDropdownToggleClick = (e: MouseEvent) => {\n e.stopPropagation()\n dropdownRef.current?.handleDropdownOpen()\n }\n\n return (\n <div\n className={classNames(\n 'rounded-xl p-3 px-5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer group relative',\n (dropdownOpen || active) && 'bg-gray-100 dark:bg-gray-700',\n )}\n onClick={onClick}\n {...rest}\n >\n <div>\n <div className=\"heading-text font-bold truncate\">{title}</div>\n <div className=\"truncate\">{conversation}</div>\n </div>\n <div\n className={classNames(\n 'rounded-xl absolute bottom-0 top-0 to-transparent ltr:right-0 ltr:bg-gradient-to-l rtl:left-0 rtl:bg-gradient-to-r group-hover:from-gray-100 dark:group-hover:from-gray-700 w-8 from-0% group-hover:w-20 group-hover:from-60% flex items-center justify-end',\n dropdownOpen &&\n 'from-gray-100 dark:from-gray-700 w-20 from-60%',\n )}\n >\n <Dropdown\n ref={dropdownRef}\n placement=\"bottom-end\"\n floatingClass={dropdownFloatingClass}\n renderTitle={\n <div\n className={classNames(\n 'p-2 opacity-0 group-hover:opacity-100',\n dropdownOpen && 'opacity-100',\n )}\n >\n <TbDots\n className=\"text-xl\"\n onClick={handleDropdownToggleClick}\n />\n </div>\n }\n onOpen={(bool) => setDropdownOpen(bool)}\n >\n <Dropdown.Item\n eventKey=\"rename\"\n onClick={(e) => handleCallback(e, onRename)}\n >\n <TbPencil className=\"text-xl\" />\n <span>Renomear</span>\n </Dropdown.Item>\n <Dropdown.Item\n className=\"text-error\"\n eventKey=\"delete\"\n onClick={(e) => handleCallback(e, onDelete)}\n >\n <TbTrash className=\"text-xl text-error\" />\n <span className=\"text-error\">Excluir</span>\n </Dropdown.Item>\n </Dropdown>\n </div>\n </div>\n )\n}\n\nexport default ChatHistoryItem\n"],"names":[],"mappings":";;;;;AAkBA,MAAM,kBAAkB,CAAC,UAAgC;AACrD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,QAAM,cAAc,OAAoB,IAAI;AAE5C,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,IACH;AAEJ,QAAM,iBAAiB,CACnB,GACA,aACC;AACD,MAAE,gBAAA;AACF,eAAA;AAAA,EACJ;AAEA,QAAM,4BAA4B,CAAC,MAAkB;AACjD,MAAE,gBAAA;AACF,gBAAY,SAAS,mBAAA;AAAA,EACzB;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,QACP;AAAA,SACC,gBAAgB,WAAW;AAAA,MAAA;AAAA,MAEhC;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,qBAAC,OAAA,EACG,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,WAAU,mCAAmC,UAAA,OAAM;AAAA,UACxD,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,aAAA,CAAa;AAAA,QAAA,GAC5C;AAAA,QACA;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,WAAW;AAAA,cACP;AAAA,cACA,gBACI;AAAA,YAAA;AAAA,YAGR,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,KAAK;AAAA,gBACL,WAAU;AAAA,gBACV,eAAe;AAAA,gBACf,aACI;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACG,WAAW;AAAA,sBACP;AAAA,sBACA,gBAAgB;AAAA,oBAAA;AAAA,oBAGpB,UAAA;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACG,WAAU;AAAA,wBACV,SAAS;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACb;AAAA,gBAAA;AAAA,gBAGR,QAAQ,CAAC,SAAS,gBAAgB,IAAI;AAAA,gBAEtC,UAAA;AAAA,kBAAA;AAAA,oBAAC,SAAS;AAAA,oBAAT;AAAA,sBACG,UAAS;AAAA,sBACT,SAAS,CAAC,MAAM,eAAe,GAAG,QAAQ;AAAA,sBAE1C,UAAA;AAAA,wBAAA,oBAAC,UAAA,EAAS,WAAU,UAAA,CAAU;AAAA,wBAC9B,oBAAC,UAAK,UAAA,WAAA,CAAQ;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAAA;AAAA,kBAElB;AAAA,oBAAC,SAAS;AAAA,oBAAT;AAAA,sBACG,WAAU;AAAA,sBACV,UAAS;AAAA,sBACT,SAAS,CAAC,MAAM,eAAe,GAAG,QAAQ;AAAA,sBAE1C,UAAA;AAAA,wBAAA,oBAAC,SAAA,EAAQ,WAAU,qBAAA,CAAqB;AAAA,wBACxC,oBAAC,QAAA,EAAK,WAAU,cAAa,UAAA,UAAA,CAAO;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACxC;AAAA,cAAA;AAAA,YAAA;AAAA,UACJ;AAAA,QAAA;AAAA,MACJ;AAAA,IAAA;AAAA,EAAA;AAGZ;"}
@@ -5,6 +5,7 @@ import "../../../../../components/ui/Form/index.js";
5
5
  import "../../../../../components/ui/Input/index.js";
6
6
  import "../../../../../components/ui/Button/index.js";
7
7
  import { usGenerativeChatStore } from "../store/generativeChatStore.js";
8
+ import useChatConversations from "../hooks/useChatConversations.js";
8
9
  import { useForm, Controller } from "react-hook-form";
9
10
  import { zodResolver } from "@hookform/resolvers/zod";
10
11
  import { z } from "zod";
@@ -14,10 +15,13 @@ import FormItem from "../../../../../components/ui/Form/FormItem.js";
14
15
  import Input from "../../../../../components/ui/Input/Input.js";
15
16
  import Button from "../../../../../components/ui/Button/Button.js";
16
17
  const validationSchema = z.object({
17
- title: z.string().min(1, "Please do not leave chat title blank!")
18
+ title: z.string().trim().min(1, "Informe um título para a conversa.")
18
19
  });
19
- const ChatHistoryRenameDialog = () => {
20
- const { renameDialog, setRenameDialog, setChatHistoryName } = usGenerativeChatStore();
20
+ const ChatHistoryRenameDialog = ({
21
+ overlayClassName
22
+ }) => {
23
+ const { renameDialog, setRenameDialog } = usGenerativeChatStore();
24
+ const { renomear } = useChatConversations();
21
25
  const {
22
26
  control,
23
27
  formState: { errors },
@@ -44,16 +48,15 @@ const ChatHistoryRenameDialog = () => {
44
48
  });
45
49
  };
46
50
  const onFormSubmit = async ({ title }) => {
47
- setChatHistoryName({
48
- id: renameDialog.id,
49
- title
50
- });
51
+ const { id } = renameDialog;
51
52
  handleDialogClose();
53
+ await renomear(id, title.trim());
52
54
  };
53
55
  return /* @__PURE__ */ jsxs(
54
56
  Dialog,
55
57
  {
56
58
  isOpen: renameDialog.open,
59
+ overlayClassName,
57
60
  onClose: handleDialogClose,
58
61
  onRequestClose: handleDialogClose,
59
62
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"ChatHistoryRenameDialog.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx"],"sourcesContent":["import { useEffect } from 'react'\nimport Dialog from '@/components/ui/Dialog'\nimport { Form, FormItem } from '@/components/ui/Form'\nimport Input from '@/components/ui/Input'\nimport Button from '@/components/ui/Button'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { useForm, Controller } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { z } from 'zod'\nimport type { ZodType } from 'zod'\n\ntype FormSchema = {\n title: string\n}\n\nconst validationSchema: ZodType<FormSchema> = z.object({\n title: z.string().min(1, 'Please do not leave chat title blank!'),\n})\n\nconst ChatHistoryRenameDialog = () => {\n const { renameDialog, setRenameDialog, setChatHistoryName } =\n usGenerativeChatStore()\n\n const {\n control,\n formState: { errors },\n handleSubmit,\n reset,\n } = useForm<FormSchema>({\n defaultValues: {\n title: renameDialog.title,\n },\n resolver: zodResolver(validationSchema),\n })\n\n useEffect(() => {\n if (renameDialog.open) {\n reset({\n title: renameDialog.title,\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [renameDialog.title, renameDialog.open])\n\n const handleDialogClose = () => {\n setRenameDialog({\n id: '',\n title: '',\n open: false,\n })\n }\n\n const onFormSubmit = async ({ title }: FormSchema) => {\n setChatHistoryName({\n id: renameDialog.id,\n title,\n })\n handleDialogClose()\n }\n\n return (\n <Dialog\n isOpen={renameDialog.open}\n onClose={handleDialogClose}\n onRequestClose={handleDialogClose}\n >\n <h5>Rename chat</h5>\n <div className=\"mt-8\">\n <Form onSubmit={handleSubmit(onFormSubmit)}>\n <FormItem\n label=\"Chat title\"\n invalid={Boolean(errors.title)}\n errorMessage={errors.title?.message}\n >\n <Controller\n name=\"title\"\n control={control}\n rules={{ required: true }}\n render={({ field }) => (\n <Input\n placeholder=\"Rename chat\"\n type=\"text\"\n autoComplete=\"off\"\n {...field}\n />\n )}\n />\n </FormItem>\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" onClick={handleDialogClose}>\n Cancel\n </Button>\n <Button variant=\"solid\" type=\"submit\">\n Rename\n </Button>\n </div>\n </Form>\n </div>\n </Dialog>\n )\n}\n\nexport default ChatHistoryRenameDialog\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAeA,MAAM,mBAAwC,EAAE,OAAO;AAAA,EACnD,OAAO,EAAE,OAAA,EAAS,IAAI,GAAG,uCAAuC;AACpE,CAAC;AAED,MAAM,0BAA0B,MAAM;AAClC,QAAM,EAAE,cAAc,iBAAiB,mBAAA,IACnC,sBAAA;AAEJ,QAAM;AAAA,IACF;AAAA,IACA,WAAW,EAAE,OAAA;AAAA,IACb;AAAA,IACA;AAAA,EAAA,IACA,QAAoB;AAAA,IACpB,eAAe;AAAA,MACX,OAAO,aAAa;AAAA,IAAA;AAAA,IAExB,UAAU,YAAY,gBAAgB;AAAA,EAAA,CACzC;AAED,YAAU,MAAM;AACZ,QAAI,aAAa,MAAM;AACnB,YAAM;AAAA,QACF,OAAO,aAAa;AAAA,MAAA,CACvB;AAAA,IACL;AAAA,EAEJ,GAAG,CAAC,aAAa,OAAO,aAAa,IAAI,CAAC;AAE1C,QAAM,oBAAoB,MAAM;AAC5B,oBAAgB;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IAAA,CACT;AAAA,EACL;AAEA,QAAM,eAAe,OAAO,EAAE,YAAwB;AAClD,uBAAmB;AAAA,MACf,IAAI,aAAa;AAAA,MACjB;AAAA,IAAA,CACH;AACD,sBAAA;AAAA,EACJ;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,QAAQ,aAAa;AAAA,MACrB,SAAS;AAAA,MACT,gBAAgB;AAAA,MAEhB,UAAA;AAAA,QAAA,oBAAC,QAAG,UAAA,cAAA,CAAW;AAAA,QACf,oBAAC,SAAI,WAAU,QACX,+BAAC,MAAA,EAAK,UAAU,aAAa,YAAY,GACrC,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACG,OAAM;AAAA,cACN,SAAS,QAAQ,OAAO,KAAK;AAAA,cAC7B,cAAc,OAAO,OAAO;AAAA,cAE5B,UAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACG,MAAK;AAAA,kBACL;AAAA,kBACA,OAAO,EAAE,UAAU,KAAA;AAAA,kBACnB,QAAQ,CAAC,EAAE,MAAA,MACP;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACG,aAAY;AAAA,sBACZ,MAAK;AAAA,sBACL,cAAa;AAAA,sBACZ,GAAG;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACR;AAAA,cAAA;AAAA,YAER;AAAA,UAAA;AAAA,UAEJ,qBAAC,OAAA,EAAI,WAAU,0BACX,UAAA;AAAA,YAAA,oBAAC,QAAA,EAAO,MAAK,UAAS,SAAS,mBAAmB,UAAA,UAElD;AAAA,gCACC,QAAA,EAAO,SAAQ,SAAQ,MAAK,UAAS,UAAA,SAAA,CAEtC;AAAA,UAAA,EAAA,CACJ;AAAA,QAAA,EAAA,CACJ,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;"}
1
+ {"version":3,"file":"ChatHistoryRenameDialog.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx"],"sourcesContent":["import { useEffect } from 'react'\nimport Dialog from '@/components/ui/Dialog'\nimport { Form, FormItem } from '@/components/ui/Form'\nimport Input from '@/components/ui/Input'\nimport Button from '@/components/ui/Button'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport useChatConversations from '../hooks/useChatConversations'\nimport { useForm, Controller } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { z } from 'zod'\nimport type { ZodType } from 'zod'\n\ntype FormSchema = {\n title: string\n}\n\nconst validationSchema: ZodType<FormSchema> = z.object({\n title: z.string().trim().min(1, 'Informe um título para a conversa.'),\n})\n\ntype ChatHistoryRenameDialogProps = {\n /** Classes do overlay (ex.: subir o z-index acima do widget flutuante). */\n overlayClassName?: string\n}\n\nconst ChatHistoryRenameDialog = ({\n overlayClassName,\n}: ChatHistoryRenameDialogProps) => {\n const { renameDialog, setRenameDialog } = usGenerativeChatStore()\n const { renomear } = useChatConversations()\n\n const {\n control,\n formState: { errors },\n handleSubmit,\n reset,\n } = useForm<FormSchema>({\n defaultValues: {\n title: renameDialog.title,\n },\n resolver: zodResolver(validationSchema),\n })\n\n useEffect(() => {\n if (renameDialog.open) {\n reset({\n title: renameDialog.title,\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [renameDialog.title, renameDialog.open])\n\n const handleDialogClose = () => {\n setRenameDialog({\n id: '',\n title: '',\n open: false,\n })\n }\n\n const onFormSubmit = async ({ title }: FormSchema) => {\n // Fecha antes da resposta: o rename é otimista e desfaz sozinho se o\n // backend recusar.\n const { id } = renameDialog\n handleDialogClose()\n await renomear(id, title.trim())\n }\n\n return (\n <Dialog\n isOpen={renameDialog.open}\n overlayClassName={overlayClassName}\n onClose={handleDialogClose}\n onRequestClose={handleDialogClose}\n >\n <h5>Rename chat</h5>\n <div className=\"mt-8\">\n <Form onSubmit={handleSubmit(onFormSubmit)}>\n <FormItem\n label=\"Chat title\"\n invalid={Boolean(errors.title)}\n errorMessage={errors.title?.message}\n >\n <Controller\n name=\"title\"\n control={control}\n rules={{ required: true }}\n render={({ field }) => (\n <Input\n placeholder=\"Rename chat\"\n type=\"text\"\n autoComplete=\"off\"\n {...field}\n />\n )}\n />\n </FormItem>\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" onClick={handleDialogClose}>\n Cancel\n </Button>\n <Button variant=\"solid\" type=\"submit\">\n Rename\n </Button>\n </div>\n </Form>\n </div>\n </Dialog>\n )\n}\n\nexport default ChatHistoryRenameDialog\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,mBAAwC,EAAE,OAAO;AAAA,EACnD,OAAO,EAAE,OAAA,EAAS,OAAO,IAAI,GAAG,oCAAoC;AACxE,CAAC;AAOD,MAAM,0BAA0B,CAAC;AAAA,EAC7B;AACJ,MAAoC;AAChC,QAAM,EAAE,cAAc,gBAAA,IAAoB,sBAAA;AAC1C,QAAM,EAAE,SAAA,IAAa,qBAAA;AAErB,QAAM;AAAA,IACF;AAAA,IACA,WAAW,EAAE,OAAA;AAAA,IACb;AAAA,IACA;AAAA,EAAA,IACA,QAAoB;AAAA,IACpB,eAAe;AAAA,MACX,OAAO,aAAa;AAAA,IAAA;AAAA,IAExB,UAAU,YAAY,gBAAgB;AAAA,EAAA,CACzC;AAED,YAAU,MAAM;AACZ,QAAI,aAAa,MAAM;AACnB,YAAM;AAAA,QACF,OAAO,aAAa;AAAA,MAAA,CACvB;AAAA,IACL;AAAA,EAEJ,GAAG,CAAC,aAAa,OAAO,aAAa,IAAI,CAAC;AAE1C,QAAM,oBAAoB,MAAM;AAC5B,oBAAgB;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IAAA,CACT;AAAA,EACL;AAEA,QAAM,eAAe,OAAO,EAAE,YAAwB;AAGlD,UAAM,EAAE,OAAO;AACf,sBAAA;AACA,UAAM,SAAS,IAAI,MAAM,KAAA,CAAM;AAAA,EACnC;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,QAAQ,aAAa;AAAA,MACrB;AAAA,MACA,SAAS;AAAA,MACT,gBAAgB;AAAA,MAEhB,UAAA;AAAA,QAAA,oBAAC,QAAG,UAAA,cAAA,CAAW;AAAA,QACf,oBAAC,SAAI,WAAU,QACX,+BAAC,MAAA,EAAK,UAAU,aAAa,YAAY,GACrC,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACG,OAAM;AAAA,cACN,SAAS,QAAQ,OAAO,KAAK;AAAA,cAC7B,cAAc,OAAO,OAAO;AAAA,cAE5B,UAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACG,MAAK;AAAA,kBACL;AAAA,kBACA,OAAO,EAAE,UAAU,KAAA;AAAA,kBACnB,QAAQ,CAAC,EAAE,MAAA,MACP;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACG,aAAY;AAAA,sBACZ,MAAK;AAAA,sBACL,cAAa;AAAA,sBACZ,GAAG;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACR;AAAA,cAAA;AAAA,YAER;AAAA,UAAA;AAAA,UAEJ,qBAAC,OAAA,EAAI,WAAU,0BACX,UAAA;AAAA,YAAA,oBAAC,QAAA,EAAO,MAAK,UAAS,SAAS,mBAAmB,UAAA,UAElD;AAAA,gCACC,QAAA,EAAO,SAAQ,SAAQ,MAAK,UAAS,UAAA,SAAA,CAEtC;AAAA,UAAA,EAAA,CACJ;AAAA,QAAA,EAAA,CACJ,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;"}
@@ -13,13 +13,15 @@ import ApprovalCard from "./ApprovalCard.js";
13
13
  import DataRequestCard from "./DataRequestCard.js";
14
14
  import { usGenerativeChatStore } from "../store/generativeChatStore.js";
15
15
  import useChatSend from "../hooks/useChatSend.js";
16
+ import useConversationMessages from "../hooks/useConversationMessages.js";
16
17
  import Card from "../../../../../components/ui/Card/Card.js";
17
18
  import ChatBox from "../../../../../components/view/ChatBox/ChatBox.js";
18
19
  const BALAO_AGENTE = "prose rounded-xl bg-gray-100 px-5 py-2.5 text-sm text-gray-900 dark:bg-gray-700 dark:text-gray-100";
19
- const ChatView = () => {
20
+ const ChatView = ({ showMobileNav = true }) => {
20
21
  const scrollRef = useRef(null);
21
22
  const { selectedConversation, chatHistory, isTyping, disabledChatFresh } = usGenerativeChatStore();
22
23
  const { handleSend, handleApproval, handleDataSubmit } = useChatSend();
24
+ const { carregando } = useConversationMessages();
23
25
  const scrollToBottom = () => {
24
26
  if (scrollRef.current?.getScrollElement) {
25
27
  const scrollElement = scrollRef.current.getScrollElement();
@@ -47,7 +49,7 @@ const ChatView = () => {
47
49
  scrollToBottom();
48
50
  };
49
51
  return /* @__PURE__ */ jsxs(Card, { className: "flex-1 h-full", bodyClass: "h-full", children: [
50
- /* @__PURE__ */ jsx(ChatMobileNav, {}),
52
+ showMobileNav && /* @__PURE__ */ jsx(ChatMobileNav, {}),
51
53
  /* @__PURE__ */ jsx(
52
54
  ChatBox,
53
55
  {
@@ -61,9 +63,9 @@ const ChatView = () => {
61
63
  botBubbleClass: "bg-transparent dark:bg-transparent p-0 rounded-none",
62
64
  errorBubbleClass: "bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/20",
63
65
  renderTyping: () => /* @__PURE__ */ jsx("div", { className: BALAO_AGENTE, children: /* @__PURE__ */ jsx(AiThinkingIndicator, {}) }),
64
- containerClass: "h-[calc(100%-30px)] xl:h-full",
66
+ containerClass: showMobileNav ? "h-[calc(100%-30px)] xl:h-full" : "h-full",
65
67
  messageListClass: "h-[calc(100%-100px)] xl:h-[calc(100%-70px)]",
66
- typing: isTyping ? {
68
+ typing: isTyping || carregando ? {
67
69
  id: "ai",
68
70
  name: "Chat AI",
69
71
  avatarImageUrl: "/img/thumbs/ai.jpg"