@stack-spot/ai-chat-widget 2.10.0 → 2.11.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/CHANGELOG.md +8 -0
- package/dist/app-metadata.json +3 -3
- package/dist/components/Selector/index.d.ts +11 -2
- package/dist/components/Selector/index.d.ts.map +1 -1
- package/dist/components/Selector/index.js +18 -17
- package/dist/components/Selector/index.js.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.d.ts +3 -1
- package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.js +31 -19
- package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/KnowledgeSources.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.js +31 -17
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +8 -6
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +12 -8
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/package.json +2 -2
- package/src/app-metadata.json +3 -3
- package/src/components/Selector/index.tsx +46 -33
- package/src/components/form/DescribedCheckboxGroup.tsx +61 -35
- package/src/views/Agents/AgentsTab.tsx +5 -5
- package/src/views/KnowledgeSources.tsx +59 -36
- package/src/views/MessageInput/AgentSelector.tsx +10 -8
- package/src/views/MessageInput/QuickCommandSelector.tsx +33 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuickCommandSelector.js","sourceRoot":"","sources":["../../../src/views/MessageInput/QuickCommandSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"QuickCommandSelector.js","sourceRoot":"","sources":["../../../src/views/MessageInput/QuickCommandSelector.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/ai-chat-widget",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@citric/core": "^6.4.0",
|
|
17
17
|
"@stack-spot/portal-components": "^2.27.3",
|
|
18
18
|
"@citric/icons": "^5.13.0",
|
|
19
|
-
"@stack-spot/portal-network": "0.212.
|
|
19
|
+
"@stack-spot/portal-network": "0.212.4",
|
|
20
20
|
"@citric/ui": "^6.10.2",
|
|
21
21
|
"@stack-spot/portal-translate": "^2.1.0",
|
|
22
22
|
"lodash": "^4.17.0",
|
package/src/app-metadata.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/ai-chat-widget",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"date": "
|
|
3
|
+
"version": "2.11.0",
|
|
4
|
+
"date": "Wed Jan 07 2026 14:53:42 GMT+0000 (Coordinated Universal Time)",
|
|
5
5
|
"dependencies": [
|
|
6
6
|
{
|
|
7
7
|
"name": "@stack-spot/app-metadata",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"name": "@stack-spot/portal-network",
|
|
124
|
-
"version": "0.212.
|
|
124
|
+
"version": "0.212.4(@stack-spot/auth@6.1.0)(@stack-spot/opa@2.5.0(@stack-spot/auth@6.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@tanstack/react-query@5.59.16(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"name": "@stack-spot/portal-theme",
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { FallbackBoundary, IconLink, Text } from '@stack-spot/citric-react'
|
|
2
2
|
import { useKeyboardControls } from '@stack-spot/portal-components'
|
|
3
|
+
import { InfiniteScroll } from '@stack-spot/portal-components/InfiniteScroll'
|
|
3
4
|
import { AgentVisibilityLevel } from '@stack-spot/portal-network'
|
|
5
|
+
import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
|
|
4
6
|
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
5
7
|
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
8
|
+
import { debounce } from 'lodash'
|
|
6
9
|
import { useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
7
10
|
import { getUrlToStackSpotAI } from '../../utils/url'
|
|
8
11
|
import { ButtonFavorite } from '../ButtonFavorite'
|
|
9
12
|
import { Fading } from '../Fading'
|
|
10
13
|
import { SelectorBox } from './styled'
|
|
11
14
|
|
|
12
|
-
type SectionVisibility = AgentVisibilityLevel
|
|
15
|
+
type SectionVisibility = AgentVisibilityLevel | VisibilityLevelEnum
|
|
13
16
|
type SelectorShortcut = '/' | '@'
|
|
14
17
|
|
|
15
18
|
interface Item {
|
|
@@ -53,6 +56,12 @@ interface ContentProps<T> {
|
|
|
53
56
|
favorite?: Favorite<T>,
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
interface PropsUseData<T> {
|
|
60
|
+
data: T[],
|
|
61
|
+
fetchNextPage?: () => void,
|
|
62
|
+
hasNextPage?: boolean,
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
interface SelectorConfig<T> {
|
|
57
66
|
resourceName: string,
|
|
58
67
|
shortcut: SelectorShortcut,
|
|
@@ -71,7 +80,7 @@ interface SelectorConfig<T> {
|
|
|
71
80
|
*
|
|
72
81
|
* @returns the data to render in the selector.
|
|
73
82
|
*/
|
|
74
|
-
useData: () => T
|
|
83
|
+
useData: (props: {filter?: string, visibility?: SectionVisibility[]}) => PropsUseData<T>,
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
interface SelectorProps<T> {
|
|
@@ -114,39 +123,27 @@ const ListItem = <T extends Item>({ item, selectorConfig, onSelect, favorite }:
|
|
|
114
123
|
|
|
115
124
|
const List = <T extends Item>({ selectorConfig, filter, visibility, onSelect, favorite }: ListProps<T>) => {
|
|
116
125
|
const t = useTranslate(dictionary)
|
|
117
|
-
const items = selectorConfig.useData()
|
|
118
|
-
const favorites = favorite?.useFavorites?.()
|
|
119
|
-
const filtered = useMemo(() => {
|
|
120
|
-
if (!filter && !visibility) return [...items]
|
|
121
|
-
const lowerFilter = filter?.toLowerCase() ?? ''
|
|
122
|
-
|
|
123
|
-
if (visibility?.toLowerCase() === 'favorite'){
|
|
124
|
-
return favorites?.filter(item =>
|
|
125
|
-
(item[selectorConfig.searchProp] as string).toLocaleLowerCase().includes(lowerFilter))
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return items.filter(item =>
|
|
129
|
-
(item[selectorConfig.searchProp] as string).toLocaleLowerCase().includes(lowerFilter) &&
|
|
130
|
-
(!visibility || item?.visibility_level?.toLowerCase() === visibility.toLowerCase()),
|
|
131
|
-
)
|
|
132
|
-
}, [filter, items, visibility, favorites])
|
|
133
|
-
|
|
126
|
+
const { data: items, fetchNextPage, hasNextPage } = selectorConfig.useData({ filter, visibility: visibility ? [visibility] : undefined })
|
|
134
127
|
|
|
135
|
-
if (!items.length) return <Text className="empty" color="light.700">{interpolate(t.noData, selectorConfig.resourceName)}</Text>
|
|
136
|
-
if (!
|
|
137
|
-
<Text className="empty" color="light.700">{interpolate(t.noResults, selectorConfig.resourceName)}</Text>
|
|
128
|
+
if (!items.length && !filter) return <Text className="empty" color="light.700">{interpolate(t.noData, selectorConfig.resourceName)}</Text>
|
|
129
|
+
if (!items?.length) return <Text className="empty" color="light.700">{interpolate(t.noResults, selectorConfig.resourceName)}</Text>
|
|
138
130
|
|
|
139
131
|
return (
|
|
140
|
-
<ul className="selector-list">
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
132
|
+
<ul className="selector-list" id="selector-list">
|
|
133
|
+
<InfiniteScroll scrollableTarget="selector-list"
|
|
134
|
+
dataLength={items?.length ?? 0}
|
|
135
|
+
next={fetchNextPage as any ?? undefined}
|
|
136
|
+
hasMore={hasNextPage ?? false}>
|
|
137
|
+
{items?.map((item, i) => (
|
|
138
|
+
<ListItem
|
|
139
|
+
key={`${item.id}${item.visibility_level}${i}`}
|
|
140
|
+
item={item}
|
|
141
|
+
selectorConfig={selectorConfig}
|
|
142
|
+
onSelect={onSelect}
|
|
143
|
+
favorite={favorite}
|
|
144
|
+
/>
|
|
145
|
+
))}
|
|
146
|
+
</InfiniteScroll>
|
|
150
147
|
</ul>
|
|
151
148
|
)
|
|
152
149
|
}
|
|
@@ -206,9 +203,25 @@ export const Selector = <T, >({ inputRef, selectorConfig, favorite }: SelectorPr
|
|
|
206
203
|
const { shortcut, regex, isEnabled } = selectorConfig
|
|
207
204
|
const [isClosed, setClosed] = useState(false)
|
|
208
205
|
const selectorRef = useRef<HTMLDivElement>(null)
|
|
206
|
+
const [debouncedFilter, setDebouncedFilter] = useState<string | undefined>(undefined)
|
|
209
207
|
const value = useCurrentChatState('nextMessage') ?? ''
|
|
210
208
|
const filter = useMemo(() => value === shortcut || regex.test(value) ? value.substring(1) : undefined, [value])
|
|
211
209
|
const shouldRender = isEnabled && filter !== undefined && !isClosed
|
|
210
|
+
|
|
211
|
+
const debouncedSetFilter = useCallback(
|
|
212
|
+
debounce((filterValue: string | undefined) => {
|
|
213
|
+
setDebouncedFilter(filterValue)
|
|
214
|
+
}, 300),
|
|
215
|
+
[],
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
debouncedSetFilter(filter)
|
|
220
|
+
return () => {
|
|
221
|
+
debouncedSetFilter.cancel()
|
|
222
|
+
}
|
|
223
|
+
}, [filter, debouncedSetFilter])
|
|
224
|
+
|
|
212
225
|
|
|
213
226
|
// Resets the closed state whenever the message input is cleared
|
|
214
227
|
useEffect(() => {
|
|
@@ -258,7 +271,7 @@ export const Selector = <T, >({ inputRef, selectorConfig, favorite }: SelectorPr
|
|
|
258
271
|
<SelectorContent
|
|
259
272
|
favorite={favorite}
|
|
260
273
|
selectorConfig={selectorConfig}
|
|
261
|
-
filter={
|
|
274
|
+
filter={debouncedFilter}
|
|
262
275
|
onClose={() => setClosed(true)}
|
|
263
276
|
inputRef={inputRef}
|
|
264
277
|
/>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Icon } from '@stack-spot/citric-icons'
|
|
2
2
|
import { Accordion, Checkbox, CheckboxGroup, FieldGroup, Input, Row, Text, useCheckboxGroupControls } from '@stack-spot/citric-react'
|
|
3
|
+
import { InfiniteScroll } from '@stack-spot/portal-components/InfiniteScroll'
|
|
3
4
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
4
|
-
import { difference, uniqBy } from 'lodash'
|
|
5
|
+
import { difference, isEqual, uniqBy } from 'lodash'
|
|
5
6
|
import { useCallback, useEffect, useState } from 'react'
|
|
7
|
+
import styled from 'styled-components'
|
|
6
8
|
import { Labeled } from '../../state/types'
|
|
7
9
|
import { ButtonFavorite, Favorite } from '../ButtonFavorite'
|
|
8
10
|
|
|
@@ -20,8 +22,16 @@ interface Props<T> {
|
|
|
20
22
|
emptyResults: React.ReactNode,
|
|
21
23
|
emptyDataset: React.ReactNode,
|
|
22
24
|
onChange?: (value: T[]) => void,
|
|
25
|
+
fetchNextPage?: () => void,
|
|
26
|
+
hasNextPage?: boolean,
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
const StyledDiv = styled.div`
|
|
30
|
+
&#ks-scrollable {
|
|
31
|
+
overflow: auto;
|
|
32
|
+
}
|
|
33
|
+
`
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* Renders a checkbox group where each option has a label and a description.
|
|
27
37
|
* The description in placed under the label and checkbox as an accordion.
|
|
@@ -29,11 +39,12 @@ interface Props<T> {
|
|
|
29
39
|
* Also renders a search input and a select all checkbox.
|
|
30
40
|
*/
|
|
31
41
|
export function DescribedCheckboxGroup<T>(
|
|
32
|
-
{ initialValue, options: opt, data, globalSelection, onChange: change, emptyDataset, emptyResults
|
|
42
|
+
{ initialValue, options: opt, data, globalSelection, onChange: change, emptyDataset, emptyResults,
|
|
43
|
+
fetchNextPage, hasNextPage,
|
|
44
|
+
}: Props<T>,
|
|
33
45
|
) {
|
|
34
46
|
const t = useTranslate(dictionary)
|
|
35
47
|
const [options, setOptions] = useState(opt)
|
|
36
|
-
|
|
37
48
|
useEffect(() => {
|
|
38
49
|
if (controls.value.length === 0 && (initialValue?.length ?? 0) > 0) controls.setValue(initialValue!)
|
|
39
50
|
}, [initialValue])
|
|
@@ -58,7 +69,13 @@ export function DescribedCheckboxGroup<T>(
|
|
|
58
69
|
onChange,
|
|
59
70
|
})
|
|
60
71
|
|
|
61
|
-
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!isEqual(opt, options)) {
|
|
74
|
+
setOptions(opt)
|
|
75
|
+
}
|
|
76
|
+
}, [opt])
|
|
77
|
+
|
|
78
|
+
return options?.length ? <>
|
|
62
79
|
<FieldGroup fullWidth>
|
|
63
80
|
<Icon icon="Search" />
|
|
64
81
|
<Input type="search" value={controls.filter} onChange={controls.setFilter} />
|
|
@@ -68,37 +85,46 @@ export function DescribedCheckboxGroup<T>(
|
|
|
68
85
|
<Checkbox value={controls.isAllSelected} onChange={v => v ? controls.selectAll() : controls.removeSelection()} />
|
|
69
86
|
<Text>{controls.isAllSelected ? t.removeAll : t.selectAll}</Text>
|
|
70
87
|
</Row>
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
88
|
+
<StyledDiv id="ks-scrollable">
|
|
89
|
+
<InfiniteScroll
|
|
90
|
+
scrollableTarget="ks-scrollable"
|
|
91
|
+
dataLength={controls.options.length}
|
|
92
|
+
next={fetchNextPage as any ?? undefined}
|
|
93
|
+
hasMore={hasNextPage ?? false}
|
|
94
|
+
>
|
|
95
|
+
<CheckboxGroup
|
|
96
|
+
options={controls.options}
|
|
97
|
+
value={controls.value}
|
|
98
|
+
onChange={controls.setValue}
|
|
99
|
+
renderKey={controls.renderKey}
|
|
100
|
+
className="option-list"
|
|
101
|
+
renderItem={(checkbox, o) => {
|
|
102
|
+
const { description, idOrSlug, name, listFavorites, onAddFavorite, onRemoveFavorite } = data(o)
|
|
103
|
+
return (
|
|
104
|
+
<Row className={controls.isUnfilteredButChecked(o) ? 'filtered-out' : ''}>
|
|
105
|
+
<Accordion header={btn => <>{checkbox}<Text>{name}</Text>{btn}</>} appearance="card" maxHeight={100}>
|
|
106
|
+
<Text appearance="microtext1" color="light.700" style={{ wordBreak: 'break-all' }}>{description}</Text>
|
|
107
|
+
</Accordion>
|
|
108
|
+
{onAddFavorite && <ButtonFavorite favorite={{
|
|
109
|
+
idOrSlug: idOrSlug,
|
|
110
|
+
listFavorites,
|
|
111
|
+
onAddFavorite: async (...args) => {
|
|
112
|
+
const res = await onAddFavorite(...args)
|
|
113
|
+
setOptions([...options]) // forces options re-rendering
|
|
114
|
+
return res
|
|
115
|
+
},
|
|
116
|
+
onRemoveFavorite: async (...args) => {
|
|
117
|
+
const res = await onRemoveFavorite?.(...args)
|
|
118
|
+
setOptions([...options]) // forces options re-rendering
|
|
119
|
+
return res ?? false
|
|
120
|
+
},
|
|
121
|
+
}} />}
|
|
122
|
+
</Row>
|
|
123
|
+
)
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
</InfiniteScroll>
|
|
127
|
+
</StyledDiv>
|
|
102
128
|
</> : emptyResults}
|
|
103
129
|
</> : emptyDataset
|
|
104
130
|
}
|
|
@@ -30,7 +30,7 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
30
30
|
const [submitEnabled, setSubmitEnabled] = useState(false)
|
|
31
31
|
const listFavorites = useFavorites()
|
|
32
32
|
const agentDefault = agentToolsClient.agentDefault.useQuery()
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
const [filter, setFilter] = useState<string | undefined>()
|
|
35
35
|
const [apiFilter, setApiFilter] = useState<string | undefined>()
|
|
36
36
|
const [isPending, startTransition] = useTransition()
|
|
@@ -47,9 +47,9 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
47
47
|
const data = workspaceAiClient.getAgentFromWorkspaceAi.useStatefulQuery({ workspaceId: workspaceId! },
|
|
48
48
|
{ enabled: !!workspaceId })
|
|
49
49
|
const workspaceAgents = data?.[0] as AgentResponseWithBuiltIn[]
|
|
50
|
-
|
|
51
|
-
const [agentsData=[], { fetchNextPage, hasNextPage }] = agentToolsClient.agentsMultipleFilters.useInfiniteQuery({
|
|
52
|
-
filters: {
|
|
50
|
+
|
|
51
|
+
const [agentsData = [], { fetchNextPage, hasNextPage }] = agentToolsClient.agentsMultipleFilters.useInfiniteQuery({
|
|
52
|
+
filters: {
|
|
53
53
|
page: 1,
|
|
54
54
|
size: 20,
|
|
55
55
|
name: apiFilter,
|
|
@@ -78,7 +78,7 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
78
78
|
return <>
|
|
79
79
|
<div className="content">
|
|
80
80
|
<DescribedRadioGroup
|
|
81
|
-
fetchNextPage={fetchNextPage}
|
|
81
|
+
fetchNextPage={fetchNextPage}
|
|
82
82
|
hasNextPage={hasNextPage && !workspaceId}
|
|
83
83
|
options={agents}
|
|
84
84
|
initialValue={initialValue}
|
|
@@ -2,6 +2,7 @@ import { Button, Tab } from '@stack-spot/citric-react'
|
|
|
2
2
|
import { Placeholder } from '@stack-spot/portal-components/Placeholder'
|
|
3
3
|
import { aiClient, dataIntegrationClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
|
|
5
|
+
import { KnowledgeSourceItemResponse } from '@stack-spot/portal-network/api/dataIntegration'
|
|
5
6
|
import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
|
|
6
7
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
8
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
@@ -64,13 +65,19 @@ const KnowledgeSourcesPanel = () => {
|
|
|
64
65
|
}, [chat])
|
|
65
66
|
|
|
66
67
|
const allTabsMap: Partial<Record<Scope, Omit<Tab, 'key'>>> = {
|
|
67
|
-
favorite: {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
favorite: {
|
|
69
|
+
label: t.favorites,
|
|
70
|
+
content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} />,
|
|
71
|
+
},
|
|
72
|
+
personal: {
|
|
73
|
+
label: t.personal,
|
|
74
|
+
content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} />,
|
|
75
|
+
},
|
|
71
76
|
shared: { label: t.shared, content: <KnowledgeSourcesTab key="shared" visibility="shared" allKS={allKS} onSubmit={onSubmit} /> },
|
|
72
|
-
workspace: {
|
|
73
|
-
|
|
77
|
+
workspace: {
|
|
78
|
+
label: t.spots,
|
|
79
|
+
content: <KnowledgeSourcesTabWorkspace key="workspace" visibility="workspace" allKS={allKS} onSubmit={onSubmit} />,
|
|
80
|
+
},
|
|
74
81
|
account: { label: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
|
|
75
82
|
}
|
|
76
83
|
|
|
@@ -95,16 +102,29 @@ const KnowledgeSourcesPanel = () => {
|
|
|
95
102
|
|
|
96
103
|
export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId, showSubmitButton = true }: TabProps) => {
|
|
97
104
|
const t = useTranslate(dictionary)
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
const [data = []] = workspaceAiClient.getKSFromWorkspaceAi.useStatefulQuery(
|
|
106
|
+
{ workspaceId: workspaceId! }, { enabled: !!workspaceId })
|
|
107
|
+
const workspaceKs = data as KnowledgeSourceItemResponse[]
|
|
108
|
+
|
|
109
|
+
const [ksListPages = [], { fetchNextPage, hasNextPage }] = dataIntegrationClient.knowledgeSourcesV2.useInfiniteQuery(
|
|
110
|
+
{
|
|
111
|
+
order: 'a-to-z',
|
|
112
|
+
visibilityList: visibility ? [visibility] : [],
|
|
113
|
+
types: ['snippet', 'api', 'event', 'custom'],
|
|
114
|
+
size: 20,
|
|
115
|
+
page: 1,
|
|
116
|
+
},
|
|
117
|
+
{ enabled: !workspaceId },
|
|
118
|
+
)
|
|
119
|
+
const knowledgeSources = workspaceId ? workspaceKs : ksListPages
|
|
120
|
+
|
|
103
121
|
const initialValue = useMemo(() => {
|
|
104
122
|
const currentlySelected = allKS.current?.map(ks => ks.id)
|
|
105
|
-
return knowledgeSources
|
|
106
|
-
}, [])
|
|
107
|
-
|
|
123
|
+
return knowledgeSources?.filter((ks: KnowledgeSourceItemResponse) => currentlySelected?.includes(ks.slug))
|
|
124
|
+
}, [knowledgeSources])
|
|
125
|
+
|
|
126
|
+
const listFavorites = dataIntegrationClient.knowledgeSourcesV2.useQuery({ visibilityList: ['favorite'] })?.items
|
|
127
|
+
|
|
108
128
|
const [addFavorite, pendingAddFav] = dataIntegrationClient.addFavoriteKnowledgeSource.useMutation()
|
|
109
129
|
const [removeFavorite, pendingRemoveFav] = dataIntegrationClient.removeFavoriteKnowledgeSource.useMutation()
|
|
110
130
|
|
|
@@ -112,7 +132,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
|
|
|
112
132
|
try {
|
|
113
133
|
await removeFavorite({ slug: idOrSlug })
|
|
114
134
|
await aiClient.knowledgeSources.invalidate()
|
|
115
|
-
await dataIntegrationClient.
|
|
135
|
+
await dataIntegrationClient.knowledgeSourcesV2.invalidate()
|
|
116
136
|
} catch (error) {
|
|
117
137
|
// eslint-disable-next-line no-console
|
|
118
138
|
console.error(error)
|
|
@@ -123,7 +143,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
|
|
|
123
143
|
const onRemoveFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
|
|
124
144
|
try {
|
|
125
145
|
await removeFavoriteKs(idOrSlug)
|
|
126
|
-
if (!pendingRemoveFav){
|
|
146
|
+
if (!pendingRemoveFav) {
|
|
127
147
|
resolve(true)
|
|
128
148
|
}
|
|
129
149
|
|
|
@@ -131,14 +151,14 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
|
|
|
131
151
|
// eslint-disable-next-line no-console
|
|
132
152
|
console.error(error)
|
|
133
153
|
reject(error)
|
|
134
|
-
}
|
|
154
|
+
}
|
|
135
155
|
})
|
|
136
156
|
|
|
137
157
|
const addFavoriteKs = async (idOrSlug: string) => {
|
|
138
158
|
try {
|
|
139
159
|
await addFavorite({ slug: idOrSlug })
|
|
140
160
|
await aiClient.knowledgeSources.invalidate()
|
|
141
|
-
await dataIntegrationClient.
|
|
161
|
+
await dataIntegrationClient.knowledgeSourcesV2.invalidate()
|
|
142
162
|
} catch (error) {
|
|
143
163
|
// eslint-disable-next-line no-console
|
|
144
164
|
console.error(error)
|
|
@@ -149,7 +169,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
|
|
|
149
169
|
const onAddFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
|
|
150
170
|
try {
|
|
151
171
|
await addFavoriteKs(idOrSlug)
|
|
152
|
-
if (!pendingAddFav){
|
|
172
|
+
if (!pendingAddFav) {
|
|
153
173
|
resolve(true)
|
|
154
174
|
}
|
|
155
175
|
|
|
@@ -157,23 +177,27 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
|
|
|
157
177
|
// eslint-disable-next-line no-console
|
|
158
178
|
console.error(error)
|
|
159
179
|
reject(error)
|
|
160
|
-
}
|
|
180
|
+
}
|
|
161
181
|
})
|
|
162
182
|
|
|
163
|
-
return (
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
return (<>
|
|
184
|
+
<div className="content">
|
|
185
|
+
<DescribedCheckboxGroup
|
|
186
|
+
options={knowledgeSources}
|
|
187
|
+
initialValue={initialValue}
|
|
188
|
+
globalSelection={allKS}
|
|
189
|
+
hasNextPage={hasNextPage && !workspaceId}
|
|
190
|
+
fetchNextPage={fetchNextPage}
|
|
191
|
+
data={(ks: KnowledgeSourceItemResponse) => ({
|
|
192
|
+
idOrSlug: ks.slug, description: ks.description, name: ks.name, listFavorites,
|
|
193
|
+
onAddFavorite, onRemoveFavorite,
|
|
194
|
+
})}
|
|
195
|
+
emptyResults={<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />}
|
|
196
|
+
emptyDataset={<Placeholder title={t.noData} description={t.noDataDescription} className="no-data-placeholder" />}
|
|
197
|
+
/>
|
|
198
|
+
</div>
|
|
199
|
+
{!!knowledgeSources?.length && showSubmitButton && <Button onClick={onSubmit}>{t.apply}</Button>}
|
|
200
|
+
</>
|
|
177
201
|
)
|
|
178
202
|
}
|
|
179
203
|
|
|
@@ -184,11 +208,10 @@ export function KnowledgeSourcesTabWorkspace({ allKS, onSubmit }: TabProps) {
|
|
|
184
208
|
component: 'ks',
|
|
185
209
|
props: { visibility: 'workspace', workspaceId: workspace.id, allKS, onSubmit },
|
|
186
210
|
})
|
|
187
|
-
|
|
211
|
+
|
|
188
212
|
return <WorkspaceTabNavigator components={workspaceTabComponents} getNavigateParam={buildNavigateParams} />
|
|
189
213
|
}
|
|
190
214
|
|
|
191
|
-
|
|
192
215
|
const dictionary = {
|
|
193
216
|
en: {
|
|
194
217
|
title: 'Knowledge Sources',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Icon } from '@stack-spot/citric-icons'
|
|
2
2
|
import { IconBox, Row, Text } from '@stack-spot/citric-react'
|
|
3
|
-
import { AgentResponseWithBuiltIn, agentToolsClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
3
|
+
import { AgentResponseWithBuiltIn, agentToolsClient, AgentVisibilityLevel, workspaceAiClient } from '@stack-spot/portal-network'
|
|
4
|
+
import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/agent-tools'
|
|
4
5
|
import { useCallback } from 'react'
|
|
5
6
|
import { Selector } from '../../components/Selector'
|
|
6
7
|
import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
@@ -54,18 +55,19 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
54
55
|
}, [chat, inputRef])
|
|
55
56
|
|
|
56
57
|
|
|
57
|
-
const getAgents = () => {
|
|
58
|
+
const getAgents = ({ filter, visibility }: {filter?: string, visibility?: AgentVisibilityLevel[] | VisibilityLevelEnum[]}) => {
|
|
58
59
|
if (spotId) {
|
|
59
|
-
return workspaceAiClient.getAgentFromWorkspaceAi.useQuery({
|
|
60
|
+
return { data: workspaceAiClient.getAgentFromWorkspaceAi.useQuery({
|
|
61
|
+
workspaceId: spotId, name: filter }) as AgentResponseWithBuiltIn[] }
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
if (isTrial) {
|
|
63
|
-
return agentToolsClient.allAgents.useQuery({ visibilities: [
|
|
65
|
+
return { data: agentToolsClient.allAgents.useQuery({ visibilities: visibility as VisibilityLevelEnum[], filter }) }
|
|
64
66
|
}
|
|
65
|
-
|
|
66
|
-
return agentToolsClient.allAgents.useQuery({
|
|
67
|
-
visibilities:
|
|
68
|
-
})
|
|
67
|
+
|
|
68
|
+
return { data: agentToolsClient.allAgents.useQuery({
|
|
69
|
+
visibilities: visibility as VisibilityLevelEnum[], filter,
|
|
70
|
+
}) }
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
return <Selector
|