@stack-spot/ai-chat-widget 1.14.0-beta.7 → 1.14.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 +15 -0
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/app-metadata.json +19 -19
- package/dist/components/Accordion.d.ts.map +1 -1
- package/dist/components/Accordion.js +3 -1
- package/dist/components/Accordion.js.map +1 -1
- package/dist/components/ButtonFavorite.d.ts +47 -0
- package/dist/components/ButtonFavorite.d.ts.map +1 -0
- package/dist/components/ButtonFavorite.js +25 -0
- package/dist/components/ButtonFavorite.js.map +1 -0
- package/dist/components/Code.d.ts.map +1 -1
- package/dist/components/FadingOverflow.d.ts.map +1 -1
- package/dist/components/FallbackBoundary/index.d.ts.map +1 -1
- package/dist/components/IconInput.d.ts.map +1 -1
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/ProgressBar.d.ts.map +1 -1
- package/dist/components/QuickStartButton.d.ts.map +1 -1
- package/dist/components/RightPanelForm.d.ts.map +1 -1
- package/dist/components/RightPanelTabs.d.ts.map +1 -1
- package/dist/components/Selector/index.d.ts +9 -1
- package/dist/components/Selector/index.d.ts.map +1 -1
- package/dist/components/Selector/index.js +19 -13
- package/dist/components/Selector/index.js.map +1 -1
- package/dist/components/StackedBadge.d.ts.map +1 -1
- package/dist/components/ToolBadge.d.ts.map +1 -1
- package/dist/components/Tooltip/context.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.d.ts +1 -1
- package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.js +5 -5
- package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
- package/dist/components/form/DescribedRadioGroup.d.ts +1 -1
- package/dist/components/form/DescribedRadioGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedRadioGroup.js +4 -4
- package/dist/components/form/DescribedRadioGroup.js.map +1 -1
- package/dist/components/form/dictionary.d.ts +19 -0
- package/dist/components/form/dictionary.d.ts.map +1 -0
- package/dist/components/form/dictionary.js +19 -0
- package/dist/components/form/dictionary.js.map +1 -0
- package/dist/components/form/styled.d.ts.map +1 -1
- package/dist/components/form/styled.js +1 -2
- package/dist/components/form/styled.js.map +1 -1
- package/dist/components/form/types.d.ts +8 -0
- package/dist/components/form/types.d.ts.map +1 -1
- package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
- package/dist/right-panel/RightPanelProvider.d.ts.map +1 -1
- package/dist/utils/agent.d.ts.map +1 -1
- package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
- package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
- package/dist/views/Agents/AgentsPanel.js +2 -0
- package/dist/views/Agents/AgentsPanel.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/AgentsTab.js +7 -2
- 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/Agents/useAgentFavorites.d.ts +8 -0
- package/dist/views/Agents/useAgentFavorites.d.ts.map +1 -0
- package/dist/views/Agents/useAgentFavorites.js +31 -0
- package/dist/views/Agents/useAgentFavorites.js.map +1 -0
- package/dist/views/Chat/AgentInfo.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +2 -2
- package/dist/views/Chat/ChatMessages.d.ts.map +1 -1
- package/dist/views/Chat/StepsList.d.ts.map +1 -1
- package/dist/views/Chat/index.d.ts.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.js +3 -2
- package/dist/views/ChatHistory/utils.js.map +1 -1
- package/dist/views/Home/BuiltInAgent.d.ts.map +1 -1
- package/dist/views/Home/index.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.js +35 -4
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +6 -4
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +25 -2
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MinimizedHeader.d.ts.map +1 -1
- package/dist/views/Stacks.d.ts.map +1 -1
- package/dist/views/Stacks.js +33 -3
- package/dist/views/Stacks.js.map +1 -1
- package/dist/views/Steps/FlowChart/HandleGroup.d.ts.map +1 -1
- package/dist/views/Steps/FlowChart/NodeStep.d.ts.map +1 -1
- package/dist/views/Steps/FlowChart/index.d.ts.map +1 -1
- package/dist/views/Steps/StepModal.d.ts.map +1 -1
- package/dist/views/Steps/StepsPanel.d.ts.map +1 -1
- package/dist/views/Workspaces.d.ts.map +1 -1
- package/dist/views/Workspaces.js +42 -5
- package/dist/views/Workspaces.js.map +1 -1
- package/package.json +3 -3
- package/src/app-metadata.json +19 -19
- package/src/components/Accordion.tsx +3 -2
- package/src/components/ButtonFavorite.tsx +100 -0
- package/src/components/Selector/index.tsx +45 -16
- package/src/components/form/DescribedCheckboxGroup.tsx +27 -11
- package/src/components/form/DescribedRadioGroup.tsx +16 -1
- package/src/components/form/dictionary.ts +18 -0
- package/src/components/form/styled.ts +1 -2
- package/src/components/form/types.ts +11 -1
- package/src/views/Agents/AgentsPanel.tsx +2 -0
- package/src/views/Agents/AgentsTab.tsx +12 -2
- package/src/views/Agents/dictionary.ts +2 -0
- package/src/views/Agents/useAgentFavorites.ts +32 -0
- package/src/views/Chat/ChatMessage.tsx +2 -2
- package/src/views/ChatHistory/utils.ts +3 -2
- package/src/views/KnowledgeSources.tsx +45 -8
- package/src/views/MessageInput/AgentSelector.tsx +8 -3
- package/src/views/MessageInput/QuickCommandSelector.tsx +25 -1
- package/src/views/Stacks.tsx +39 -4
- package/src/views/Workspaces.tsx +49 -8
|
@@ -1,11 +1,12 @@
|
|
|
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 } from '@stack-spot/portal-network'
|
|
4
|
+
import { aiClient, dataIntegrationClient } from '@stack-spot/portal-network'
|
|
5
5
|
import { KnowledgeSourceItemResponse, VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
|
|
6
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
7
|
import { difference, uniqBy } from 'lodash'
|
|
8
8
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
9
|
+
import { ButtonFavorite } from '../components/ButtonFavorite'
|
|
9
10
|
import { DescribedCheckboxGroup } from '../components/form/DescribedCheckboxGroup'
|
|
10
11
|
import { IconInput } from '../components/IconInput'
|
|
11
12
|
import { RightPanelTabs } from '../components/RightPanelTabs'
|
|
@@ -54,10 +55,12 @@ const KnowledgeSourcesPanel = () => {
|
|
|
54
55
|
useEffect(() => {
|
|
55
56
|
allKS.current = chat.get('knowledgeSources') ?? []
|
|
56
57
|
}, [chat])
|
|
57
|
-
|
|
58
|
+
|
|
58
59
|
const tabs = isTrial ? [
|
|
60
|
+
{ title: t.favorites, content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
|
|
59
61
|
{ title: t.personal, content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
|
|
60
62
|
]: [
|
|
63
|
+
{ title: t.favorites, content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
|
|
61
64
|
{ title: t.personal, content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
|
|
62
65
|
{ title: t.shared, content: <KnowledgeSourcesTab key="shared" visibility="shared" allKS={allKS} onSubmit={onSubmit} /> },
|
|
63
66
|
{ title: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
|
|
@@ -69,18 +72,46 @@ const KnowledgeSourcesPanel = () => {
|
|
|
69
72
|
const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
70
73
|
const t = useTranslate(dictionary)
|
|
71
74
|
const [filter, setFilter] = useState('')
|
|
75
|
+
|
|
72
76
|
const knowledgeSources = aiClient.knowledgeSources.useQuery({
|
|
73
77
|
visibility, order: 'a-to-z', types: ['snippet', 'api', 'event', 'custom'],
|
|
74
78
|
})
|
|
79
|
+
const listFavorites = dataIntegrationClient.knowledgeSources.useQuery({ visibility: 'favorite' })
|
|
80
|
+
const [addFavorite, pendingAddFav] = dataIntegrationClient.addFavoriteKnowledgeSource.useMutation()
|
|
81
|
+
const [removeFavorite, pendingRemoveFav] = dataIntegrationClient.removeFavoriteKnowledgeSource.useMutation()
|
|
82
|
+
|
|
83
|
+
const onRemoveFavorite = async (idOrSlug: string) => {
|
|
84
|
+
try {
|
|
85
|
+
await removeFavorite({ slug: idOrSlug })
|
|
86
|
+
await aiClient.knowledgeSources.invalidate()
|
|
87
|
+
await dataIntegrationClient.knowledgeSources.invalidate()
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.error(error)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const onAddFavorite = async (idOrSlug: string) => {
|
|
95
|
+
try {
|
|
96
|
+
await addFavorite({ slug: idOrSlug })
|
|
97
|
+
await aiClient.knowledgeSources.invalidate()
|
|
98
|
+
await dataIntegrationClient.knowledgeSources.invalidate()
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// eslint-disable-next-line no-console
|
|
101
|
+
console.error(error)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
75
105
|
const [value, setValue] = useState<KnowledgeSourceItemResponse[]>((() => {
|
|
76
106
|
const currentlySelected = allKS.current?.map(ks => ks.id)
|
|
77
107
|
return knowledgeSources.filter(ks => currentlySelected?.includes(ks.slug))
|
|
78
108
|
})())
|
|
79
109
|
const filtered = useMemo(
|
|
80
|
-
() => filter
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
110
|
+
() => filter
|
|
111
|
+
// Recreate the list so that the favorites list is taken into account
|
|
112
|
+
? knowledgeSources.filter(ks => value.includes(ks) || ks.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
113
|
+
: [...knowledgeSources]
|
|
114
|
+
, [knowledgeSources, filter, value, listFavorites],
|
|
84
115
|
)
|
|
85
116
|
|
|
86
117
|
const onChange = useCallback((newValue: KnowledgeSourceItemResponse[]) => {
|
|
@@ -99,6 +130,10 @@ const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
|
99
130
|
<IconInput icon={<Search />} value={filter} onChange={setFilter} className="search" />
|
|
100
131
|
{!!filtered.length && <DescribedCheckboxGroup
|
|
101
132
|
options={filtered}
|
|
133
|
+
renderAfterElement={({ slug }) => (
|
|
134
|
+
<ButtonFavorite
|
|
135
|
+
favorite={{ idOrSlug: slug, listFavorites, onAddFavorite, onRemoveFavorite, pendingAddFav, pendingRemoveFav }} />
|
|
136
|
+
)}
|
|
102
137
|
keygen={ks => ks.id}
|
|
103
138
|
value={value}
|
|
104
139
|
onChange={onChange}
|
|
@@ -110,10 +145,10 @@ const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit }: TabProps) => {
|
|
|
110
145
|
}
|
|
111
146
|
className="option-list"
|
|
112
147
|
/>}
|
|
113
|
-
{!!
|
|
148
|
+
{!!filtered.length && !filtered.length && (
|
|
114
149
|
<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />
|
|
115
150
|
)}
|
|
116
|
-
{!
|
|
151
|
+
{!filtered.length && <Placeholder title={t.noData} description={t.noDataDescription} className="no-data-placeholder" />}
|
|
117
152
|
</div>
|
|
118
153
|
{!!filtered.length && <Button onClick={onSubmit}>{t.apply}</Button>}
|
|
119
154
|
</>
|
|
@@ -124,6 +159,7 @@ const dictionary = {
|
|
|
124
159
|
en: {
|
|
125
160
|
title: 'Knowledge Sources',
|
|
126
161
|
description: 'By selecting one or more knowledge sources, they will be consulted to generate the responses.',
|
|
162
|
+
favorites: 'Favorites',
|
|
127
163
|
personal: 'Personal',
|
|
128
164
|
shared: 'Shared',
|
|
129
165
|
account: 'Account',
|
|
@@ -136,6 +172,7 @@ const dictionary = {
|
|
|
136
172
|
pt: {
|
|
137
173
|
title: 'Knowledge Sources',
|
|
138
174
|
description: 'Ao selecionar um ou mais knowledge sources, eles serão consultados para gerar as respostas.',
|
|
175
|
+
favorites: 'Favoritos',
|
|
139
176
|
personal: 'Pessoal',
|
|
140
177
|
shared: 'Compartilhado',
|
|
141
178
|
account: 'Conta',
|
|
@@ -7,11 +7,15 @@ import { useCallback } from 'react'
|
|
|
7
7
|
import { Selector } from '../../components/Selector'
|
|
8
8
|
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
9
9
|
import { agentRegex } from '../../regex'
|
|
10
|
+
import { useAgentFavorites } from '../Agents/useAgentFavorites'
|
|
10
11
|
|
|
11
12
|
export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
12
13
|
inputRef: React.RefObject<HTMLTextAreaElement | HTMLInputElement>, }) => {
|
|
13
14
|
const chat = useCurrentChat()
|
|
14
15
|
const isAgentEnabled = useCurrentChatState('features').agent
|
|
16
|
+
|
|
17
|
+
const { listFavorites, onAddFavorite, onRemoveFavorite, pendingAddFav, pendingRemoveFav } = useAgentFavorites()
|
|
18
|
+
|
|
15
19
|
const onSelectItem = useCallback((agent: AgentResponse) => {
|
|
16
20
|
const newValue = `@${agent.slug}`
|
|
17
21
|
chat.set('nextMessage', undefined)
|
|
@@ -36,16 +40,17 @@ export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
const AgentItem = ({ avatar, name }: AgentResponse) => {
|
|
39
|
-
const
|
|
43
|
+
const avatarComponent = avatar ? <Image width="32" height="32" radius="full" src={avatar} /> : <IconBox size="md"><Agent /></IconBox>
|
|
40
44
|
|
|
41
45
|
return <Flex flexWrap="nowrap" alignItems="center" sx={{ gap: '8px' }}>
|
|
42
|
-
{
|
|
46
|
+
{avatarComponent}
|
|
43
47
|
<p className="selector-title">{name}</p>
|
|
44
48
|
</Flex>
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
return <Selector
|
|
48
52
|
inputRef={inputRef}
|
|
53
|
+
favorite={{ listFavorites, onAddFavorite, onRemoveFavorite, pendingAddFav, pendingRemoveFav }}
|
|
49
54
|
selectorConfig={{
|
|
50
55
|
resourceName: 'Agent',
|
|
51
56
|
shortcut: '@',
|
|
@@ -53,7 +58,7 @@ export const AgentSelector = ({ inputRef, isTrial }: { isTrial: boolean,
|
|
|
53
58
|
regex: agentRegex,
|
|
54
59
|
urlBuilder: (agent) => `/agents/${agent?.id}`,
|
|
55
60
|
searchProp: 'name',
|
|
56
|
-
sections: isTrial ? ['personal', 'builtIn'] : ['personal', 'account', 'shared', 'builtIn'],
|
|
61
|
+
sections: isTrial ? ['favorite', 'personal', 'builtIn'] : ['favorite', 'personal', 'account', 'shared', 'builtIn'],
|
|
57
62
|
renderComponentItem: AgentItem,
|
|
58
63
|
isEnabled: isAgentEnabled,
|
|
59
64
|
onSelect: onSelectItem,
|
|
@@ -11,6 +11,29 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
11
11
|
const chat = useCurrentChat()
|
|
12
12
|
const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
|
|
13
13
|
|
|
14
|
+
const listFavorites = aiClient.quickCommands.useQuery({ visibility: 'favorite' })
|
|
15
|
+
const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
|
|
16
|
+
const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteQuickCommand.useMutation()
|
|
17
|
+
|
|
18
|
+
const onAddFavorite = async(idOrSlug?: string) => {
|
|
19
|
+
try {
|
|
20
|
+
await addFavorite({ slug: idOrSlug || '' })
|
|
21
|
+
await aiClient.quickCommands.invalidate()
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// eslint-disable-next-line no-console
|
|
24
|
+
console.error(error)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const onRemoveFavorite = async(idOrSlug?: string) => {
|
|
28
|
+
try {
|
|
29
|
+
await removeFavorite({ slug: idOrSlug || '' })
|
|
30
|
+
await aiClient.quickCommands.invalidate()
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
33
|
+
console.error(error)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
14
37
|
const onSelectItem = useCallback((qc: QuickCommandListResponse) => {
|
|
15
38
|
const newValue = `/${qc.slug}`
|
|
16
39
|
chat.set('nextMessage', newValue)
|
|
@@ -27,6 +50,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
27
50
|
|
|
28
51
|
return <Selector
|
|
29
52
|
inputRef={inputRef}
|
|
53
|
+
favorite={{ listFavorites, onAddFavorite, onRemoveFavorite, pendingAddFav, pendingRemoveFav }}
|
|
30
54
|
selectorConfig={{
|
|
31
55
|
resourceName: 'Quick Command',
|
|
32
56
|
shortcut: '/',
|
|
@@ -34,7 +58,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
34
58
|
searchProp: 'slug',
|
|
35
59
|
urlBuilder: (qc) => `/quick-command/${qc?.slug}`,
|
|
36
60
|
regex: quickCommandRegex,
|
|
37
|
-
sections: isTrial ? ['personal'] : ['personal', 'workspace', 'account', 'shared'],
|
|
61
|
+
sections: isTrial ? ['favorite', 'personal'] : ['favorite', 'personal', 'workspace', 'account', 'shared'],
|
|
38
62
|
isEnabled: isQuickCommandEnabled,
|
|
39
63
|
onSelect: onSelectItem,
|
|
40
64
|
renderComponentItem: QuickCommandItem,
|
package/src/views/Stacks.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { aiClient } from '@stack-spot/portal-network'
|
|
|
5
5
|
import { GetAiStackResponse, VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
|
|
6
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
7
|
import { useEffect, useMemo, useState } from 'react'
|
|
8
|
+
import { ButtonFavorite } from '../components/ButtonFavorite'
|
|
8
9
|
import { DescribedRadioGroup } from '../components/form/DescribedRadioGroup'
|
|
9
10
|
import { IconInput } from '../components/IconInput'
|
|
10
11
|
import { RightPanelTabs } from '../components/RightPanelTabs'
|
|
@@ -34,11 +35,14 @@ export const Stacks = () => {
|
|
|
34
35
|
const StacksPanel = () => {
|
|
35
36
|
const t = useTranslate(dictionary)
|
|
36
37
|
const chat = useCurrentChat()
|
|
38
|
+
|
|
37
39
|
const isTrial = checkIsTrial()
|
|
38
40
|
|
|
39
41
|
const tabs = useMemo(() => isTrial ? [
|
|
42
|
+
{ title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" /> },
|
|
40
43
|
{ title: t.personal, content: <StacksTab key="personal" visibility="personal" /> },
|
|
41
44
|
]: [
|
|
45
|
+
{ title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" /> },
|
|
42
46
|
{ title: t.personal, content: <StacksTab key="personal" visibility="personal" /> },
|
|
43
47
|
{ title: t.shared, content: <StacksTab key="shared" visibility="shared" /> },
|
|
44
48
|
{ title: t.account, content: <StacksTab key="account" visibility="account" /> },
|
|
@@ -52,12 +56,38 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
|
|
|
52
56
|
const { close } = useRightPanel()
|
|
53
57
|
const chat = useCurrentChat()
|
|
54
58
|
const [filter, setFilter] = useState('')
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
const listFavorites = aiClient.aiStacks.useQuery({ visibility: 'favorite' })
|
|
61
|
+
const [addFavorite, pendingAddFav] = aiClient.addFavoriteStackAi.useMutation()
|
|
62
|
+
const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteStackAi.useMutation()
|
|
63
|
+
|
|
64
|
+
const onRemoveFavorite = async (idOrSlug: string) => {
|
|
65
|
+
try {
|
|
66
|
+
await removeFavorite({ stackId: idOrSlug })
|
|
67
|
+
await aiClient.aiStacks.invalidate()
|
|
68
|
+
} catch (error) {
|
|
69
|
+
// eslint-disable-next-line no-console
|
|
70
|
+
console.error(error)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const onAddFavorite = async (idOrSlug: string) => {
|
|
75
|
+
try {
|
|
76
|
+
await addFavorite({ stackId: idOrSlug })
|
|
77
|
+
await aiClient.aiStacks.invalidate()
|
|
78
|
+
} catch (error) {
|
|
79
|
+
// eslint-disable-next-line no-console
|
|
80
|
+
console.error(error)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//@ts-ignore
|
|
56
85
|
const stacks = aiClient.aiStacks.useQuery({ visibility, order: 'a-to-z' })
|
|
57
86
|
const [value, setValue] = useState<GetAiStackResponse | undefined>(stacks.find(s => s.id === chat.get('stack')?.id))
|
|
58
|
-
const filtered = useMemo(
|
|
59
|
-
|
|
60
|
-
|
|
87
|
+
const filtered = useMemo(() => filter ?
|
|
88
|
+
// Recreate the list so that the favorites list is taken into account
|
|
89
|
+
stacks.filter(s => s === value || s.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : [...stacks],
|
|
90
|
+
[stacks, listFavorites, filter, value],
|
|
61
91
|
)
|
|
62
92
|
|
|
63
93
|
function submit() {
|
|
@@ -71,6 +101,9 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
|
|
|
71
101
|
<IconInput icon={<Search />} value={filter} onChange={setFilter} className="search" />
|
|
72
102
|
{!!filtered.length && <DescribedRadioGroup
|
|
73
103
|
options={filtered}
|
|
104
|
+
renderAfterElement={({ id }) =>
|
|
105
|
+
<ButtonFavorite favorite={{ idOrSlug:id, listFavorites, onAddFavorite, onRemoveFavorite, pendingAddFav, pendingRemoveFav }} />
|
|
106
|
+
}
|
|
74
107
|
keygen={s => s.id}
|
|
75
108
|
value={value}
|
|
76
109
|
onChange={setValue}
|
|
@@ -103,6 +136,7 @@ const dictionary = {
|
|
|
103
136
|
noSearchResultsDescription: 'Please, try another search term.',
|
|
104
137
|
noData: 'There are no stacks in this category yet.',
|
|
105
138
|
noDataDescription: 'Use the tabs above to try other categories or use the AI portal to create new stacks.',
|
|
139
|
+
favorites: 'Favoritos',
|
|
106
140
|
},
|
|
107
141
|
pt: {
|
|
108
142
|
title: 'Stacks AI',
|
|
@@ -115,5 +149,6 @@ const dictionary = {
|
|
|
115
149
|
noSearchResultsDescription: 'Por favor, tente outra busca.',
|
|
116
150
|
noData: 'Ainda não há stacks nesta categoria.',
|
|
117
151
|
noDataDescription: 'Use as abas acima para tentar outras categorias ou use o Portal AI para criar novas stacks.',
|
|
152
|
+
favorites: 'Favorites',
|
|
118
153
|
},
|
|
119
154
|
} satisfies Dictionary
|
package/src/views/Workspaces.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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 {
|
|
5
|
-
import {
|
|
4
|
+
import { workspaceClient } from '@stack-spot/portal-network'
|
|
5
|
+
import { WorkspaceReadResponse } from '@stack-spot/portal-network/api/workspace'
|
|
6
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
7
|
import { useEffect, useMemo, useState } from 'react'
|
|
8
8
|
import { DescribedRadioGroup } from '../components/form/DescribedRadioGroup'
|
|
9
9
|
import { IconInput } from '../components/IconInput'
|
|
10
|
-
import {
|
|
10
|
+
import { RightPanelTabs } from '../components/RightPanelTabs'
|
|
11
11
|
import { useCurrentChat, useWidget, useWidgetState } from '../context/hooks'
|
|
12
12
|
import { useRightPanel } from '../right-panel/hooks'
|
|
13
13
|
|
|
@@ -23,22 +23,60 @@ export const Workspaces = () => {
|
|
|
23
23
|
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
if (panel === 'workspace') open(
|
|
26
|
-
<
|
|
26
|
+
<WorkspacesPanel key={chat.id} />,
|
|
27
27
|
{ title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) },
|
|
28
28
|
)
|
|
29
29
|
}, [panel, t, chat.id])
|
|
30
|
-
|
|
31
30
|
return null
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
const WorkspacesPanel = () => {
|
|
34
|
+
const t = useTranslate(dictionary)
|
|
35
|
+
const chat = useCurrentChat()
|
|
36
|
+
|
|
37
|
+
return <RightPanelTabs key={chat.id} tabs={[
|
|
38
|
+
// { title: t.favorites, content: <WorkspaceSourcesTab key="favorite" visibility="favorite" /> },
|
|
39
|
+
{ title: t.all, content: <WorkspaceSourcesTab key="all" /> },
|
|
40
|
+
]}
|
|
41
|
+
/>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const WorkspaceSourcesTab = () => {
|
|
35
45
|
const t = useTranslate(dictionary)
|
|
36
46
|
const { close } = useRightPanel()
|
|
37
47
|
const chat = useCurrentChat()
|
|
38
48
|
const [filter, setFilter] = useState('')
|
|
39
|
-
const workspaces = workspaceAiClient.workspacesAi.useQuery({})
|
|
40
|
-
const [value, setValue] = useState<WorkspaceResponse | undefined>(workspaces.find(w => w.id === chat.get('workspace')?.id))
|
|
49
|
+
// const workspaces = workspaceAiClient.workspacesAi.useQuery({ visibility })
|
|
50
|
+
// const [value, setValue] = useState<WorkspaceResponse | undefined>(workspaces.find(w => w.id === chat.get('workspace')?.id))
|
|
51
|
+
const workspaces = workspaceClient.workspaces.useQuery({ aclOnly: false })
|
|
52
|
+
|
|
53
|
+
const [value, setValue] = useState<WorkspaceReadResponse | undefined>(workspaces.find(w => w.id === chat.get('workspace')?.id))
|
|
54
|
+
// const listFavorites = workspaceAiClient.workspacesAi.useQuery({ visibility: 'favorite' })
|
|
55
|
+
|
|
56
|
+
// const [addFavorite, pendingAddFav] = workspaceAiClient.addFavoriteWorkspaceAi.useMutation()
|
|
57
|
+
// const [removeFavorite, pendingRemoveFav] = workspaceAiClient.removeFavoriteWorkspaceAi.useMutation()
|
|
58
|
+
|
|
59
|
+
// const onAddFavorite = async(idOrSlug: string) => {
|
|
60
|
+
// try {
|
|
61
|
+
// await addFavorite({ workspaceId: idOrSlug })
|
|
62
|
+
// await workspaceAiClient.workspacesAi.invalidate()
|
|
63
|
+
// } catch (error) {
|
|
64
|
+
// // eslint-disable-next-line no-console
|
|
65
|
+
// console.error(error)
|
|
66
|
+
// }
|
|
67
|
+
// }
|
|
68
|
+
// const onRemoveFavorite = async(idOrSlug: string) => {
|
|
69
|
+
// try {
|
|
70
|
+
// await removeFavorite({ workspaceId: idOrSlug })
|
|
71
|
+
// await workspaceAiClient.workspacesAi.invalidate()
|
|
72
|
+
// } catch (error) {
|
|
73
|
+
// // eslint-disable-next-line no-console
|
|
74
|
+
// console.error(error)
|
|
75
|
+
// }
|
|
76
|
+
// }
|
|
77
|
+
|
|
41
78
|
const filtered = useMemo(
|
|
79
|
+
// Recreate the list so that the favorites list is taken into account
|
|
42
80
|
() => filter ? workspaces.filter(w => w === value || w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : workspaces,
|
|
43
81
|
[workspaces, filter, value],
|
|
44
82
|
)
|
|
@@ -47,7 +85,6 @@ const WorkspacesPanel = () => {
|
|
|
47
85
|
if (value) chat.set('workspace', { id: value.id, label: value.name })
|
|
48
86
|
close()
|
|
49
87
|
}
|
|
50
|
-
|
|
51
88
|
return (
|
|
52
89
|
<>
|
|
53
90
|
<div className="content">
|
|
@@ -83,6 +120,8 @@ const dictionary = {
|
|
|
83
120
|
noSearchResultsDescription: 'Please, try another search term.',
|
|
84
121
|
noData: 'There are no workspaces yet.',
|
|
85
122
|
noDataDescription: 'Use the AI portal to create new workspaces.',
|
|
123
|
+
all: 'All',
|
|
124
|
+
favorites: 'Favorites',
|
|
86
125
|
},
|
|
87
126
|
pt: {
|
|
88
127
|
title: 'Workspaces',
|
|
@@ -92,5 +131,7 @@ const dictionary = {
|
|
|
92
131
|
noSearchResultsDescription: 'Por favor, tente outra busca.',
|
|
93
132
|
noData: 'Ainda não há workspace.',
|
|
94
133
|
noDataDescription: 'Use o Portal AI para criar novos workspaces.',
|
|
134
|
+
all: 'Todos',
|
|
135
|
+
favorites: 'Favoritos',
|
|
95
136
|
},
|
|
96
137
|
} satisfies Dictionary
|