@stack-spot/ai-chat-widget 1.17.1 → 1.18.0-beta.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.js +1 -1
- package/dist/app-metadata.json +2 -2
- package/dist/components/ComponentNavigator.d.ts +21 -0
- package/dist/components/ComponentNavigator.d.ts.map +1 -0
- package/dist/components/ComponentNavigator.js +33 -0
- package/dist/components/ComponentNavigator.js.map +1 -0
- package/dist/components/ListGroup.d.ts +46 -0
- package/dist/components/ListGroup.d.ts.map +1 -0
- package/dist/components/ListGroup.js +16 -0
- package/dist/components/ListGroup.js.map +1 -0
- package/dist/components/RightPanelForm.d.ts.map +1 -1
- package/dist/components/RightPanelForm.js +29 -1
- package/dist/components/RightPanelForm.js.map +1 -1
- package/dist/components/Selector/index.js +5 -5
- package/dist/components/Selector/index.js.map +1 -1
- package/dist/components/Selector/styled.d.ts +3 -1
- package/dist/components/Selector/styled.d.ts.map +1 -1
- package/dist/components/Selector/styled.js +2 -1
- package/dist/components/Selector/styled.js.map +1 -1
- package/dist/components/WorkspaceTabNavigator.d.ts +15 -0
- package/dist/components/WorkspaceTabNavigator.d.ts.map +1 -0
- package/dist/components/WorkspaceTabNavigator.js +95 -0
- package/dist/components/WorkspaceTabNavigator.js.map +1 -0
- package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.js +23 -2
- package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
- package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
- package/dist/views/Agents/AgentsPanel.js +19 -11
- package/dist/views/Agents/AgentsPanel.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts +9 -3
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/AgentsTab.js +25 -7
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/Agents/dictionary.d.ts +1 -1
- package/dist/views/Agents/dictionary.d.ts.map +1 -1
- package/dist/views/Agents/dictionary.js +2 -0
- package/dist/views/Agents/dictionary.js.map +1 -1
- package/dist/views/ChatHistory/utils.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.js +8 -3
- package/dist/views/ChatHistory/utils.js.map +1 -1
- package/dist/views/KnowledgeSources.d.ts +12 -0
- package/dist/views/KnowledgeSources.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.js +20 -6
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +4 -3
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.js +2 -2
- package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +9 -3
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
- package/dist/views/MessageInput/dictionary.js +2 -0
- package/dist/views/MessageInput/dictionary.js.map +1 -1
- package/dist/views/Stacks.d.ts +9 -0
- package/dist/views/Stacks.d.ts.map +1 -1
- package/dist/views/Stacks.js +37 -14
- package/dist/views/Stacks.js.map +1 -1
- package/dist/views/Workspaces/WorkspacesTab.d.ts +20 -0
- package/dist/views/Workspaces/WorkspacesTab.d.ts.map +1 -0
- package/dist/views/Workspaces/WorkspacesTab.js +64 -0
- package/dist/views/Workspaces/WorkspacesTab.js.map +1 -0
- package/dist/views/{Workspaces.d.ts → Workspaces/index.d.ts} +1 -1
- package/dist/views/Workspaces/index.d.ts.map +1 -0
- package/dist/views/Workspaces/index.js +76 -0
- package/dist/views/Workspaces/index.js.map +1 -0
- package/package.json +2 -2
- package/src/app-metadata.json +2 -2
- package/src/components/ComponentNavigator.tsx +78 -0
- package/src/components/ListGroup.tsx +76 -0
- package/src/components/RightPanelForm.tsx +29 -1
- package/src/components/Selector/index.tsx +5 -5
- package/src/components/Selector/styled.ts +3 -2
- package/src/components/WorkspaceTabNavigator.tsx +170 -0
- package/src/components/form/DescribedCheckboxGroup.tsx +45 -14
- package/src/views/Agents/AgentsPanel.tsx +21 -11
- package/src/views/Agents/AgentsTab.tsx +42 -9
- package/src/views/Agents/dictionary.ts +3 -0
- package/src/views/ChatHistory/utils.ts +9 -3
- package/src/views/KnowledgeSources.tsx +37 -14
- package/src/views/MessageInput/AgentSelector.tsx +4 -3
- package/src/views/MessageInput/ButtonGroup.tsx +3 -3
- package/src/views/MessageInput/QuickCommandSelector.tsx +10 -3
- package/src/views/MessageInput/dictionary.ts +2 -0
- package/src/views/Stacks.tsx +57 -17
- package/src/views/Workspaces/WorkspacesTab.tsx +117 -0
- package/src/views/Workspaces/index.tsx +85 -0
- package/dist/views/Workspaces.d.ts.map +0 -1
- package/dist/views/Workspaces.js +0 -103
- package/dist/views/Workspaces.js.map +0 -1
- package/src/views/Workspaces.tsx +0 -137
|
@@ -2,7 +2,7 @@ import { theme } from '@stack-spot/portal-theme'
|
|
|
2
2
|
import { styled } from 'styled-components'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
export const SelectorBox = styled.div
|
|
5
|
+
export const SelectorBox = styled.div<{tabsCount: number}>`
|
|
6
6
|
position: absolute;
|
|
7
7
|
bottom: 0;
|
|
8
8
|
|
|
@@ -53,6 +53,8 @@ export const SelectorBox = styled.div`
|
|
|
53
53
|
display: flex;
|
|
54
54
|
flex-direction: row;
|
|
55
55
|
align-items: center;
|
|
56
|
+
align-items: flex-start;
|
|
57
|
+
height: ${({ tabsCount }) => 34 + (tabsCount * 34)}px;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
ul {
|
|
@@ -105,7 +107,6 @@ export const SelectorBox = styled.div`
|
|
|
105
107
|
gap: 2px;
|
|
106
108
|
overflow-y: auto;
|
|
107
109
|
flex: 1;
|
|
108
|
-
max-height: 170px;
|
|
109
110
|
|
|
110
111
|
li {
|
|
111
112
|
display: flex;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Box, Flex, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { ArrowRight, Circle, Search, Times } from '@citric/icons'
|
|
3
|
+
import { Avatar, IconButton } from '@citric/ui'
|
|
4
|
+
import { Placeholder } from '@stack-spot/portal-components/Placeholder'
|
|
5
|
+
import { workspaceAiClient } from '@stack-spot/portal-network'
|
|
6
|
+
import { WorkspaceResponse, WorkspaceVisibilityLevelEnum } from '@stack-spot/portal-network/api/workspace-ai'
|
|
7
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
8
|
+
import { memo, useMemo, useState } from 'react'
|
|
9
|
+
import { useRightPanel } from '../right-panel/hooks'
|
|
10
|
+
import { ButtonFavorite } from './ButtonFavorite'
|
|
11
|
+
import { ComponentNavigator, ComponentNavigatorProps, NavigationItem, NavigationMap, useComponentNavigation } from './ComponentNavigator'
|
|
12
|
+
import { IconInput } from './IconInput'
|
|
13
|
+
import { ListGroup } from './ListGroup'
|
|
14
|
+
|
|
15
|
+
export const CardSpace = ({ onClick, name, icon }: { onClick: VoidFunction, name: string, icon: React.ReactElement }) =>
|
|
16
|
+
<Flex
|
|
17
|
+
onClick={onClick}
|
|
18
|
+
flex={1}
|
|
19
|
+
alignItems="center"
|
|
20
|
+
justifyContent="space-between"
|
|
21
|
+
mr={2}
|
|
22
|
+
bg="light.400"
|
|
23
|
+
r="sm"
|
|
24
|
+
p={3}
|
|
25
|
+
sx={{ cursor: 'pointer' }}
|
|
26
|
+
>
|
|
27
|
+
<Flex alignContent="center" alignItems="center" sx={{ gap: '8px' }} >
|
|
28
|
+
<Avatar size="xxs" appearance="square" sx={{ bg: 'light.600', r: 'xxs' }}>
|
|
29
|
+
<IconBox>
|
|
30
|
+
{icon}
|
|
31
|
+
</IconBox>
|
|
32
|
+
</Avatar>
|
|
33
|
+
<Text>{name}</Text>
|
|
34
|
+
</Flex>
|
|
35
|
+
<IconButton><ArrowRight /></IconButton>
|
|
36
|
+
</Flex>
|
|
37
|
+
|
|
38
|
+
interface WorkspaceSourcesTabProps {
|
|
39
|
+
visibility: WorkspaceVisibilityLevelEnum,
|
|
40
|
+
onClick: (workspace: WorkspaceResponse) => void,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const WorkspaceSourcesTab = ({ visibility, onClick }: WorkspaceSourcesTabProps) => {
|
|
44
|
+
const t = useTranslate(dictionary)
|
|
45
|
+
const [filter, setFilter] = useState('')
|
|
46
|
+
const workspaces = workspaceAiClient.workspacesAi.useQuery({ visibility })
|
|
47
|
+
const listFavorites = workspaceAiClient.workspacesAi.useQuery({ visibility: 'favorite' })
|
|
48
|
+
const [addFavorite, pendingAddFav] = workspaceAiClient.addFavoriteWorkspaceAi.useMutation()
|
|
49
|
+
const [removeFavorite, pendingRemoveFav] = workspaceAiClient.removeFavoriteWorkspaceAi.useMutation()
|
|
50
|
+
|
|
51
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
52
|
+
const onAddFavorite = async (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
|
|
53
|
+
try {
|
|
54
|
+
await addFavorite({ workspaceId: idOrSlug })
|
|
55
|
+
await workspaceAiClient.workspacesAi.invalidate()
|
|
56
|
+
if (!pendingAddFav) {
|
|
57
|
+
resolve(true)
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.error(error)
|
|
62
|
+
reject(error)
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
67
|
+
const onRemoveFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
|
|
68
|
+
try {
|
|
69
|
+
await removeFavorite({ workspaceId: idOrSlug })
|
|
70
|
+
await workspaceAiClient.workspacesAi.invalidate()
|
|
71
|
+
if (!pendingRemoveFav) {
|
|
72
|
+
resolve(true)
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// eslint-disable-next-line no-console
|
|
76
|
+
console.error(error)
|
|
77
|
+
reject(error)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const filtered = useMemo(
|
|
82
|
+
// Recreate the list so that the favorites list is taken into account
|
|
83
|
+
() => filter ? workspaces.filter(w => w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : [...workspaces],
|
|
84
|
+
[workspaces, filter, listFavorites],
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<Box w={12}>
|
|
90
|
+
<IconInput icon={<Search />} value={filter} onChange={setFilter} className="search" />
|
|
91
|
+
</Box>
|
|
92
|
+
{!!filtered.length &&
|
|
93
|
+
<ListGroup
|
|
94
|
+
list={filtered}
|
|
95
|
+
keygen={w => w.id}
|
|
96
|
+
onClick={onClick}
|
|
97
|
+
style={{ gap: '6px', display: 'flex', flexDirection: 'column' }}
|
|
98
|
+
renderLabel={w => <CardSpace name={w.name} icon={<Circle />} onClick={() => onClick(w)} />}
|
|
99
|
+
renderDescription={w => w.description}
|
|
100
|
+
renderAfterElement={(w) =>
|
|
101
|
+
<ButtonFavorite favorite={{ idOrSlug: w?.id, listFavorites, onAddFavorite, onRemoveFavorite }} />}
|
|
102
|
+
optionClassName={w => (filter && !w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
103
|
+
? 'filtered-out'
|
|
104
|
+
: ''
|
|
105
|
+
}
|
|
106
|
+
className="option-list"
|
|
107
|
+
/>
|
|
108
|
+
}
|
|
109
|
+
{!!workspaces.length && !filtered.length &&
|
|
110
|
+
<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} className="no-data-placeholder" />}
|
|
111
|
+
{!workspaces.length && <Placeholder title={t.noData} description={t.noDataDescription} />}
|
|
112
|
+
</>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
const WorkspaceHeader = <T extends NavigationMap, K extends keyof T>({ data }: { data: NavigationItem<T, K> }) => {
|
|
118
|
+
const { close: closeRightPanel } = useRightPanel()
|
|
119
|
+
const workspaceId = (data.props as any)['workspaceId']
|
|
120
|
+
if (!workspaceId) return
|
|
121
|
+
|
|
122
|
+
const workspace = workspaceAiClient.workspaceAi.useQuery({ id: workspaceId })
|
|
123
|
+
return <Flex justifyContent="space-between" alignItems="center" flex={1}>
|
|
124
|
+
{data.component === 'workspaceResource' ? 'Spaces' : workspace.name}
|
|
125
|
+
{data.fullScreen && <IconButton title={'t.close'} aria-label={'t.close'} onClick={closeRightPanel}> <Times /> </IconButton>}
|
|
126
|
+
</Flex>
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
interface WorkspaceTabNavigatorProps {
|
|
131
|
+
getNavigateParam: (workspace: WorkspaceResponse) => NavigationItem<NavigationMap, string>,
|
|
132
|
+
visibility?: WorkspaceVisibilityLevelEnum,
|
|
133
|
+
className?: string,
|
|
134
|
+
}
|
|
135
|
+
export function WorkspaceTabNavigator<T extends NavigationMap, K extends keyof T>({ components, getNavigateParam, visibility, className }:
|
|
136
|
+
Omit<ComponentNavigatorProps<T, K>, 'initialItem'> & WorkspaceTabNavigatorProps) {
|
|
137
|
+
|
|
138
|
+
const workspaceTabComponents = useMemo(() => ({
|
|
139
|
+
workspace: memo(function WorkspacesTab() {
|
|
140
|
+
const { navigate } = useComponentNavigation()
|
|
141
|
+
return (<WorkspaceSourcesTab visibility={visibility ?? 'all'} onClick={(w) => navigate(getNavigateParam(w))} />)
|
|
142
|
+
}),
|
|
143
|
+
...components,
|
|
144
|
+
}), [components])
|
|
145
|
+
|
|
146
|
+
return <ComponentNavigator
|
|
147
|
+
initialItem={{ component: 'workspace' }}
|
|
148
|
+
components={workspaceTabComponents}
|
|
149
|
+
className={className}
|
|
150
|
+
renderTitle={(data) => <WorkspaceHeader data={data} />}
|
|
151
|
+
/>
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const dictionary = {
|
|
155
|
+
en: {
|
|
156
|
+
noSearchResults: "Your search didn't yield results.",
|
|
157
|
+
noSearchResultsDescription: 'Please, try another search term.',
|
|
158
|
+
noData: 'There are no spaces yet.',
|
|
159
|
+
noDataDescription: 'Use the AI portal to create new spaces.',
|
|
160
|
+
apply: 'Apply',
|
|
161
|
+
},
|
|
162
|
+
pt: {
|
|
163
|
+
noSearchResults: 'Sua busca não produziu resultados',
|
|
164
|
+
noSearchResultsDescription: 'Por favor, tente outra busca.',
|
|
165
|
+
noData: 'Ainda não há spaces.',
|
|
166
|
+
noDataDescription: 'Use o Portal AI para criar novos spaces.',
|
|
167
|
+
apply: 'Apply',
|
|
168
|
+
},
|
|
169
|
+
} satisfies Dictionary
|
|
170
|
+
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Checkbox, Text } from '@citric/core'
|
|
1
|
+
import { Checkbox, Flex, Text } from '@citric/core'
|
|
2
2
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
3
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
3
4
|
import { useMemo } from 'react'
|
|
4
5
|
import { Accordion } from '../Accordion'
|
|
5
6
|
import { RadioCheckBox } from './styled'
|
|
@@ -9,30 +10,40 @@ import { CheckProps } from './types'
|
|
|
9
10
|
* Renders a checkbox group where each option has a label and a description.
|
|
10
11
|
* The description in placed under the label and checkbox as an accordion.
|
|
11
12
|
*/
|
|
12
|
-
export function DescribedCheckboxGroup<T>({
|
|
13
|
-
keygen,
|
|
14
|
-
onChange,
|
|
15
|
-
options,
|
|
16
|
-
renderDescription,
|
|
17
|
-
renderLabel,
|
|
13
|
+
export function DescribedCheckboxGroup<T>({
|
|
14
|
+
keygen,
|
|
15
|
+
onChange,
|
|
16
|
+
options,
|
|
17
|
+
renderDescription,
|
|
18
|
+
renderLabel,
|
|
18
19
|
renderBeforeElement,
|
|
19
20
|
renderAfterElement,
|
|
20
|
-
optionClassName,
|
|
21
|
-
optionStyle,
|
|
22
|
-
value,
|
|
23
|
-
className,
|
|
21
|
+
optionClassName,
|
|
22
|
+
optionStyle,
|
|
23
|
+
value,
|
|
24
|
+
className,
|
|
24
25
|
style }: CheckProps<T>) {
|
|
26
|
+
const t = useTranslate(dictionary)
|
|
27
|
+
const allSelected = options.length > 0 && options.every(option => value.includes(option))
|
|
28
|
+
|
|
29
|
+
const handleSelectAll = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
30
|
+
if (e.target.checked) {
|
|
31
|
+
onChange(options)
|
|
32
|
+
} else {
|
|
33
|
+
onChange([])
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
const items = useMemo(() => options.map((option) => {
|
|
26
38
|
const label = renderLabel(option)
|
|
27
39
|
const description = renderDescription(option)
|
|
28
|
-
|
|
29
40
|
const header = (
|
|
30
41
|
<label>
|
|
31
42
|
<Checkbox
|
|
32
43
|
checked={value.includes(option)}
|
|
33
44
|
onChange={(e) => {
|
|
34
45
|
if (e.target.checked && !value.includes(option)) onChange([...value, option])
|
|
35
|
-
else onChange(value.filter(item => item !== option))
|
|
46
|
+
else onChange(value.filter(item => item !== option))
|
|
36
47
|
}}
|
|
37
48
|
/>
|
|
38
49
|
{typeof label === 'string' ? <Text>{label}</Text> : label}
|
|
@@ -55,5 +66,25 @@ export function DescribedCheckboxGroup<T>({
|
|
|
55
66
|
)
|
|
56
67
|
}), [options, value])
|
|
57
68
|
|
|
58
|
-
return <RadioCheckBox style={style} className={className}>
|
|
69
|
+
return <RadioCheckBox style={style} className={className}>
|
|
70
|
+
<Flex as="li" alignItems="center" sx={{ pl: 4 }}>
|
|
71
|
+
<Checkbox
|
|
72
|
+
checked={allSelected}
|
|
73
|
+
onChange={handleSelectAll}
|
|
74
|
+
/>
|
|
75
|
+
<Text>{allSelected ? t.removeAll : t.selectAll}</Text>
|
|
76
|
+
</Flex>
|
|
77
|
+
{items}
|
|
78
|
+
</RadioCheckBox>
|
|
59
79
|
}
|
|
80
|
+
|
|
81
|
+
const dictionary = {
|
|
82
|
+
en: {
|
|
83
|
+
selectAll: 'Select all',
|
|
84
|
+
removeAll: 'Remove all',
|
|
85
|
+
},
|
|
86
|
+
pt: {
|
|
87
|
+
selectAll: 'Selecionar todos',
|
|
88
|
+
removeAll: 'Remover todos',
|
|
89
|
+
},
|
|
90
|
+
} satisfies Dictionary
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react'
|
|
2
2
|
import { RightPanelTabs } from '../../components/RightPanelTabs'
|
|
3
3
|
import { useCurrentChat } from '../../context/hooks'
|
|
4
|
+
import { isAgentDefault } from '../../utils/agent'
|
|
4
5
|
import { checkIsTrial } from '../../utils/check-is-trial'
|
|
5
|
-
import { AgentsTab } from './AgentsTab'
|
|
6
|
+
import { AgentsTab, AgentsTabWorkspace } from './AgentsTab'
|
|
6
7
|
import { useAgentsDictionary } from './dictionary'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -12,18 +13,27 @@ export const AgentsPanel = () => {
|
|
|
12
13
|
const t = useAgentsDictionary()
|
|
13
14
|
const chat = useCurrentChat()
|
|
14
15
|
const isTrial = checkIsTrial()
|
|
16
|
+
const agent = useRef(chat.get('agent'))
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!isAgentDefault(chat.get('agent')?.slug)) {
|
|
20
|
+
agent.current = chat.get('agent')
|
|
21
|
+
}
|
|
22
|
+
}, [chat])
|
|
15
23
|
|
|
16
24
|
const tabs= useMemo(() => isTrial ? [
|
|
17
|
-
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="FAVORITE" /> },
|
|
18
|
-
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" /> },
|
|
19
|
-
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
|
|
25
|
+
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="FAVORITE" agent={agent} /> },
|
|
26
|
+
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" agent={agent} /> },
|
|
27
|
+
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" agent={agent} /> },
|
|
20
28
|
]: [
|
|
21
|
-
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="FAVORITE" /> },
|
|
22
|
-
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" /> },
|
|
23
|
-
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
|
|
24
|
-
{ title: t.shared, content: <AgentsTab key="shared" visibility="SHARED" /> },
|
|
25
|
-
{ title: t.
|
|
26
|
-
|
|
29
|
+
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="FAVORITE" agent={agent} /> },
|
|
30
|
+
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" agent={agent} /> },
|
|
31
|
+
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" agent={agent} /> },
|
|
32
|
+
{ title: t.shared, content: <AgentsTab key="shared" visibility="SHARED" agent={agent} /> },
|
|
33
|
+
{ title: t.spaces, content: <AgentsTabWorkspace key="workspace" visibility="WORKSPACE" agent={agent} /> },
|
|
34
|
+
{ title: t.account, content: <AgentsTab key="account" visibility="ACCOUNT" agent={agent} /> },
|
|
35
|
+
|
|
36
|
+
], [t, isTrial, agent])
|
|
27
37
|
|
|
28
38
|
return <RightPanelTabs key={chat.id} tabs={tabs} />
|
|
29
39
|
}
|
|
@@ -2,21 +2,32 @@ import { Button, IconBox, Text } from '@citric/core'
|
|
|
2
2
|
import { Agent, Search } from '@citric/icons'
|
|
3
3
|
import { Placeholder } from '@stack-spot/portal-components/Placeholder'
|
|
4
4
|
import { MiniLogo } from '@stack-spot/portal-components/svg'
|
|
5
|
-
import { agentClient } from '@stack-spot/portal-network'
|
|
5
|
+
import { agentClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
6
6
|
import { AgentResponse, VisibilityLevel } from '@stack-spot/portal-network/api/agent'
|
|
7
|
-
import {
|
|
7
|
+
import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
|
|
8
|
+
import { useCallback, useMemo, useState } from 'react'
|
|
8
9
|
import { ButtonFavorite } from '../../components/ButtonFavorite'
|
|
10
|
+
import { NavigationItem } from '../../components/ComponentNavigator'
|
|
9
11
|
import { DescribedRadioGroup } from '../../components/form/DescribedRadioGroup'
|
|
10
12
|
import { IconInput } from '../../components/IconInput'
|
|
13
|
+
import { WorkspaceTabNavigator } from '../../components/WorkspaceTabNavigator'
|
|
11
14
|
import { useCurrentChat } from '../../context/hooks'
|
|
12
15
|
import { useRightPanel } from '../../right-panel/hooks'
|
|
16
|
+
import { ChatProperties } from '../../state/ChatState'
|
|
13
17
|
import { isAgentDefault } from '../../utils/agent'
|
|
14
18
|
import { AgentDescription } from './AgentDescription'
|
|
15
19
|
import { useAgentsDictionary } from './dictionary'
|
|
16
20
|
import { AgentLabel } from './styled'
|
|
17
21
|
import { useAgentFavorites } from './useAgentFavorites'
|
|
18
22
|
|
|
19
|
-
export
|
|
23
|
+
export interface AgentTabProps {
|
|
24
|
+
visibility: VisibilityLevel | 'BUILT-IN',
|
|
25
|
+
workspaceId?: string,
|
|
26
|
+
agent: React.MutableRefObject<ChatProperties['agent']>,
|
|
27
|
+
showSubmitButton?: boolean,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = true }: AgentTabProps) => {
|
|
20
31
|
const t = useAgentsDictionary()
|
|
21
32
|
const { close } = useRightPanel()
|
|
22
33
|
const chat = useCurrentChat()
|
|
@@ -26,10 +37,14 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
26
37
|
|
|
27
38
|
const agentsBuiltIn = agentClient.publicAgents.useQuery({})
|
|
28
39
|
const agentDefault = agentsBuiltIn.find((agent) => isAgentDefault(agent.slug))
|
|
29
|
-
const agents =
|
|
30
|
-
|
|
40
|
+
const agents = workspaceId
|
|
41
|
+
? workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId })
|
|
42
|
+
: visibility === 'BUILT-IN' ? agentsBuiltIn : agentClient.agents.useQuery({ visibility })
|
|
43
|
+
|
|
31
44
|
const [value, setValue] = useState<AgentResponse | undefined>(
|
|
32
|
-
|
|
45
|
+
agent.current
|
|
46
|
+
? agents.find(a => a.id === agent.current?.id)
|
|
47
|
+
: chat.get('agent') ? agents.find(a => a.id === chat.get('agent')?.id) : agentDefault,
|
|
33
48
|
)
|
|
34
49
|
|
|
35
50
|
const filtered = useMemo(
|
|
@@ -53,6 +68,13 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
53
68
|
close()
|
|
54
69
|
}
|
|
55
70
|
|
|
71
|
+
const onChange = useCallback((newValue: AgentResponse) => {
|
|
72
|
+
const isBuiltIn = visibility === 'BUILT-IN' || agentsBuiltIn.some((agent) => agent.id === newValue.id)
|
|
73
|
+
|
|
74
|
+
setValue(newValue)
|
|
75
|
+
agent.current = { ...newValue, builtIn: isBuiltIn, label: newValue.name }
|
|
76
|
+
}, [])
|
|
77
|
+
|
|
56
78
|
return (
|
|
57
79
|
<>
|
|
58
80
|
<div className="content">
|
|
@@ -65,7 +87,7 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
65
87
|
)}
|
|
66
88
|
keygen={a => a.id}
|
|
67
89
|
value={value}
|
|
68
|
-
onChange={
|
|
90
|
+
onChange={onChange}
|
|
69
91
|
renderLabel={({ name, avatar, id }) => (
|
|
70
92
|
<AgentLabel>
|
|
71
93
|
{id ? (avatar ? <img src={avatar} /> : <IconBox size="xs"><Agent /></IconBox>) : <MiniLogo />}
|
|
@@ -74,7 +96,7 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
74
96
|
)}
|
|
75
97
|
renderDescription={a => <AgentDescription
|
|
76
98
|
agentId={a.id}
|
|
77
|
-
visibility={visibility}
|
|
99
|
+
visibility={visibility}
|
|
78
100
|
description={a.description}
|
|
79
101
|
llm={a.llm_config?.model_slug}
|
|
80
102
|
numberOfKnowledgeSources={a.knowledge_sources_config?.knowledge_sources?.length ?? 0}
|
|
@@ -89,7 +111,18 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
89
111
|
<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} className="no-data-placeholder" />}
|
|
90
112
|
{!agents.length && <Placeholder title={t.noData} description={t.noDataDescription} />}
|
|
91
113
|
</div>
|
|
92
|
-
{!!filtered.length && <Button onClick={submit} disabled={!value}>{t.apply}</Button>}
|
|
114
|
+
{!!filtered.length && showSubmitButton && <Button onClick={submit} disabled={!value}>{t.apply}</Button>}
|
|
93
115
|
</>
|
|
94
116
|
)
|
|
95
117
|
}
|
|
118
|
+
|
|
119
|
+
export function AgentsTabWorkspace({ agent, visibility, showSubmitButton }: AgentTabProps) {
|
|
120
|
+
const workspaceTabComponents = useMemo(() => ({ agent: AgentsTab }), [agent])
|
|
121
|
+
|
|
122
|
+
const buildNavigateParams = (workspace: WorkspaceResponse): NavigationItem<typeof workspaceTabComponents> => ({
|
|
123
|
+
component: 'agent',
|
|
124
|
+
props: { visibility, workspaceId: workspace.id, agent, showSubmitButton },
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
return <WorkspaceTabNavigator components={workspaceTabComponents} getNavigateParam={buildNavigateParams} />
|
|
128
|
+
}
|
|
@@ -17,6 +17,7 @@ const dictionary = {
|
|
|
17
17
|
description: 'Description',
|
|
18
18
|
favorites: 'Favorites',
|
|
19
19
|
tools: 'Tools',
|
|
20
|
+
spaces: 'Spaces',
|
|
20
21
|
},
|
|
21
22
|
pt: {
|
|
22
23
|
title: 'Agentes',
|
|
@@ -34,6 +35,8 @@ const dictionary = {
|
|
|
34
35
|
description: 'Descrição',
|
|
35
36
|
favorites: 'Favoritos',
|
|
36
37
|
tools: 'Ferramentas',
|
|
38
|
+
spaces: 'Spaces',
|
|
39
|
+
|
|
37
40
|
},
|
|
38
41
|
} satisfies Dictionary
|
|
39
42
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { agentClient, aiClient, workspaceClient } from '@stack-spot/portal-network'
|
|
1
|
+
import { agentClient, aiClient, workspaceAiClient, workspaceClient } from '@stack-spot/portal-network'
|
|
2
2
|
import { ChatProperties } from '../../state/ChatState'
|
|
3
3
|
import { LabeledWithImage } from '../../state/types'
|
|
4
4
|
|
|
@@ -44,9 +44,15 @@ export async function findWorkspace(id: string | null): Promise<ChatProperties['
|
|
|
44
44
|
*/
|
|
45
45
|
export async function getAllAgents(): Promise<LabeledWithImage[]> {
|
|
46
46
|
try {
|
|
47
|
-
const [agents, publicAgents] = await Promise.all([
|
|
47
|
+
const [agents, publicAgents, workspaceAgents] = await Promise.all([
|
|
48
|
+
agentClient.agents.query({}),
|
|
49
|
+
agentClient.publicAgents.query({}),
|
|
50
|
+
workspaceAiClient.workspacesContentsByType.query({ contentType: 'agent' }),
|
|
51
|
+
])
|
|
52
|
+
|
|
48
53
|
const builtInAgents = publicAgents.map((a) => ({ id: a.id, label: a.name, image: a.avatar, slug: a.slug, builtIn: true }))
|
|
49
|
-
return agents.map(a => ({ id: a.id, label: a.name, image: a.avatar, slug: a.slug, builtIn: false }))
|
|
54
|
+
return [...agents, ... workspaceAgents.agents].map(a => ({ id: a.id, label: a.name, image: a.avatar, slug: a.slug, builtIn: false }))
|
|
55
|
+
.concat(builtInAgents)
|
|
50
56
|
} catch (error) {
|
|
51
57
|
// eslint-disable-next-line no-console
|
|
52
58
|
console.error(error)
|
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
import { Button } from '@citric/core'
|
|
2
2
|
import { Search } from '@citric/icons'
|
|
3
3
|
import { Placeholder } from '@stack-spot/portal-components/Placeholder'
|
|
4
|
-
import { aiClient, dataIntegrationClient } from '@stack-spot/portal-network'
|
|
4
|
+
import { aiClient, dataIntegrationClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
5
5
|
import { KnowledgeSourceItemResponse, VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
|
|
6
|
+
import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
|
|
6
7
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
8
|
import { difference, uniqBy } from 'lodash'
|
|
8
9
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
9
10
|
import { ButtonFavorite } from '../components/ButtonFavorite'
|
|
11
|
+
import { NavigationItem } from '../components/ComponentNavigator'
|
|
10
12
|
import { DescribedCheckboxGroup } from '../components/form/DescribedCheckboxGroup'
|
|
11
13
|
import { IconInput } from '../components/IconInput'
|
|
12
14
|
import { RightPanelTabs } from '../components/RightPanelTabs'
|
|
15
|
+
import { WorkspaceTabNavigator } from '../components/WorkspaceTabNavigator'
|
|
13
16
|
import { useCurrentChat, useWidget, useWidgetState } from '../context/hooks'
|
|
14
17
|
import { useRightPanel } from '../right-panel/hooks'
|
|
15
18
|
import { ChatProperties } from '../state/ChatState'
|
|
16
19
|
import { checkIsTrial } from '../utils/check-is-trial'
|
|
17
20
|
|
|
18
|
-
interface TabProps {
|
|
21
|
+
export interface TabProps {
|
|
19
22
|
visibility: VisibilityLevelEnum,
|
|
20
|
-
onSubmit: () => void,
|
|
21
23
|
allKS: React.MutableRefObject<ChatProperties['knowledgeSources']>,
|
|
24
|
+
workspaceId?: string,
|
|
25
|
+
showSubmitButton?: boolean,
|
|
26
|
+
onSubmit?: () => void,
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export const KnowledgeSources = () => {
|
|
@@ -55,7 +60,7 @@ const KnowledgeSourcesPanel = () => {
|
|
|
55
60
|
useEffect(() => {
|
|
56
61
|
allKS.current = chat.get('knowledgeSources') ?? []
|
|
57
62
|
}, [chat])
|
|
58
|
-
|
|
63
|
+
|
|
59
64
|
const tabs = isTrial ? [
|
|
60
65
|
{ title: t.favorites, content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
|
|
61
66
|
{ title: t.personal, content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
|
|
@@ -63,19 +68,23 @@ const KnowledgeSourcesPanel = () => {
|
|
|
63
68
|
{ title: t.favorites, content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
|
|
64
69
|
{ title: t.personal, content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
|
|
65
70
|
{ title: t.shared, content: <KnowledgeSourcesTab key="shared" visibility="shared" allKS={allKS} onSubmit={onSubmit} /> },
|
|
66
|
-
{ title: t.
|
|
71
|
+
{ title: t.spaces, content: <KnowledgeSourcesTabWorkspace key="workspace" visibility="workspace" allKS={allKS} onSubmit={onSubmit} /> },
|
|
72
|
+
{ title: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
|
|
67
73
|
]
|
|
68
|
-
|
|
74
|
+
|
|
69
75
|
return <RightPanelTabs key={chat.id} tabs={tabs} />
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
78
|
+
export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId, showSubmitButton = true }: TabProps) => {
|
|
73
79
|
const t = useTranslate(dictionary)
|
|
74
80
|
const [filter, setFilter] = useState('')
|
|
75
|
-
|
|
76
|
-
const knowledgeSources =
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
|
|
82
|
+
const knowledgeSources = workspaceId
|
|
83
|
+
? workspaceAiClient.getKSFromWorkspaceAi.useQuery({ workspaceId })
|
|
84
|
+
: aiClient.knowledgeSources.useQuery({
|
|
85
|
+
visibility, order: 'a-to-z', types: ['snippet', 'api', 'event', 'custom'],
|
|
86
|
+
})
|
|
87
|
+
|
|
79
88
|
const listFavorites = dataIntegrationClient.knowledgeSources.useQuery({ visibility: 'favorite' })
|
|
80
89
|
const [addFavorite, pendingAddFav] = dataIntegrationClient.addFavoriteKnowledgeSource.useMutation()
|
|
81
90
|
const [removeFavorite, pendingRemoveFav] = dataIntegrationClient.removeFavoriteKnowledgeSource.useMutation()
|
|
@@ -131,7 +140,7 @@ const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
|
131
140
|
reject(error)
|
|
132
141
|
}
|
|
133
142
|
})
|
|
134
|
-
|
|
143
|
+
|
|
135
144
|
const [value, setValue] = useState<KnowledgeSourceItemResponse[]>((() => {
|
|
136
145
|
const currentlySelected = allKS.current?.map(ks => ks.id)
|
|
137
146
|
return knowledgeSources.filter(ks => currentlySelected?.includes(ks.slug))
|
|
@@ -139,7 +148,7 @@ const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
|
139
148
|
const filtered = useMemo(
|
|
140
149
|
() => filter
|
|
141
150
|
// Recreate the list so that the favorites list is taken into account
|
|
142
|
-
? knowledgeSources.filter(ks => value.includes(ks) || ks.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
151
|
+
? knowledgeSources.filter(ks => value.includes(ks) || ks.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
143
152
|
: [...knowledgeSources]
|
|
144
153
|
, [knowledgeSources, filter, value, listFavorites],
|
|
145
154
|
)
|
|
@@ -181,11 +190,23 @@ const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
|
181
190
|
)}
|
|
182
191
|
{!filtered.length && <Placeholder title={t.noData} description={t.noDataDescription} className="no-data-placeholder" />}
|
|
183
192
|
</div>
|
|
184
|
-
{!!filtered.length && <Button onClick={onSubmit}>{t.apply}</Button>}
|
|
193
|
+
{!!filtered.length && showSubmitButton && <Button onClick={onSubmit}>{t.apply}</Button>}
|
|
185
194
|
</>
|
|
186
195
|
)
|
|
187
196
|
}
|
|
188
197
|
|
|
198
|
+
export function KnowledgeSourcesTabWorkspace({ allKS, onSubmit }: TabProps) {
|
|
199
|
+
const workspaceTabComponents = useMemo(() => ({ ks: KnowledgeSourcesTab }), [allKS, onSubmit])
|
|
200
|
+
|
|
201
|
+
const buildNavigateParams = (workspace: WorkspaceResponse): NavigationItem<typeof workspaceTabComponents> => ({
|
|
202
|
+
component: 'ks',
|
|
203
|
+
props: { visibility: 'workspace', workspaceId: workspace.id, allKS, onSubmit },
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return <WorkspaceTabNavigator components={workspaceTabComponents} getNavigateParam={buildNavigateParams} />
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
189
210
|
const dictionary = {
|
|
190
211
|
en: {
|
|
191
212
|
title: 'Knowledge Sources',
|
|
@@ -199,6 +220,7 @@ const dictionary = {
|
|
|
199
220
|
noSearchResultsDescription: 'Please, try another search term.',
|
|
200
221
|
noData: 'There are no knowledge sources in this category yet.',
|
|
201
222
|
noDataDescription: 'Use the tabs above to try other categories or use the AI portal to create new knowledge sources.',
|
|
223
|
+
spaces: 'Spaces',
|
|
202
224
|
},
|
|
203
225
|
pt: {
|
|
204
226
|
title: 'Knowledge Sources',
|
|
@@ -212,5 +234,6 @@ const dictionary = {
|
|
|
212
234
|
noSearchResultsDescription: 'Por favor, tente outra busca.',
|
|
213
235
|
noData: 'Ainda não há knowledge sources nesta categoria.',
|
|
214
236
|
noDataDescription: 'Use as abas acima para tentar outras categorias ou use o Portal AI para criar novos knowledge sources.',
|
|
237
|
+
spaces: 'Spaces',
|
|
215
238
|
},
|
|
216
239
|
} satisfies Dictionary
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Flex, IconBox, Image } from '@citric/core'
|
|
2
2
|
import { Agent } from '@citric/icons'
|
|
3
|
-
import { agentClient } from '@stack-spot/portal-network'
|
|
3
|
+
import { agentClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { AgentResponse } from '@stack-spot/portal-network/api/agent'
|
|
5
5
|
import { uniqBy } from 'lodash'
|
|
6
6
|
import { useCallback } from 'react'
|
|
@@ -46,6 +46,7 @@ export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
|
46
46
|
const personalAgents = agentClient.agents.useQuery({ visibility: 'PERSONAL' })
|
|
47
47
|
const publicAgents = agentClient.publicAgents.useQuery({})
|
|
48
48
|
const builtInsAgents = [...publicAgents.map((agent) => ({ ...agent, visibility_level: 'builtIn' }))]
|
|
49
|
+
const workspaceAgents = workspaceAiClient.workspacesContentsByType.useQuery({ contentType: 'agent' })
|
|
49
50
|
let accountAgents: AgentResponse[] = []
|
|
50
51
|
let sharedAgents: AgentResponse[] = []
|
|
51
52
|
if (!isTrial) {
|
|
@@ -53,7 +54,7 @@ export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
|
53
54
|
sharedAgents = agentClient.agents.useQuery({ visibility: 'SHARED' }) || []
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
return uniqBy([...personalAgents, ...accountAgents, ...sharedAgents, ...builtInsAgents], 'id')
|
|
57
|
+
return uniqBy([...personalAgents, ...workspaceAgents.agents, ...accountAgents, ...sharedAgents, ...builtInsAgents], 'id')
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
return <Selector
|
|
@@ -66,7 +67,7 @@ export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
|
66
67
|
regex: agentRegex,
|
|
67
68
|
urlBuilder: (agent) => `/agents/${agent?.id}`,
|
|
68
69
|
searchProp: 'name',
|
|
69
|
-
sections: isTrial ? ['favorite', 'personal', 'builtIn'] : ['favorite', 'personal', 'account', 'shared', 'builtIn'],
|
|
70
|
+
sections: isTrial ? ['favorite', 'personal', 'builtIn'] : ['favorite', 'personal', 'workspace', 'account', 'shared', 'builtIn'],
|
|
70
71
|
renderComponentItem: AgentItem,
|
|
71
72
|
isEnabled: isAgentEnabled,
|
|
72
73
|
onSelect: onSelectItem,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChevronRight, Code, KnowledgeSource, Send, Stack, Times
|
|
1
|
+
import { ChevronRight, Circle, Code, KnowledgeSource, Send, Stack, Times } from '@citric/icons'
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
3
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
4
4
|
import { useEffect, useRef } from 'react'
|
|
@@ -62,8 +62,8 @@ export const ButtonGroup = ({ onSend, onCancel, expanded, setExpanded, isLoading
|
|
|
62
62
|
style={{ width: expanded ? featureButtonsWidth.current : 0 }}
|
|
63
63
|
>
|
|
64
64
|
{features.workspace && (
|
|
65
|
-
<IconButton aria-label={t.
|
|
66
|
-
<
|
|
65
|
+
<IconButton aria-label={t.space} title={t.space} onClick={() => widget.set('panel', 'workspace')}>
|
|
66
|
+
<Circle />
|
|
67
67
|
</IconButton>
|
|
68
68
|
)}
|
|
69
69
|
{features.knowledgeSource && (
|