RowSelectionHeader.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { AnimatePresence, motion } from 'framer-motion'
  2. import { Copy, X } from 'lucide-react'
  3. import { toast } from 'sonner'
  4. import {
  5. copyToClipboard,
  6. DropdownMenu,
  7. DropdownMenuContent,
  8. DropdownMenuItem,
  9. DropdownMenuTrigger,
  10. } from 'ui'
  11. import { type LogData } from '../Settings/Logs/Logs.types'
  12. import {
  13. buildLogsPrompt,
  14. formatLogsAsJson,
  15. formatLogsAsMarkdown,
  16. } from '../Settings/Logs/Logs.utils'
  17. import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
  18. import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown'
  19. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  20. import { useDataTable } from '@/components/ui/DataTable/providers/DataTableProvider'
  21. import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
  22. import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
  23. // TODO - format Logs as JSON, as markdown, and as prompt
  24. export const RowSelectionHeader = () => {
  25. const { openSidebar } = useSidebarManagerSnapshot()
  26. const aiSnap = useAiAssistantStateSnapshot()
  27. const { table } = useDataTable()
  28. const selectedRows = table.getSelectedRowModel().rows.map((x) => x.original) as LogData[]
  29. const handleOpenAiAssistant = () => {
  30. const prompt = buildLogsPrompt(selectedRows)
  31. openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
  32. aiSnap.newChat({ initialMessage: prompt })
  33. }
  34. const onCopy = (format: 'json' | 'markdown') => {
  35. const text =
  36. format === 'json' ? formatLogsAsJson(selectedRows) : formatLogsAsMarkdown(selectedRows)
  37. copyToClipboard(text, () => {
  38. toast.success(
  39. `Copied ${selectedRows.length} log${selectedRows.length !== 1 ? 's' : ''} as ${format.toUpperCase()}`
  40. )
  41. })
  42. }
  43. return (
  44. <div className="relative">
  45. <AnimatePresence>
  46. {selectedRows.length > 0 && (
  47. <motion.div
  48. initial={{ height: 0, opacity: 0 }}
  49. animate={{ height: '36px', opacity: 1 }}
  50. exit={{ height: 0, opacity: 0 }}
  51. transition={{
  52. type: 'spring',
  53. stiffness: 420,
  54. damping: 30,
  55. mass: 0.4,
  56. }}
  57. className="pl-4 pr-2 flex items-center justify-between border-t absolute top-0 z-99 bg-surface-75 w-full"
  58. style={{ overflow: 'hidden' }}
  59. >
  60. <p className="text-xs">
  61. {selectedRows.length} row{selectedRows.length > 1 ? 's' : ''} selected
  62. </p>
  63. <div className="flex items-center justify-center gap-x-1.5">
  64. <DropdownMenu>
  65. <DropdownMenuTrigger asChild>
  66. <ButtonTooltip
  67. type="default"
  68. size="tiny"
  69. icon={<Copy size={12} />}
  70. className="w-7"
  71. tooltip={{ content: { side: 'bottom', text: 'Copy selected logs' } }}
  72. />
  73. </DropdownMenuTrigger>
  74. <DropdownMenuContent align="end" className="w-44">
  75. <DropdownMenuItem onClick={() => onCopy('json')} className="gap-2 text-xs">
  76. <Copy size={13} />
  77. Copy as JSON
  78. </DropdownMenuItem>
  79. <DropdownMenuItem onClick={() => onCopy('markdown')} className="gap-2 text-xs">
  80. <Copy size={13} />
  81. Copy as Markdown
  82. </DropdownMenuItem>
  83. </DropdownMenuContent>
  84. </DropdownMenu>
  85. <AiAssistantDropdown
  86. label="Explain with AI"
  87. buildPrompt={() => buildLogsPrompt(selectedRows)}
  88. onOpenAssistant={handleOpenAiAssistant}
  89. telemetrySource="log_explorer"
  90. />
  91. <ButtonTooltip
  92. type="text"
  93. icon={<X />}
  94. className="px-1"
  95. onClick={() => table.resetRowSelection()}
  96. tooltip={{ content: { side: 'bottom', text: 'Clear selection' } }}
  97. />
  98. </div>
  99. </motion.div>
  100. )}
  101. </AnimatePresence>
  102. </div>
  103. )
  104. }