-
Notifications
You must be signed in to change notification settings - Fork 10
oint-1334 ConnectionCard and ConnectionStatus components #603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,7 +3,14 @@ import type {ConnectionExpanded, ConnectorName} from '@openint/api-v1/models' | |||||||||||||||||||||||||||||||||
import {Settings} from 'lucide-react' | ||||||||||||||||||||||||||||||||||
import React, {useRef, useState} from 'react' | ||||||||||||||||||||||||||||||||||
import {cn} from '@openint/shadcn/lib/utils' | ||||||||||||||||||||||||||||||||||
import {Card, CardContent} from '@openint/shadcn/ui' | ||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||
Card, | ||||||||||||||||||||||||||||||||||
CardContent, | ||||||||||||||||||||||||||||||||||
Tooltip, | ||||||||||||||||||||||||||||||||||
TooltipContent, | ||||||||||||||||||||||||||||||||||
TooltipProvider, | ||||||||||||||||||||||||||||||||||
TooltipTrigger, | ||||||||||||||||||||||||||||||||||
} from '@openint/shadcn/ui' | ||||||||||||||||||||||||||||||||||
import {titleCase} from '@openint/util/string-utils' | ||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||
ConnectionStatusPill, | ||||||||||||||||||||||||||||||||||
|
@@ -36,7 +43,12 @@ export function ConnectionCard({ | |||||||||||||||||||||||||||||||||
connection.connector?.display_name || | ||||||||||||||||||||||||||||||||||
titleCase(connection.connector_name) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const {borderColor} = getConnectionStatusStyles(connection.status) | ||||||||||||||||||||||||||||||||||
const { | ||||||||||||||||||||||||||||||||||
borderColor, | ||||||||||||||||||||||||||||||||||
pillColor, | ||||||||||||||||||||||||||||||||||
icon: StatusIcon, | ||||||||||||||||||||||||||||||||||
message, | ||||||||||||||||||||||||||||||||||
} = getConnectionStatusStyles(connection.status) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const handleMouseEnter = () => { | ||||||||||||||||||||||||||||||||||
if (onPress) { | ||||||||||||||||||||||||||||||||||
|
@@ -63,6 +75,38 @@ export function ConnectionCard({ | |||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
onMouseEnter={handleMouseEnter} | ||||||||||||||||||||||||||||||||||
onMouseLeave={handleMouseLeave}> | ||||||||||||||||||||||||||||||||||
{/* Status indicator in top-left corner with tooltip */} | ||||||||||||||||||||||||||||||||||
{connection.status && connection.status !== 'healthy' && ( | ||||||||||||||||||||||||||||||||||
<TooltipProvider> | ||||||||||||||||||||||||||||||||||
<Tooltip delayDuration={200}> | ||||||||||||||||||||||||||||||||||
<TooltipTrigger asChild> | ||||||||||||||||||||||||||||||||||
<div className="absolute left-2 top-2 z-10 cursor-help"> | ||||||||||||||||||||||||||||||||||
<div className={cn('h-2 w-2 rounded-full', pillColor)} /> | ||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||
</TooltipTrigger> | ||||||||||||||||||||||||||||||||||
<TooltipContent | ||||||||||||||||||||||||||||||||||
className="z-50 flex max-w-[260px] items-start gap-2.5" | ||||||||||||||||||||||||||||||||||
side="bottom" | ||||||||||||||||||||||||||||||||||
align="start" | ||||||||||||||||||||||||||||||||||
sideOffset={5}> | ||||||||||||||||||||||||||||||||||
<StatusIcon | ||||||||||||||||||||||||||||||||||
className={cn( | ||||||||||||||||||||||||||||||||||
'mt-0.5 h-4 w-4 flex-shrink-0', | ||||||||||||||||||||||||||||||||||
connection.status === 'error' | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The inline status icon color logic duplicates styling. Consider extracting status-to-color mapping to a helper for consistency. |
||||||||||||||||||||||||||||||||||
? 'text-rose-600' | ||||||||||||||||||||||||||||||||||
: connection.status === 'disconnected' | ||||||||||||||||||||||||||||||||||
? 'text-amber-600' | ||||||||||||||||||||||||||||||||||
: 'text-slate-600', | ||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||
<span className="text-background text-xs leading-relaxed"> | ||||||||||||||||||||||||||||||||||
{message} | ||||||||||||||||||||||||||||||||||
</span> | ||||||||||||||||||||||||||||||||||
</TooltipContent> | ||||||||||||||||||||||||||||||||||
</Tooltip> | ||||||||||||||||||||||||||||||||||
</TooltipProvider> | ||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
<CardContent | ||||||||||||||||||||||||||||||||||
className="flex h-full flex-col items-center justify-center p-4 py-2" | ||||||||||||||||||||||||||||||||||
onClick={onPress}> | ||||||||||||||||||||||||||||||||||
Comment on lines
110
to
112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: onClick handler on CardContent could trigger both onPress and onReconnect when clicking the reconnect button |
||||||||||||||||||||||||||||||||||
|
@@ -92,11 +136,15 @@ export function ConnectionCard({ | |||||||||||||||||||||||||||||||||
{connection.id} | ||||||||||||||||||||||||||||||||||
</pre> | ||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
{connection.status && ( | ||||||||||||||||||||||||||||||||||
<ConnectionStatusPill | ||||||||||||||||||||||||||||||||||
status={connection.status} | ||||||||||||||||||||||||||||||||||
onClick={onReconnect} | ||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
{/* Reconnect button for disconnected status */} | ||||||||||||||||||||||||||||||||||
{connection.status === 'disconnected' && ( | ||||||||||||||||||||||||||||||||||
<div className="mt-2"> | ||||||||||||||||||||||||||||||||||
<ConnectionStatusPill | ||||||||||||||||||||||||||||||||||
status={connection.status} | ||||||||||||||||||||||||||||||||||
onClick={onReconnect} | ||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
Comment on lines
+141
to
148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: onReconnect prop might be undefined when status is disconnected. Add a check or make the prop required
Suggested change
|
||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,13 @@ | |
|
||
import type {ConnectionExpanded} from '@openint/api-v1/models' | ||
|
||
import {AlertCircle, CheckCircle2, HelpCircle, XCircle} from 'lucide-react' | ||
import { | ||
AlertCircle, | ||
CheckCircle2, | ||
HelpCircle, | ||
RotateCcw, | ||
XCircle, | ||
} from 'lucide-react' | ||
import React from 'react' | ||
import {cn} from '@openint/shadcn/lib/utils' | ||
import { | ||
|
@@ -122,16 +128,21 @@ export function ConnectionStatusPill({ | |
<Tooltip delayDuration={200}> | ||
<TooltipTrigger asChild> | ||
<div className={cn('inline-flex', className)}> | ||
<div className={cn('flex items-center gap-1')}> | ||
<div className={cn('h-2 w-2 rounded-full', pillColor)} /> | ||
{status !== 'disconnected' ? ( | ||
{status !== 'disconnected' ? ( | ||
<div className={cn('flex items-center gap-1')}> | ||
<div className={cn('h-2 w-2 rounded-full', pillColor)} /> | ||
<div className="text-xs text-gray-500">{label}</div> | ||
) : ( | ||
<Button variant="ghost" onClick={onClick}> | ||
Reconnect | ||
</Button> | ||
)} | ||
</div> | ||
</div> | ||
) : ( | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
onClick={onClick} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: onClick handler is optional but no disabled state handling |
||
className="group h-7 gap-1.5 px-3 text-xs font-medium shadow-none transition-colors"> | ||
<RotateCcw className="h-3 w-3 transition-transform duration-500 group-hover:-rotate-[360deg]" /> | ||
Reconnect | ||
</Button> | ||
)} | ||
</div> | ||
</TooltipTrigger> | ||
<TooltipContent | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,10 +36,29 @@ export const Error: Story = { | |
|
||
// Disconnected status | ||
export const Disconnected: Story = { | ||
args: {status: 'disconnected'}, | ||
args: { | ||
status: 'disconnected', | ||
onClick: () => alert('Reconnect clicked!'), | ||
}, | ||
} | ||
|
||
// Manual status | ||
export const Manual: Story = { | ||
args: {status: 'manual'}, | ||
} | ||
|
||
// Reconnect button showcase | ||
export const ReconnectButton: Story = { | ||
args: { | ||
status: 'disconnected', | ||
onClick: () => console.log('Reconnecting...'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Using console.log for demo purposes. Consider using alert() for consistency with other stories or add a comment explaining the logging choice. |
||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: | ||
'Shows the improved Reconnect button with icon and outline variant when connection is disconnected.', | ||
}, | ||
}, | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -125,6 +125,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'HubSpot Connection', | ||||||
status: 'healthy' as const, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding 'status' field without proper type definition. The code is adding a 'status' property to objects that satisfy the ConnectionExpanded type, but there's no indication that this field is defined in the type. This will likely cause TypeScript type errors and could lead to runtime issues if the field is expected by other parts of the application. The status values ('healthy', 'error', 'disconnected', etc.) are being forcibly typed using 'as const' without proper validation against an expected enum or type definition.
|
||||||
}, | ||||||
'hubspot-with-integration': { | ||||||
id: 'conn_hubspot_01HN4QZXG7YPBR8MXQT4KBWQ5N', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Duplicate connection ID with 'hubspot-basic' (line 116)
Suggested change
|
||||||
|
@@ -139,6 +140,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'HubSpot Connection with Integration', | ||||||
status: 'healthy' as const, | ||||||
}, | ||||||
'hubspot-without-logo': { | ||||||
id: 'conn_hubspot_123', | ||||||
|
@@ -156,6 +158,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'HubSpot No Logo', | ||||||
status: 'error' as const, | ||||||
}, | ||||||
'notion-basic': { | ||||||
id: 'conn_notion_01HN4QZXG7YPBR8MXQT4KBWQ5N', | ||||||
|
@@ -170,6 +173,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Notion Connection', | ||||||
status: 'disconnected' as const, | ||||||
}, | ||||||
'notion-with-integration': { | ||||||
id: 'conn_notion_01HN4QZXG7YPBR8MXQT4KBWQ5N', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Duplicate connection ID with 'notion-basic' (line 164)
Suggested change
|
||||||
|
@@ -184,6 +188,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Notion Connection with Integration', | ||||||
status: 'manual' as const, | ||||||
}, | ||||||
'notion-without-logo': { | ||||||
id: 'conn_notion_123', | ||||||
|
@@ -201,6 +206,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Notion No Logo', | ||||||
status: 'unknown' as const, | ||||||
}, | ||||||
'google-drive-basic': { | ||||||
id: 'conn_google-drive_01HN4QZXG7YPBR8MXQT4KBWQ5N', | ||||||
|
@@ -215,6 +221,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Google Drive Connection', | ||||||
status: 'healthy' as const, | ||||||
}, | ||||||
'google-drive-with-integration': { | ||||||
id: 'conn_google-drive_01HN4QZXG7YPBR8MXQT4KBWQ5N', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Duplicate connection ID with 'google-drive-basic' (line 212)
Suggested change
|
||||||
|
@@ -229,6 +236,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Google Drive Connection with Integration', | ||||||
status: 'healthy' as const, | ||||||
}, | ||||||
'google-drive-without-logo': { | ||||||
id: 'conn_gdrive_123', | ||||||
|
@@ -246,6 +254,7 @@ const connections = { | |||||
settings: {}, | ||||||
disabled: false, | ||||||
display_name: 'Google Drive No Logo', | ||||||
status: 'disconnected' as const, | ||||||
}, | ||||||
} satisfies Record<string, ConnectionExpanded> | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Empty onPress handler could be confusing. Consider removing it if not needed or adding a meaningful action.