選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

index.tsx 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import {
  2. Accordion,
  3. AccordionContent,
  4. AccordionItem,
  5. AccordionTrigger,
  6. } from '@/components/ui/accordion';
  7. import {
  8. Sheet,
  9. SheetContent,
  10. SheetHeader,
  11. SheetTitle,
  12. } from '@/components/ui/sheet';
  13. import { INodeEvent, MessageEventType } from '@/hooks/use-send-message';
  14. import { IModalProps } from '@/interfaces/common';
  15. import { cn } from '@/lib/utils';
  16. import { NotebookText } from 'lucide-react';
  17. import { useCallback, useMemo } from 'react';
  18. import JsonView from 'react18-json-view';
  19. import 'react18-json-view/src/style.css';
  20. import { useCacheChatLog } from '../hooks/use-cache-chat-log';
  21. import useGraphStore from '../store';
  22. type LogSheetProps = IModalProps<any> &
  23. Pick<ReturnType<typeof useCacheChatLog>, 'currentEventListWithoutMessage'>;
  24. function JsonViewer({
  25. data,
  26. title,
  27. }: {
  28. data: Record<string, any>;
  29. title: string;
  30. }) {
  31. return (
  32. <section className="space-y-2">
  33. <div>{title}</div>
  34. <JsonView
  35. src={data}
  36. displaySize
  37. collapseStringsAfterLength={100000000000}
  38. className="w-full h-[200px] break-words overflow-auto p-2 bg-slate-800"
  39. />
  40. </section>
  41. );
  42. }
  43. export function LogSheet({
  44. hideModal,
  45. currentEventListWithoutMessage,
  46. }: LogSheetProps) {
  47. const getNode = useGraphStore((state) => state.getNode);
  48. const getNodeName = useCallback(
  49. (nodeId: string) => {
  50. return getNode(nodeId)?.data.name;
  51. },
  52. [getNode],
  53. );
  54. const finishedNodeList = useMemo(() => {
  55. return currentEventListWithoutMessage.filter(
  56. (x) => x.event === MessageEventType.NodeFinished,
  57. ) as INodeEvent[];
  58. }, [currentEventListWithoutMessage]);
  59. return (
  60. <Sheet open onOpenChange={hideModal} modal={false}>
  61. <SheetContent className="top-20 right-96">
  62. <SheetHeader>
  63. <SheetTitle className="flex items-center gap-1">
  64. <NotebookText className="size-4" />
  65. Log
  66. </SheetTitle>
  67. </SheetHeader>
  68. <section className="max-h-[82vh] overflow-auto">
  69. {finishedNodeList.map((x, idx) => (
  70. <section key={idx}>
  71. <Accordion type="single" collapsible>
  72. <AccordionItem value={idx.toString()}>
  73. <AccordionTrigger>
  74. <div className="flex gap-2 items-center">
  75. <span>{getNodeName(x.data?.component_id)}</span>
  76. <span className="text-text-sub-title text-xs">
  77. {x.data.elapsed_time?.toString().slice(0, 6)}
  78. </span>
  79. <span
  80. className={cn(
  81. 'border-background -end-1 -top-1 size-2 rounded-full border-2 bg-dot-green',
  82. { 'text-dot-green': x.data.error === null },
  83. { 'text-dot-red': x.data.error !== null },
  84. )}
  85. >
  86. <span className="sr-only">Online</span>
  87. </span>
  88. </div>
  89. </AccordionTrigger>
  90. <AccordionContent>
  91. <div className="space-y-2">
  92. <JsonViewer
  93. data={x.data.inputs}
  94. title="Input"
  95. ></JsonViewer>
  96. <JsonViewer
  97. data={x.data.outputs}
  98. title="Output"
  99. ></JsonViewer>
  100. </div>
  101. </AccordionContent>
  102. </AccordionItem>
  103. </Accordion>
  104. </section>
  105. ))}
  106. </section>
  107. </SheetContent>
  108. </Sheet>
  109. );
  110. }