@stack-spot/ai-chat-widget 1.18.0-beta.8 → 1.18.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 (107) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/StackspotAIWidget.js +1 -1
  3. package/dist/app-metadata.json +3 -3
  4. package/dist/components/RightPanelForm.d.ts.map +1 -1
  5. package/dist/components/RightPanelForm.js +1 -29
  6. package/dist/components/RightPanelForm.js.map +1 -1
  7. package/dist/components/Selector/index.js +5 -5
  8. package/dist/components/Selector/index.js.map +1 -1
  9. package/dist/components/Selector/styled.d.ts +1 -3
  10. package/dist/components/Selector/styled.d.ts.map +1 -1
  11. package/dist/components/Selector/styled.js +1 -2
  12. package/dist/components/Selector/styled.js.map +1 -1
  13. package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
  14. package/dist/components/form/DescribedCheckboxGroup.js +2 -23
  15. package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/state/ChatEntry.d.ts +4 -0
  21. package/dist/state/ChatEntry.d.ts.map +1 -1
  22. package/dist/state/ChatEntry.js.map +1 -1
  23. package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
  24. package/dist/views/Agents/AgentsPanel.js +11 -19
  25. package/dist/views/Agents/AgentsPanel.js.map +1 -1
  26. package/dist/views/Agents/AgentsTab.d.ts +3 -9
  27. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  28. package/dist/views/Agents/AgentsTab.js +7 -25
  29. package/dist/views/Agents/AgentsTab.js.map +1 -1
  30. package/dist/views/Agents/dictionary.d.ts +1 -1
  31. package/dist/views/Agents/dictionary.d.ts.map +1 -1
  32. package/dist/views/Agents/dictionary.js +0 -2
  33. package/dist/views/Agents/dictionary.js.map +1 -1
  34. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  35. package/dist/views/Chat/ChatMessage.js +5 -5
  36. package/dist/views/Chat/ChatMessage.js.map +1 -1
  37. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  38. package/dist/views/ChatHistory/utils.js +3 -12
  39. package/dist/views/ChatHistory/utils.js.map +1 -1
  40. package/dist/views/KnowledgeSources.d.ts +0 -12
  41. package/dist/views/KnowledgeSources.d.ts.map +1 -1
  42. package/dist/views/KnowledgeSources.js +6 -20
  43. package/dist/views/KnowledgeSources.js.map +1 -1
  44. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  45. package/dist/views/MessageInput/AgentSelector.js +7 -11
  46. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  47. package/dist/views/MessageInput/ButtonGroup.js +2 -2
  48. package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
  49. package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
  50. package/dist/views/MessageInput/QuickCommandSelector.js +4 -11
  51. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
  52. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  53. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  54. package/dist/views/MessageInput/dictionary.js +0 -2
  55. package/dist/views/MessageInput/dictionary.js.map +1 -1
  56. package/dist/views/Stacks.d.ts +0 -9
  57. package/dist/views/Stacks.d.ts.map +1 -1
  58. package/dist/views/Stacks.js +14 -37
  59. package/dist/views/Stacks.js.map +1 -1
  60. package/dist/views/{Workspaces/index.d.ts → Workspaces.d.ts} +1 -1
  61. package/dist/views/Workspaces.d.ts.map +1 -0
  62. package/dist/views/Workspaces.js +103 -0
  63. package/dist/views/Workspaces.js.map +1 -0
  64. package/package.json +2 -2
  65. package/src/app-metadata.json +3 -3
  66. package/src/components/RightPanelForm.tsx +1 -29
  67. package/src/components/Selector/index.tsx +5 -5
  68. package/src/components/Selector/styled.ts +2 -3
  69. package/src/components/form/DescribedCheckboxGroup.tsx +14 -45
  70. package/src/index.ts +2 -0
  71. package/src/state/ChatEntry.ts +4 -0
  72. package/src/views/Agents/AgentsPanel.tsx +11 -21
  73. package/src/views/Agents/AgentsTab.tsx +9 -42
  74. package/src/views/Agents/dictionary.ts +0 -3
  75. package/src/views/Chat/ChatMessage.tsx +6 -5
  76. package/src/views/ChatHistory/utils.ts +3 -13
  77. package/src/views/KnowledgeSources.tsx +14 -37
  78. package/src/views/MessageInput/AgentSelector.tsx +8 -19
  79. package/src/views/MessageInput/ButtonGroup.tsx +3 -3
  80. package/src/views/MessageInput/QuickCommandSelector.tsx +4 -15
  81. package/src/views/MessageInput/dictionary.ts +0 -2
  82. package/src/views/Stacks.tsx +17 -57
  83. package/src/views/Workspaces.tsx +137 -0
  84. package/dist/components/ComponentNavigator.d.ts +0 -21
  85. package/dist/components/ComponentNavigator.d.ts.map +0 -1
  86. package/dist/components/ComponentNavigator.js +0 -33
  87. package/dist/components/ComponentNavigator.js.map +0 -1
  88. package/dist/components/ListGroup.d.ts +0 -46
  89. package/dist/components/ListGroup.d.ts.map +0 -1
  90. package/dist/components/ListGroup.js +0 -16
  91. package/dist/components/ListGroup.js.map +0 -1
  92. package/dist/components/WorkspaceTabNavigator.d.ts +0 -17
  93. package/dist/components/WorkspaceTabNavigator.d.ts.map +0 -1
  94. package/dist/components/WorkspaceTabNavigator.js +0 -95
  95. package/dist/components/WorkspaceTabNavigator.js.map +0 -1
  96. package/dist/views/Workspaces/WorkspacesTab.d.ts +0 -20
  97. package/dist/views/Workspaces/WorkspacesTab.d.ts.map +0 -1
  98. package/dist/views/Workspaces/WorkspacesTab.js +0 -64
  99. package/dist/views/Workspaces/WorkspacesTab.js.map +0 -1
  100. package/dist/views/Workspaces/index.d.ts.map +0 -1
  101. package/dist/views/Workspaces/index.js +0 -76
  102. package/dist/views/Workspaces/index.js.map +0 -1
  103. package/src/components/ComponentNavigator.tsx +0 -78
  104. package/src/components/ListGroup.tsx +0 -76
  105. package/src/components/WorkspaceTabNavigator.tsx +0 -177
  106. package/src/views/Workspaces/WorkspacesTab.tsx +0 -121
  107. package/src/views/Workspaces/index.tsx +0 -85
@@ -1,78 +0,0 @@
1
- import { Flex } from '@citric/core'
2
- import { ArrowLeft } from '@citric/icons'
3
- import { IconButton } from '@citric/ui'
4
- import { createContext, useCallback, useContext, useMemo, useState } from 'react'
5
-
6
- export type NavigationMap = Record<string, React.ComponentType<any>>
7
-
8
- export type NavigationItem<T extends NavigationMap, K extends keyof T = keyof T> = {
9
- component: K,
10
- props?: T[K] extends React.ComponentType<infer P> ? P : never,
11
- fullScreen?: boolean,
12
- }
13
-
14
- export interface NavigationContextType<T extends NavigationMap> {
15
- navigate: <K extends keyof T>(item: NavigationItem<T, K>) => Promise<void>,
16
- goBack: () => void,
17
- canGoBack: boolean,
18
- currentItem: NavigationItem<T>,
19
- }
20
-
21
- export interface ComponentNavigatorProps<T extends NavigationMap, K extends keyof T> {
22
- initialItem: NavigationItem<T, K>,
23
- components: T,
24
- renderTitle?: (item: NavigationItem<T, keyof T>) => React.ReactNode,
25
- className?: string,
26
- }
27
-
28
- const NavigationContext = createContext<NavigationContextType<NavigationMap> | null>(null)
29
-
30
- export function ComponentNavigator<T extends NavigationMap, K extends keyof T>({
31
- initialItem,
32
- components,
33
- renderTitle,
34
- className,
35
- }: ComponentNavigatorProps<T, K>) {
36
- const [navigationStack, setNavigationStack] = useState<NavigationItem<T>[]>([initialItem])
37
- const currentItem = navigationStack[navigationStack.length - 1]
38
-
39
- const navigate = useCallback((item: NavigationItem<T>) => { setNavigationStack((prev) => [...prev, item]) }, [])
40
- const canGoBack = navigationStack.length > 1
41
- const goBack = useCallback(() => {
42
- if (canGoBack) {
43
- setNavigationStack((prev) => prev.slice(0, -1))
44
- }
45
- }, [canGoBack])
46
-
47
- const navigationContext = useMemo(() => ({ navigate, goBack, canGoBack, currentItem }), [navigate, goBack, canGoBack, currentItem])
48
- const Component = components[currentItem.component]
49
- const isFullScreen = currentItem.fullScreen
50
-
51
- if (!Component) {
52
- // eslint-disable-next-line no-console
53
- console.error(`Componente not found: ${String(currentItem.component)}`)
54
- }
55
-
56
- return (<NavigationContext.Provider value={navigationContext as NavigationContextType<NavigationMap>}>
57
- <div className={`content-navigator ${className || isFullScreen ? 'full' : ''}`} role="navigation">
58
- {canGoBack && (
59
- <Flex alignItems="center" w={12} sx={{ gap: '4px' }}>
60
- <IconButton onClick={goBack} appearance="square" className="back-button" aria-label="Back">
61
- <ArrowLeft />
62
- </IconButton>
63
- {renderTitle?.(currentItem)}
64
- </Flex>
65
- )}
66
- <Component {...(currentItem.props as any)} />
67
- </div>
68
- </NavigationContext.Provider>
69
- )
70
- }
71
-
72
- export function useComponentNavigation<T extends NavigationMap>(): NavigationContextType<T> {
73
- const context = useContext(NavigationContext)
74
- if (!context) {
75
- throw new Error('useComponentNavigation should be used inside ComponentNavigator')
76
- }
77
- return context
78
- }
@@ -1,76 +0,0 @@
1
- import { Box, Flex, Text } from '@citric/core'
2
- import { WithStyle } from '@stack-spot/portal-theme'
3
- import { useMemo } from 'react'
4
-
5
-
6
- interface ListGroupProps<T> extends WithStyle {
7
- /**
8
- * The list available.
9
- */
10
- list: T[],
11
- /**
12
- * A function that renders an option as a label. This can either return a string or a React Element.
13
- */
14
- renderLabel: (item: T) => React.ReactNode,
15
- /**
16
- * A function that renders an option as a description. This can either return a string or a React Element.
17
- */
18
- renderDescription?: (item: T) => React.ReactNode,
19
- /**
20
- * A function that renders a element before the content
21
- */
22
- renderBeforeElement?: (item: T) => React.ReactNode,
23
- /**
24
- * A function that renders a element after the content
25
- */
26
- renderAfterElement?: (item: T) => React.ReactNode,
27
- /**
28
- * A function that gives a custom className to the rendered option.
29
- */
30
- optionClassName?: (item: T) => string | undefined,
31
- /**
32
- * A function that gives a custom style to the rendered option.
33
- */
34
- optionStyle?: (item: T) => React.CSSProperties | undefined,
35
- /**
36
- * A function that generates a unique id for the option.
37
- */
38
- keygen: (item: T) => React.Key,
39
- /**
40
- * A function to call whenever the item click.
41
- */
42
- onClick: (item: T) => void,
43
- }
44
-
45
- /**
46
- * Renders a radio button group where each option has a label and a description.
47
- * The description in placed under the label and radio button as an accordion.
48
- */
49
- export function ListGroup<T>(
50
- {
51
- list,
52
- renderLabel,
53
- renderBeforeElement,
54
- renderAfterElement,
55
- className,
56
- keygen,
57
- style }: ListGroupProps<T>,
58
- ) {
59
- const items = useMemo(() => list.map((listItem) => {
60
- const label = renderLabel(listItem)
61
- const content = typeof label === 'string' ? <Text>{label}</Text> : label
62
-
63
- return (
64
- <li key={keygen(listItem)}>
65
- <Flex alignItems="center">
66
- {renderBeforeElement?.(listItem)}
67
- {content}
68
- {renderAfterElement?.(listItem)}
69
- </Flex>
70
- </li>
71
- )
72
- }), [list])
73
-
74
- return <Box as="ul" m={0} p={0} w={12} style={style} className={className}>{items}</Box>
75
- }
76
-
@@ -1,177 +0,0 @@
1
- import { Box, Flex, IconBox, Image, 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
- interface CardSpaceProps {
16
- onClick: VoidFunction,
17
- name: string,
18
- icon: React.ReactElement,
19
- logoUrl?: string | null,
20
- }
21
-
22
- export const CardSpace = ({ onClick, name, icon, logoUrl }: CardSpaceProps) =>
23
- <Flex
24
- onClick={onClick}
25
- flex={1}
26
- alignItems="center"
27
- justifyContent="space-between"
28
- mr={2}
29
- bg="light.400"
30
- r="sm"
31
- p={3}
32
- sx={{ cursor: 'pointer' }}
33
- >
34
- <Flex alignContent="center" alignItems="center" sx={{ gap: '8px', m: 1 }} >
35
- <Avatar size="xxs" appearance="square" sx={{ bg: 'light.600', r: 'xxs' }}>
36
- {logoUrl ? <Image src={logoUrl} /> : <IconBox> {icon} </IconBox>}
37
- </Avatar>
38
- <Text appearance="body2">{name}</Text>
39
- </Flex>
40
- <IconButton><ArrowRight /></IconButton>
41
- </Flex>
42
-
43
- interface WorkspaceSourcesTabProps {
44
- visibility: WorkspaceVisibilityLevelEnum,
45
- onClick: (workspace: WorkspaceResponse) => void,
46
- }
47
-
48
- const WorkspaceSourcesTab = ({ visibility, onClick }: WorkspaceSourcesTabProps) => {
49
- const t = useTranslate(dictionary)
50
- const [filter, setFilter] = useState('')
51
- const workspaces = workspaceAiClient.workspacesAi.useQuery({ visibility })
52
- const listFavorites = workspaceAiClient.workspacesAi.useQuery({ visibility: 'favorite' })
53
- const [addFavorite, pendingAddFav] = workspaceAiClient.addFavoriteWorkspaceAi.useMutation()
54
- const [removeFavorite, pendingRemoveFav] = workspaceAiClient.removeFavoriteWorkspaceAi.useMutation()
55
-
56
- // eslint-disable-next-line no-async-promise-executor
57
- const onAddFavorite = async (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
58
- try {
59
- await addFavorite({ workspaceId: idOrSlug })
60
- await workspaceAiClient.workspacesAi.invalidate()
61
- if (!pendingAddFav) {
62
- resolve(true)
63
- }
64
- } catch (error) {
65
- // eslint-disable-next-line no-console
66
- console.error(error)
67
- reject(error)
68
- }
69
- })
70
-
71
- // eslint-disable-next-line no-async-promise-executor
72
- const onRemoveFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
73
- try {
74
- await removeFavorite({ workspaceId: idOrSlug })
75
- await workspaceAiClient.workspacesAi.invalidate()
76
- if (!pendingRemoveFav) {
77
- resolve(true)
78
- }
79
- } catch (error) {
80
- // eslint-disable-next-line no-console
81
- console.error(error)
82
- reject(error)
83
- }
84
- })
85
-
86
- const filtered = useMemo(
87
- // Recreate the list so that the favorites list is taken into account
88
- () => filter ? workspaces.filter(w => w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : [...workspaces],
89
- [workspaces, filter, listFavorites],
90
- )
91
-
92
- return (
93
- <>
94
- <Box w={12}>
95
- <IconInput icon={<Search />} value={filter} onChange={setFilter} className="search" />
96
- </Box>
97
-
98
- {!!filtered.length &&
99
- <ListGroup
100
- list={filtered}
101
- keygen={w => w.id}
102
- onClick={onClick}
103
- style={{ gap: '6px', display: 'flex', flexDirection: 'column' }}
104
- renderLabel={w => <CardSpace name={w.name} logoUrl={w.logo} icon={<Circle />} onClick={() => onClick(w)} />}
105
- renderDescription={w => w.description}
106
- renderAfterElement={(w) =>
107
- <ButtonFavorite favorite={{ idOrSlug: w?.id, listFavorites, onAddFavorite, onRemoveFavorite }} />}
108
- optionClassName={w => (filter && !w.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
109
- ? 'filtered-out'
110
- : ''
111
- }
112
- className="option-list"
113
- />
114
- }
115
- <Box w={12}>
116
- {!!workspaces.length && !filtered.length &&
117
- <Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} className="no-data-placeholder" />}
118
- {!workspaces.length && <Placeholder title={t.noData} description={t.noDataDescription} />}
119
- </Box>
120
- </>
121
- )
122
- }
123
-
124
-
125
- const WorkspaceHeader = <T extends NavigationMap, K extends keyof T>({ data }: { data: NavigationItem<T, K> }) => {
126
- const { close: closeRightPanel } = useRightPanel()
127
- const workspaceId = (data.props as any)['workspaceId']
128
- if (!workspaceId) return
129
-
130
- const workspace = workspaceAiClient.workspaceAi.useQuery({ id: workspaceId })
131
- return <Flex justifyContent="space-between" alignItems="center" flex={1}>
132
- {data.component === 'workspaceResource' ? 'Spaces' : workspace.name}
133
- {data.fullScreen && <IconButton title={'t.close'} aria-label={'t.close'} onClick={closeRightPanel}> <Times /> </IconButton>}
134
- </Flex>
135
- }
136
-
137
- interface WorkspaceTabNavigatorProps {
138
- getNavigateParam: (workspace: WorkspaceResponse) => NavigationItem<NavigationMap, string>,
139
- visibility?: WorkspaceVisibilityLevelEnum,
140
- className?: string,
141
- }
142
- export function WorkspaceTabNavigator<T extends NavigationMap, K extends keyof T>({ components, getNavigateParam, visibility, className }:
143
- Omit<ComponentNavigatorProps<T, K>, 'initialItem'> & WorkspaceTabNavigatorProps) {
144
-
145
- const workspaceTabComponents = useMemo(() => ({
146
- workspace: memo(function WorkspacesTab() {
147
- const { navigate } = useComponentNavigation()
148
- return (<WorkspaceSourcesTab visibility={visibility ?? 'all'} onClick={(w) => navigate(getNavigateParam(w))} />)
149
- }),
150
- ...components,
151
- }), [components])
152
-
153
- return <ComponentNavigator
154
- initialItem={{ component: 'workspace' }}
155
- components={workspaceTabComponents}
156
- className={className}
157
- renderTitle={(data) => <WorkspaceHeader data={data} />}
158
- />
159
- }
160
-
161
- const dictionary = {
162
- en: {
163
- noSearchResults: "Your search didn't yield results.",
164
- noSearchResultsDescription: 'Please, try another search term.',
165
- noData: 'There are no spaces yet.',
166
- noDataDescription: 'Use the AI portal to create new spaces.',
167
- apply: 'Apply',
168
- },
169
- pt: {
170
- noSearchResults: 'Sua busca não produziu resultados',
171
- noSearchResultsDescription: 'Por favor, tente outra busca.',
172
- noData: 'Ainda não há spaces.',
173
- noDataDescription: 'Use o Portal AI para criar novos spaces.',
174
- apply: 'Apply',
175
- },
176
- } satisfies Dictionary
177
-
@@ -1,121 +0,0 @@
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 { Loading } from '../../components/FallbackBoundary/Loading'
10
- import { ListGroup } from '../../components/ListGroup'
11
- import { CardSpace, WorkspaceTabNavigator } from '../../components/WorkspaceTabNavigator'
12
- import { ChatProperties } from '../../state/ChatState'
13
- import { AgentsTab } from '../Agents/AgentsTab'
14
- import { KnowledgeSourcesTab } from '../KnowledgeSources'
15
- import { StacksTab } from '../Stacks'
16
-
17
- const SpaceCard = ({ workspaceId }: { workspaceId: string }) => {
18
- const workspace = workspaceAiClient.workspaceAi.useQuery({ id: workspaceId })
19
- return <Flex flexDirection="column" sx={{ gap: '8px' }}>
20
- <Flex flexDirection="column" sx={{ gap: '4px' }}>
21
- <Flex alignContent="center" alignItems="center" sx={{ gap: '8px', m: 1 }} >
22
- <Avatar size="xxs" appearance="square" sx={{ bg: 'light.600', r: 'xxs' }}>
23
- {workspace.logo ? <Image src={workspace.logo} /> : <IconBox> <Circle /> </IconBox>}
24
- </Avatar>
25
- <Text appearance="body2" weight="medium">{workspace.name} </Text>
26
- </Flex>
27
- <Text colorScheme="light.700">{workspace.description}</Text>
28
- </Flex>
29
- </Flex>
30
- }
31
-
32
- export interface TabProps {
33
- visibility: WorkspaceVisibilityLevelEnum,
34
- allKS: React.MutableRefObject<ChatProperties['knowledgeSources']>,
35
- agent: React.MutableRefObject<ChatProperties['agent']>,
36
- stack: React.MutableRefObject<ChatProperties['stack']>,
37
- workspaceId?: string,
38
- onSubmit: () => void,
39
- }
40
-
41
- export interface WorkspaceResource {
42
- id: string,
43
- resourceType: 'agent' | 'ks' | 'stack',
44
- displayName: string,
45
- icon: React.ReactElement,
46
- workspaceId?: string,
47
- }
48
-
49
- const showSubmitButton = false
50
-
51
- export const WorkspaceResources = ({ workspaceId, allKS, agent, stack }: Omit<TabProps, 'onSubmit'>) => {
52
- const { navigate } = useComponentNavigation<typeof workspaceTabComponents>()
53
- const [isPending, startTransition] = useTransition()
54
- const resourceTypes: WorkspaceResource[] = [
55
- { id: 'agents', resourceType: 'agent', displayName: 'Agents', workspaceId, icon: <Agent /> },
56
- { id: 'ks', resourceType: 'ks', displayName: 'Knowledge Sources', workspaceId, icon: <KnowledgeSource /> },
57
- { id: 'stack', resourceType: 'stack', displayName: 'Stacks', workspaceId, icon: <Stack /> },
58
- ]
59
-
60
- const handleNavigate = (resource: WorkspaceResource) => {
61
- startTransition(() => {
62
- if (resource.resourceType === 'agent')
63
- navigate({ component: 'agent', props: { visibility: 'WORKSPACE', agent, workspaceId, showSubmitButton }, fullScreen: true })
64
-
65
- if (resource.resourceType === 'ks')
66
- navigate({ component: 'ks', props: { visibility: 'workspace', allKS, workspaceId, showSubmitButton }, fullScreen: true })
67
-
68
- if (resource.resourceType === 'stack')
69
- navigate({ component: 'stack', props: { visibility: 'workspace', stack, workspaceId, showSubmitButton }, fullScreen: true })
70
- })
71
- }
72
-
73
- return (<>
74
- {workspaceId && <SpaceCard workspaceId={workspaceId} />}
75
- {isPending ? <Loading /> :
76
- <ListGroup
77
- list={resourceTypes}
78
- keygen={w => w.id}
79
- onClick={(resource) => { handleNavigate(resource) }}
80
- renderLabel={r => <CardSpace name={r.displayName} icon={r.icon} onClick={() => handleNavigate(r)} />}
81
- style={{ gap: '6px', display: 'flex', flexDirection: 'column' }}
82
- />
83
- }
84
- </>
85
- )
86
- }
87
-
88
- const workspaceTabComponents = {
89
- workspaceResource: WorkspaceResources,
90
- agent: AgentsTab,
91
- ks: KnowledgeSourcesTab,
92
- stack: StacksTab,
93
- }
94
-
95
- export function WorkspacesTab({ visibility, allKS, agent, stack, onSubmit }: TabProps) {
96
- const t = useTranslate(dictionary)
97
- const buildNavigateParams = (workspace: WorkspaceResponse) => ({
98
- component: 'workspaceResource',
99
- props: { allKS, agent, stack, visibility, workspaceId: workspace.id } satisfies Omit<TabProps, 'onSubmit'>,
100
- fullScreen: true,
101
- })
102
-
103
- return (<>
104
- <WorkspaceTabNavigator
105
- components={workspaceTabComponents}
106
- getNavigateParam={buildNavigateParams}
107
- visibility={visibility}
108
- />
109
- <Button className="workspace-submit" onClick={onSubmit} >{t.apply}</Button>
110
- </>
111
- )
112
- }
113
-
114
- const dictionary = {
115
- en: {
116
- apply: 'Apply',
117
- },
118
- pt: {
119
- apply: 'Aplicar',
120
- },
121
- } satisfies Dictionary
@@ -1,85 +0,0 @@
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