@stack-spot/ai-chat-widget 0.1.0 → 0.2.0
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.
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +3 -1
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/chat-interceptors/send-message.d.ts.map +1 -1
- package/dist/chat-interceptors/send-message.js +19 -7
- package/dist/chat-interceptors/send-message.js.map +1 -1
- package/dist/components/RightPanelTabs.d.ts.map +1 -1
- package/dist/components/RightPanelTabs.js +1 -0
- package/dist/components/RightPanelTabs.js.map +1 -1
- package/dist/components/form/styled.d.ts.map +1 -1
- package/dist/components/form/styled.js +2 -1
- package/dist/components/form/styled.js.map +1 -1
- package/dist/context/hooks.d.ts.map +1 -1
- package/dist/context/hooks.js +1 -5
- package/dist/context/hooks.js.map +1 -1
- package/dist/features.d.ts.map +1 -1
- package/dist/features.js +1 -0
- package/dist/features.js.map +1 -1
- package/dist/right-panel/DefaultPanel.d.ts +2 -2
- package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
- package/dist/right-panel/DefaultPanel.js +2 -1
- package/dist/right-panel/DefaultPanel.js.map +1 -1
- package/dist/right-panel/hooks.d.ts +2 -2
- package/dist/right-panel/hooks.d.ts.map +1 -1
- package/dist/state/ChatEntry.d.ts +7 -0
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatEntry.js +0 -3
- package/dist/state/ChatEntry.js.map +1 -1
- package/dist/state/ChatState.d.ts +4 -1
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js.map +1 -1
- package/dist/state/WidgetState.d.ts +19 -8
- package/dist/state/WidgetState.d.ts.map +1 -1
- package/dist/state/WidgetState.js +0 -19
- package/dist/state/WidgetState.js.map +1 -1
- package/dist/utils/chat.js +1 -1
- package/dist/utils/chat.js.map +1 -1
- package/dist/utils/knowledge-source.d.ts +7 -0
- package/dist/utils/knowledge-source.d.ts.map +1 -0
- package/dist/utils/knowledge-source.js +38 -0
- package/dist/utils/knowledge-source.js.map +1 -0
- package/dist/views/Agents.d.ts.map +1 -1
- package/dist/views/Agents.js +129 -1
- package/dist/views/Agents.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +9 -4
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/styled.d.ts.map +1 -1
- package/dist/views/Chat/styled.js +24 -0
- package/dist/views/Chat/styled.js.map +1 -1
- package/dist/views/KSDocument.d.ts +2 -0
- package/dist/views/KSDocument.d.ts.map +1 -0
- package/dist/views/KSDocument.js +40 -0
- package/dist/views/KSDocument.js.map +1 -0
- package/dist/views/KnowledgeSources.js +7 -5
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.js +5 -3
- package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +2 -4
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts +2 -0
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +11 -3
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/dist/views/Stacks.js +7 -5
- package/dist/views/Stacks.js.map +1 -1
- package/dist/views/Workspaces.js +7 -5
- package/dist/views/Workspaces.js.map +1 -1
- package/package.json +2 -2
- package/src/StackspotAIWidget.tsx +4 -0
- package/src/chat-interceptors/send-message.ts +20 -8
- package/src/components/RightPanelTabs.tsx +1 -0
- package/src/components/form/styled.ts +2 -1
- package/src/context/hooks.ts +1 -4
- package/src/features.ts +1 -0
- package/src/right-panel/DefaultPanel.tsx +5 -4
- package/src/right-panel/hooks.tsx +2 -2
- package/src/state/ChatEntry.ts +8 -3
- package/src/state/ChatState.ts +5 -1
- package/src/state/WidgetState.ts +14 -26
- package/src/utils/chat.ts +1 -1
- package/src/utils/knowledge-source.ts +43 -0
- package/src/views/Agents.tsx +186 -1
- package/src/views/Chat/ChatMessage.tsx +18 -4
- package/src/views/Chat/styled.ts +24 -0
- package/src/views/KSDocument.tsx +58 -0
- package/src/views/KnowledgeSources.tsx +8 -5
- package/src/views/MessageInput/ButtonGroup.tsx +9 -7
- package/src/views/MessageInput/index.tsx +2 -5
- package/src/views/MessageInput/styled.ts +11 -3
- package/src/views/Stacks.tsx +8 -5
- package/src/views/Workspaces.tsx +8 -5
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Flex, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { Score } from '@citric/icons'
|
|
3
|
+
import { aiClient } from '@stack-spot/portal-network'
|
|
4
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
5
|
+
import { useEffect } from 'react'
|
|
6
|
+
import { Code } from '../components/Code'
|
|
7
|
+
import { useWidget, useWidgetState } from '../context/hooks'
|
|
8
|
+
import { useRightPanel } from '../right-panel/hooks'
|
|
9
|
+
import { extractCodeFromKSDocument } from '../utils/knowledge-source'
|
|
10
|
+
|
|
11
|
+
export const KSDocument = () => {
|
|
12
|
+
const t = useTranslate(dictionary)
|
|
13
|
+
const panel = useWidgetState('panel')
|
|
14
|
+
const ks = useWidgetState('currentKSInPanel')
|
|
15
|
+
const { open } = useRightPanel()
|
|
16
|
+
const widget = useWidget()
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (panel === 'ks-details' && ks) open(
|
|
20
|
+
<KSDocumentPanel documentId={ks.documentId} slug={ks.slug} />,
|
|
21
|
+
{
|
|
22
|
+
title: (
|
|
23
|
+
<Flex flexDirection="row" alignItems="center" flex="1">
|
|
24
|
+
<Text appearance="h5" style={{ flex: 1 }}>{ks.name}</Text>
|
|
25
|
+
<Flex flexDirection="row" alignItems="center" style={{ gap: '5px' }} title="Score" aria-label="Score">
|
|
26
|
+
<IconBox><Score /></IconBox>
|
|
27
|
+
<Text>{ks.score.toFixed(2)}</Text>
|
|
28
|
+
</Flex>
|
|
29
|
+
</Flex>
|
|
30
|
+
),
|
|
31
|
+
description: t.description,
|
|
32
|
+
onClose: () => widget.set('panel', undefined),
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
}, [panel, ks, t])
|
|
36
|
+
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const KSDocumentPanel = ({ slug, documentId }: { slug: string, documentId: string }) => {
|
|
41
|
+
const document = aiClient.knowledgeSourceDocument.useQuery({ slug, customId: documentId })
|
|
42
|
+
const { snippet, language, text } = extractCodeFromKSDocument(document)
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
{text && <Text>{text}</Text>}
|
|
46
|
+
<Code language={language}>{snippet}</Code>
|
|
47
|
+
</>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const dictionary = {
|
|
52
|
+
en: {
|
|
53
|
+
description: 'Knowledge Source details',
|
|
54
|
+
},
|
|
55
|
+
pt: {
|
|
56
|
+
description: 'Detalhes do Knowledge Source',
|
|
57
|
+
},
|
|
58
|
+
} satisfies Dictionary
|
|
@@ -13,16 +13,16 @@ import { useRightPanel } from '../right-panel/hooks'
|
|
|
13
13
|
|
|
14
14
|
export const KnowledgeSources = () => {
|
|
15
15
|
const t = useTranslate(dictionary)
|
|
16
|
-
const
|
|
16
|
+
const panel = useWidgetState('panel')
|
|
17
17
|
const { open } = useRightPanel()
|
|
18
18
|
const widget = useWidget()
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
if (
|
|
21
|
+
if (panel === 'ks') open(
|
|
22
22
|
<KnowledgeSourcesPanel />,
|
|
23
|
-
{ title: t.title, description: t.description, onClose: () => widget.set('
|
|
23
|
+
{ title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) },
|
|
24
24
|
)
|
|
25
|
-
}, [
|
|
25
|
+
}, [panel, t])
|
|
26
26
|
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
@@ -74,7 +74,10 @@ const KnowledgeSourcesTab = ({ visibility }: { visibility: VisibilityLevelEnum }
|
|
|
74
74
|
}}
|
|
75
75
|
renderLabel={ks => ks.name}
|
|
76
76
|
renderDescription={ks => ks.description}
|
|
77
|
-
optionClassName={ks => (filter && !ks.name.includes(filter) && value.includes(ks))
|
|
77
|
+
optionClassName={ks => (filter && !ks.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()) && value.includes(ks))
|
|
78
|
+
? 'filtered-out'
|
|
79
|
+
: ''
|
|
80
|
+
}
|
|
78
81
|
className="option-list"
|
|
79
82
|
/>}
|
|
80
83
|
{!!knowledgeSources.length && !filtered.length && (
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { ChevronRight,
|
|
1
|
+
import { ChevronRight, KnowledgeSource, Send, Stack, Times, Workspace } from '@citric/icons'
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
|
+
import { MiniLogo } from '@stack-spot/portal-components/svg'
|
|
3
4
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
4
5
|
import { useEffect, useRef } from 'react'
|
|
5
|
-
import { useWidget } from '../../context/hooks'
|
|
6
|
+
import { useCurrentChatState, useWidget } from '../../context/hooks'
|
|
6
7
|
import { MessageInputFeatures } from '../../features'
|
|
7
8
|
import { useMessageInputDictionary } from './dictionary'
|
|
8
9
|
|
|
@@ -20,6 +21,7 @@ export const ButtonGroup = ({ features, onSend, onCancel, expanded, setExpanded,
|
|
|
20
21
|
const widget = useWidget()
|
|
21
22
|
const featureButtonsWidth = useRef<number | undefined>()
|
|
22
23
|
const featureButtons = useRef<HTMLDivElement>(null)
|
|
24
|
+
const agent = useCurrentChatState('agent')
|
|
23
25
|
const hasFeatureButtons = features.agent || features.workspace || features.knowledgeSource || features.stack
|
|
24
26
|
|
|
25
27
|
useEffect(() => {
|
|
@@ -37,12 +39,12 @@ export const ButtonGroup = ({ features, onSend, onCancel, expanded, setExpanded,
|
|
|
37
39
|
style={{ width: expanded ? featureButtonsWidth.current : 0 }}
|
|
38
40
|
>
|
|
39
41
|
{features.agent && (
|
|
40
|
-
<IconButton aria-label={t.agent} title={t.agent} onClick={() => widget.set('
|
|
41
|
-
<
|
|
42
|
+
<IconButton aria-label={t.agent} title={t.agent} className="agent" onClick={() => widget.set('panel', 'agent')}>
|
|
43
|
+
{agent?.image ? <img src={agent.image} /> : <MiniLogo />}
|
|
42
44
|
</IconButton>
|
|
43
45
|
)}
|
|
44
46
|
{features.workspace && (
|
|
45
|
-
<IconButton aria-label={t.workspace} title={t.workspace} onClick={() => widget.set('
|
|
47
|
+
<IconButton aria-label={t.workspace} title={t.workspace} onClick={() => widget.set('panel', 'workspace')}>
|
|
46
48
|
<Workspace />
|
|
47
49
|
</IconButton>
|
|
48
50
|
)}
|
|
@@ -50,13 +52,13 @@ export const ButtonGroup = ({ features, onSend, onCancel, expanded, setExpanded,
|
|
|
50
52
|
<IconButton
|
|
51
53
|
aria-label={t.knowledgeSource}
|
|
52
54
|
title={t.knowledgeSource}
|
|
53
|
-
onClick={() => widget.set('
|
|
55
|
+
onClick={() => widget.set('panel', 'ks')}
|
|
54
56
|
>
|
|
55
57
|
<KnowledgeSource />
|
|
56
58
|
</IconButton>
|
|
57
59
|
)}
|
|
58
60
|
{features.stack && (
|
|
59
|
-
<IconButton aria-label={t.stack} title={t.stack} onClick={() => widget.set('
|
|
61
|
+
<IconButton aria-label={t.stack} title={t.stack} onClick={() => widget.set('panel', 'stack')}>
|
|
60
62
|
<Stack />
|
|
61
63
|
</IconButton>
|
|
62
64
|
)}
|
|
@@ -9,15 +9,12 @@ import { ChatEntry } from '../../state/ChatEntry'
|
|
|
9
9
|
import { ButtonGroup } from './ButtonGroup'
|
|
10
10
|
import { useMessageInputDictionary } from './dictionary'
|
|
11
11
|
import { InfoBar } from './InfoBar'
|
|
12
|
-
import { MessageInputBox } from './styled'
|
|
12
|
+
import { MAX_INPUT_HEIGHT, MessageInputBox, MIN_INPUT_HEIGHT } from './styled'
|
|
13
13
|
|
|
14
14
|
interface Props {
|
|
15
15
|
features: MessageInputFeatures,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const MAX_INPUT_HEIGHT = 300
|
|
19
|
-
const MAX_INPUT_HEIGHT_MINIMIZED = 30
|
|
20
|
-
|
|
21
18
|
export const MessageInput = ({ features }: Props) => {
|
|
22
19
|
const t = useMessageInputDictionary()
|
|
23
20
|
const [focused, setFocused] = useState(false)
|
|
@@ -58,7 +55,7 @@ export const MessageInput = ({ features }: Props) => {
|
|
|
58
55
|
onKeyDown={onKeyDown}
|
|
59
56
|
onIncreaseSize={() => setExpanded(false)}
|
|
60
57
|
onResetSize={() => !expansionLocked.current && setExpanded(true)}
|
|
61
|
-
maxHeight={isMinimized ?
|
|
58
|
+
maxHeight={isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT}
|
|
62
59
|
/>
|
|
63
60
|
<ButtonGroup
|
|
64
61
|
features={features}
|
|
@@ -4,6 +4,8 @@ import { styled } from 'styled-components'
|
|
|
4
4
|
|
|
5
5
|
const INFO_BAR_HEIGHT = 42
|
|
6
6
|
const INFO_BAR_DISPLACEMENT = 4
|
|
7
|
+
export const MAX_INPUT_HEIGHT = 300
|
|
8
|
+
export const MIN_INPUT_HEIGHT = 24
|
|
7
9
|
|
|
8
10
|
export const MessageInputBox = styled.div`
|
|
9
11
|
display: flex;
|
|
@@ -103,7 +105,7 @@ export const MessageInputBox = styled.div`
|
|
|
103
105
|
flex-direction: row;
|
|
104
106
|
align-items: center;
|
|
105
107
|
gap: 4px;
|
|
106
|
-
margin-bottom:
|
|
108
|
+
margin-bottom: 1px;
|
|
107
109
|
|
|
108
110
|
button {
|
|
109
111
|
border: none;
|
|
@@ -144,6 +146,12 @@ export const MessageInputBox = styled.div`
|
|
|
144
146
|
transform: rotate(180deg);
|
|
145
147
|
}
|
|
146
148
|
}
|
|
149
|
+
|
|
150
|
+
&.agent img {
|
|
151
|
+
width: 80%;
|
|
152
|
+
height: 80%;
|
|
153
|
+
border-radius: 50%;
|
|
154
|
+
}
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
.feature-buttons {
|
|
@@ -185,8 +193,8 @@ export const MessageInputBox = styled.div`
|
|
|
185
193
|
border: none;
|
|
186
194
|
flex: 1;
|
|
187
195
|
padding: 0;
|
|
188
|
-
height:
|
|
189
|
-
padding:
|
|
196
|
+
height: ${MIN_INPUT_HEIGHT}px;
|
|
197
|
+
padding: 0;
|
|
190
198
|
transition: height 0.3s;
|
|
191
199
|
background-color: transparent;
|
|
192
200
|
&:focus {
|
package/src/views/Stacks.tsx
CHANGED
|
@@ -13,16 +13,16 @@ import { useRightPanel } from '../right-panel/hooks'
|
|
|
13
13
|
|
|
14
14
|
export const Stacks = () => {
|
|
15
15
|
const t = useTranslate(dictionary)
|
|
16
|
-
const
|
|
16
|
+
const panel = useWidgetState('panel')
|
|
17
17
|
const { open } = useRightPanel()
|
|
18
18
|
const widget = useWidget()
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
if (
|
|
21
|
+
if (panel === 'stack') open(
|
|
22
22
|
<StacksPanel />,
|
|
23
|
-
{ title: t.title, description: t.description, onClose: () => widget.set('
|
|
23
|
+
{ title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) },
|
|
24
24
|
)
|
|
25
|
-
}, [
|
|
25
|
+
}, [panel, t])
|
|
26
26
|
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
@@ -65,7 +65,10 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
|
|
|
65
65
|
onChange={setValue}
|
|
66
66
|
renderLabel={s => s.name}
|
|
67
67
|
renderDescription={s => s.use_case}
|
|
68
|
-
optionClassName={s => (s === value && filter && !s.name.includes(filter))
|
|
68
|
+
optionClassName={s => (s === value && filter && !s.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
69
|
+
? 'filtered-out'
|
|
70
|
+
: ''
|
|
71
|
+
}
|
|
69
72
|
className="option-list"
|
|
70
73
|
/>}
|
|
71
74
|
{!!stacks.length && !filtered.length && <Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />}
|
package/src/views/Workspaces.tsx
CHANGED
|
@@ -13,16 +13,16 @@ import { useRightPanel } from '../right-panel/hooks'
|
|
|
13
13
|
|
|
14
14
|
export const Workspaces = () => {
|
|
15
15
|
const t = useTranslate(dictionary)
|
|
16
|
-
const
|
|
16
|
+
const panel = useWidgetState('panel')
|
|
17
17
|
const { open } = useRightPanel()
|
|
18
18
|
const widget = useWidget()
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
if (
|
|
21
|
+
if (panel === 'workspace') open(
|
|
22
22
|
<RightPanelForm><WorkspacesPanel /></RightPanelForm>,
|
|
23
|
-
{ title: t.title, description: t.description, onClose: () => widget.set('
|
|
23
|
+
{ title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) },
|
|
24
24
|
)
|
|
25
|
-
}, [
|
|
25
|
+
}, [panel, t])
|
|
26
26
|
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
@@ -55,7 +55,10 @@ const WorkspacesPanel = () => {
|
|
|
55
55
|
onChange={setValue}
|
|
56
56
|
renderLabel={w => w.name}
|
|
57
57
|
renderDescription={w => w.description}
|
|
58
|
-
optionClassName={w => (w === value && filter && !w.name.includes(filter))
|
|
58
|
+
optionClassName={w => (w === value && filter && !w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
59
|
+
? 'filtered-out'
|
|
60
|
+
: ''
|
|
61
|
+
}
|
|
59
62
|
className="option-list"
|
|
60
63
|
/>}
|
|
61
64
|
{!!workspaces.length && !filtered.length && <Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />}
|