From aa57984bde7b4b6117c3d88bf421447560bdc50d Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 11 Oct 2024 03:55:35 +0100 Subject: [PATCH 01/14] build: added missing dependency --- extensions/react-widget/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index d449d0a3..677a6564 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -40,6 +40,7 @@ }, "dependencies": { "@babel/plugin-transform-flow-strip-types": "^7.23.3", + "@bpmn-io/snarkdown": "^2.2.0", "@parcel/resolver-glob": "^2.12.0", "@parcel/transformer-svg-react": "^2.12.0", "@parcel/transformer-typescript-tsc": "^2.12.0", From 0481e766ae420bbab3ed86b106448d3338952277 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Mon, 14 Oct 2024 12:30:57 +0100 Subject: [PATCH 02/14] chore: updated Query and WidgetProps interface with source property --- extensions/react-widget/src/types/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index a55b6342..bd27910b 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -1,16 +1,21 @@ export type MESSAGE_TYPE = 'QUESTION' | 'ANSWER' | 'ERROR'; + export type Status = 'idle' | 'loading' | 'failed'; + export type FEEDBACK = 'LIKE' | 'DISLIKE'; + export type THEME = 'light' | 'dark'; + export interface Query { prompt: string; response?: string; feedback?: FEEDBACK; error?: string; - sources?: { title: string; text: string }[]; + sources?: { title: string; text: string, source:string }[]; conversationId?: string | null; title?: string | null; } + export interface WidgetProps { apiHost?: string; apiKey?: string; @@ -24,4 +29,5 @@ export interface WidgetProps { buttonIcon?:string; buttonBg?:string; collectFeedback?:boolean + showSources?: boolean } \ No newline at end of file From 848beb11dfe0fb50b056b0fbb9fce2545080c846 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Mon, 14 Oct 2024 12:33:56 +0100 Subject: [PATCH 03/14] chore: corrected typo in var declaration --- extensions/react-widget/src/requests/streamingApi.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/react-widget/src/requests/streamingApi.ts b/extensions/react-widget/src/requests/streamingApi.ts index 9cb9fddc..d5f79fe1 100644 --- a/extensions/react-widget/src/requests/streamingApi.ts +++ b/extensions/react-widget/src/requests/streamingApi.ts @@ -1,8 +1,10 @@ import { FEEDBACK } from "@/types"; + interface HistoryItem { prompt: string; response?: string; } + interface FetchAnswerStreamingProps { question?: string; apiKey?: string; @@ -12,12 +14,14 @@ interface FetchAnswerStreamingProps { apiHost?: string; onEvent?: (event: MessageEvent) => void; } + interface FeedbackPayload { question: string; answer: string; apikey: string; feedback: FEEDBACK; } + export function fetchAnswerStreaming({ question = '', apiKey = '', @@ -46,7 +50,7 @@ export function fetchAnswerStreaming({ const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); - let counterrr = 0; + let counter = 0; const processStream = ({ done, value, @@ -56,7 +60,7 @@ export function fetchAnswerStreaming({ return; } - counterrr += 1; + counter += 1; const chunk = decoder.decode(value); From 62802eb13882e6ba8581e62610670e8639bf830f Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Mon, 14 Oct 2024 12:37:02 +0100 Subject: [PATCH 04/14] chore: styled component styles for sources, added showSources prop to widget, handled sources data.type, and rendering sources when available --- .../src/components/DocsGPTWidget.tsx | 166 +++++++++++++----- 1 file changed, 124 insertions(+), 42 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 83defbcf..4e13a931 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -1,14 +1,15 @@ "use client"; -import React, { useRef } from 'react' +import React, { useRef, useState } from 'react' import DOMPurify from 'dompurify'; -import styled, { keyframes, createGlobalStyle } from 'styled-components'; -import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon } from '@radix-ui/react-icons'; +import styled, { keyframes, createGlobalStyle, ThemeProvider } from 'styled-components'; +import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon, ExternalLinkIcon } from '@radix-ui/react-icons'; import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetProps } from '../types/index'; import { fetchAnswerStreaming, sendFeedback } from '../requests/streamingApi'; -import { ThemeProvider } from 'styled-components'; import Like from "../assets/like.svg" import Dislike from "../assets/dislike.svg" import MarkdownIt from 'markdown-it'; + + const themes = { dark: { bg: '#222327', @@ -35,6 +36,7 @@ const themes = { } } } + const GlobalStyles = createGlobalStyle` .response pre { padding: 8px; @@ -70,6 +72,7 @@ const GlobalStyles = createGlobalStyle` line-break: loose !important; } `; + const Overlay = styled.div` position: fixed; top: 0; @@ -80,6 +83,7 @@ const Overlay = styled.div` z-index: 999; transition: opacity 0.5s; ` + const WidgetContainer = styled.div<{ modal: boolean }>` display: block; position: fixed; @@ -98,6 +102,7 @@ const WidgetContainer = styled.div<{ modal: boolean }>` overflow: auto; } `; + const StyledContainer = styled.div` display: flex; position: relative; @@ -111,6 +116,7 @@ const StyledContainer = styled.div` box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); transition: visibility 0.3s, opacity 0.3s; `; + const FloatingButton = styled.div<{ bgcolor: string }>` position: fixed; display: flex; @@ -130,6 +136,7 @@ const FloatingButton = styled.div<{ bgcolor: string }>` transition: transform 0.2s ease-in-out; } `; + const CancelButton = styled.button` cursor: pointer; position: absolute; @@ -201,6 +208,7 @@ const Conversation = styled.div<{ size: string }>` width:${props => props.size === 'large' ? '90vw' : props.size === 'medium' ? '60vw' : '400px'} !important; } `; + const Feedback = styled.div` background-color: transparent; font-weight: normal; @@ -209,6 +217,7 @@ const Feedback = styled.div` padding: 6px; clear: both; `; + const MessageBubble = styled.div<{ type: MESSAGE_TYPE }>` display: block; font-size: 16px; @@ -220,6 +229,7 @@ const MessageBubble = styled.div<{ type: MESSAGE_TYPE }>` visibility: visible !important; } `; + const Message = styled.div<{ type: MESSAGE_TYPE }>` background: ${props => props.type === 'QUESTION' ? 'linear-gradient(to bottom right, #8860DB, #6D42C5)' : @@ -235,6 +245,7 @@ const Message = styled.div<{ type: MESSAGE_TYPE }>` padding: 0.75rem; border-radius: 0.375rem; `; + const ErrorAlert = styled.div` color: #b91c1c; border:0.1px solid #b91c1c; @@ -247,6 +258,7 @@ const ErrorAlert = styled.div` border-radius: 0.375rem; justify-content: space-evenly; ` + //dot loading animation const dotBounce = keyframes` 0%, 80%, 100% { @@ -261,10 +273,12 @@ const DotAnimation = styled.div` display: inline-block; animation: ${dotBounce} 1s infinite ease-in-out; `; + // delay classes as styled components const Delay = styled(DotAnimation) <{ delay: number }>` animation-delay: ${props => props.delay + 'ms'}; `; + const PromptContainer = styled.form<{ size: string }>` background-color: transparent; height: ${props => props.size == 'large' ? '60px' : '40px'}; @@ -272,6 +286,7 @@ const PromptContainer = styled.form<{ size: string }>` display: flex; justify-content: space-evenly; `; + const StyledInput = styled.input` width: 100%; border: 1px solid #686877; @@ -282,6 +297,7 @@ const StyledInput = styled.input` color: ${props => props.theme.text}; outline: none; `; + const StyledButton = styled.button<{ size: string }>` display: flex; justify-content: center; @@ -301,6 +317,7 @@ const StyledButton = styled.button<{ size: string }>` &:disabled { opacity: 60%; }`; + const HeroContainer = styled.div` position: absolute; top: 50%; @@ -316,6 +333,7 @@ const HeroContainer = styled.div` margin: 0 auto; padding: 2px; `; + const HeroWrapper = styled.div` background-color: ${props => props.theme.primary.bg}; border-radius: 10px; @@ -329,12 +347,51 @@ const HeroTitle = styled.h3` margin-bottom: 5px; padding: 2px; `; + const HeroDescription = styled.p` color: ${props => props.theme.text}; font-size: 14px; line-height: 1.5; `; +const SourcesContainer = styled.div` + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 8px; +`; + +const SourceBox = styled.div` + background-color: ${props => props.theme.secondary.bg}; + border-radius: 6px; + padding: 8px; + font-size: 12px; + cursor: pointer; + display: flex; + align-items: center; + gap: 4px; + max-width: 200px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +const LoadingIndicator = styled.div` + display: inline-block; + width: 20px; + height: 20px; + border: 2px solid ${props => props.theme.secondary.text}; + border-radius: 50%; + border-top-color: transparent; + animation: spin 1s linear infinite; + + @keyframes spin { + to { + transform: rotate(360deg); + } + } +`; + const Hero = ({ title, description, theme }: { title: string, description: string, theme: string }) => { return ( <> @@ -354,6 +411,7 @@ const Hero = ({ title, description, theme }: { title: string, description: strin ); }; + export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', @@ -366,14 +424,15 @@ export const DocsGPTWidget = ({ theme = 'dark', buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/message.svg', buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)', - collectFeedback = true + collectFeedback = true, + showSources = true }: WidgetProps) => { const [prompt, setPrompt] = React.useState(''); const [status, setStatus] = React.useState('idle'); const [queries, setQueries] = React.useState([]) const [conversationId, setConversationId] = React.useState(null) const [open, setOpen] = React.useState(false) - const [eventInterrupt, setEventInterrupt] = React.useState(false); //click or scroll by user while autoScrolling + const [eventInterrupt, setEventInterrupt] = React.useState(false); const isBubbleHovered = useRef(false) const endMessageRef = React.useRef(null); const md = new MarkdownIt(); @@ -381,6 +440,7 @@ export const DocsGPTWidget = ({ const handleUserInterrupt = () => { (status === 'loading') && setEventInterrupt(true); } + const scrollToBottom = (element: Element | null) => { //recursive function to scroll to the last child of the last child ... // to get to the bottom most element @@ -394,6 +454,7 @@ export const DocsGPTWidget = ({ const lastChild = element?.children?.[element.children.length - 1] lastChild && scrollToBottom(lastChild) }; + React.useEffect(() => { !eventInterrupt && scrollToBottom(endMessageRef.current); }, [queries.length, queries[queries.length - 1]?.response]); @@ -440,7 +501,6 @@ export const DocsGPTWidget = ({ conversationId: conversationId, onEvent: (event: MessageEvent) => { const data = JSON.parse(event.data); - // check if the 'end' event has been received if (data.type === 'end') { setStatus('idle'); } @@ -453,6 +513,11 @@ export const DocsGPTWidget = ({ setQueries(updatedQueries); setStatus('idle') } + else if (data.type === 'sources') { + const updatedQueries = [...queries]; + updatedQueries[updatedQueries.length - 1].sources = data.sources; + setQueries(updatedQueries); + } else { const result = data.answer; const streamingResponse = queries[queries.length - 1].response ? queries[queries.length - 1].response : ''; @@ -468,11 +533,9 @@ export const DocsGPTWidget = ({ updatedQueries[updatedQueries.length - 1].error = 'Something went wrong !' setQueries(updatedQueries); setStatus('idle') - //setEventInterrupt(false) } - } - // submit handler + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setEventInterrupt(false); @@ -480,9 +543,11 @@ export const DocsGPTWidget = ({ setPrompt('') await stream(prompt) } + const handleImageError = (event: React.SyntheticEvent) => { event.currentTarget.src = "https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png"; }; + return ( {open && size === 'large' && @@ -525,36 +590,51 @@ export const DocsGPTWidget = ({ } { - query.response ? { isBubbleHovered.current = true }} type='ANSWER'> - -
- - - {collectFeedback && - - handleFeedback("LIKE", index)} /> - handleFeedback("DISLIKE", index)} /> - } - - :
+ query.response ? ( + { isBubbleHovered.current = true }} type='ANSWER'> + {showSources && query.sources && ( + + {query.sources.map((source, sourceIndex) => ( + window.open(source.source, '_blank', 'noopener,noreferrer')} + title={source.title} + > + {source.title} + + + ))} + + )} + +
+ + {collectFeedback && + + handleFeedback("LIKE", index)} /> + handleFeedback("DISLIKE", index)} /> + } + + ) : ( +
{ query.error ? @@ -574,10 +654,12 @@ export const DocsGPTWidget = ({ }
+ ) } - ) + + ); }) - : + : } Date: Mon, 28 Oct 2024 17:33:40 +0100 Subject: [PATCH 05/14] chore: wrapped the base component with ThemeProvider at the root level to make theme props available globally --- .../src/components/DocsGPTWidget.tsx | 111 ++++-------------- extensions/react-widget/src/main.tsx | 40 ++++++- 2 files changed, 59 insertions(+), 92 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 4e13a931..704954d9 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -1,42 +1,15 @@ "use client"; -import React, { useRef, useState } from 'react' +import React, { useRef } from 'react' import DOMPurify from 'dompurify'; -import styled, { keyframes, createGlobalStyle, ThemeProvider } from 'styled-components'; -import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon, ExternalLinkIcon } from '@radix-ui/react-icons'; +import styled, { keyframes, createGlobalStyle, } from 'styled-components'; +import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon, } from '@radix-ui/react-icons'; import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetProps } from '../types/index'; import { fetchAnswerStreaming, sendFeedback } from '../requests/streamingApi'; +import QuerySources from "./QuerySources"; import Like from "../assets/like.svg" import Dislike from "../assets/dislike.svg" import MarkdownIt from 'markdown-it'; - -const themes = { - dark: { - bg: '#222327', - text: '#fff', - primary: { - text: "#FAFAFA", - bg: '#222327' - }, - secondary: { - text: "#A1A1AA", - bg: "#38383b" - } - }, - light: { - bg: '#fff', - text: '#000', - primary: { - text: "#222327", - bg: "#fff" - }, - secondary: { - text: "#A1A1AA", - bg: "#F6F6F6" - } - } -} - const GlobalStyles = createGlobalStyle` .response pre { padding: 8px; @@ -354,44 +327,6 @@ const HeroDescription = styled.p` line-height: 1.5; `; -const SourcesContainer = styled.div` - display: flex; - flex-wrap: wrap; - gap: 8px; - margin-bottom: 8px; -`; - -const SourceBox = styled.div` - background-color: ${props => props.theme.secondary.bg}; - border-radius: 6px; - padding: 8px; - font-size: 12px; - cursor: pointer; - display: flex; - align-items: center; - gap: 4px; - max-width: 200px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -`; - -const LoadingIndicator = styled.div` - display: inline-block; - width: 20px; - height: 20px; - border: 2px solid ${props => props.theme.secondary.text}; - border-radius: 50%; - border-top-color: transparent; - animation: spin 1s linear infinite; - - @keyframes spin { - to { - transform: rotate(360deg); - } - } -`; - const Hero = ({ title, description, theme }: { title: string, description: string, theme: string }) => { return ( <> @@ -412,6 +347,8 @@ const Hero = ({ title, description, theme }: { title: string, description: strin ); }; + + export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', @@ -494,13 +431,14 @@ export const DocsGPTWidget = ({ try { await fetchAnswerStreaming( { - question: question, - apiKey: apiKey, - apiHost: apiHost, + question, + apiKey, + apiHost, history: queries, - conversationId: conversationId, + conversationId, onEvent: (event: MessageEvent) => { const data = JSON.parse(event.data); + if (data.type === 'end') { setStatus('idle'); } @@ -513,10 +451,11 @@ export const DocsGPTWidget = ({ setQueries(updatedQueries); setStatus('idle') } - else if (data.type === 'sources') { + else if (data.type === 'source') { const updatedQueries = [...queries]; - updatedQueries[updatedQueries.length - 1].sources = data.sources; - setQueries(updatedQueries); + updatedQueries[updatedQueries.length - 1].sources = data.source; + setQueries(updatedQueries); + } else { const result = data.answer; @@ -549,15 +488,17 @@ export const DocsGPTWidget = ({ }; return ( - +<> {open && size === 'large' && { setOpen(false) }} /> } + setOpen(!open)} hidden={open}> + {open && @@ -593,18 +534,7 @@ export const DocsGPTWidget = ({ query.response ? ( { isBubbleHovered.current = true }} type='ANSWER'> {showSources && query.sources && ( - - {query.sources.map((source, sourceIndex) => ( - window.open(source.source, '_blank', 'noopener,noreferrer')} - title={source.title} - > - {source.title} - - - ))} - + )} } + @@ -676,6 +607,6 @@ export const DocsGPTWidget = ({ } - + ) } \ No newline at end of file diff --git a/extensions/react-widget/src/main.tsx b/extensions/react-widget/src/main.tsx index 4fb3bbb4..6ada95dc 100644 --- a/extensions/react-widget/src/main.tsx +++ b/extensions/react-widget/src/main.tsx @@ -1,11 +1,47 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import { DocsGPTWidget } from './components/DocsGPTWidget'; +import { ThemeProvider } from 'styled-components'; +import { THEME } from './types'; + +const themes = { + dark: { + bg: '#222327', + text: '#fff', + primary: { + text: "#FAFAFA", + bg: '#222327' + }, + secondary: { + text: "#A1A1AA", + bg: "#38383b" + } + }, + + light: { + bg: '#fff', + text: '#000', + primary: { + text: "#222327", + bg: "#fff" + }, + secondary: { + text: "#A1A1AA", + bg: "#F6F6F6" + } + } +} if (typeof window !== 'undefined') { - const renderWidget = (elementId: string, props = {}) => { + const renderWidget = (elementId: string, props={ + theme: "dark" as THEME + }) => { const root = createRoot(document.getElementById(elementId) as HTMLElement); - root.render(); + root.render( + + + + ); }; (window as any).renderDocsGPTWidget = renderWidget; } From 656f4da8f9f3bd0d554d086ef5d6dadbc4da0518 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Mon, 28 Oct 2024 17:34:35 +0100 Subject: [PATCH 06/14] feat: rendering of response source --- .../src/components/QuerySources.tsx | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 extensions/react-widget/src/components/QuerySources.tsx diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx new file mode 100644 index 00000000..d322c48d --- /dev/null +++ b/extensions/react-widget/src/components/QuerySources.tsx @@ -0,0 +1,166 @@ +import React, { useState } from 'react'; +import {Query, THEME} from "../types/index" +import styled from 'styled-components'; +import { ExternalLinkIcon, FileTextIcon } from '@radix-ui/react-icons' + + +const SourcesWrapper = styled.div` +margin-bottom: 1rem; +display: flex; +flex-direction: column; +overflow: hidden; +` + +const SourcesHeader = styled.div` + margin: 0.5rem 0; + display: flex; + align-items: center; + gap: 0.75rem; +` + +const SourcesTitle = styled.p` + font-size: 1rem; + font-weight: 600; + color: ${props => props.theme.text}; +` + +const SourcesGrid = styled.div` + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0.5rem; + margin-left: 0.75rem; + margin-right: 1.25rem; + max-width: 90vw; + overflow-x: scroll; + + @media(min-width: 768px){ + max-width: 70vw; + } +` + +const SourceItem = styled.div` +height: 7rem; +cursor: pointer; +display: flex; +flex-direction: column; +justify-content: space-between; +border-radius: 1.25rem; +background-color: ${props =>props.theme.secondary.bg}; +padding: 1rem; +color:${props => props.theme.text}; +transform: background-color .2s, color .2s; + +&:hover{ + background-color: ${props => props.theme.primary.bg}; + color: ${props => props.theme.primary.text}; +} +` + +const SourceText = styled.p` + height: 3rem; + overflow: hidden; + text-overflow: ellipsis; +font-size: 0.75rem; +line-height: 1rem; +color: ${props => props.theme.text}; +` + +const SourceLink = styled.div` + margin-top: 0.875rem; + display: flex; + flex-direction: row; + align-items: center; + gap: 0.375rem; + text-decoration: underline; + text-underline-offset: 2px; +` + +const SourceLinkText = styled.p` + margin-top: 0.125rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 0.75rem; + line-height: 1rem; +` + +const Tooltip = styled.div` + position: absolute; + left: 50%; + z-index: 30; + max-height: 12rem; + width: 10rem; + transform: translateX(-50%) translateY(3px); + border-radius: 0.75rem; + background-color: ${props => props.theme.bg}; + padding: 1rem; + color: ${props => props.theme.text}; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + + @media (min-width: 640px) { + width: 14rem; + } +` + +const TooltipText = styled.p` + max-height: 10.25rem; + overflow-y: auto; + word-break: break-word; + border-radius: 0.375rem; + font-size: 0.875rem; + line-height: 1.25rem; +` + +type TQuerySources = { + sources: Pick["sources"], + theme?: THEME +} + +const QuerySources = ({sources, theme}:TQuerySources) => { + const [activeTooltip, setActiveTooltip] = useState(null) + + return ( + + + + Sources + + + + {sources?.slice(0, 3)?.map((source, index) => ( + setActiveTooltip(index)} + onMouseLeave={() => setActiveTooltip(null)} + > + {source.text} + + source.source && source.source !== 'local' + ? window.open(source.source, '_blank', 'noopener,noreferrer') + : null + } + > + + + {source.source && source.source !== 'local' ? source.source : source.title} + + + {activeTooltip === index && ( + setActiveTooltip(index)} + onMouseLeave={() => setActiveTooltip(null)} + > + + {source.text} + + + )} + + ))} + + + ) +} + +export default QuerySources \ No newline at end of file From 1a9f47b1bcb6668e3e90e1d72cf289afc7547ea4 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Mon, 4 Nov 2024 16:33:00 +0100 Subject: [PATCH 07/14] chore: modified query sources and removed tooltip --- .../src/components/DocsGPTWidget.tsx | 4 +- .../src/components/QuerySources.tsx | 65 ++----------------- 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index c59377e7..1354e4e8 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -454,7 +454,9 @@ export const DocsGPTWidget = ({ else if (data.type === 'source') { const updatedQueries = [...queries]; updatedQueries[updatedQueries.length - 1].sources = data.source; - setQueries(updatedQueries); + setQueries(updatedQueries); + console.log("SOURCE:", data); + } else { diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx index d322c48d..504bb917 100644 --- a/extensions/react-widget/src/components/QuerySources.tsx +++ b/extensions/react-widget/src/components/QuerySources.tsx @@ -1,25 +1,26 @@ -import React, { useState } from 'react'; import {Query, THEME} from "../types/index" import styled from 'styled-components'; import { ExternalLinkIcon, FileTextIcon } from '@radix-ui/react-icons' const SourcesWrapper = styled.div` -margin-bottom: 1rem; +padding: 12px; +margin-left: 4px; +margin-bottom: 0.75rem; display: flex; flex-direction: column; overflow: hidden; ` const SourcesHeader = styled.div` - margin: 0.5rem 0; + margin: 0.3rem 0; display: flex; align-items: center; gap: 0.75rem; ` const SourcesTitle = styled.p` - font-size: 1rem; + font-size: 0.75rem; font-weight: 600; color: ${props => props.theme.text}; ` @@ -39,7 +40,6 @@ const SourcesGrid = styled.div` ` const SourceItem = styled.div` -height: 7rem; cursor: pointer; display: flex; flex-direction: column; @@ -56,17 +56,7 @@ transform: background-color .2s, color .2s; } ` -const SourceText = styled.p` - height: 3rem; - overflow: hidden; - text-overflow: ellipsis; -font-size: 0.75rem; -line-height: 1rem; -color: ${props => props.theme.text}; -` - const SourceLink = styled.div` - margin-top: 0.875rem; display: flex; flex-direction: row; align-items: center; @@ -76,7 +66,6 @@ const SourceLink = styled.div` ` const SourceLinkText = styled.p` - margin-top: 0.125rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -84,45 +73,16 @@ const SourceLinkText = styled.p` line-height: 1rem; ` -const Tooltip = styled.div` - position: absolute; - left: 50%; - z-index: 30; - max-height: 12rem; - width: 10rem; - transform: translateX(-50%) translateY(3px); - border-radius: 0.75rem; - background-color: ${props => props.theme.bg}; - padding: 1rem; - color: ${props => props.theme.text}; - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - - @media (min-width: 640px) { - width: 14rem; - } -` - -const TooltipText = styled.p` - max-height: 10.25rem; - overflow-y: auto; - word-break: break-word; - border-radius: 0.375rem; - font-size: 0.875rem; - line-height: 1.25rem; -` - type TQuerySources = { sources: Pick["sources"], theme?: THEME } const QuerySources = ({sources, theme}:TQuerySources) => { - const [activeTooltip, setActiveTooltip] = useState(null) - return ( - + Sources @@ -130,10 +90,7 @@ const QuerySources = ({sources, theme}:TQuerySources) => { {sources?.slice(0, 3)?.map((source, index) => ( setActiveTooltip(index)} - onMouseLeave={() => setActiveTooltip(null)} > - {source.text} source.source && source.source !== 'local' @@ -146,16 +103,6 @@ const QuerySources = ({sources, theme}:TQuerySources) => { {source.source && source.source !== 'local' ? source.source : source.title} - {activeTooltip === index && ( - setActiveTooltip(index)} - onMouseLeave={() => setActiveTooltip(null)} - > - - {source.text} - - - )} ))} From 3e87d83ae8e624981b67ea5fa4913be351582ac6 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Tue, 5 Nov 2024 21:50:42 +0100 Subject: [PATCH 08/14] chore: adjusted spacing in source bubble --- extensions/react-widget/src/components/QuerySources.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx index 504bb917..edb7fc0c 100644 --- a/extensions/react-widget/src/components/QuerySources.tsx +++ b/extensions/react-widget/src/components/QuerySources.tsx @@ -4,7 +4,7 @@ import { ExternalLinkIcon, FileTextIcon } from '@radix-ui/react-icons' const SourcesWrapper = styled.div` -padding: 12px; +padding: 8px; margin-left: 4px; margin-bottom: 0.75rem; display: flex; @@ -46,7 +46,8 @@ flex-direction: column; justify-content: space-between; border-radius: 1.25rem; background-color: ${props =>props.theme.secondary.bg}; -padding: 1rem; +padding-left: 0.75rem; +padding-right: 0.75rem; color:${props => props.theme.text}; transform: background-color .2s, color .2s; From 1a8f89573d717e986935605c9fad327f66e6273e Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sat, 9 Nov 2024 01:09:22 +0100 Subject: [PATCH 09/14] feat: query sources in widget --- .../src/components/DocsGPTWidget.tsx | 4 +-- .../src/components/QuerySources.tsx | 29 ++++--------------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 1354e4e8..bea3de3a 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -351,7 +351,7 @@ const Hero = ({ title, description, theme }: { title: string, description: strin export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', - apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', + apiKey = '0d7407f7-a843-42fb-ad83-dd4a213a935d', avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png', title = 'Get AI assistance', description = 'DocsGPT\'s AI Chatbot is here to help', @@ -536,7 +536,7 @@ export const DocsGPTWidget = ({ query.response ? ( { isBubbleHovered.current = true }} type='ANSWER'> {showSources && query.sources && ( - + )} props.theme.text}; -` - const SourcesGrid = styled.div` display: grid; grid-template-columns: repeat(3, 1fr); @@ -57,12 +44,12 @@ transform: background-color .2s, color .2s; } ` -const SourceLink = styled.div` +const SourceLink = styled.div<{$hasExternalSource: boolean}>` display: flex; flex-direction: row; align-items: center; gap: 0.375rem; - text-decoration: underline; + text-decoration: ${({$hasExternalSource}) => ($hasExternalSource? "underline": "none")}; text-underline-offset: 2px; ` @@ -76,16 +63,11 @@ const SourceLinkText = styled.p` type TQuerySources = { sources: Pick["sources"], - theme?: THEME } -const QuerySources = ({sources, theme}:TQuerySources) => { +const QuerySources = ({sources}:TQuerySources) => { return ( - - - Sources - {sources?.slice(0, 3)?.map((source, index) => ( @@ -93,6 +75,7 @@ const QuerySources = ({sources, theme}:TQuerySources) => { key={index} > source.source && source.source !== 'local' ? window.open(source.source, '_blank', 'noopener,noreferrer') From 97916bf925638b85f08d053e1fa0006d3e21977f Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sun, 10 Nov 2024 03:08:35 +0100 Subject: [PATCH 10/14] chore: returned themes cofig into DocsGPTWidget component --- .../src/components/DocsGPTWidget.tsx | 28 ++++++++++++++- extensions/react-widget/src/main.tsx | 36 +------------------ 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 341c9d14..809ececc 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -10,7 +10,33 @@ import Like from "../assets/like.svg" import Dislike from "../assets/dislike.svg" import MarkdownIt from 'markdown-it'; +const themes = { + dark: { + bg: '#222327', + text: '#fff', + primary: { + text: "#FAFAFA", + bg: '#222327' + }, + secondary: { + text: "#A1A1AA", + bg: "#38383b" + } + }, + light: { + bg: '#fff', + text: '#000', + primary: { + text: "#222327", + bg: "#fff" + }, + secondary: { + text: "#A1A1AA", + bg: "#F6F6F6" + } + } +} const sizesConfig = { small: { size: 'small', width: '320px', height: '400px' }, @@ -631,7 +657,7 @@ export const DocsGPTWidget = ({ onClick={() => handleFeedback("DISLIKE", index)} /> } - :
+ : (
{ query.error ? diff --git a/extensions/react-widget/src/main.tsx b/extensions/react-widget/src/main.tsx index 6ada95dc..368dc394 100644 --- a/extensions/react-widget/src/main.tsx +++ b/extensions/react-widget/src/main.tsx @@ -1,46 +1,12 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import { DocsGPTWidget } from './components/DocsGPTWidget'; -import { ThemeProvider } from 'styled-components'; -import { THEME } from './types'; - -const themes = { - dark: { - bg: '#222327', - text: '#fff', - primary: { - text: "#FAFAFA", - bg: '#222327' - }, - secondary: { - text: "#A1A1AA", - bg: "#38383b" - } - }, - - light: { - bg: '#fff', - text: '#000', - primary: { - text: "#222327", - bg: "#fff" - }, - secondary: { - text: "#A1A1AA", - bg: "#F6F6F6" - } - } -} if (typeof window !== 'undefined') { - const renderWidget = (elementId: string, props={ - theme: "dark" as THEME - }) => { + const renderWidget = (elementId: string, props={}) => { const root = createRoot(document.getElementById(elementId) as HTMLElement); root.render( - - ); }; (window as any).renderDocsGPTWidget = renderWidget; From 25feab9a2918b7d044aecc0e38c201f6c9180a36 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sun, 10 Nov 2024 03:11:41 +0100 Subject: [PATCH 11/14] chore: removed unused import --- extensions/react-widget/src/components/DocsGPTWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 809ececc..16b2be1c 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useRef } from 'react' import DOMPurify from 'dompurify'; -import styled, { keyframes, createGlobalStyle, ThemeProvider, } from 'styled-components'; +import styled, { keyframes, ThemeProvider, } from 'styled-components'; import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon, } from '@radix-ui/react-icons'; import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetProps } from '../types/index'; import { fetchAnswerStreaming, sendFeedback } from '../requests/streamingApi'; From a7aae3ff7e54b615d7803741867c50cbc53b72bf Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sun, 10 Nov 2024 03:29:56 +0100 Subject: [PATCH 12/14] style: minor adjustments in border-radius and spacings --- .../react-widget/src/components/QuerySources.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx index 7090a96a..325930df 100644 --- a/extensions/react-widget/src/components/QuerySources.tsx +++ b/extensions/react-widget/src/components/QuerySources.tsx @@ -4,9 +4,7 @@ import { ExternalLinkIcon } from '@radix-ui/react-icons' const SourcesWrapper = styled.div` -padding: 8px; -margin-left: 4px; -margin-bottom: 0.75rem; +margin: 4px; display: flex; flex-direction: column; overflow: hidden; @@ -16,8 +14,6 @@ const SourcesGrid = styled.div` display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; - margin-left: 0.75rem; - margin-right: 1.25rem; max-width: 90vw; overflow-x: scroll; @@ -31,10 +27,10 @@ cursor: pointer; display: flex; flex-direction: column; justify-content: space-between; -border-radius: 1.25rem; +border-radius: 6px; background-color: ${props =>props.theme.secondary.bg}; -padding-left: 0.75rem; -padding-right: 0.75rem; + padding-left: 12px; +padding-right: 12px; color:${props => props.theme.text}; transform: background-color .2s, color .2s; From 2c8a2945f02c43c3953a8db614f0f8923710b6af Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sun, 17 Nov 2024 10:34:22 +0100 Subject: [PATCH 13/14] feat: better sources scroll management --- .../src/components/QuerySources.tsx | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx index 325930df..a619a822 100644 --- a/extensions/react-widget/src/components/QuerySources.tsx +++ b/extensions/react-widget/src/components/QuerySources.tsx @@ -1,6 +1,7 @@ import {Query} from "../types/index" import styled from 'styled-components'; import { ExternalLinkIcon } from '@radix-ui/react-icons' +import { useEffect, useMemo, useState } from "react"; const SourcesWrapper = styled.div` @@ -57,16 +58,41 @@ const SourceLinkText = styled.p` line-height: 1rem; ` +const OtherSources = styled.button` +cursor: pointer; +background: transparent; +color: #8860DB; +border: none; +outline: none; +margin-top: 0.5rem; +align-self: flex-start; +` + type TQuerySources = { sources: Pick["sources"], } const QuerySources = ({sources}:TQuerySources) => { - return ( - +const [showAllSources, setShowAllSources] = useState(false) +const visibleSources = useMemo(() => { + if(!sources) return []; + + return showAllSources? sources : sources.slice(0, 3) +}, [sources, showAllSources]) + +const handleToggleShowAll = () => { + setShowAllSources(prev => !prev) +} + +if(!sources || sources.length === 0){ + return null; +} + +return ( + - {sources?.slice(0, 3)?.map((source, index) => ( + {visibleSources?.map((source, index) => ( @@ -86,6 +112,15 @@ const QuerySources = ({sources}:TQuerySources) => { ))} + + { + sources.length > 3 && ( + { + showAllSources ? `Show less` : `+ ${sources.length - 3} more` + } + + ) +} ) } From b78d2bd4b109e8a4d5f04890b3e53bd5d93407b1 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 18 Feb 2025 02:09:13 +0530 Subject: [PATCH 14/14] (feat:widget) add optional sources --- extensions/react-widget/package-lock.json | 667 +----------------- .../src/components/DocsGPTWidget.tsx | 102 ++- .../src/components/QuerySources.tsx | 128 ---- extensions/react-widget/src/types/index.ts | 5 +- 4 files changed, 112 insertions(+), 790 deletions(-) delete mode 100644 extensions/react-widget/src/components/QuerySources.tsx diff --git a/extensions/react-widget/package-lock.json b/extensions/react-widget/package-lock.json index bae94d08..a2120e91 100644 --- a/extensions/react-widget/package-lock.json +++ b/extensions/react-widget/package-lock.json @@ -10,6 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@babel/plugin-transform-flow-strip-types": "^7.23.3", + "@bpmn-io/snarkdown": "^2.2.0", "@parcel/resolver-glob": "^2.12.0", "@parcel/transformer-svg-react": "^2.12.0", "@parcel/transformer-typescript-tsc": "^2.12.0", @@ -1838,6 +1839,13 @@ "node": ">=6.9.0" } }, + "node_modules/@bpmn-io/snarkdown": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@bpmn-io/snarkdown/-/snarkdown-2.2.0.tgz", + "integrity": "sha512-bVD7FIoaBDZeCJkMRgnBPDeptPlto87wt2qaCjf5t8iLaevDmTPaREd6FpBEGsHlUdHFFZWRk4qAoEC5So2M0Q==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", @@ -1885,17 +1893,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -2269,6 +2266,7 @@ "version": "2.12.0", "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.12.0.tgz", "integrity": "sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q==", + "dev": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", "@parcel/cache": "2.12.0", @@ -2308,6 +2306,7 @@ "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -2369,6 +2368,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.2.0.tgz", "integrity": "sha512-xlrmCPqy58D4Fg5umV7bpwDx5Vyt7MlnQPxW68vae5+BA4GSWetfZt+Cs5dtotMG2oCHzZxhIPt7YZ7NRyQzLA==", + "dev": true, "dependencies": { "nullthrows": "^1.1.1" }, @@ -4568,7 +4568,7 @@ "version": "0.5.11", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", - "devOptional": true, + "dev": true, "dependencies": { "tslib": "^2.4.0" } @@ -4598,35 +4598,6 @@ "@types/trusted-types": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "peer": true - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4658,16 +4629,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", - "dev": true, - "peer": true, - "dependencies": { - "undici-types": "~6.20.0" - } - }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -4709,198 +4670,11 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "dev": true }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "peer": true - }, "node_modules/abortcontroller-polyfill": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", - "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true }, "node_modules/ajv": { "version": "6.12.6", @@ -5005,6 +4779,7 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -5065,13 +4840,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "peer": true - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5163,6 +4931,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, "engines": { "node": ">=0.8" } @@ -5372,6 +5141,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "dev": true, "engines": { "node": ">=6" } @@ -5379,7 +5149,8 @@ "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true }, "node_modules/electron-to-chromium": { "version": "1.5.72", @@ -5395,20 +5166,6 @@ "node": ">= 4" } }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -5437,13 +5194,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true, - "peer": true - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5460,53 +5210,6 @@ "node": ">=0.8.0" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "peer": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5516,16 +5219,6 @@ "node": ">=0.10.0" } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5616,13 +5309,6 @@ "node": ">=6" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "peer": true - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -5631,13 +5317,6 @@ "node": ">=4" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "peer": true - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -5843,47 +5522,6 @@ "node": ">=0.12.0" } }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6184,16 +5822,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.11.5" - } - }, "node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", @@ -6283,13 +5911,6 @@ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "license": "MIT" }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "peer": true - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6302,29 +5923,6 @@ "node": ">=8.6" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6387,13 +5985,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, "node_modules/node-addon-api": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", @@ -9168,16 +8759,6 @@ "node": ">=6" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -9316,6 +8897,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -9365,16 +8947,6 @@ "semver": "bin/semver.js" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -9396,17 +8968,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -9473,16 +9034,6 @@ "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/term-size": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", @@ -9495,86 +9046,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true - }, "node_modules/timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", @@ -9621,6 +9092,7 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9635,13 +9107,6 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "peer": true - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -9728,101 +9193,11 @@ "node": ">= 4" } }, - "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", - "dev": true, - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==" }, - "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index d6273eaa..8aa2e0e6 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -35,7 +35,7 @@ const themes = { bg: "#F6F6F6" } } -} +}; const sizesConfig = { small: { size: 'small', width: '320px', height: '400px' }, @@ -274,7 +274,7 @@ const Conversation = styled.div` text-align: left; overflow-y: auto; scrollbar-width: thin; - scrollbar-color: #4a4a4a transparent; /* thumb color track color */ + scrollbar-color: ${props => props.theme.secondary.bg} transparent; /* thumb color track color */ `; const Feedback = styled.div` background-color: transparent; @@ -470,6 +470,75 @@ const Tagline = styled.div` `; +const SourcesList = styled.div` + display: flex; + margin:12px 0px; + flex-wrap: wrap; + gap: 8px; +`; + +const SourceLink = styled.a` + color: ${props => props.theme.primary.text}; + text-decoration: none; + background: ${props => props.theme.secondary.bg}; + padding: 4px 12px; + border-radius: 85px; + font-size: 14px; + transition: opacity 0.2s ease; + display: inline-block; + text-align: center; + max-width: 25%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.5; + + &:hover { + opacity: 0.8; + } +`; + +const ExtraButton = styled.button` + color: #9971EC; + background: transparent; + border-radius: 85px; + padding: 4px 12px; + font-size: 14px; + border: none; + cursor: pointer; + transition: opacity 0.2s ease; + text-align: center; + height:auto; + &:hover { + opacity: 0.8; + } +`; +const SourcesComponent = ({ sources }: { sources: Array<{ source: string; title: string }> }) => { + const [showAll, setShowAll] = React.useState(false); + const visibleSources = showAll ? sources : sources.slice(0, 3); + const extraCount = sources.length - 3; + + return ( + + {visibleSources.map((source, idx) => ( + + {source.title} + + ))} + {sources.length > 3 && ( + setShowAll(!showAll)}> + {showAll ? "Show less" : `+ ${extraCount} more`} + + )} + + ); +}; const Hero = ({ title, description, theme }: { title: string, description: string, theme: string }) => { return ( @@ -524,7 +593,8 @@ export const DocsGPTWidget = (props: WidgetProps) => { } export const WidgetCore = ({ apiHost = 'https://gptcloud.arc53.com', - apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', + apiKey = "74039c6d-bff7-44ce-ae55-2973cbf13837", + //apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png', title = 'Get AI assistance', description = 'DocsGPT\'s AI Chatbot is here to help', @@ -534,8 +604,9 @@ export const WidgetCore = ({ theme = 'dark', collectFeedback = true, isOpen = false, - prefilledQuery = "", - handleClose + showSources = true, + handleClose, + prefilledQuery = '' }: WidgetCoreProps) => { const [prompt, setPrompt] = React.useState(""); const [mounted, setMounted] = React.useState(false); @@ -638,8 +709,10 @@ export const WidgetCore = ({ setQueries(updatedQueries); setStatus('idle') } - else if (data.type === 'source') { - // handle the case where data type === 'source' + else if (data.type === 'source' && showSources) { + const updatedQueries = [...queries]; + updatedQueries[updatedQueries.length - 1].sources = data.source; + setQueries(updatedQueries); } else { const result = data.answer ? data.answer : ''; //Fallback to an empty string if data.answer is undefined @@ -666,13 +739,12 @@ export const WidgetCore = ({ await appendQuery(prompt) } - const appendQuery = async (userQuery:string) => { - console.log(userQuery) - if(!userQuery) + const appendQuery = async (userQuery: string) => { + if (!userQuery) return; setEventInterrupt(false); - queries.push({ prompt:userQuery}); + queries.push({ prompt: userQuery }); setPrompt(''); await stream(userQuery); } @@ -711,7 +783,8 @@ export const WidgetCore = ({ return ( { - query.prompt && + query.prompt && + @@ -721,6 +794,9 @@ export const WidgetCore = ({ } { query.response ? { isBubbleHovered.current = true }} type='ANSWER'> + {showSources && query.sources && query.sources.length > 0 && query.sources.some(source => source.source !== 'local') && ( + source.source !== 'local')} /> + )} ) -} \ No newline at end of file +} diff --git a/extensions/react-widget/src/components/QuerySources.tsx b/extensions/react-widget/src/components/QuerySources.tsx deleted file mode 100644 index a619a822..00000000 --- a/extensions/react-widget/src/components/QuerySources.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import {Query} from "../types/index" -import styled from 'styled-components'; -import { ExternalLinkIcon } from '@radix-ui/react-icons' -import { useEffect, useMemo, useState } from "react"; - - -const SourcesWrapper = styled.div` -margin: 4px; -display: flex; -flex-direction: column; -overflow: hidden; -` - -const SourcesGrid = styled.div` - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0.5rem; - max-width: 90vw; - overflow-x: scroll; - - @media(min-width: 768px){ - max-width: 70vw; - } -` - -const SourceItem = styled.div` -cursor: pointer; -display: flex; -flex-direction: column; -justify-content: space-between; -border-radius: 6px; -background-color: ${props =>props.theme.secondary.bg}; - padding-left: 12px; -padding-right: 12px; -color:${props => props.theme.text}; -transform: background-color .2s, color .2s; - -&:hover{ - background-color: ${props => props.theme.primary.bg}; - color: ${props => props.theme.primary.text}; -} -` - -const SourceLink = styled.div<{$hasExternalSource: boolean}>` - display: flex; - flex-direction: row; - align-items: center; - gap: 0.375rem; - text-decoration: ${({$hasExternalSource}) => ($hasExternalSource? "underline": "none")}; - text-underline-offset: 2px; -` - -const SourceLinkText = styled.p` - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 0.75rem; - line-height: 1rem; -` - -const OtherSources = styled.button` -cursor: pointer; -background: transparent; -color: #8860DB; -border: none; -outline: none; -margin-top: 0.5rem; -align-self: flex-start; -` - -type TQuerySources = { - sources: Pick["sources"], -} - -const QuerySources = ({sources}:TQuerySources) => { -const [showAllSources, setShowAllSources] = useState(false) - -const visibleSources = useMemo(() => { - if(!sources) return []; - - return showAllSources? sources : sources.slice(0, 3) -}, [sources, showAllSources]) - -const handleToggleShowAll = () => { - setShowAllSources(prev => !prev) -} - -if(!sources || sources.length === 0){ - return null; -} - -return ( - - - {visibleSources?.map((source, index) => ( - - - source.source && source.source !== 'local' - ? window.open(source.source, '_blank', 'noopener,noreferrer') - : null - } - > - - - {source.source && source.source !== 'local' ? source.source : source.title} - - - - ))} - - - { - sources.length > 3 && ( - { - showAllSources ? `Show less` : `+ ${sources.length - 3} more` - } - - ) -} - - ) -} - -export default QuerySources \ No newline at end of file diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index 34ab66a2..5c6dada3 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -37,8 +37,7 @@ export interface WidgetProps { buttonText?:string; buttonBg?:string; collectFeedback?:boolean; - deafultOpen?: boolean; - showSources?: boolean + showSources?: boolean; defaultOpen?: boolean; } export interface WidgetCoreProps extends WidgetProps { @@ -61,4 +60,4 @@ export interface Result { text:string; title:string; source:string; -} \ No newline at end of file +}