From d0c71d8c91fba5d75df8372aca7fe6465fdac6d7 Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Tue, 22 Oct 2024 20:19:38 -0400 Subject: [PATCH 1/8] Add Tabs component for storybook usage --- packages/ui/components/Tabs.tsx | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/ui/components/Tabs.tsx diff --git a/packages/ui/components/Tabs.tsx b/packages/ui/components/Tabs.tsx new file mode 100644 index 00000000..849908c8 --- /dev/null +++ b/packages/ui/components/Tabs.tsx @@ -0,0 +1,38 @@ +import {type ReactElement} from 'react' +import { + Tabs as ShadcnTabs, + TabsContent, + TabsList, + TabsTrigger, +} from '../shadcn/Tabs' + +interface TabsProps { + tabConfig: Array<{ + key: string + title: string + content: ReactElement + }> + defaultValue: string +} + +export function Tabs({tabConfig, defaultValue}: TabsProps) { + return ( + + + {tabConfig.map((config) => ( + + {config.title} + + ))} + + {tabConfig.map((config) => ( + + {config.content} + + ))} + + ) +} From 84ac994851f62b9ef25fdbc1c0e566ad5af74e55 Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Tue, 22 Oct 2024 20:21:01 -0400 Subject: [PATCH 2/8] Update Connections card component and story --- .../ui/domain-components/ConnectionCard.tsx | 40 ++++++++++++------- packages/ui/stories/ConnectionCard.stories.js | 7 ++-- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/packages/ui/domain-components/ConnectionCard.tsx b/packages/ui/domain-components/ConnectionCard.tsx index a3ad6490..e31d83a7 100644 --- a/packages/ui/domain-components/ConnectionCard.tsx +++ b/packages/ui/domain-components/ConnectionCard.tsx @@ -1,35 +1,45 @@ -import { useState } from 'react' -import { - Card, - CardContent, -} from '../shadcn' -import { Plus } from 'lucide-react' +import {Plus} from 'lucide-react' +import {useState} from 'react' +import {Card, CardContent} from '../shadcn' export function ConnectionCard({ logo, name, + onClick, }: { logo: string name: string + onClick: () => void }) { const [isHovered, setIsHovered] = useState(false) return ( setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - > - + onMouseLeave={() => setIsHovered(false)}> + {isHovered ? ( -
+
- Add {/* Set to 14px and semibold */} + + Add + {' '} + {/* Set to 14px and semibold */}
) : ( -
- {`${name} {/* 32x32 logo with 10px padding */} -

{name}

{/* Changed to font-semibold */} +
+ {`${name}{' '} +

+ {name} +

{' '}
)} diff --git a/packages/ui/stories/ConnectionCard.stories.js b/packages/ui/stories/ConnectionCard.stories.js index 6e551016..9d5607ac 100644 --- a/packages/ui/stories/ConnectionCard.stories.js +++ b/packages/ui/stories/ConnectionCard.stories.js @@ -1,6 +1,7 @@ import {fn} from '@storybook/test' +import logoGreenhouse from '../../../apps/web/public/_assets/logo-greenhouse.svg' import {ConnectionCard} from '../domain-components/ConnectionCard' -import logoGreenhouse from '../../../apps/web/public/_assets/logo-greenhouse.svg'; + // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export export default { title: 'Example/ConnectionCard', @@ -21,5 +22,5 @@ export default { // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Primary = { - args: { logo: logoGreenhouse, name: 'Greenhouse' }, -}; + args: {logo: logoGreenhouse, name: 'Greenhouse'}, +} From 6d07612dc903059bc1c0db3e38a08454188557a2 Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Tue, 22 Oct 2024 20:21:41 -0400 Subject: [PATCH 3/8] Update add connections tab content to use new card --- .../components/ConnectIntegrations.tsx | 34 +++ .../components/ConnectionPortal.tsx | 243 +++++++++--------- .../components/IntegrationSearch.tsx | 89 ++++--- 3 files changed, 206 insertions(+), 160 deletions(-) create mode 100644 packages/engine-frontend/components/ConnectIntegrations.tsx diff --git a/packages/engine-frontend/components/ConnectIntegrations.tsx b/packages/engine-frontend/components/ConnectIntegrations.tsx new file mode 100644 index 00000000..9419ce5a --- /dev/null +++ b/packages/engine-frontend/components/ConnectIntegrations.tsx @@ -0,0 +1,34 @@ +import { + WithConnectConfig, + type ConnectorConfigFilters, +} from '../hocs/WithConnectConfig' +import {IntegrationSearch} from './IntegrationSearch' + +export function ConnectIntegrations({ + connectorConfigFilters, + connectorNames = [], + onEvent, +}: { + connectorConfigFilters: ConnectorConfigFilters + connectorNames?: string[] + onEvent: (event: any) => void +}) { + return ( + + {({ccfgs}) => { + const filteredCcfgs = ccfgs.filter( + (c) => !connectorNames.includes(c.connectorName), + ) + + return ( + { + if (onEvent) onEvent(e) + }} + /> + ) + }} + + ) +} diff --git a/packages/engine-frontend/components/ConnectionPortal.tsx b/packages/engine-frontend/components/ConnectionPortal.tsx index 8e2e8821..7e07f9d6 100644 --- a/packages/engine-frontend/components/ConnectionPortal.tsx +++ b/packages/engine-frontend/components/ConnectionPortal.tsx @@ -13,12 +13,13 @@ import { Separator, useToast, } from '@openint/ui' -import {Tabs, TabsContent, TabsList, TabsTrigger} from '@openint/ui/shadcn/Tabs' +import {Tabs} from '@openint/ui/components/Tabs' import {cn} from '@openint/ui/utils' import {R} from '@openint/util' import {WithConnectConfig} from '../hocs/WithConnectConfig' import {_trpcReact} from '../providers/TRPCProvider' import {ConnectDialog} from './ConnectDialog' +import {ConnectIntegrations} from './ConnectIntegrations' type ConnectEventType = 'open' | 'close' | 'error' @@ -77,139 +78,135 @@ export function ConnectionPortal({className}: ConnectionPortalProps) { const connectionCount = connections.length console.log({connectionCount}) - return ( -
- {/* Listing by categories */} - - - - My Connections ({connectionCount}) - - - Add a Connection - - - - {connectionCount === 0 ? ( -
-
-

- No connections yet -

-

- Add a connection to get started -

-
- { - if (event.type === 'close') { - listConnectionsRes.refetch(); // Trigger refetch - } - }} - > -
- ) : ( -
- {listConnectionsRes.isLoading ? ( -
- -
- ) : ( - categoriesWithConnections.map((category) => ( -
- {category.connections.map((conn) => ( - <> -
-
- -
-
-

- {conn.connectorName - .charAt(0) - .toUpperCase() + - conn.connectorName.slice(1)} -

- - {category.name} - -
- {conn.pipelineIds.length > 0 && ( -
- {conn.syncInProgress ? ( -
- -

- Syncing... -

-
- ) : ( -

Successfully synced

- )} -
- )} -
-
- - - - - - - deleteResource.mutate({id: conn.id}) - }> - - Delete - - - - -
- {/* TODO: Improve the condition to hide the separator for the last item, right now it iterates - over all categories and all connections, would be good to have a single array of connections with the category - information included already */} - - - ))} -
- )) - )} -
- )} -
- + const tabConfig = [ + { + key: 'connections', + title: `My Connections (${connectionCount})`, + content: + connectionCount === 0 ? (

- Setup a new Connection -

-

- Choose a connector config to start + No connections yet

+

Add a connection to get started

{ if (event.type === 'close') { - listConnectionsRes.refetch(); // Trigger refetch - } - }} - > + listConnectionsRes.refetch() // Trigger refetch + } + }}>
-
-
+ ) : ( +
+ {listConnectionsRes.isLoading ? ( +
+ +
+ ) : ( + categoriesWithConnections.map((category) => ( +
+ {category.connections.map((conn) => ( + <> +
+
+ +
+
+

+ {conn.connectorName + .charAt(0) + .toUpperCase() + + conn.connectorName.slice(1)} +

+ + {category.name} + +
+ {conn.pipelineIds.length > 0 && ( +
+ {conn.syncInProgress ? ( +
+ +

+ Syncing... +

+
+ ) : ( +

Successfully synced

+ )} +
+ )} +
+
+ + + + + + + deleteResource.mutate({id: conn.id}) + }> + + Delete + + + + +
+ {/* TODO: Improve the condition to hide the separator for the last item, right now it iterates + over all categories and all connections, would be good to have a single array of connections with the category + information included already */} + + + ))} +
+ )) + )} +
+ ), + }, + { + key: 'add-connection', + title: 'Add a Connection', + content: ( +
+
+

+ Setup a new Connection +

+

+ Choose a connector config to start +

+
+ { + if (event.type === 'close') { + listConnectionsRes.refetch() // Trigger refetch + } + }} + /> +
+ ), + }, + ] + + return ( +
+
) }} diff --git a/packages/engine-frontend/components/IntegrationSearch.tsx b/packages/engine-frontend/components/IntegrationSearch.tsx index aaa64c43..9fde6ffb 100644 --- a/packages/engine-frontend/components/IntegrationSearch.tsx +++ b/packages/engine-frontend/components/IntegrationSearch.tsx @@ -2,7 +2,8 @@ import {Loader, Search} from 'lucide-react' import React from 'react' -import {Card, cn, ConnectorLogo, Input} from '@openint/ui' +import {Input} from '@openint/ui' +import {ConnectionCard} from '@openint/ui/domain-components/ConnectionCard' import type {ConnectorConfig} from '../hocs/WithConnectConfig' import type {ConnectEventType} from '../hocs/WithConnectorConnect' import {WithConnectorConnect} from '../hocs/WithConnectorConnect' @@ -35,6 +36,16 @@ export function IntegrationSearch({ ccfg: connectorConfigs.find((ccfg) => ccfg.id === int.connector_config_id)!, })) + const intsByCategory = ints?.reduce( + (acc, int) => { + int.ccfg.verticals.forEach((vertical) => { + acc[vertical] = (acc[vertical] || []).concat(int) + }) + return acc + }, + {} as Record, + ) + return (
{/* Search integrations */} @@ -58,42 +69,46 @@ export function IntegrationSearch({
) : ( -
- {ints?.map((int) => ( - { - onEvent?.({ - type: e.type, - integration: { - connectorConfigId: int.connector_config_id, - id: int.id, - }, - }) - }}> - {({openConnect}) => ( - openConnect()}> - - - {int.name} - - - )} - - ))} +
+ {Object.entries(intsByCategory ?? {}).map( + ([category, categoryInts]) => ( +
+

+ {category + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ')} +

+
+ {categoryInts.map((int) => ( + { + onEvent?.({ + type: e.type, + integration: { + connectorConfigId: int.connector_config_id, + id: int.id, + }, + }) + }}> + {({openConnect}) => ( + + )} + + ))} +
+
+ ), + )}
)}
From 3fd87fa61f2c440bc172128fdd36551ec92c760e Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Wed, 23 Oct 2024 18:38:35 -0400 Subject: [PATCH 4/8] UI improvements based on code review --- packages/ui/domain-components/ConnectionCard.tsx | 8 ++++---- packages/ui/shadcn/Dialog.tsx | 2 +- packages/ui/shadcn/Tabs.tsx | 8 +++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/ui/domain-components/ConnectionCard.tsx b/packages/ui/domain-components/ConnectionCard.tsx index e31d83a7..5b9b60ce 100644 --- a/packages/ui/domain-components/ConnectionCard.tsx +++ b/packages/ui/domain-components/ConnectionCard.tsx @@ -18,11 +18,11 @@ export function ConnectionCard({ className="relative h-[120px] w-[120px] cursor-pointer rounded-lg border border-gray-300 bg-white p-0 transition-colors duration-300 ease-in-out hover:border-[#8A7DFF] hover:bg-[#F8F7FF]" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}> - + {isHovered ? ( -
+
Add diff --git a/packages/ui/shadcn/Dialog.tsx b/packages/ui/shadcn/Dialog.tsx index 411c0b82..3f71f3dc 100644 --- a/packages/ui/shadcn/Dialog.tsx +++ b/packages/ui/shadcn/Dialog.tsx @@ -3,7 +3,6 @@ import * as DialogPrimitive from '@radix-ui/react-dialog' import {X} from 'lucide-react' import React from 'react' - import {cn} from '../utils' const Dialog = DialogPrimitive.Root @@ -48,6 +47,7 @@ const DialogContent = React.forwardRef< ref={ref} className={cn( 'fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0', + 'left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%]', className, )} {...props}> diff --git a/packages/ui/shadcn/Tabs.tsx b/packages/ui/shadcn/Tabs.tsx index 3da9d009..1193681e 100644 --- a/packages/ui/shadcn/Tabs.tsx +++ b/packages/ui/shadcn/Tabs.tsx @@ -11,7 +11,8 @@ const TabsList = React.forwardRef< Date: Wed, 23 Oct 2024 18:40:01 -0400 Subject: [PATCH 5/8] Split Portal tabs content into separate components --- .../components/AddConnectionTabContent.tsx | 29 ++++ .../components/ConnectionPortal.tsx | 144 +++--------------- .../components/ConnectionsTabContent.tsx | 120 +++++++++++++++ 3 files changed, 166 insertions(+), 127 deletions(-) create mode 100644 packages/engine-frontend/components/AddConnectionTabContent.tsx create mode 100644 packages/engine-frontend/components/ConnectionsTabContent.tsx diff --git a/packages/engine-frontend/components/AddConnectionTabContent.tsx b/packages/engine-frontend/components/AddConnectionTabContent.tsx new file mode 100644 index 00000000..7267fec8 --- /dev/null +++ b/packages/engine-frontend/components/AddConnectionTabContent.tsx @@ -0,0 +1,29 @@ +import type {ConnectorConfigFilters} from '../hocs/WithConnectConfig' +import {ConnectIntegrations} from './ConnectIntegrations' + +interface AddConnectionTabContentProps { + connectorConfigFilters: ConnectorConfigFilters + refetch: () => void +} + +export function AddConnectionTabContent({ + connectorConfigFilters, + refetch, +}: AddConnectionTabContentProps) { + return ( +
+
+

Setup a new Connection

+

Choose a connector config to start

+
+ { + if (event.type === 'close') { + refetch() + } + }} + /> +
+ ) +} diff --git a/packages/engine-frontend/components/ConnectionPortal.tsx b/packages/engine-frontend/components/ConnectionPortal.tsx index 7e07f9d6..f558029d 100644 --- a/packages/engine-frontend/components/ConnectionPortal.tsx +++ b/packages/engine-frontend/components/ConnectionPortal.tsx @@ -1,25 +1,15 @@ 'use client' -import {Loader, Settings} from 'lucide-react' import type {Id} from '@openint/cdk' import type {UIPropsNoChildren} from '@openint/ui' -import { - Badge, - ConnectorLogo, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, - Separator, - useToast, -} from '@openint/ui' +import {useToast} from '@openint/ui' import {Tabs} from '@openint/ui/components/Tabs' import {cn} from '@openint/ui/utils' import {R} from '@openint/util' import {WithConnectConfig} from '../hocs/WithConnectConfig' import {_trpcReact} from '../providers/TRPCProvider' -import {ConnectDialog} from './ConnectDialog' -import {ConnectIntegrations} from './ConnectIntegrations' +import {AddConnectionTabContent} from './AddConnectionTabContent' +import {ConnectionsTabContent} from './ConnectionsTabContent' type ConnectEventType = 'open' | 'close' | 'error' @@ -82,130 +72,30 @@ export function ConnectionPortal({className}: ConnectionPortalProps) { { key: 'connections', title: `My Connections (${connectionCount})`, - content: - connectionCount === 0 ? ( -
-
-

- No connections yet -

-

Add a connection to get started

-
- { - if (event.type === 'close') { - listConnectionsRes.refetch() // Trigger refetch - } - }}> -
- ) : ( -
- {listConnectionsRes.isLoading ? ( -
- -
- ) : ( - categoriesWithConnections.map((category) => ( -
- {category.connections.map((conn) => ( - <> -
-
- -
-
-

- {conn.connectorName - .charAt(0) - .toUpperCase() + - conn.connectorName.slice(1)} -

- - {category.name} - -
- {conn.pipelineIds.length > 0 && ( -
- {conn.syncInProgress ? ( -
- -

- Syncing... -

-
- ) : ( -

Successfully synced

- )} -
- )} -
-
- - - - - - - deleteResource.mutate({id: conn.id}) - }> - - Delete - - - - -
- {/* TODO: Improve the condition to hide the separator for the last item, right now it iterates - over all categories and all connections, would be good to have a single array of connections with the category - information included already */} - - - ))} -
- )) - )} -
- ), + content: ( + + ), }, { key: 'add-connection', title: 'Add a Connection', content: ( -
-
-

- Setup a new Connection -

-

- Choose a connector config to start -

-
- { - if (event.type === 'close') { - listConnectionsRes.refetch() // Trigger refetch - } - }} - /> -
+ ), }, ] return ( -
+
) diff --git a/packages/engine-frontend/components/ConnectionsTabContent.tsx b/packages/engine-frontend/components/ConnectionsTabContent.tsx new file mode 100644 index 00000000..fa2e274e --- /dev/null +++ b/packages/engine-frontend/components/ConnectionsTabContent.tsx @@ -0,0 +1,120 @@ +import {Loader, Settings} from 'lucide-react' +import { + Badge, + ConnectorLogo, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + Separator, +} from '@openint/ui' +import type {ConnectorConfig} from '../hocs/WithConnectConfig' +import {ConnectDialog} from './ConnectDialog' + +interface ConnectionsTabContentProps { + connectionCount: number + categoriesWithConnections: Array<{ + name: string + connections: Array<{ + id: string + connectorConfig: ConnectorConfig + connectorName: string + pipelineIds: string[] + syncInProgress: boolean + }> + }> + refetch: () => void + isLoading: boolean + deleteResource: ({id}: {id: string}) => void +} + +export function ConnectionsTabContent({ + connectionCount, + refetch, + isLoading, + deleteResource, + categoriesWithConnections, +}: ConnectionsTabContentProps) { + return connectionCount === 0 ? ( +
+
+

No connections yet

+

Add a connection to get started

+
+ { + if (event.type === 'close') { + refetch() // Trigger refetch + } + }}> +
+ ) : ( +
+ {isLoading ? ( +
+ +
+ ) : ( + categoriesWithConnections.map((category) => ( +
+ {category.connections.map((conn) => ( + <> +
+
+ +
+
+

+ {conn.connectorName.charAt(0).toUpperCase() + + conn.connectorName.slice(1)} +

+ {category.name} +
+ {conn.pipelineIds.length > 0 && ( +
+ {conn.syncInProgress ? ( +
+ +

Syncing...

+
+ ) : ( +

Successfully synced

+ )} +
+ )} +
+
+ + + + + + deleteResource({id: conn.id})}> + + Delete + + + + +
+ {/* TODO: Improve the condition to hide the separator for the last item, right now it iterates + over all categories and all connections, would be good to have a single array of connections with the category + information included already */} + + + ))} +
+ )) + )} +
+ ) +} From ab1996013e15c797747195cd657415644862679e Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Wed, 23 Oct 2024 18:47:36 -0400 Subject: [PATCH 6/8] Fix search input align with content --- packages/engine-frontend/components/IntegrationSearch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine-frontend/components/IntegrationSearch.tsx b/packages/engine-frontend/components/IntegrationSearch.tsx index 9fde6ffb..25c13b81 100644 --- a/packages/engine-frontend/components/IntegrationSearch.tsx +++ b/packages/engine-frontend/components/IntegrationSearch.tsx @@ -49,7 +49,7 @@ export function IntegrationSearch({ return (
{/* Search integrations */} -
+
{/* top-2.5 is not working for some reason due to tailwind setup */} From 42dd1a8fd12c023e163d112abc6f381dfde40d89 Mon Sep 17 00:00:00 2001 From: Rodrigo Arze Leon Date: Thu, 24 Oct 2024 17:08:41 -0400 Subject: [PATCH 7/8] Fix casing for category header --- .../components/IntegrationSearch.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/engine-frontend/components/IntegrationSearch.tsx b/packages/engine-frontend/components/IntegrationSearch.tsx index 25c13b81..bfe42808 100644 --- a/packages/engine-frontend/components/IntegrationSearch.tsx +++ b/packages/engine-frontend/components/IntegrationSearch.tsx @@ -74,10 +74,15 @@ export function IntegrationSearch({ ([category, categoryInts]) => (

- {category - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' ')} + {category.length < 5 + ? category.toUpperCase() + : category + .split('-') + .map( + (word) => + word.charAt(0).toUpperCase() + word.slice(1), + ) + .join(' ')}

{categoryInts.map((int) => ( From 6965fc18c1a81842d4c14014bbf87f9132653ef4 Mon Sep 17 00:00:00 2001 From: Amadeo Pellicce Date: Thu, 24 Oct 2024 15:19:47 -0700 Subject: [PATCH 8/8] fixing orgId assignment --- apps/web/app/connect/portal/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/connect/portal/page.tsx b/apps/web/app/connect/portal/page.tsx index 38df2faf..8fac6e6c 100644 --- a/apps/web/app/connect/portal/page.tsx +++ b/apps/web/app/connect/portal/page.tsx @@ -55,7 +55,7 @@ export default async function PortalPage({ } const isAgMode = - viewer.orgId = 'org_2nJZrA4Dk8i3wszhm6PsP3M2Vwy' || + viewer.orgId === 'org_2nJZrA4Dk8i3wszhm6PsP3M2Vwy' || viewer.orgId === 'org_2lcCCimyICKI8cpPNQt195h5zrP' || viewer.orgId === 'org_2ms9FdeczlbrDIHJLcwGdpv3dTx'