@stack-spot/ai-chat-widget 1.17.0 → 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.
Files changed (94) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/StackspotAIWidget.js +1 -1
  3. package/dist/app-metadata.json +4 -4
  4. package/dist/components/ComponentNavigator.d.ts +21 -0
  5. package/dist/components/ComponentNavigator.d.ts.map +1 -0
  6. package/dist/components/ComponentNavigator.js +33 -0
  7. package/dist/components/ComponentNavigator.js.map +1 -0
  8. package/dist/components/ListGroup.d.ts +46 -0
  9. package/dist/components/ListGroup.d.ts.map +1 -0
  10. package/dist/components/ListGroup.js +16 -0
  11. package/dist/components/ListGroup.js.map +1 -0
  12. package/dist/components/RightPanelForm.d.ts.map +1 -1
  13. package/dist/components/RightPanelForm.js +29 -1
  14. package/dist/components/RightPanelForm.js.map +1 -1
  15. package/dist/components/Selector/index.js +5 -5
  16. package/dist/components/Selector/index.js.map +1 -1
  17. package/dist/components/Selector/styled.d.ts +3 -1
  18. package/dist/components/Selector/styled.d.ts.map +1 -1
  19. package/dist/components/Selector/styled.js +2 -1
  20. package/dist/components/Selector/styled.js.map +1 -1
  21. package/dist/components/WorkspaceTabNavigator.d.ts +15 -0
  22. package/dist/components/WorkspaceTabNavigator.d.ts.map +1 -0
  23. package/dist/components/WorkspaceTabNavigator.js +95 -0
  24. package/dist/components/WorkspaceTabNavigator.js.map +1 -0
  25. package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
  26. package/dist/components/form/DescribedCheckboxGroup.js +23 -2
  27. package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
  28. package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
  29. package/dist/views/Agents/AgentsPanel.js +19 -11
  30. package/dist/views/Agents/AgentsPanel.js.map +1 -1
  31. package/dist/views/Agents/AgentsTab.d.ts +9 -3
  32. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  33. package/dist/views/Agents/AgentsTab.js +25 -7
  34. package/dist/views/Agents/AgentsTab.js.map +1 -1
  35. package/dist/views/Agents/dictionary.d.ts +1 -1
  36. package/dist/views/Agents/dictionary.d.ts.map +1 -1
  37. package/dist/views/Agents/dictionary.js +2 -0
  38. package/dist/views/Agents/dictionary.js.map +1 -1
  39. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  40. package/dist/views/ChatHistory/utils.js +8 -3
  41. package/dist/views/ChatHistory/utils.js.map +1 -1
  42. package/dist/views/KnowledgeSources.d.ts +12 -0
  43. package/dist/views/KnowledgeSources.d.ts.map +1 -1
  44. package/dist/views/KnowledgeSources.js +20 -6
  45. package/dist/views/KnowledgeSources.js.map +1 -1
  46. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  47. package/dist/views/MessageInput/AgentSelector.js +4 -3
  48. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  49. package/dist/views/MessageInput/ButtonGroup.js +2 -2
  50. package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
  51. package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
  52. package/dist/views/MessageInput/QuickCommandSelector.js +9 -3
  53. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
  54. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  55. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  56. package/dist/views/MessageInput/dictionary.js +2 -0
  57. package/dist/views/MessageInput/dictionary.js.map +1 -1
  58. package/dist/views/Stacks.d.ts +9 -0
  59. package/dist/views/Stacks.d.ts.map +1 -1
  60. package/dist/views/Stacks.js +37 -14
  61. package/dist/views/Stacks.js.map +1 -1
  62. package/dist/views/Workspaces/WorkspacesTab.d.ts +20 -0
  63. package/dist/views/Workspaces/WorkspacesTab.d.ts.map +1 -0
  64. package/dist/views/Workspaces/WorkspacesTab.js +64 -0
  65. package/dist/views/Workspaces/WorkspacesTab.js.map +1 -0
  66. package/dist/views/{Workspaces.d.ts → Workspaces/index.d.ts} +1 -1
  67. package/dist/views/Workspaces/index.d.ts.map +1 -0
  68. package/dist/views/Workspaces/index.js +76 -0
  69. package/dist/views/Workspaces/index.js.map +1 -0
  70. package/package.json +3 -3
  71. package/src/app-metadata.json +4 -4
  72. package/src/components/ComponentNavigator.tsx +78 -0
  73. package/src/components/ListGroup.tsx +76 -0
  74. package/src/components/RightPanelForm.tsx +29 -1
  75. package/src/components/Selector/index.tsx +5 -5
  76. package/src/components/Selector/styled.ts +3 -2
  77. package/src/components/WorkspaceTabNavigator.tsx +170 -0
  78. package/src/components/form/DescribedCheckboxGroup.tsx +45 -14
  79. package/src/views/Agents/AgentsPanel.tsx +21 -11
  80. package/src/views/Agents/AgentsTab.tsx +42 -9
  81. package/src/views/Agents/dictionary.ts +3 -0
  82. package/src/views/ChatHistory/utils.ts +9 -3
  83. package/src/views/KnowledgeSources.tsx +37 -14
  84. package/src/views/MessageInput/AgentSelector.tsx +4 -3
  85. package/src/views/MessageInput/ButtonGroup.tsx +3 -3
  86. package/src/views/MessageInput/QuickCommandSelector.tsx +10 -3
  87. package/src/views/MessageInput/dictionary.ts +2 -0
  88. package/src/views/Stacks.tsx +57 -17
  89. package/src/views/Workspaces/WorkspacesTab.tsx +117 -0
  90. package/src/views/Workspaces/index.tsx +85 -0
  91. package/dist/views/Workspaces.d.ts.map +0 -1
  92. package/dist/views/Workspaces.js +0 -103
  93. package/dist/views/Workspaces.js.map +0 -1
  94. package/src/views/Workspaces.tsx +0 -137
@@ -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, Workspace } from '@citric/icons'
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.workspace} title={t.workspace} onClick={() => widget.set('panel', 'workspace')}>
66
- <Workspace />
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 && (
@@ -1,5 +1,5 @@
1
1
  import { QuickCommand } from '@citric/icons'
2
- import { aiClient } from '@stack-spot/portal-network'
2
+ import { aiClient, workspaceAiClient } from '@stack-spot/portal-network'
3
3
  import { QuickCommandListResponse } from '@stack-spot/portal-network/api/ai'
4
4
  import { useCallback } from 'react'
5
5
  import { Selector } from '../../components/Selector'
@@ -74,8 +74,15 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
74
74
  inputRef.current.focus()
75
75
  }, [chat, inputRef])
76
76
 
77
+ const getQuickCommands = () => {
78
+ const quickCommands = aiClient.quickCommands.useQuery({ order: 'a-to-z' })
79
+ const quickCommandsFiltered = quickCommands.filter((qc) => qc.visibility_level.toLowerCase() !== 'workspace')
80
+ const workspaceQuickCommands = workspaceAiClient.workspacesContentsByType.useQuery({ contentType: 'quick_command' })
81
+ return [...quickCommandsFiltered, ...workspaceQuickCommands.qcs]
82
+ }
83
+
77
84
  const QuickCommandItem = ({ slug, description }: QuickCommandListResponse) => <>
78
- <p className="selector-title">/{slug.toUpperCase()}</p>
85
+ <p className="selector-title">/{slug?.toUpperCase()}</p>
79
86
  <p className="selector-description">{description}</p>
80
87
  </>
81
88
 
@@ -95,7 +102,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
95
102
  isEnabled: isQuickCommandEnabled,
96
103
  onSelect: onSelectItem,
97
104
  renderComponentItem: QuickCommandItem,
98
- useData: () => aiClient.quickCommands.useQuery({ order: 'a-to-z' }),
105
+ useData: getQuickCommands,
99
106
  }}
100
107
  />
101
108
  }
@@ -5,6 +5,7 @@ const dictionary = {
5
5
  stack: 'Select stack',
6
6
  code: 'Open code editor',
7
7
  workspace: 'Select workspace',
8
+ space: 'Select space',
8
9
  knowledgeSource: 'Select knowledge sources',
9
10
  agent: 'Select agent',
10
11
  collapse: 'Hide buttons',
@@ -24,6 +25,7 @@ const dictionary = {
24
25
  stack: 'Selecionar stack',
25
26
  code: 'Abrir editor de código',
26
27
  workspace: 'Selecionar workspace',
28
+ space: 'Select Space',
27
29
  knowledgeSource: 'Selecionar knowledge sources',
28
30
  agent: 'Selecionar agente',
29
31
  collapse: 'Esconder botões',
@@ -1,16 +1,20 @@
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, workspaceAiClient } from '@stack-spot/portal-network'
5
5
  import { GetAiStackResponse, 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
- import { useEffect, useMemo, useState } from 'react'
8
+ import { useCallback, useEffect, useMemo, useRef, 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'
11
13
  import { RightPanelTabs } from '../components/RightPanelTabs'
14
+ import { WorkspaceTabNavigator } from '../components/WorkspaceTabNavigator'
12
15
  import { useCurrentChat, useWidget, useWidgetState } from '../context/hooks'
13
16
  import { useRightPanel } from '../right-panel/hooks'
17
+ import { ChatProperties } from '../state/ChatState'
14
18
  import { checkIsTrial } from '../utils/check-is-trial'
15
19
 
16
20
  /**
@@ -35,23 +39,35 @@ export const Stacks = () => {
35
39
  const StacksPanel = () => {
36
40
  const t = useTranslate(dictionary)
37
41
  const chat = useCurrentChat()
38
-
39
42
  const isTrial = checkIsTrial()
43
+ const stack = useRef(chat.get('stack'))
44
+
45
+ useEffect(() => {
46
+ stack.current = chat.get('stack')
47
+ }, [chat])
40
48
 
41
49
  const tabs = useMemo(() => isTrial ? [
42
- { title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" /> },
43
- { title: t.personal, content: <StacksTab key="personal" visibility="personal" /> },
50
+ { title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" stack={stack} /> },
51
+ { title: t.personal, content: <StacksTab key="personal" visibility="personal" stack={stack} /> },
44
52
  ]: [
45
- { title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" /> },
46
- { title: t.personal, content: <StacksTab key="personal" visibility="personal" /> },
47
- { title: t.shared, content: <StacksTab key="shared" visibility="shared" /> },
48
- { title: t.account, content: <StacksTab key="account" visibility="account" /> },
53
+ { title: t.favorites, content: <StacksTab key="favorites" visibility="favorite" stack={stack} /> },
54
+ { title: t.personal, content: <StacksTab key="personal" visibility="personal" stack={stack} /> },
55
+ { title: t.shared, content: <StacksTab key="shared" visibility="shared" stack={stack} /> },
56
+ { title: t.spaces, content: <StacksTabWorkspace key="workspace" visibility="workspace" stack={stack} /> },
57
+ { title: t.account, content: <StacksTab key="account" visibility="account" stack={stack} /> },
49
58
  ], [t, isTrial])
50
59
 
51
60
  return <RightPanelTabs key={chat.id} tabs={tabs} />
52
61
  }
53
62
 
54
- const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
63
+ export interface StacksTabProps {
64
+ visibility: VisibilityLevelEnum,
65
+ workspaceId?: string,
66
+ stack: React.MutableRefObject<ChatProperties['stack']>,
67
+ showSubmitButton?: boolean,
68
+ }
69
+
70
+ export const StacksTab = ({ visibility, workspaceId, stack, showSubmitButton = true }: StacksTabProps) => {
55
71
  const t = useTranslate(dictionary)
56
72
  const { close } = useRightPanel()
57
73
  const chat = useCurrentChat()
@@ -111,13 +127,19 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
111
127
  }
112
128
  })
113
129
 
114
- //@ts-ignore
115
- const stacks = aiClient.aiStacks.useQuery({ visibility, order: 'a-to-z' })
116
- const [value, setValue] = useState<GetAiStackResponse | undefined>(stacks.find(s => s.id === chat.get('stack')?.id))
130
+
131
+
132
+ const stacks = workspaceId
133
+ ? workspaceAiClient.getStackFromWorkspaceAi.useQuery({ workspaceId })
134
+ //@ts-ignore
135
+ : aiClient.aiStacks.useQuery({ visibility, order: 'a-to-z' })
136
+
137
+ const currentStackId = stack.current ? stack.current.id : chat.get('stack')?.id
138
+ const [value, setValue] = useState<GetAiStackResponse | undefined>(stacks.find(s => s.id === currentStackId))
117
139
  const filtered = useMemo(() => filter ?
118
140
  // Recreate the list so that the favorites list is taken into account
119
- stacks.filter(s => s === value || s.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : [...stacks],
120
- [stacks, listFavorites, filter, value],
141
+ stacks.filter(s => s === value || s.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : [...stacks],
142
+ [stacks, listFavorites, filter, value],
121
143
  )
122
144
 
123
145
  function submit() {
@@ -125,6 +147,11 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
125
147
  close()
126
148
  }
127
149
 
150
+ const onChange = useCallback((newValue: GetAiStackResponse) => {
151
+ setValue(newValue)
152
+ stack.current = { ...newValue, label: newValue.name }
153
+ }, [])
154
+
128
155
  return (
129
156
  <>
130
157
  <div className="content">
@@ -136,7 +163,7 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
136
163
  }
137
164
  keygen={s => s.id}
138
165
  value={value}
139
- onChange={setValue}
166
+ onChange={onChange}
140
167
  renderLabel={s => s.name}
141
168
  renderDescription={s => s.use_case}
142
169
  optionClassName={s => (s === value && filter && !s.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
@@ -149,11 +176,22 @@ const StacksTab = ({ visibility }: { visibility: VisibilityLevelEnum }) => {
149
176
  <Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} className="no-data-placeholder"/>}
150
177
  {!stacks.length && <Placeholder title={t.noData} description={t.noDataDescription} />}
151
178
  </div>
152
- {!!filtered.length && <Button onClick={submit} disabled={!value}>{t.apply}</Button>}
179
+ {!!filtered.length && showSubmitButton && <Button onClick={submit} disabled={!value}>{t.apply}</Button>}
153
180
  </>
154
181
  )
155
182
  }
156
183
 
184
+ function StacksTabWorkspace({ stack, visibility, showSubmitButton }: StacksTabProps) {
185
+ const workspaceTabComponents = useMemo(() => ({ stack: StacksTab }), [stack])
186
+
187
+ const buildNavigateParams = (workspace: WorkspaceResponse): NavigationItem<typeof workspaceTabComponents> => ({
188
+ component: 'stack',
189
+ props: { visibility, workspaceId: workspace.id, stack, showSubmitButton },
190
+ })
191
+
192
+ return <WorkspaceTabNavigator components={workspaceTabComponents} getNavigateParam={buildNavigateParams} />
193
+ }
194
+
157
195
  const dictionary = {
158
196
  en: {
159
197
  title: 'Stacks AI',
@@ -167,6 +205,7 @@ const dictionary = {
167
205
  noData: 'There are no stacks in this category yet.',
168
206
  noDataDescription: 'Use the tabs above to try other categories or use the AI portal to create new stacks.',
169
207
  favorites: 'Favorites',
208
+ spaces: 'Spaces',
170
209
  },
171
210
  pt: {
172
211
  title: 'Stacks AI',
@@ -180,5 +219,6 @@ const dictionary = {
180
219
  noData: 'Ainda não há stacks nesta categoria.',
181
220
  noDataDescription: 'Use as abas acima para tentar outras categorias ou use o Portal AI para criar novas stacks.',
182
221
  favorites: 'Favoritos',
222
+ spaces: 'Spaces',
183
223
  },
184
224
  } satisfies Dictionary
@@ -0,0 +1,117 @@
1
+ import { Button, Flex, IconBox, Image, Text } from '@citric/core'
2
+ import { Agent, Circle, KnowledgeSource, Stack } from '@citric/icons'
3
+ import { Avatar } from '@citric/ui'
4
+ import { workspaceAiClient } from '@stack-spot/portal-network'
5
+ import { WorkspaceResponse, WorkspaceVisibilityLevelEnum } from '@stack-spot/portal-network/api/workspace-ai'
6
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
7
+ import { useTransition } from 'react'
8
+ import { useComponentNavigation } from '../../components/ComponentNavigator'
9
+ import { ListGroup } from '../../components/ListGroup'
10
+ import { CardSpace, WorkspaceTabNavigator } from '../../components/WorkspaceTabNavigator'
11
+ import { ChatProperties } from '../../state/ChatState'
12
+ import { AgentsTab } from '../Agents/AgentsTab'
13
+ import { KnowledgeSourcesTab } from '../KnowledgeSources'
14
+ import { StacksTab } from '../Stacks'
15
+
16
+ const SpaceCard = ({ workspaceId }: { workspaceId: string }) => {
17
+ const workspace = workspaceAiClient.workspaceAi.useQuery({ id: workspaceId })
18
+ return <Flex flexDirection="column" sx={{ gap: '8px' }}>
19
+ <Flex alignItems="center" sx={{ gap: '4px' }}>
20
+ {workspace.logo
21
+ ? <Image src={workspace.logo} />
22
+ : <Avatar size="xxs" appearance="square" sx={{ bg: 'light.500' }}><IconBox><Circle /></IconBox></Avatar>}
23
+ <Text appearance="body2" weight="medium">{workspace.name} </Text>
24
+ </Flex>
25
+
26
+ <Text colorScheme="light.700">{workspace.description}</Text>
27
+ </Flex>
28
+ }
29
+
30
+ export interface TabProps {
31
+ visibility: WorkspaceVisibilityLevelEnum,
32
+ allKS: React.MutableRefObject<ChatProperties['knowledgeSources']>,
33
+ agent: React.MutableRefObject<ChatProperties['agent']>,
34
+ stack: React.MutableRefObject<ChatProperties['stack']>,
35
+ workspaceId?: string,
36
+ onSubmit: () => void,
37
+ }
38
+
39
+ export interface WorkspaceResource {
40
+ id: string,
41
+ resourceType: 'agent' | 'ks' | 'stack',
42
+ displayName: string,
43
+ icon: React.ReactElement,
44
+ workspaceId?: string,
45
+ }
46
+
47
+ const showSubmitButton = false
48
+
49
+ export const WorkspaceResources = ({ workspaceId, allKS, agent, stack }: Omit<TabProps, 'onSubmit'>) => {
50
+ const { navigate } = useComponentNavigation<typeof workspaceTabComponents>()
51
+ const [isPending, startTransition] = useTransition()
52
+ const resourceTypes: WorkspaceResource[] = [
53
+ { id: 'agents', resourceType: 'agent', displayName: 'Agents', workspaceId, icon: <Agent /> },
54
+ { id: 'ks', resourceType: 'ks', displayName: 'Knowledge Sources', workspaceId, icon: <KnowledgeSource /> },
55
+ { id: 'stack', resourceType: 'stack', displayName: 'Stacks', workspaceId, icon: <Stack /> },
56
+ ]
57
+
58
+ const handleNavigate = (resource: WorkspaceResource) => {
59
+ startTransition(() => {
60
+ if (resource.resourceType === 'agent')
61
+ navigate({ component: 'agent', props: { visibility: 'WORKSPACE', agent, workspaceId, showSubmitButton }, fullScreen: true })
62
+
63
+ if (resource.resourceType === 'ks')
64
+ navigate({ component: 'ks', props: { visibility: 'workspace', allKS, workspaceId, showSubmitButton }, fullScreen: true })
65
+
66
+ if (resource.resourceType === 'stack')
67
+ navigate({ component: 'stack', props: { visibility: 'workspace', stack, workspaceId, showSubmitButton }, fullScreen: true })
68
+ })
69
+ }
70
+
71
+ return (<>
72
+ {workspaceId && <SpaceCard workspaceId={workspaceId} />}
73
+ <ListGroup
74
+ list={resourceTypes}
75
+ keygen={w => w.id}
76
+ onClick={(resource) => { handleNavigate(resource) }}
77
+ renderLabel={r => <CardSpace name={r.displayName} icon={r.icon} onClick={() => handleNavigate(r)} />}
78
+ style={{ gap: '6px', display: 'flex', flexDirection: 'column', opacity: isPending ? '0.5' : '1' }}
79
+ />
80
+ </>
81
+ )
82
+ }
83
+
84
+ const workspaceTabComponents = {
85
+ workspaceResource: WorkspaceResources,
86
+ agent: AgentsTab,
87
+ ks: KnowledgeSourcesTab,
88
+ stack: StacksTab,
89
+ }
90
+
91
+ export function WorkspacesTab({ visibility, allKS, agent, stack, onSubmit }: TabProps) {
92
+ const t = useTranslate(dictionary)
93
+ const buildNavigateParams = (workspace: WorkspaceResponse) => ({
94
+ component: 'workspaceResource',
95
+ props: { allKS, agent, stack, visibility, workspaceId: workspace.id } satisfies Omit<TabProps, 'onSubmit'>,
96
+ fullScreen: true,
97
+ })
98
+
99
+ return (<>
100
+ <WorkspaceTabNavigator
101
+ components={workspaceTabComponents}
102
+ getNavigateParam={buildNavigateParams}
103
+ visibility={visibility}
104
+ />
105
+ <Button className="workspace-submit" onClick={onSubmit} >{t.apply}</Button>
106
+ </>
107
+ )
108
+ }
109
+
110
+ const dictionary = {
111
+ en: {
112
+ apply: 'Apply',
113
+ },
114
+ pt: {
115
+ apply: 'Aplicar',
116
+ },
117
+ } satisfies Dictionary
@@ -0,0 +1,85 @@
1
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
2
+ import { useCallback, useEffect, useRef } from 'react'
3
+ import { RightPanelTabs } from '../../components/RightPanelTabs'
4
+ import { useCurrentChat, useWidget, useWidgetState } from '../../context/hooks'
5
+ import { useRightPanel } from '../../right-panel/hooks'
6
+ import { WorkspacesTab } from './WorkspacesTab'
7
+
8
+ /**
9
+ * Renders the Workspace selection form in the Right Panel if this is the panel that is currently opened.
10
+ */
11
+ export const Workspaces = () => {
12
+ const t = useTranslate(dictionary)
13
+ const panel = useWidgetState('panel')
14
+ const { open } = useRightPanel()
15
+ const widget = useWidget()
16
+ const chat = useCurrentChat()
17
+
18
+ useEffect(() => {
19
+ if (panel === 'workspace') open(
20
+ <WorkspacesPanel key={chat.id} />,
21
+ { title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) },
22
+ )
23
+ }, [panel, t, chat.id])
24
+ return null
25
+ }
26
+
27
+ const WorkspacesPanel = () => {
28
+ const t = useTranslate(dictionary)
29
+ const chat = useCurrentChat()
30
+ const allKS = useRef(chat.get('knowledgeSources') ?? [])
31
+ const agent = useRef(chat.get('agent'))
32
+ const stack = useRef(chat.get('stack'))
33
+ const { close } = useRightPanel()
34
+
35
+ const onSubmit = useCallback(() => {
36
+ chat.set('knowledgeSources', allKS.current)
37
+ chat.set('stack', stack.current)
38
+ chat.set('agent', agent.current)
39
+ close()
40
+ }, [chat])
41
+
42
+ useEffect(() => {
43
+ allKS.current = chat.get('knowledgeSources') ?? []
44
+ agent.current = chat.get('agent')
45
+ stack.current = chat.get('stack')
46
+ }, [chat])
47
+
48
+
49
+ return <RightPanelTabs key={chat.id} tabs={[
50
+ {
51
+ title: t.favorites,
52
+ content: <WorkspacesTab key="favorite" visibility="favorite" allKS={allKS} agent={agent} stack={stack} onSubmit={onSubmit} />,
53
+ },
54
+ {
55
+ title: t.all,
56
+ content: <WorkspacesTab key="all" visibility="all" allKS={allKS} agent={agent} stack={stack} onSubmit={onSubmit} />,
57
+ },
58
+ ]}
59
+ />
60
+ }
61
+
62
+ const dictionary = {
63
+ en: {
64
+ title: 'Spaces',
65
+ description: 'By selecting a space, its Knowledge Sources (KSs), Agents, Quick Commands and Stacks Ai will be consulted to generate the answers.',
66
+ apply: 'Apply',
67
+ noSearchResults: "Your search didn't yield results.",
68
+ noSearchResultsDescription: 'Please, try another search term.',
69
+ noData: 'There are no spaces yet.',
70
+ noDataDescription: 'Use the AI portal to create new spaces.',
71
+ all: 'All',
72
+ favorites: 'Favorites',
73
+ },
74
+ pt: {
75
+ title: 'Spaces',
76
+ description: 'Ao selecionar um space, seus Knowledge Sources (KSs), Agentes, Quick Commands e Stacks Ai serão consultados para gerar as respostas.',
77
+ apply: 'Aplicar',
78
+ noSearchResults: 'Sua busca não produziu resultados',
79
+ noSearchResultsDescription: 'Por favor, tente outra busca.',
80
+ noData: 'Ainda não há spaces.',
81
+ noDataDescription: 'Use o Portal AI para criar novos spaces.',
82
+ all: 'Todos',
83
+ favorites: 'Favoritos',
84
+ },
85
+ } satisfies Dictionary
@@ -1 +0,0 @@
1
- {"version":3,"file":"Workspaces.d.ts","sourceRoot":"","sources":["../../src/views/Workspaces.tsx"],"names":[],"mappings":"AAaA;;GAEG;AACH,eAAO,MAAM,UAAU,YActB,CAAA"}
@@ -1,103 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Button } from '@citric/core';
3
- import { Search } from '@citric/icons';
4
- import { Placeholder } from '@stack-spot/portal-components/Placeholder';
5
- import { workspaceClient } from '@stack-spot/portal-network';
6
- import { useTranslate } from '@stack-spot/portal-translate';
7
- import { useEffect, useMemo, useState } from 'react';
8
- import { DescribedRadioGroup } from '../components/form/DescribedRadioGroup.js';
9
- import { IconInput } from '../components/IconInput.js';
10
- import { RightPanelTabs } from '../components/RightPanelTabs.js';
11
- import { useCurrentChat, useWidget, useWidgetState } from '../context/hooks.js';
12
- import { useRightPanel } from '../right-panel/hooks.js';
13
- /**
14
- * Renders the Workspace selection form in the Right Panel if this is the panel that is currently opened.
15
- */
16
- export const Workspaces = () => {
17
- const t = useTranslate(dictionary);
18
- const panel = useWidgetState('panel');
19
- const { open } = useRightPanel();
20
- const widget = useWidget();
21
- const chat = useCurrentChat();
22
- useEffect(() => {
23
- if (panel === 'workspace')
24
- open(_jsx(WorkspacesPanel, {}, chat.id), { title: t.title, description: t.description, onClose: () => widget.set('panel', undefined) });
25
- }, [panel, t, chat.id]);
26
- return null;
27
- };
28
- const WorkspacesPanel = () => {
29
- const t = useTranslate(dictionary);
30
- const chat = useCurrentChat();
31
- return _jsx(RightPanelTabs, { tabs: [
32
- // { title: t.favorites, content: <WorkspaceSourcesTab key="favorite" visibility="favorite" /> },
33
- { title: t.all, content: _jsx(WorkspaceSourcesTab, {}, "all") },
34
- ] }, chat.id);
35
- };
36
- const WorkspaceSourcesTab = () => {
37
- const t = useTranslate(dictionary);
38
- const { close } = useRightPanel();
39
- const chat = useCurrentChat();
40
- const [filter, setFilter] = useState('');
41
- // const workspaces = workspaceAiClient.workspacesAi.useQuery({ visibility })
42
- // const [value, setValue] = useState<WorkspaceResponse | undefined>(workspaces.find(w => w.id === chat.get('workspace')?.id))
43
- const workspaces = workspaceClient.workspaces.useQuery({ aclOnly: false });
44
- const [value, setValue] = useState(workspaces.find(w => w.id === chat.get('workspace')?.id));
45
- // const listFavorites = workspaceAiClient.workspacesAi.useQuery({ visibility: 'favorite' })
46
- // const [addFavorite, pendingAddFav] = workspaceAiClient.addFavoriteWorkspaceAi.useMutation()
47
- // const [removeFavorite, pendingRemoveFav] = workspaceAiClient.removeFavoriteWorkspaceAi.useMutation()
48
- // const onAddFavorite = async(idOrSlug: string) => {
49
- // try {
50
- // await addFavorite({ workspaceId: idOrSlug })
51
- // await workspaceAiClient.workspacesAi.invalidate()
52
- // } catch (error) {
53
- // // eslint-disable-next-line no-console
54
- // console.error(error)
55
- // }
56
- // }
57
- // const onRemoveFavorite = async(idOrSlug: string) => {
58
- // try {
59
- // await removeFavorite({ workspaceId: idOrSlug })
60
- // await workspaceAiClient.workspacesAi.invalidate()
61
- // } catch (error) {
62
- // // eslint-disable-next-line no-console
63
- // console.error(error)
64
- // }
65
- // }
66
- const filtered = useMemo(
67
- // Recreate the list so that the favorites list is taken into account
68
- () => filter ? workspaces.filter(w => w === value || w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : workspaces, [workspaces, filter, value]);
69
- function submit() {
70
- if (value)
71
- chat.set('workspace', { id: value.id, label: value.name });
72
- close();
73
- }
74
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "content", children: [_jsx(IconInput, { icon: _jsx(Search, {}), value: filter, onChange: setFilter, className: "search" }), !!filtered.length && _jsx(DescribedRadioGroup, { options: filtered, keygen: w => w.id, value: value, onChange: setValue, renderLabel: w => w.name, renderDescription: w => w.description, optionClassName: w => (w === value && filter && !w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
75
- ? 'filtered-out'
76
- : '', className: "option-list" }), !!workspaces.length && !filtered.length &&
77
- _jsx(Placeholder, { title: t.noSearchResults, description: t.noSearchResultsDescription, className: "no-data-placeholder" }), !workspaces.length && _jsx(Placeholder, { title: t.noData, description: t.noDataDescription })] }), !!filtered.length && _jsx(Button, { onClick: submit, disabled: !value, children: t.apply })] }));
78
- };
79
- const dictionary = {
80
- en: {
81
- title: 'Workspaces',
82
- description: 'By selecting a workspace, its Knowledge Sources (KSs) will be consulted to generate the answers.',
83
- apply: 'Apply',
84
- noSearchResults: "Your search didn't yield results.",
85
- noSearchResultsDescription: 'Please, try another search term.',
86
- noData: 'There are no workspaces yet.',
87
- noDataDescription: 'Use the AI portal to create new workspaces.',
88
- all: 'All',
89
- favorites: 'Favorites',
90
- },
91
- pt: {
92
- title: 'Workspaces',
93
- description: 'Ao selecionar um workspace, seus Knowledge Sources (KSs) serão consultados para gerar as respostas.',
94
- apply: 'Aplicar',
95
- noSearchResults: 'Sua busca não produziu resultados',
96
- noSearchResultsDescription: 'Por favor, tente outra busca.',
97
- noData: 'Ainda não há workspace.',
98
- noDataDescription: 'Use o Portal AI para criar novos workspaces.',
99
- all: 'Todos',
100
- favorites: 'Favoritos',
101
- },
102
- };
103
- //# sourceMappingURL=Workspaces.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Workspaces.js","sourceRoot":"","sources":["../../src/views/Workspaces.tsx"],"names":[],"mappings":"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"}