Skip to content

Commit 679c341

Browse files
fix(selectors-hydration): confluence, jira, teams (#1907)
* fix(jira): issue and project selector * fix endpoints * remove # for selector * fix chat selector * add preview card for jira * fix inf calls for teams * fix inf teams calls * inf confluence calls * fix confluence selector * add small # back for slack channel selector * fix wealthbox selector
1 parent 7b48d6e commit 679c341

File tree

7 files changed

+236
-86
lines changed

7 files changed

+236
-86
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/channel-selector/components/slack-channel-selector.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,7 @@ export function SlackChannelSelector({
147147
<div className='flex max-w-[calc(100%-20px)] items-center gap-2 overflow-hidden'>
148148
<SlackIcon className='h-4 w-4 text-[#611f69]' />
149149
{cachedChannelName ? (
150-
<>
151-
<Hash className='h-1.5 w-1.5' />
152-
<span className='truncate font-normal'>{cachedChannelName}</span>
153-
</>
150+
<span className='truncate font-normal'>{cachedChannelName}</span>
154151
) : (
155152
<span className='truncate text-muted-foreground'>{label}</span>
156153
)}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/confluence-file-selector.tsx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,23 @@ export function ConfluenceFileSelector({
210210
}
211211

212212
const data = await response.json()
213-
if (data.file) {
214-
setSelectedFile(data.file)
215-
onFileInfoChange?.(data.file)
216-
} else {
217-
const fileInfo: ConfluenceFileInfo = {
218-
id: data.id || pageId,
219-
name: data.title || `Page ${pageId}`,
220-
mimeType: 'confluence/page',
221-
webViewLink: undefined,
222-
modifiedTime: undefined,
223-
spaceId: undefined,
224-
url: undefined,
225-
}
226-
setSelectedFile(fileInfo)
227-
onFileInfoChange?.(fileInfo)
213+
const fileInfo: ConfluenceFileInfo = {
214+
id: data.id || pageId,
215+
name: data.title || `Page ${pageId}`,
216+
mimeType: 'confluence/page',
217+
webViewLink: `https://${domain}/wiki/pages/${data.id}`,
218+
modifiedTime: data.version?.when,
219+
spaceId: data.spaceId,
220+
url: `https://${domain}/wiki/pages/${data.id}`,
221+
}
222+
setSelectedFile(fileInfo)
223+
onFileInfoChange?.(fileInfo)
224+
225+
// Cache the page name in display names store
226+
if (selectedCredentialId) {
227+
useDisplayNamesStore
228+
.getState()
229+
.setDisplayNames('files', selectedCredentialId, { [fileInfo.id]: fileInfo.name })
228230
}
229231
} catch (error) {
230232
logger.error('Error fetching page info:', error)
@@ -394,6 +396,13 @@ export function ConfluenceFileSelector({
394396
}
395397
}, [value, onFileInfoChange])
396398

399+
// Fetch page info on mount if we have a value but no selectedFile state
400+
useEffect(() => {
401+
if (value && selectedCredentialId && domain && !selectedFile) {
402+
fetchPageInfo(value)
403+
}
404+
}, [value, selectedCredentialId, domain, selectedFile, fetchPageInfo])
405+
397406
// Handle file selection
398407
const handleSelectFile = (file: ConfluenceFileInfo) => {
399408
setSelectedFileId(file.id)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/jira-issue-selector.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ export function JiraIssueSelector({
435435
}
436436
}, [value, onIssueInfoChange])
437437

438+
// Fetch issue info on mount if we have a value but no selectedIssue state
439+
useEffect(() => {
440+
if (value && selectedCredentialId && domain && projectId && !selectedIssue) {
441+
fetchIssueInfo(value)
442+
}
443+
}, [value, selectedCredentialId, domain, projectId, selectedIssue, fetchIssueInfo])
444+
438445
// Handle issue selection
439446
const handleSelectIssue = (issue: JiraIssueInfo) => {
440447
setSelectedIssueId(issue.id)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/teams-message-selector.tsx

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export function TeamsMessageSelector({
8484
const initialFetchRef = useRef(false)
8585
const [error, setError] = useState<string | null>(null)
8686
const [selectionStage, setSelectionStage] = useState<'team' | 'channel' | 'chat'>(selectionType)
87+
const lastRestoredValueRef = useRef<string | null>(null)
8788

8889
// Get cached display name
8990
const cachedMessageName = useDisplayNamesStore(
@@ -240,6 +241,18 @@ export function TeamsMessageSelector({
240241

241242
setChannels(channelsData)
242243

244+
// Cache channel names in display names store
245+
if (selectedCredentialId && channelsData.length > 0) {
246+
const channelMap = channelsData.reduce(
247+
(acc: Record<string, string>, channel: TeamsMessageInfo) => {
248+
acc[channel.channelId!] = channel.displayName
249+
return acc
250+
},
251+
{}
252+
)
253+
useDisplayNamesStore.getState().setDisplayNames('files', selectedCredentialId, channelMap)
254+
}
255+
243256
// If we have a selected channel ID, find it in the list
244257
if (selectedChannelId) {
245258
const channel = channelsData.find(
@@ -304,6 +317,14 @@ export function TeamsMessageSelector({
304317

305318
setChats(chatsData)
306319

320+
if (selectedCredentialId && chatsData.length > 0) {
321+
const chatMap = chatsData.reduce((acc: Record<string, string>, chat: TeamsMessageInfo) => {
322+
acc[chat.id] = chat.displayName
323+
return acc
324+
}, {})
325+
useDisplayNamesStore.getState().setDisplayNames('files', selectedCredentialId, chatMap)
326+
}
327+
307328
// If we have a selected chat ID, find it in the list
308329
if (selectedChatId) {
309330
const chat = chatsData.find((c: TeamsMessageInfo) => c.chatId === selectedChatId)
@@ -547,6 +568,19 @@ export function TeamsMessageSelector({
547568

548569
if (response.ok) {
549570
const data = await response.json()
571+
572+
// Cache all chat names
573+
if (data.chats && selectedCredentialId) {
574+
const chatMap = data.chats.reduce(
575+
(acc: Record<string, string>, c: { id: string; displayName: string }) => {
576+
acc[c.id] = c.displayName
577+
return acc
578+
},
579+
{}
580+
)
581+
useDisplayNamesStore.getState().setDisplayNames('files', selectedCredentialId, chatMap)
582+
}
583+
550584
const chat = data.chats.find((c: { id: string; displayName: string }) => c.id === chatId)
551585
if (chat) {
552586
const chatInfo: TeamsMessageInfo = {
@@ -691,14 +725,20 @@ export function TeamsMessageSelector({
691725
// Restore selection whenever the canonical value changes
692726
useEffect(() => {
693727
if (value && selectedCredentialId) {
694-
if (selectionType === 'team') {
695-
restoreTeamSelection(value)
696-
} else if (selectionType === 'chat') {
697-
restoreChatSelection(value)
698-
} else if (selectionType === 'channel') {
699-
restoreChannelSelection(value)
728+
// Only restore if we haven't already restored this value
729+
if (lastRestoredValueRef.current !== value) {
730+
lastRestoredValueRef.current = value
731+
732+
if (selectionType === 'team') {
733+
restoreTeamSelection(value)
734+
} else if (selectionType === 'chat') {
735+
restoreChatSelection(value)
736+
} else if (selectionType === 'channel') {
737+
restoreChannelSelection(value)
738+
}
700739
}
701740
} else {
741+
lastRestoredValueRef.current = null
702742
setSelectedMessage(null)
703743
}
704744
}, [

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/wealthbox-file-selector.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ export function WealthboxFileSelector({
194194
if (data.item) {
195195
setSelectedItem(data.item)
196196
onFileInfoChange?.(data.item)
197+
198+
// Cache the item name in display names store
199+
if (selectedCredentialId) {
200+
useDisplayNamesStore
201+
.getState()
202+
.setDisplayNames('files', selectedCredentialId, { [data.item.id]: data.item.name })
203+
}
204+
197205
return data.item
198206
}
199207
} else {
@@ -233,7 +241,20 @@ export function WealthboxFileSelector({
233241
}
234242
}, [selectedCredentialId, open, fetchAvailableItems])
235243

236-
// Fetch the selected item metadata only once when needed
244+
// Fetch item info on mount if we have a value but no selectedItem state
245+
useEffect(() => {
246+
if (value && selectedCredentialId && !selectedItem) {
247+
fetchItemById(value)
248+
}
249+
}, [value, selectedCredentialId, selectedItem, fetchItemById])
250+
251+
// Clear selectedItem when value is cleared
252+
useEffect(() => {
253+
if (!value) {
254+
setSelectedItem(null)
255+
onFileInfoChange?.(null)
256+
}
257+
}, [value, onFileInfoChange])
237258

238259
// Handle search input changes with debouncing
239260
const handleSearchChange = useCallback(

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/project-selector/components/jira-project-selector.tsx

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
4-
import { Check, ChevronDown, RefreshCw } from 'lucide-react'
4+
import { Check, ChevronDown, ExternalLink, RefreshCw, X } from 'lucide-react'
55
import { JiraIcon } from '@/components/icons'
66
import { Button } from '@/components/ui/button'
77
import {
@@ -74,6 +74,7 @@ export function JiraProjectSelector({
7474
const [projects, setProjects] = useState<JiraProjectInfo[]>([])
7575
const [selectedCredentialId, setSelectedCredentialId] = useState<string>(credentialId || '')
7676
const [selectedProjectId, setSelectedProjectId] = useState(value)
77+
const [selectedProject, setSelectedProject] = useState<JiraProjectInfo | null>(null)
7778
const [isLoading, setIsLoading] = useState(false)
7879
const [showOAuthModal, setShowOAuthModal] = useState(false)
7980
const initialFetchRef = useRef(false)
@@ -210,8 +211,10 @@ export function JiraProjectSelector({
210211
}
211212

212213
if (projectInfo) {
214+
setSelectedProject(projectInfo)
213215
onProjectInfoChange?.(projectInfo)
214216
} else {
217+
setSelectedProject(null)
215218
onProjectInfoChange?.(null)
216219
}
217220
} catch (error) {
@@ -322,6 +325,7 @@ export function JiraProjectSelector({
322325
(project: JiraProjectInfo) => project.id === selectedProjectId
323326
)
324327
if (projectInfo) {
328+
setSelectedProject(projectInfo)
325329
onProjectInfoChange?.(projectInfo)
326330
} else if (!searchQuery && selectedProjectId) {
327331
// If we can't find the project in the list, try to fetch it directly
@@ -370,10 +374,18 @@ export function JiraProjectSelector({
370374
// Clear callback when value is cleared
371375
useEffect(() => {
372376
if (!value) {
377+
setSelectedProject(null)
373378
onProjectInfoChange?.(null)
374379
}
375380
}, [value, onProjectInfoChange])
376381

382+
// Fetch project info on mount if we have a value but no selectedProject state
383+
useEffect(() => {
384+
if (value && selectedCredentialId && domain && !selectedProject) {
385+
fetchProjectInfo(value)
386+
}
387+
}, [value, selectedCredentialId, domain, selectedProject, fetchProjectInfo])
388+
377389
// Handle open change
378390
const handleOpenChange = (isOpen: boolean) => {
379391
setOpen(isOpen)
@@ -386,6 +398,7 @@ export function JiraProjectSelector({
386398
// Handle project selection
387399
const handleSelectProject = (project: JiraProjectInfo) => {
388400
setSelectedProjectId(project.id)
401+
setSelectedProject(project)
389402
onChange(project.id, project)
390403
onProjectInfoChange?.(project)
391404
setOpen(false)
@@ -401,6 +414,7 @@ export function JiraProjectSelector({
401414
// Clear selection
402415
const handleClearSelection = () => {
403416
setSelectedProjectId('')
417+
setSelectedProject(null)
404418
setError(null)
405419
onChange('', undefined)
406420
onProjectInfoChange?.(null)
@@ -558,6 +572,55 @@ export function JiraProjectSelector({
558572
</PopoverContent>
559573
)}
560574
</Popover>
575+
576+
{/* Project preview */}
577+
{showPreview && selectedProject && (
578+
<div className='relative mt-2 rounded-md border border-muted bg-muted/10 p-2'>
579+
<div className='absolute top-2 right-2'>
580+
<Button
581+
variant='ghost'
582+
size='icon'
583+
className='h-5 w-5 hover:bg-muted'
584+
onClick={handleClearSelection}
585+
>
586+
<X className='h-3 w-3' />
587+
</Button>
588+
</div>
589+
<div className='flex items-center gap-3 pr-4'>
590+
<div className='flex h-6 w-6 flex-shrink-0 items-center justify-center rounded bg-muted/20'>
591+
{selectedProject.avatarUrl ? (
592+
<img
593+
src={selectedProject.avatarUrl}
594+
alt={selectedProject.name}
595+
className='h-6 w-6 rounded'
596+
/>
597+
) : (
598+
<JiraIcon className='h-4 w-4' />
599+
)}
600+
</div>
601+
<div className='min-w-0 flex-1 overflow-hidden'>
602+
<div className='flex items-center gap-2'>
603+
<h4 className='truncate font-medium text-xs'>{selectedProject.name}</h4>
604+
<span className='whitespace-nowrap text-muted-foreground text-xs'>
605+
{selectedProject.key}
606+
</span>
607+
</div>
608+
{selectedProject.url ? (
609+
<a
610+
href={selectedProject.url}
611+
target='_blank'
612+
rel='noopener noreferrer'
613+
className='flex items-center gap-1 text-foreground text-xs hover:underline'
614+
onClick={(e) => e.stopPropagation()}
615+
>
616+
<span>Open in Jira</span>
617+
<ExternalLink className='h-3 w-3' />
618+
</a>
619+
) : null}
620+
</div>
621+
</div>
622+
</div>
623+
)}
561624
</div>
562625

563626
{showOAuthModal && (

0 commit comments

Comments
 (0)