Skip to content

Commit 7989137

Browse files
Merge pull request #1317 from utin-francis-peter/feat/sources-in-react-widget
Feat/sources in react widget
2 parents 361f689 + 7d0445c commit 7989137

File tree

5 files changed

+146
-5
lines changed

5 files changed

+146
-5
lines changed

extensions/react-widget/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
},
4242
"dependencies": {
4343
"@babel/plugin-transform-flow-strip-types": "^7.23.3",
44+
"@bpmn-io/snarkdown": "^2.2.0",
4445
"@parcel/resolver-glob": "^2.12.0",
4546
"@parcel/transformer-svg-react": "^2.12.0",
4647
"@parcel/transformer-typescript-tsc": "^2.12.0",
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import {Query} from "../types/index"
2+
import styled from 'styled-components';
3+
import { ExternalLinkIcon } from '@radix-ui/react-icons'
4+
import { useEffect, useMemo, useState } from "react";
5+
6+
7+
const SourcesWrapper = styled.div`
8+
margin: 4px;
9+
display: flex;
10+
flex-direction: column;
11+
overflow: hidden;
12+
`
13+
14+
const SourcesGrid = styled.div`
15+
display: grid;
16+
grid-template-columns: repeat(3, 1fr);
17+
gap: 0.5rem;
18+
max-width: 90vw;
19+
overflow-x: scroll;
20+
21+
@media(min-width: 768px){
22+
max-width: 70vw;
23+
}
24+
`
25+
26+
const SourceItem = styled.div`
27+
cursor: pointer;
28+
display: flex;
29+
flex-direction: column;
30+
justify-content: space-between;
31+
border-radius: 6px;
32+
background-color: ${props =>props.theme.secondary.bg};
33+
padding-left: 12px;
34+
padding-right: 12px;
35+
color:${props => props.theme.text};
36+
transform: background-color .2s, color .2s;
37+
38+
&:hover{
39+
background-color: ${props => props.theme.primary.bg};
40+
color: ${props => props.theme.primary.text};
41+
}
42+
`
43+
44+
const SourceLink = styled.div<{$hasExternalSource: boolean}>`
45+
display: flex;
46+
flex-direction: row;
47+
align-items: center;
48+
gap: 0.375rem;
49+
text-decoration: ${({$hasExternalSource}) => ($hasExternalSource? "underline": "none")};
50+
text-underline-offset: 2px;
51+
`
52+
53+
const SourceLinkText = styled.p`
54+
white-space: nowrap;
55+
overflow: hidden;
56+
text-overflow: ellipsis;
57+
font-size: 0.75rem;
58+
line-height: 1rem;
59+
`
60+
61+
const OtherSources = styled.button`
62+
cursor: pointer;
63+
background: transparent;
64+
color: #8860DB;
65+
border: none;
66+
outline: none;
67+
margin-top: 0.5rem;
68+
align-self: flex-start;
69+
`
70+
71+
type TQuerySources = {
72+
sources: Pick<Query, "sources">["sources"],
73+
}
74+
75+
const QuerySources = ({sources}:TQuerySources) => {
76+
const [showAllSources, setShowAllSources] = useState(false)
77+
78+
const visibleSources = useMemo(() => {
79+
if(!sources) return [];
80+
81+
return showAllSources? sources : sources.slice(0, 3)
82+
}, [sources, showAllSources])
83+
84+
const handleToggleShowAll = () => {
85+
setShowAllSources(prev => !prev)
86+
}
87+
88+
if(!sources || sources.length === 0){
89+
return null;
90+
}
91+
92+
return (
93+
<SourcesWrapper>
94+
<SourcesGrid>
95+
{visibleSources?.map((source, index) => (
96+
<SourceItem
97+
key={index}
98+
>
99+
<SourceLink
100+
$hasExternalSource={!!source.source && source.source !== "local"}
101+
onClick={() =>
102+
source.source && source.source !== 'local'
103+
? window.open(source.source, '_blank', 'noopener,noreferrer')
104+
: null
105+
}
106+
>
107+
<ExternalLinkIcon />
108+
<SourceLinkText title={source.source && source.source !== 'local' ? source.source : source.title}>
109+
{source.source && source.source !== 'local' ? source.source : source.title}
110+
</SourceLinkText>
111+
</SourceLink>
112+
</SourceItem>
113+
))}
114+
</SourcesGrid>
115+
116+
{
117+
sources.length > 3 && (
118+
<OtherSources onClick={handleToggleShowAll}>{
119+
showAllSources ? `Show less` : `+ ${sources.length - 3} more`
120+
}</OtherSources>
121+
122+
)
123+
}
124+
</SourcesWrapper>
125+
)
126+
}
127+
128+
export default QuerySources
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
12
//development
23
import { createRoot } from "react-dom/client";
34
import { App } from "./App";
45
import React from "react";
56
const container = document.getElementById("app") as HTMLElement;
67
const root = createRoot(container)
7-
root.render(<App />);
8+
root.render(<App />);

extensions/react-widget/src/requests/streamingApi.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { FEEDBACK } from "@/types";
2+
23
interface HistoryItem {
34
prompt: string;
45
response?: string;
56
}
7+
68
interface FetchAnswerStreamingProps {
79
question?: string;
810
apiKey?: string;
@@ -12,12 +14,14 @@ interface FetchAnswerStreamingProps {
1214
apiHost?: string;
1315
onEvent?: (event: MessageEvent) => void;
1416
}
17+
1518
interface FeedbackPayload {
1619
question: string;
1720
answer: string;
1821
apikey: string;
1922
feedback: FEEDBACK;
2023
}
24+
2125
export function fetchAnswerStreaming({
2226
question = '',
2327
apiKey = '',
@@ -46,7 +50,7 @@ export function fetchAnswerStreaming({
4650

4751
const reader = response.body.getReader();
4852
const decoder = new TextDecoder('utf-8');
49-
let counterrr = 0;
53+
let counter = 0;
5054
const processStream = ({
5155
done,
5256
value,
@@ -56,7 +60,7 @@ export function fetchAnswerStreaming({
5660
return;
5761
}
5862

59-
counterrr += 1;
63+
counter += 1;
6064

6165
const chunk = decoder.decode(value);
6266

extensions/react-widget/src/types/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
export type MESSAGE_TYPE = 'QUESTION' | 'ANSWER' | 'ERROR';
2+
23
export type Status = 'idle' | 'loading' | 'failed';
4+
35
export type FEEDBACK = 'LIKE' | 'DISLIKE';
6+
47
export type THEME = 'light' | 'dark';
8+
59
export interface Query {
610
prompt: string;
711
response?: string;
812
feedback?: FEEDBACK;
913
error?: string;
10-
sources?: { title: string; text: string }[];
14+
sources?: { title: string; text: string, source:string }[];
1115
conversationId?: string | null;
1216
title?: string | null;
1317
}
18+
1419
export interface WidgetProps {
1520
apiHost?: string;
1621
apiKey?: string;
@@ -32,6 +37,8 @@ export interface WidgetProps {
3237
buttonText?:string;
3338
buttonBg?:string;
3439
collectFeedback?:boolean;
40+
deafultOpen?: boolean;
41+
showSources?: boolean
3542
defaultOpen?: boolean;
3643
}
3744
export interface WidgetCoreProps extends WidgetProps {
@@ -54,4 +61,4 @@ export interface Result {
5461
text:string;
5562
title:string;
5663
source:string;
57-
}
64+
}

0 commit comments

Comments
 (0)