@stack-spot/ai-chat-widget 2.9.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/app-metadata.json +3 -3
  3. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
  4. package/dist/chat-interceptors/quick-commands.js +14 -5
  5. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  6. package/dist/components/Selector/index.d.ts +11 -2
  7. package/dist/components/Selector/index.d.ts.map +1 -1
  8. package/dist/components/Selector/index.js +18 -17
  9. package/dist/components/Selector/index.js.map +1 -1
  10. package/dist/components/form/DescribedCheckboxGroup.d.ts +3 -1
  11. package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
  12. package/dist/components/form/DescribedCheckboxGroup.js +31 -19
  13. package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
  14. package/dist/views/Agents/AgentsTab.js.map +1 -1
  15. package/dist/views/KnowledgeSources.d.ts.map +1 -1
  16. package/dist/views/KnowledgeSources.js +31 -17
  17. package/dist/views/KnowledgeSources.js.map +1 -1
  18. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  19. package/dist/views/MessageInput/AgentSelector.js +8 -6
  20. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  21. package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
  22. package/dist/views/MessageInput/QuickCommandSelector.js +12 -8
  23. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/app-metadata.json +3 -3
  26. package/src/chat-interceptors/quick-commands.ts +14 -5
  27. package/src/components/Selector/index.tsx +46 -33
  28. package/src/components/form/DescribedCheckboxGroup.tsx +61 -35
  29. package/src/views/Agents/AgentsTab.tsx +5 -5
  30. package/src/views/KnowledgeSources.tsx +59 -36
  31. package/src/views/MessageInput/AgentSelector.tsx +10 -8
  32. package/src/views/MessageInput/QuickCommandSelector.tsx +33 -23
@@ -2,6 +2,7 @@ import { Button, Tab } from '@stack-spot/citric-react'
2
2
  import { Placeholder } from '@stack-spot/portal-components/Placeholder'
3
3
  import { aiClient, dataIntegrationClient, workspaceAiClient } from '@stack-spot/portal-network'
4
4
  import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
5
+ import { KnowledgeSourceItemResponse } from '@stack-spot/portal-network/api/dataIntegration'
5
6
  import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
6
7
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
7
8
  import React, { useCallback, useEffect, useMemo, useRef } from 'react'
@@ -64,13 +65,19 @@ const KnowledgeSourcesPanel = () => {
64
65
  }, [chat])
65
66
 
66
67
  const allTabsMap: Partial<Record<Scope, Omit<Tab, 'key'>>> = {
67
- favorite: { label: t.favorites,
68
- content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
69
- personal: { label: t.personal,
70
- content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
68
+ favorite: {
69
+ label: t.favorites,
70
+ content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} />,
71
+ },
72
+ personal: {
73
+ label: t.personal,
74
+ content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} />,
75
+ },
71
76
  shared: { label: t.shared, content: <KnowledgeSourcesTab key="shared" visibility="shared" allKS={allKS} onSubmit={onSubmit} /> },
72
- workspace: { label: t.spots,
73
- content: <KnowledgeSourcesTabWorkspace key="workspace" visibility="workspace" allKS={allKS} onSubmit={onSubmit} /> },
77
+ workspace: {
78
+ label: t.spots,
79
+ content: <KnowledgeSourcesTabWorkspace key="workspace" visibility="workspace" allKS={allKS} onSubmit={onSubmit} />,
80
+ },
74
81
  account: { label: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
75
82
  }
76
83
 
@@ -95,16 +102,29 @@ const KnowledgeSourcesPanel = () => {
95
102
 
96
103
  export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId, showSubmitButton = true }: TabProps) => {
97
104
  const t = useTranslate(dictionary)
98
- const knowledgeSources = workspaceId
99
- ? workspaceAiClient.getKSFromWorkspaceAi.useQuery({ workspaceId })
100
- : aiClient.knowledgeSources.useQuery({
101
- visibility, order: 'a-to-z', types: ['snippet', 'api', 'event', 'custom'],
102
- })
105
+ const [data = []] = workspaceAiClient.getKSFromWorkspaceAi.useStatefulQuery(
106
+ { workspaceId: workspaceId! }, { enabled: !!workspaceId })
107
+ const workspaceKs = data as KnowledgeSourceItemResponse[]
108
+
109
+ const [ksListPages = [], { fetchNextPage, hasNextPage }] = dataIntegrationClient.knowledgeSourcesV2.useInfiniteQuery(
110
+ {
111
+ order: 'a-to-z',
112
+ visibilityList: visibility ? [visibility] : [],
113
+ types: ['snippet', 'api', 'event', 'custom'],
114
+ size: 20,
115
+ page: 1,
116
+ },
117
+ { enabled: !workspaceId },
118
+ )
119
+ const knowledgeSources = workspaceId ? workspaceKs : ksListPages
120
+
103
121
  const initialValue = useMemo(() => {
104
122
  const currentlySelected = allKS.current?.map(ks => ks.id)
105
- return knowledgeSources.filter(ks => currentlySelected?.includes(ks.slug))
106
- }, [])
107
- const listFavorites = dataIntegrationClient.knowledgeSources.useQuery({ visibility: 'favorite' })
123
+ return knowledgeSources?.filter((ks: KnowledgeSourceItemResponse) => currentlySelected?.includes(ks.slug))
124
+ }, [knowledgeSources])
125
+
126
+ const listFavorites = dataIntegrationClient.knowledgeSourcesV2.useQuery({ visibilityList: ['favorite'] })?.items
127
+
108
128
  const [addFavorite, pendingAddFav] = dataIntegrationClient.addFavoriteKnowledgeSource.useMutation()
109
129
  const [removeFavorite, pendingRemoveFav] = dataIntegrationClient.removeFavoriteKnowledgeSource.useMutation()
110
130
 
@@ -112,7 +132,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
112
132
  try {
113
133
  await removeFavorite({ slug: idOrSlug })
114
134
  await aiClient.knowledgeSources.invalidate()
115
- await dataIntegrationClient.knowledgeSources.invalidate()
135
+ await dataIntegrationClient.knowledgeSourcesV2.invalidate()
116
136
  } catch (error) {
117
137
  // eslint-disable-next-line no-console
118
138
  console.error(error)
@@ -123,7 +143,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
123
143
  const onRemoveFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
124
144
  try {
125
145
  await removeFavoriteKs(idOrSlug)
126
- if (!pendingRemoveFav){
146
+ if (!pendingRemoveFav) {
127
147
  resolve(true)
128
148
  }
129
149
 
@@ -131,14 +151,14 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
131
151
  // eslint-disable-next-line no-console
132
152
  console.error(error)
133
153
  reject(error)
134
- }
154
+ }
135
155
  })
136
156
 
137
157
  const addFavoriteKs = async (idOrSlug: string) => {
138
158
  try {
139
159
  await addFavorite({ slug: idOrSlug })
140
160
  await aiClient.knowledgeSources.invalidate()
141
- await dataIntegrationClient.knowledgeSources.invalidate()
161
+ await dataIntegrationClient.knowledgeSourcesV2.invalidate()
142
162
  } catch (error) {
143
163
  // eslint-disable-next-line no-console
144
164
  console.error(error)
@@ -149,7 +169,7 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
149
169
  const onAddFavorite = (idOrSlug: string) => new Promise<boolean>(async (resolve, reject) => {
150
170
  try {
151
171
  await addFavoriteKs(idOrSlug)
152
- if (!pendingAddFav){
172
+ if (!pendingAddFav) {
153
173
  resolve(true)
154
174
  }
155
175
 
@@ -157,23 +177,27 @@ export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId,
157
177
  // eslint-disable-next-line no-console
158
178
  console.error(error)
159
179
  reject(error)
160
- }
180
+ }
161
181
  })
162
182
 
163
- return (
164
- <>
165
- <div className="content">
166
- <DescribedCheckboxGroup
167
- options={knowledgeSources}
168
- initialValue={initialValue}
169
- globalSelection={allKS}
170
- data={ks => ({ idOrSlug: ks.slug, description: ks.description, name: ks.name, listFavorites, onAddFavorite, onRemoveFavorite })}
171
- emptyResults={<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />}
172
- emptyDataset={<Placeholder title={t.noData} description={t.noDataDescription} className="no-data-placeholder" />}
173
- />
174
- </div>
175
- {!!knowledgeSources.length && showSubmitButton && <Button onClick={onSubmit}>{t.apply}</Button>}
176
- </>
183
+ return (<>
184
+ <div className="content">
185
+ <DescribedCheckboxGroup
186
+ options={knowledgeSources}
187
+ initialValue={initialValue}
188
+ globalSelection={allKS}
189
+ hasNextPage={hasNextPage && !workspaceId}
190
+ fetchNextPage={fetchNextPage}
191
+ data={(ks: KnowledgeSourceItemResponse) => ({
192
+ idOrSlug: ks.slug, description: ks.description, name: ks.name, listFavorites,
193
+ onAddFavorite, onRemoveFavorite,
194
+ })}
195
+ emptyResults={<Placeholder title={t.noSearchResults} description={t.noSearchResultsDescription} />}
196
+ emptyDataset={<Placeholder title={t.noData} description={t.noDataDescription} className="no-data-placeholder" />}
197
+ />
198
+ </div>
199
+ {!!knowledgeSources?.length && showSubmitButton && <Button onClick={onSubmit}>{t.apply}</Button>}
200
+ </>
177
201
  )
178
202
  }
179
203
 
@@ -184,11 +208,10 @@ export function KnowledgeSourcesTabWorkspace({ allKS, onSubmit }: TabProps) {
184
208
  component: 'ks',
185
209
  props: { visibility: 'workspace', workspaceId: workspace.id, allKS, onSubmit },
186
210
  })
187
-
211
+
188
212
  return <WorkspaceTabNavigator components={workspaceTabComponents} getNavigateParam={buildNavigateParams} />
189
213
  }
190
214
 
191
-
192
215
  const dictionary = {
193
216
  en: {
194
217
  title: 'Knowledge Sources',
@@ -1,6 +1,7 @@
1
1
  import { Icon } from '@stack-spot/citric-icons'
2
2
  import { IconBox, Row, Text } from '@stack-spot/citric-react'
3
- import { AgentResponseWithBuiltIn, agentToolsClient, workspaceAiClient } from '@stack-spot/portal-network'
3
+ import { AgentResponseWithBuiltIn, agentToolsClient, AgentVisibilityLevel, workspaceAiClient } from '@stack-spot/portal-network'
4
+ import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/agent-tools'
4
5
  import { useCallback } from 'react'
5
6
  import { Selector } from '../../components/Selector'
6
7
  import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
@@ -54,18 +55,19 @@ export const AgentSelector = ({ inputRef, isTrial }: {
54
55
  }, [chat, inputRef])
55
56
 
56
57
 
57
- const getAgents = () => {
58
+ const getAgents = ({ filter, visibility }: {filter?: string, visibility?: AgentVisibilityLevel[] | VisibilityLevelEnum[]}) => {
58
59
  if (spotId) {
59
- return workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId: spotId }) as AgentResponseWithBuiltIn[]
60
+ return { data: workspaceAiClient.getAgentFromWorkspaceAi.useQuery({
61
+ workspaceId: spotId, name: filter }) as AgentResponseWithBuiltIn[] }
60
62
  }
61
63
 
62
64
  if (isTrial) {
63
- return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in', 'recently_used'] })
65
+ return { data: agentToolsClient.allAgents.useQuery({ visibilities: visibility as VisibilityLevelEnum[], filter }) }
64
66
  }
65
-
66
- return agentToolsClient.allAgents.useQuery({
67
- visibilities: ['account', 'shared', 'personal', 'built_in', 'recently_used', 'workspace'],
68
- })
67
+
68
+ return { data: agentToolsClient.allAgents.useQuery({
69
+ visibilities: visibility as VisibilityLevelEnum[], filter,
70
+ }) }
69
71
  }
70
72
 
71
73
  return <Selector
@@ -1,6 +1,6 @@
1
1
  import { Icon } from '@stack-spot/citric-icons'
2
- import { aiClient, workspaceAiClient } from '@stack-spot/portal-network'
3
- import { QuickCommandResponse } from '@stack-spot/portal-network/api/ai'
2
+ import { AgentVisibilityLevel, aiClient, workspaceAiClient } from '@stack-spot/portal-network'
3
+ import { QuickCommandResponse, VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
4
4
  import { useCallback } from 'react'
5
5
  import { Selector } from '../../components/Selector'
6
6
  import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
@@ -8,17 +8,16 @@ import { quickCommandRegex } from '../../regex'
8
8
 
9
9
  type QuickCommandResponseWithSpaceName = QuickCommandResponse & { spaceName?: string }
10
10
 
11
- export const QuickCommandSelector = ({ inputRef, isTrial }:
11
+ export const QuickCommandSelector = ({ inputRef, isTrial }:
12
12
  { isTrial: boolean, inputRef: React.RefObject<HTMLTextAreaElement | HTMLInputElement> }) => {
13
13
  const chat = useCurrentChat()
14
- const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
14
+ const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
15
15
  const spotId = useWidgetState('features')?.workspaceId
16
16
 
17
- const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' })
18
17
  const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
19
18
  const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteQuickCommand.useMutation()
20
19
 
21
- const addFavoriteQc = async(idOrSlug?: string) => {
20
+ const addFavoriteQc = async (idOrSlug?: string) => {
22
21
  try {
23
22
  await addFavorite({ slug: idOrSlug || '' })
24
23
  await aiClient.allQuickCommands.invalidate()
@@ -32,7 +31,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
32
31
  const onAddFavorite = (idOrSlug?: string) => new Promise<boolean>(async (resolve, reject) => {
33
32
  try {
34
33
  await addFavoriteQc(idOrSlug)
35
- if (!pendingAddFav){
34
+ if (!pendingAddFav) {
36
35
  resolve(true)
37
36
  }
38
37
 
@@ -40,10 +39,10 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
40
39
  // eslint-disable-next-line no-console
41
40
  console.error(error)
42
41
  reject(error)
43
- }
44
- })
42
+ }
43
+ })
45
44
 
46
- const removeFavoriteQc = async(idOrSlug?: string) => {
45
+ const removeFavoriteQc = async (idOrSlug?: string) => {
47
46
  try {
48
47
  await removeFavorite({ slug: idOrSlug || '' })
49
48
  await aiClient.allQuickCommands.invalidate()
@@ -57,7 +56,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
57
56
  const onRemoveFavorite = (idOrSlug?: string) => new Promise<boolean>(async (resolve, reject) => {
58
57
  try {
59
58
  await removeFavoriteQc(idOrSlug)
60
- if (!pendingRemoveFav){
59
+ if (!pendingRemoveFav) {
61
60
  resolve(true)
62
61
  }
63
62
 
@@ -65,9 +64,9 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
65
64
  // eslint-disable-next-line no-console
66
65
  console.error(error)
67
66
  reject(error)
68
- }
67
+ }
69
68
  })
70
-
69
+
71
70
  const onSelectItem = useCallback((qc: QuickCommandResponseWithSpaceName) => {
72
71
  const newValue = `/${qc.slug}`
73
72
  chat.set('nextMessage', newValue)
@@ -77,12 +76,19 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
77
76
  inputRef.current.focus()
78
77
  }, [chat, inputRef])
79
78
 
80
- const getQuickCommands = () => {
79
+ const getQuickCommands = ({ filter, visibility }: { filter?: string, visibility?: AgentVisibilityLevel[] | VisibilityLevelEnum[] }) => {
80
+
81
81
  if (spotId) {
82
- return workspaceAiClient.getQCFromWorkspaceAi.useQuery({ workspaceId: spotId })
82
+ return { data: workspaceAiClient.getQCFromWorkspaceAi.useQuery({ workspaceId: spotId, name: filter }) }
83
83
  }
84
84
 
85
- const quickCommands = aiClient.allQuickCommands.useQuery({ order: 'a-to-z' })
85
+ const [quickCommands, { fetchNextPage, hasNextPage }] = aiClient.allQuickCommandsV3.useInfiniteQuery({
86
+ order: 'a-to-z',
87
+ visibilityList: visibility as VisibilityLevelEnum[],
88
+ name: filter,
89
+ page: 1, size: 20,
90
+ })
91
+
86
92
  const quickCommandsFiltered = quickCommands.filter(
87
93
  (qc) => qc.visibility_level.toLowerCase() !== 'workspace',
88
94
  )
@@ -92,11 +98,17 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
92
98
  })
93
99
 
94
100
  const workspaceQuickCommandsWithWorkspaceName: QuickCommandResponseWithSpaceName[] =
95
- workspaceQuickCommands.flatMap(({ qcs, space_name }) =>
96
- qcs?.map((qc) => ({ ...qc, spaceName: space_name })),
97
- ) as QuickCommandResponseWithSpaceName[]
101
+ workspaceQuickCommands.flatMap(({ qcs, space_name }) =>
102
+ qcs?.map((qc) => ({ ...qc, spaceName: space_name })),
103
+ ) as QuickCommandResponseWithSpaceName[]
104
+
105
+ const filteredWorkspaceQuickCommand = filter ? workspaceQuickCommandsWithWorkspaceName?.filter((qc) =>
106
+ qc.name?.toLowerCase().includes(filter!)) : workspaceQuickCommandsWithWorkspaceName
98
107
 
99
- return [...quickCommandsFiltered, ...workspaceQuickCommandsWithWorkspaceName]
108
+ const data = !visibility ? [...quickCommandsFiltered, ...filteredWorkspaceQuickCommand] : (
109
+ visibility.includes('workspace') ? filteredWorkspaceQuickCommand : quickCommandsFiltered
110
+ )
111
+ return { data, fetchNextPage: fetchNextPage, hasNextPage }
100
112
  }
101
113
 
102
114
  const QuickCommandItem = ({ slug, description, spaceName }: QuickCommandResponseWithSpaceName) => <>
@@ -107,9 +119,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
107
119
 
108
120
  return <Selector
109
121
  inputRef={inputRef}
110
- favorite={{
111
- useFavorites, onAddFavorite, onRemoveFavorite, favoriteIsSlug: true,
112
- }}
122
+ favorite={{ onAddFavorite, onRemoveFavorite, favoriteIsSlug: true }}
113
123
  selectorConfig={{
114
124
  resourceName: 'Quick Command',
115
125
  shortcut: '/',