@flamingo-stack/openframe-frontend-core 0.0.222 → 0.0.223

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 (183) hide show
  1. package/dist/{chunk-AIKPR6BE.js → chunk-4VHWSAQR.js} +6069 -5235
  2. package/dist/chunk-4VHWSAQR.js.map +1 -0
  3. package/dist/{chunk-GMNE7P7V.cjs → chunk-4WBVMIKQ.cjs} +26 -26
  4. package/dist/{chunk-GMNE7P7V.cjs.map → chunk-4WBVMIKQ.cjs.map} +1 -1
  5. package/dist/{chunk-QYRV6MKX.js → chunk-53EA4QPZ.js} +13 -7
  6. package/dist/chunk-53EA4QPZ.js.map +1 -0
  7. package/dist/{chunk-4JOWZLEL.cjs → chunk-7TKYFZ3L.cjs} +7 -7
  8. package/dist/{chunk-4JOWZLEL.cjs.map → chunk-7TKYFZ3L.cjs.map} +1 -1
  9. package/dist/{chunk-IZA5WF44.cjs → chunk-ABBU7QOM.cjs} +12 -12
  10. package/dist/{chunk-IZA5WF44.cjs.map → chunk-ABBU7QOM.cjs.map} +1 -1
  11. package/dist/{chunk-KM4KK2A6.cjs → chunk-ENDUMC7Z.cjs} +2558 -1724
  12. package/dist/chunk-ENDUMC7Z.cjs.map +1 -0
  13. package/dist/{chunk-CCSEXVI4.js → chunk-GYYGA24C.js} +2 -2
  14. package/dist/{chunk-RMOHKAHA.js → chunk-ISWWP2BH.js} +3 -3
  15. package/dist/{chunk-QNYH3WUU.cjs → chunk-JUWPBMQM.cjs} +13 -7
  16. package/dist/chunk-JUWPBMQM.cjs.map +1 -0
  17. package/dist/{chunk-A2SFHYVF.cjs → chunk-KXLTWANQ.cjs} +10 -10
  18. package/dist/{chunk-A2SFHYVF.cjs.map → chunk-KXLTWANQ.cjs.map} +1 -1
  19. package/dist/{chunk-ND24XSVT.js → chunk-TA6Z2AKD.js} +3 -3
  20. package/dist/chunk-TA6Z2AKD.js.map +1 -0
  21. package/dist/{chunk-HRIAZQ5D.js → chunk-WOKB6RJ7.js} +3 -3
  22. package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
  23. package/dist/components/chat/chat-composer.d.ts.map +1 -1
  24. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  25. package/dist/components/chat/chat-message-skeleton.d.ts +19 -4
  26. package/dist/components/chat/chat-message-skeleton.d.ts.map +1 -1
  27. package/dist/components/chat/chat-panel-header-mobile.d.ts +24 -0
  28. package/dist/components/chat/chat-panel-header-mobile.d.ts.map +1 -0
  29. package/dist/components/chat/chat-panel-header.d.ts +6 -0
  30. package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
  31. package/dist/components/chat/chat-quick-action-row.d.ts +31 -0
  32. package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -0
  33. package/dist/components/chat/embeddable-chat.d.ts +27 -0
  34. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  35. package/dist/components/chat/entity-cards/dispatch.d.ts +14 -0
  36. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  37. package/dist/components/chat/entity-cards/github-activity-card.d.ts +10 -1
  38. package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -1
  39. package/dist/components/chat/guide-welcome.d.ts.map +1 -1
  40. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +9 -0
  41. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  42. package/dist/components/chat/hooks/use-slash-commands.d.ts +26 -0
  43. package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
  44. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +12 -1
  45. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  46. package/dist/components/chat/hooks/use-unified-chat.d.ts +12 -0
  47. package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
  48. package/dist/components/chat/index.cjs +9 -3
  49. package/dist/components/chat/index.cjs.map +1 -1
  50. package/dist/components/chat/index.js +8 -2
  51. package/dist/components/chat/mingo-chat-history.d.ts +10 -0
  52. package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
  53. package/dist/components/chat/mingo-info-card.d.ts +63 -0
  54. package/dist/components/chat/mingo-info-card.d.ts.map +1 -0
  55. package/dist/components/chat/mingo-welcome.d.ts +14 -1
  56. package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
  57. package/dist/components/chat/types/chat.types.d.ts +6 -0
  58. package/dist/components/chat/types/chat.types.d.ts.map +1 -1
  59. package/dist/components/chat/types/unified-chat-state.types.d.ts +30 -0
  60. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  61. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  62. package/dist/components/contact/index.cjs +4 -4
  63. package/dist/components/contact/index.js +3 -3
  64. package/dist/components/features/index.cjs +3 -3
  65. package/dist/components/features/index.js +2 -2
  66. package/dist/components/index.cjs +110 -104
  67. package/dist/components/index.cjs.map +1 -1
  68. package/dist/components/index.js +36 -30
  69. package/dist/components/index.js.map +1 -1
  70. package/dist/components/navigation/app-layout-drawer.d.ts +7 -0
  71. package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
  72. package/dist/components/navigation/index.cjs +3 -3
  73. package/dist/components/navigation/index.js +2 -2
  74. package/dist/components/onboarding-guides/index.cjs +26 -26
  75. package/dist/components/onboarding-guides/index.js +4 -4
  76. package/dist/components/tickets/index.cjs +67 -67
  77. package/dist/components/tickets/index.js +5 -5
  78. package/dist/components/ui/actions-menu.d.ts +9 -0
  79. package/dist/components/ui/actions-menu.d.ts.map +1 -1
  80. package/dist/components/ui/dropdown-button.d.ts +2 -2
  81. package/dist/components/ui/dropdown-button.d.ts.map +1 -1
  82. package/dist/components/ui/index.cjs +9 -3
  83. package/dist/components/ui/index.cjs.map +1 -1
  84. package/dist/components/ui/index.js +8 -2
  85. package/dist/components/ui/modal-v2.d.ts.map +1 -1
  86. package/dist/components/ui/more-actions-menu.d.ts +13 -0
  87. package/dist/components/ui/more-actions-menu.d.ts.map +1 -1
  88. package/dist/components/ui/square-avatar.d.ts +4 -0
  89. package/dist/components/ui/square-avatar.d.ts.map +1 -1
  90. package/dist/components/ui/textarea.d.ts.map +1 -1
  91. package/dist/hooks/index.cjs +2 -2
  92. package/dist/hooks/index.js +1 -1
  93. package/dist/hooks/ui/use-auto-limit-tags.d.ts +7 -1
  94. package/dist/hooks/ui/use-auto-limit-tags.d.ts.map +1 -1
  95. package/dist/index.cjs +9 -3
  96. package/dist/index.cjs.map +1 -1
  97. package/dist/index.js +8 -2
  98. package/package.json +1 -1
  99. package/src/components/chat/chat-archive-page.tsx +32 -7
  100. package/src/components/chat/chat-composer.tsx +6 -2
  101. package/src/components/chat/chat-message-enhanced.tsx +24 -7
  102. package/src/components/chat/chat-message-list.tsx +1 -1
  103. package/src/components/chat/chat-message-skeleton.tsx +60 -60
  104. package/src/components/chat/chat-panel-header-mobile.tsx +94 -0
  105. package/src/components/chat/chat-panel-header.tsx +78 -50
  106. package/src/components/chat/chat-quick-action-row.tsx +146 -0
  107. package/src/components/chat/embeddable-chat.tsx +140 -45
  108. package/src/components/chat/entity-cards/dispatch.tsx +770 -232
  109. package/src/components/chat/entity-cards/github-activity-card.tsx +9 -3
  110. package/src/components/chat/guide-welcome.tsx +11 -8
  111. package/src/components/chat/hooks/use-nats-chat-adapter.ts +80 -7
  112. package/src/components/chat/hooks/use-slash-commands.ts +39 -0
  113. package/src/components/chat/hooks/use-sse-chat-adapter.ts +49 -45
  114. package/src/components/chat/hooks/use-unified-chat.ts +31 -8
  115. package/src/components/chat/mingo-chat-history.tsx +118 -36
  116. package/src/components/chat/mingo-info-card.tsx +214 -0
  117. package/src/components/chat/mingo-welcome.tsx +89 -36
  118. package/src/components/chat/types/chat.types.ts +4 -0
  119. package/src/components/chat/types/unified-chat-state.types.ts +35 -0
  120. package/src/components/chat/utils/process-historical-messages.ts +8 -0
  121. package/src/components/content-loading-container.tsx +1 -1
  122. package/src/components/empty-state.tsx +3 -3
  123. package/src/components/faq-accordion.tsx +2 -2
  124. package/src/components/features/changelog-manager.tsx +2 -2
  125. package/src/components/features/highlight-config-section.tsx +2 -2
  126. package/src/components/features/og-editor-preview.tsx +3 -3
  127. package/src/components/features/release-media-manager.tsx +2 -2
  128. package/src/components/loading/card-skeleton.tsx +3 -3
  129. package/src/components/loading/device-card-skeleton.tsx +1 -1
  130. package/src/components/loading/margin-report-skeleton.tsx +2 -2
  131. package/src/components/loading/organization-card-skeleton.tsx +1 -1
  132. package/src/components/loading/organization-icon-skeleton.tsx +1 -1
  133. package/src/components/loading/page-layout-skeleton.tsx +9 -9
  134. package/src/components/loading/users-grid-skeleton.tsx +2 -2
  135. package/src/components/logs-list.tsx +1 -1
  136. package/src/components/media-carousel.tsx +1 -1
  137. package/src/components/navigation/app-layout-drawer.tsx +70 -6
  138. package/src/components/open-source-features.tsx +2 -2
  139. package/src/components/ui/actions-menu.tsx +36 -13
  140. package/src/components/ui/allowed-domains-input.tsx +3 -3
  141. package/src/components/ui/cursor-pagination.tsx +1 -1
  142. package/src/components/ui/dropdown-button.tsx +6 -6
  143. package/src/components/ui/info-row.tsx +2 -2
  144. package/src/components/ui/modal-v2.tsx +8 -1
  145. package/src/components/ui/more-actions-menu.tsx +13 -0
  146. package/src/components/ui/square-avatar.tsx +6 -1
  147. package/src/components/ui/tags-input.tsx +1 -1
  148. package/src/components/ui/textarea.tsx +18 -4
  149. package/src/components/vendor-icon.tsx +1 -1
  150. package/src/components/vendor-tag.tsx +1 -1
  151. package/src/components/why-it-matters.tsx +1 -1
  152. package/src/hooks/ui/use-auto-limit-tags.ts +22 -8
  153. package/src/stories/ActionsMenu.stories.tsx +256 -0
  154. package/src/stories/AppLayoutSidebar.stories.tsx +6 -0
  155. package/src/stories/Board.stories.tsx +1 -1
  156. package/src/stories/ChatMingoInfoCards.stories.tsx +748 -0
  157. package/src/stories/ChatTicketList.stories.tsx +1 -1
  158. package/src/stories/DataTable.stories.tsx +17 -13
  159. package/src/stories/EmbeddableChat.stories.tsx +233 -1
  160. package/src/stories/MingoInfoCard.stories.tsx +193 -0
  161. package/src/stories/MingoOnboardingCard.stories.tsx +1 -1
  162. package/src/stories/Modal.stories.tsx +1 -0
  163. package/src/stories/NotificationDrawer.stories.tsx +14 -3
  164. package/src/stories/PageActions.stories.tsx +4 -4
  165. package/src/stories/PageContainer.stories.tsx +5 -5
  166. package/src/stories/PageLayout.stories.tsx +1 -1
  167. package/src/stories/TabSelector.stories.tsx +2 -2
  168. package/src/stories/Tag.stories.tsx +10 -5
  169. package/src/stories/TicketInfoSection.stories.tsx +23 -11
  170. package/src/stories/Toaster.stories.tsx +5 -5
  171. package/src/stories/__fixtures__/chat-card-decorator.tsx +44 -0
  172. package/dist/chunk-AIKPR6BE.js.map +0 -1
  173. package/dist/chunk-KM4KK2A6.cjs.map +0 -1
  174. package/dist/chunk-ND24XSVT.js.map +0 -1
  175. package/dist/chunk-QNYH3WUU.cjs.map +0 -1
  176. package/dist/chunk-QYRV6MKX.js.map +0 -1
  177. package/src/stories/.TicketDescriptionViewer.stories.md +0 -39
  178. package/src/stories/.TicketKnowledgeBaseList.stories.md +0 -36
  179. package/src/stories/TicketDescriptionViewer.stories.tsx +0 -70
  180. package/src/stories/TicketKnowledgeBaseList.stories.tsx +0 -51
  181. /package/dist/{chunk-CCSEXVI4.js.map → chunk-GYYGA24C.js.map} +0 -0
  182. /package/dist/{chunk-RMOHKAHA.js.map → chunk-ISWWP2BH.js.map} +0 -0
  183. /package/dist/{chunk-HRIAZQ5D.js.map → chunk-WOKB6RJ7.js.map} +0 -0
@@ -56,6 +56,7 @@ import { ChatComposer } from './chat-composer'
56
56
  import { useChatDialogManager } from './hooks/use-chat-dialog-manager'
57
57
  import { ChatDialogModals } from './mingo-chat-modals'
58
58
  import { ChatMessageList } from './chat-message-list'
59
+ import { ChatMessageListSkeleton } from './chat-message-skeleton'
59
60
  import { SourceActionButton } from './source-action-button'
60
61
  import { NavLinkAnchorViaRuntime } from './nav-link-anchor-via-runtime'
61
62
  import { ChatAttachmentChipStrip } from './chat-attachment-bar'
@@ -70,6 +71,7 @@ import {
70
71
  type ChatMode,
71
72
  type UseUnifiedChatModes,
72
73
  } from './hooks/use-unified-chat'
74
+ import type { UnifiedChatState } from './types/unified-chat-state.types'
73
75
  import type {
74
76
  UseNatsChatAdapterConfig,
75
77
  FetchDialogsParams,
@@ -79,7 +81,7 @@ import { useChatAttachments } from './hooks/use-chat-attachments'
79
81
  import { useChatAttachmentImageGallery } from './hooks/use-chat-attachment-image-gallery'
80
82
  import { useChatIdentity } from './hooks/use-chat-identity'
81
83
  import { useCloseOnNavigation } from './hooks/use-close-on-navigation'
82
- import { fetchSlashCommands, type SlashCommandSummary } from './hooks/use-slash-commands'
84
+ import { fetchSlashCommands, useSlashCommandRegistry, type SlashCommandSummary } from './hooks/use-slash-commands'
83
85
 
84
86
  import type { ChatRef } from './chat-ref.types'
85
87
  import type { ChatInputRef, SlashCommandActionId } from './types/component.types'
@@ -162,6 +164,35 @@ export interface EmbeddableChatProps {
162
164
  */
163
165
  modes?: UseUnifiedChatModes
164
166
 
167
+ /**
168
+ * Pre-built Mingo-mode state, supplied by the host instead of letting the
169
+ * built-in NATS adapter own it. When provided, the panel renders Mingo mode
170
+ * from this object and opens no subscription of its own — the host keeps
171
+ * chat data + streaming in its own store/cache so it survives the panel
172
+ * unmounting (no `keepMounted` needed). The host should then NOT pass
173
+ * `modes.mingo` (Guide-mode wiring via `modes.guide` is unaffected).
174
+ */
175
+ mingoState?: UnifiedChatState
176
+
177
+ /**
178
+ * Dialog-management capabilities for injected Mingo mode (`mingoState`).
179
+ *
180
+ * When the host injects `mingoState`, it doesn't pass `modes.mingo` (that
181
+ * would re-activate the idle built-in adapter), so the rename/archive/
182
+ * restore/archive-page affordances can't read their capability flags off the
183
+ * callback config. Supply them here instead. `canRename`/`canArchive` default
184
+ * to `true` when `mingoState` is set; the archive page + restore are shown
185
+ * only when their callbacks are provided. Ignored unless `mingoState` is set.
186
+ */
187
+ mingoDialogCapabilities?: {
188
+ canRename?: boolean
189
+ canArchive?: boolean
190
+ fetchArchivedDialogs?: (
191
+ params: FetchDialogsParams,
192
+ ) => Promise<FetchDialogsResult>
193
+ unarchiveDialog?: (id: string) => Promise<void>
194
+ }
195
+
165
196
  /**
166
197
  * Controlled active-mode. When provided, `onActiveModeChange` MUST
167
198
  * also be provided. For uncontrolled use see `defaultActiveMode`.
@@ -605,6 +636,8 @@ function EmbeddableChatInner({
605
636
  extras,
606
637
  tableIdForDocumentType,
607
638
  modes,
639
+ mingoState,
640
+ mingoDialogCapabilities,
608
641
  activeMode: controlledActiveMode,
609
642
  onActiveModeChange,
610
643
  defaultActiveMode,
@@ -698,35 +731,9 @@ function EmbeddableChatInner({
698
731
  // Imperative handle to the chat input.
699
732
  const chatInputRef = useRef<ChatInputRef | null>(null)
700
733
 
701
- // Async lookup of the slash-command registry for the current source.
702
- const [commandsById, setCommandsById] = useState<Map<string, SlashCommandSummary>>(
703
- () => new Map(),
704
- )
705
- const [commandsLoaded, setCommandsLoaded] = useState(false)
706
- useEffect(() => {
707
- if (!isOpen) return
708
- let cancelled = false
709
- const ctrl = new AbortController()
710
- setCommandsLoaded(false)
711
- fetchSlashCommands('', ctrl.signal, commandsUrl)
712
- .then((commands) => {
713
- if (cancelled) return
714
- const map = new Map<string, SlashCommandSummary>()
715
- for (const cmd of commands) map.set(cmd.id, cmd)
716
- setCommandsById(map)
717
- setCommandsLoaded(true)
718
- })
719
- .catch((err) => {
720
- if (!cancelled && (err as Error)?.name !== 'AbortError') {
721
- console.warn('[embeddable-chat] failed to fetch slash commands:', err)
722
- setCommandsLoaded(true)
723
- }
724
- })
725
- return () => {
726
- cancelled = true
727
- ctrl.abort()
728
- }
729
- }, [isOpen, source, commandsUrl])
734
+ // The slash-command registry (Guide onboarding cards) is loaded via
735
+ // react-query below, after `activeMode` is resolved — gated on Guide mode and
736
+ // cached across remounts. See `commandsById` / `commandsLoaded`.
730
737
 
731
738
  // Slash-command autocomplete config — passed to <ChatInput>.
732
739
  const slashCommandsProp = useMemo(
@@ -774,6 +781,36 @@ function EmbeddableChatInner({
774
781
  return { guide: guideOptions }
775
782
  }, [modes, tableIdForDocumentType])
776
783
 
784
+ // Resolve dialog-management capabilities (rename / archive / archive-page /
785
+ // restore) from a single source. With injected `mingoState` they come from
786
+ // `mingoDialogCapabilities` (the host doesn't pass `modes.mingo`); otherwise
787
+ // from the callback-config shape, where the presence of a callback IS the
788
+ // capability. Both feed the same gating below so the JSX has one source.
789
+ const mingoCaps = useMemo(() => {
790
+ if (mingoState) {
791
+ // Default OFF: the row ⋯ menu (Rename / Archive) and the archive page are
792
+ // shown only when the host explicitly opts in — same capability-gating as
793
+ // the archive button (`fetchArchivedDialogs` presence). Otherwise the menu
794
+ // would advertise actions the host hasn't actually wired (no-ops).
795
+ return {
796
+ canRename: mingoDialogCapabilities?.canRename ?? false,
797
+ canArchive: mingoDialogCapabilities?.canArchive ?? false,
798
+ fetchArchivedDialogs: mingoDialogCapabilities?.fetchArchivedDialogs,
799
+ unarchiveDialog: mingoDialogCapabilities?.unarchiveDialog,
800
+ }
801
+ }
802
+ return {
803
+ canRename: !!effectiveModes.mingo?.renameDialog,
804
+ canArchive: !!effectiveModes.mingo?.archiveDialog,
805
+ fetchArchivedDialogs: effectiveModes.mingo?.fetchArchivedDialogs,
806
+ unarchiveDialog: effectiveModes.mingo?.unarchiveDialog,
807
+ }
808
+ }, [mingoState, mingoDialogCapabilities, effectiveModes])
809
+
810
+ // "Does Mingo mode exist?" — true via either the callback config OR injected
811
+ // state. Gates the guide↔mingo back-chevron and the guide-mode banner.
812
+ const hasMingoMode = !!effectiveModes.mingo || !!mingoState
813
+
777
814
  // Initial active mode picks the first configured slot when neither
778
815
  // controlled `activeMode` nor `defaultActiveMode` is provided. Guide
779
816
  // wins ties so legacy callers see no behaviour change.
@@ -795,6 +832,22 @@ function EmbeddableChatInner({
795
832
  [controlledActiveMode, onActiveModeChange],
796
833
  )
797
834
 
835
+ // Slash-command registry (Guide onboarding cards) via the shared
836
+ // `useSlashCommandRegistry` react-query hook:
837
+ // - `enabled: activeMode === 'guide'` → never fetched in Mingo mode, so
838
+ // opening the default Mingo panel doesn't hit the commands endpoint.
839
+ // - Shares one cache entry (keyed on `commandsUrl`) with the SSE adapter's
840
+ // `displayRef` lookup, so Guide mode fetches `commands` ONCE, not twice.
841
+ // - Cached with `staleTime/gcTime: Infinity` inside the hook, so toggling
842
+ // to Guide or reopening the (remounting) drawer reads from cache.
843
+ const { commands: commandsList, loaded: commandsLoaded } =
844
+ useSlashCommandRegistry(commandsUrl, { enabled: activeMode === 'guide' })
845
+ const commandsById = useMemo(() => {
846
+ const map = new Map<string, SlashCommandSummary>()
847
+ for (const cmd of commandsList) map.set(cmd.id, cmd)
848
+ return map
849
+ }, [commandsList])
850
+
798
851
  const {
799
852
  messages: rawMessages,
800
853
  isLoading: chatLoading,
@@ -817,9 +870,12 @@ function EmbeddableChatInner({
817
870
  renameDialog,
818
871
  archiveDialog,
819
872
  isDialogsLoading,
873
+ dialogsError,
874
+ reloadDialogs,
875
+ isMessagesLoading,
820
876
  hasMoreDialogs,
821
877
  loadMoreDialogs,
822
- } = useUnifiedChat({ modes: effectiveModes, activeMode })
878
+ } = useUnifiedChat({ modes: effectiveModes, activeMode, mingoStateOverride: mingoState })
823
879
 
824
880
  // Chat-attachment hooks (v2 attachment feature).
825
881
  const {
@@ -884,7 +940,14 @@ function EmbeddableChatInner({
884
940
  rawMessages.map((m) => ({
885
941
  id: m.id,
886
942
  role: m.role as 'user' | 'assistant',
887
- name: m.role === 'assistant' ? 'Mingo AI' : 'You',
943
+ // Host-supplied per-message name/avatar win (e.g. the signed-in user's
944
+ // full name + photo on a `user` bubble); fall back to the role default
945
+ // when the host doesn't provide them.
946
+ name: m.name ?? (m.role === 'assistant' ? 'Mingo' : 'You'),
947
+ avatar: m.avatar ?? null,
948
+ // Forward the host's authorType so user bubbles get the same accent
949
+ // name color as the standalone /mingo page (user → 'admin').
950
+ ...(m.authorType ? { authorType: m.authorType } : {}),
888
951
  content: m.segments && m.segments.length > 0 ? m.segments : m.content,
889
952
  timestamp: new Date(),
890
953
  assistantType: m.role === 'assistant' ? ('mingo' as const) : undefined,
@@ -951,8 +1014,8 @@ function EmbeddableChatInner({
951
1014
  clearMessages,
952
1015
  renameDialog,
953
1016
  archiveDialog,
954
- fetchArchivedDialogs: effectiveModes.mingo?.fetchArchivedDialogs,
955
- unarchiveDialog: effectiveModes.mingo?.unarchiveDialog,
1017
+ fetchArchivedDialogs: mingoCaps.fetchArchivedDialogs,
1018
+ unarchiveDialog: mingoCaps.unarchiveDialog,
956
1019
  })
957
1020
 
958
1021
  const handleOpen = useCallback(() => setIsOpen(true), [setIsOpen])
@@ -983,12 +1046,24 @@ function EmbeddableChatInner({
983
1046
  }, [source, discussRef, setIsOpen])
984
1047
 
985
1048
  const hasMessages = messages.length > 0
1049
+ // First dialog page in flight and nothing cached yet — we don't yet know if
1050
+ // the user is new or returning, so the Mingo empty state shows a skeleton
1051
+ // rather than flashing the new-user greeting+grid before the list lands.
1052
+ const dialogsInitialLoading = isDialogsLoading && dialogs.length === 0
1053
+ // Dialog list failed to load (e.g. backend down) and we have nothing cached.
1054
+ // Distinct from "no chats" so the Mingo empty state can offer a retry instead
1055
+ // of the new-user greeting (which misleadingly advertises Guide).
1056
+ const dialogsLoadError = dialogsError && dialogs.length === 0
986
1057
  // A conversation is "open" the instant a chat is selected (`isOpeningDialog` /
987
1058
  // `isViewingArchived` are set synchronously on click) — not only once its
988
1059
  // history has loaded (`hasMessages`). Driving the surface + content branch
989
1060
  // off this makes the normal-chat open animate identically to the archived
990
1061
  // one instead of lagging behind the message fetch.
991
1062
  const hasConversation = hasMessages || isOpeningDialog || isViewingArchived
1063
+ // Opening a dialog whose history hasn't arrived yet — show a message-list
1064
+ // skeleton instead of an empty thread so the open reads as "loading" rather
1065
+ // than a blank flash before the bubbles stream in.
1066
+ const messagesInitialLoading = isMessagesLoading && !hasMessages
992
1067
  // Keys the content region so each distinct view (open conversation, Mingo
993
1068
  // welcome, Guide onboarding) remounts on switch → fades in for 200ms, the
994
1069
  // same feel as the surface flip. Switching dialogs stays "conversation" so
@@ -999,7 +1074,7 @@ function EmbeddableChatInner({
999
1074
  const isGuideEmpty = !hasConversation && activeMode === 'guide'
1000
1075
  // The guide-empty back-chevron returns to Mingo — only offer it when Mingo
1001
1076
  // mode actually exists to return to (guide is normally entered from Mingo).
1002
- const guideCanReturnToMingo = isGuideEmpty && !!effectiveModes.mingo
1077
+ const guideCanReturnToMingo = isGuideEmpty && hasMingoMode
1003
1078
  const sourceLabel = source === 'flamingo' ? 'Knowledge Base' : 'Data Room'
1004
1079
 
1005
1080
  // Empty-state chip grid — derived directly from the fetched slash commands.
@@ -1127,12 +1202,12 @@ function EmbeddableChatInner({
1127
1202
  : undefined
1128
1203
  }
1129
1204
  onRename={
1130
- activeDialogId && activeDialog && effectiveModes.mingo?.renameDialog
1205
+ activeDialogId && activeDialog && mingoCaps.canRename
1131
1206
  ? () => setRenameTarget(activeDialog)
1132
1207
  : undefined
1133
1208
  }
1134
1209
  onArchive={
1135
- activeDialogId && activeDialog && effectiveModes.mingo?.archiveDialog
1210
+ activeDialogId && activeDialog && mingoCaps.canArchive
1136
1211
  ? () => setArchiveTarget(activeDialog)
1137
1212
  : undefined
1138
1213
  }
@@ -1144,7 +1219,7 @@ function EmbeddableChatInner({
1144
1219
  Guide mode is active AND the default (Mingo) mode also exists:
1145
1220
  the banner contrasts the temporary Guide session against the
1146
1221
  default chat, so it's meaningless in a guide-only setup. */}
1147
- {activeMode === 'guide' && !!effectiveModes.mingo && (
1222
+ {activeMode === 'guide' && hasMingoMode && (
1148
1223
  <GuideModeBanner className="animate-in fade-in-0 duration-200" />
1149
1224
  )}
1150
1225
 
@@ -1164,17 +1239,38 @@ function EmbeddableChatInner({
1164
1239
  >
1165
1240
  {hasConversation ? (
1166
1241
  <div className="flex-1 flex flex-col min-h-0">
1242
+ {messagesInitialLoading ? (
1243
+ // Match the real list's `fullWidth` layout so swapping
1244
+ // skeleton → bubbles doesn't shift the column. The panel
1245
+ // wrapper above already pads (`p-[var(--spacing-system-m)]`),
1246
+ // so the skeleton sits flush (no inner px/pb).
1247
+ <ChatMessageListSkeleton
1248
+ fullWidth
1249
+ className="flex-1"
1250
+ />
1251
+ ) : (
1167
1252
  <ChatMessageList
1168
1253
  messages={messages}
1169
1254
  isTyping={chatLoading}
1170
1255
  autoScroll={true}
1171
1256
  assistantType="mingo"
1172
- assistantIcon={<MingoIcon className="h-4 w-4" color="white" />}
1257
+ assistantIcon={
1258
+ <MingoIcon
1259
+ className="h-6 w-6"
1260
+ cornerColor="var(--ods-flamingo-cyan-base)"
1261
+ />
1262
+ }
1173
1263
  renderEntityCard={renderEntityCard}
1174
1264
  NavLinkAnchor={NavLinkAnchorViaRuntime}
1175
1265
  className="flex-1"
1266
+ // No inner `px`/`pb`: the panel wrapper already pads with
1267
+ // `p-[var(--spacing-system-m)]`. The default content class
1268
+ // adds `px-[var(--spacing-system-m)]` + `pb-…xs`, which
1269
+ // double-inset the thread; `pb-0` overrides via twMerge.
1270
+ contentClassName="max-w-none pb-0"
1176
1271
  fullWidth
1177
1272
  />
1273
+ )}
1178
1274
  {lastSources &&
1179
1275
  (lastSources.cited.length > 0 ||
1180
1276
  lastSources.uncited.length > 0) &&
@@ -1207,20 +1303,19 @@ function EmbeddableChatInner({
1207
1303
  // Derived internally (returning-user variation) — placed
1208
1304
  // after the spread so it can't be overridden by the prop.
1209
1305
  hasExistingChats={dialogs.length > 0}
1306
+ isLoadingHistory={dialogsInitialLoading}
1307
+ loadError={dialogsLoadError}
1308
+ onRetry={reloadDialogs}
1210
1309
  dialogHistory={
1211
1310
  dialogs.length > 0 ? (
1212
1311
  <MingoChatHistory
1213
1312
  dialogs={dialogs}
1214
1313
  onSelectDialog={handleSelectDialog}
1215
1314
  onRequestRename={
1216
- effectiveModes.mingo?.renameDialog
1217
- ? setRenameTarget
1218
- : undefined
1315
+ mingoCaps.canRename ? setRenameTarget : undefined
1219
1316
  }
1220
1317
  onRequestArchive={
1221
- effectiveModes.mingo?.archiveDialog
1222
- ? setArchiveTarget
1223
- : undefined
1318
+ mingoCaps.canArchive ? setArchiveTarget : undefined
1224
1319
  }
1225
1320
  hasMore={hasMoreDialogs}
1226
1321
  isLoadingMore={isDialogsLoading && dialogs.length > 0}