Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
Ag touches (#56)
Browse files Browse the repository at this point in the history
* fixing first name

* reusing same ConnectDialog for AG and non AG portals and styling AG portal

* bubling up handlers to trigger refetch on adding component

* improving error state and triggering refetch
  • Loading branch information
pellicceama authored Oct 18, 2024
1 parent 6765c53 commit 63664f8
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 171 deletions.
20 changes: 9 additions & 11 deletions connectors/connector-postgres/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ const agTableMappings = [
{from: 'integration_ats_candidate', to: 'IntegrationATSCandidate'},
{from: 'integration_ats_job_opening', to: 'IntegrationATSJobOpening'},
{from: 'integration_ats_offer', to: 'IntegrationATSOffer'},
{from: 'integration_connection', to: 'IntegrationConnection'},
{from: 'integration_ats_opening', to: 'IntegrationATSOpening'},
{from: 'integration_connection', to: 'IntegrationConnection'}
]

async function setupTable({
Expand Down Expand Up @@ -193,7 +192,7 @@ export const postgresServer = {
),
)
},
destinationSync: ({endUser, source, settings: {databaseUrl, migrateTables}}) => {
destinationSync: ({endUser, source, settings: {databaseUrl}}) => {
console.log('[destinationSync] Will makePostgresClient', {
// databaseUrl,
// migrationsPath: __dirname + '/migrations',
Expand All @@ -210,10 +209,6 @@ export const postgresServer = {

const migrationRan: Record<string, boolean> = {}
async function runMigration(pool: DatabasePool, tableName: string) {
if (!migrateTables) {
console.log('[destinationSync] Will not run migration for', tableName, 'as migrateTables is false');
return;
}
console.log('will run migration for', tableName)
if (migrationRan[tableName]) {
return
Expand Down Expand Up @@ -250,7 +245,7 @@ export const postgresServer = {
isOpenInt: true,
}

const isAgInsert =
const isAgInsert =
endUser?.orgId === 'org_2lcCCimyICKI8cpPNQt195h5zrP' ||
endUser?.orgId === 'org_2ms9FdeczlbrDIHJLcwGdpv3dTx'

Expand All @@ -261,10 +256,13 @@ export const postgresServer = {
rowToInsert['external_job_id'] = data.entity?.raw?.id || '';
} else if (tableName === 'IntegrationAtsCandidate') {
rowToInsert['opening_external_id'] = data.entity?.raw?.id || '';
rowToInsert['candidate_name'] = data.entity?.raw?.name + ' ' + data.entity?.raw?.last_name || '';
rowToInsert['candidate_name'] = data.entity?.raw?.first_name + ' ' + data.entity?.raw?.last_name || '';
} else if (tableName === 'IntegrationAtsJobOpening') {
rowToInsert['opening_external_id'] = data.entity?.raw?.opening_id || '';
rowToInsert['job_id'] = data.entity?.raw?.job_id || '';
rowToInsert['opening_external_id'] = data.entity?.raw?.id || '';
// NOTE Job openings are nested within Jobs and that o bject does not contain an id of the parent (job id)
// Depends on the implementation we may have to change this, leaving empty for now
// https://developers.greenhouse.io/harvest.html#the-job-object
rowToInsert['job_id'] = '';
} else if (tableName === 'IntegrationAtsOffer') {
// Note: These fields seemed duplicated from the nested objects
rowToInsert['opening_external_id'] = data.entity?.raw?.opening?.id || '';
Expand Down
157 changes: 28 additions & 129 deletions packages/engine-frontend/components/AGConnectionPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,14 @@

import {AlertTriangle} from 'lucide-react'
import React from 'react'
import type {Id, Vertical} from '@openint/cdk'
import {VERTICAL_BY_KEY} from '@openint/cdk'
import type {Id} from '@openint/cdk'
import type {UIPropsNoChildren} from '@openint/ui'
import {
Card,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
ResourceCard,
} from '@openint/ui'
import { Card, ResourceCard } from '@openint/ui'
import {cn} from '@openint/ui/utils'
import {R} from '@openint/util'
import {WithConnectConfig} from '../hocs/WithConnectConfig'
import type {ConnectorConfigFilters} from '../hocs/WithConnectConfig'
import {_trpcReact} from '../providers/TRPCProvider'
import {ConnectButton} from './ConnectButton'
import {IntegrationSearch} from './IntegrationSearch'
import {ConnectDialog} from './ConnectDialog'
import {AgResourceRowActions} from './AgResourceRowActions'

type ConnectEventType = 'open' | 'close' | 'error'
Expand Down Expand Up @@ -57,10 +45,14 @@ const AGConnectionPortalComponent: React.FC<AGConnectionPortalProps> = ({
// const iframe = document.getElementById('openint-connect-iframeId');
// iframe?.contentWindow.postMessage({type: 'triggerConnectDialog', value: true },'*');

const handleMessage = React.useCallback((event: MessageEvent) => {
const handleMessage = React.useCallback(async (event: MessageEvent) => {
if (event.data.type === 'triggerConnectDialog') {
console.log('triggerConnectDialog', event.data.value)
setOpenDialog(event.data.value || true)
if(event.data.value) {
await listConnectionsRes.refetch().then(() => {
setOpenDialog(event.data.value)
})
}
}
}, [])

Expand Down Expand Up @@ -100,6 +92,12 @@ const AGConnectionPortalComponent: React.FC<AGConnectionPortalProps> = ({
),
}))

if (categoriesWithConnections.length > 1) {
console.warn(
'AG Connection Portal only currently supports 1 category being rendered via postMessage',
)
}

return (
<div className={cn('mb-4', className)}>
{/* Listing by categories */}
Expand All @@ -126,18 +124,23 @@ const AGConnectionPortalComponent: React.FC<AGConnectionPortalProps> = ({
/>
</ResourceCard>
))}
<NewConnectionCard
category={category}
hasExisting={category.connections.length > 0}
connectorNames={category.connections.map(
(c) => c.connectorName,
)}
/>
{category.connections.length === 0 && (
<Card className="drop-shadow-small flex w-full flex-col items-center justify-center space-y-3 rounded-lg border border-solid border-[#e0e0e5] bg-[#f8f8fc] p-6 text-center">
<div className="flex flex-row gap-2">
<AlertTriangle className="size-8 text-[#C27B1A]" />
<h3 className="text-black-dark mb-2 text-[24px] font-semibold leading-[36px] tracking-tight antialiased">
{`No data source connected`}
</h3>
</div>
</Card>
)}
{openDialog && (
<AgConnectDialog
<ConnectDialog
connectorConfigFilters={{verticalKey: category.key}}
open={openDialog}
setOpen={setOpenDialog}
// trigger refetch of connections
onEvent={() => listConnectionsRes.refetch()}
/>
)}
</div>
Expand All @@ -154,107 +157,3 @@ export const AGConnectionPortal = React.memo(
AGConnectionPortalComponent,
areEqual,
)

const NewConnectionCard = ({
category,
hasExisting,
connectorNames,
}: {
category: Vertical
hasExisting: boolean
connectorNames: string[]
}) => (
<Card className="drop-shadow-small flex w-full flex-col items-center justify-center space-y-3 rounded-lg border border-solid border-[#e0e0e5] bg-[#f8f8fc] p-6 text-center">
<div className="flex flex-row gap-2">
<AlertTriangle className="size-8 text-orange-300" />
<h3 className="text-black-dark mb-2 text-[24px] font-semibold leading-[36px] tracking-tight antialiased">
{hasExisting
? `Connect another ${category.name} integration`
: `No ${category.name} integration connected`}
</h3>
</div>

<p className="text-black-mid mb-4 text-sm font-semibold antialiased">
Connect an integration here ASAP. This integration is needed to keep your{' '}
{category.name} data accurate.
</p>
<ConnectButton
// className="bg-purple-400 hover:bg-purple-500"
className="rounded-md bg-[#8192FF] px-4 py-2 text-white hover:bg-[#6774CC]"
connectorNames={connectorNames}
connectorConfigFilters={{
verticalKey: category.key,
}}></ConnectButton>
</Card>
)

function AgConnectDialog({
connectorConfigFilters,
open,
setOpen,
}: {
connectorConfigFilters: ConnectorConfigFilters
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
}) {
console.log('AgConnectDialog', open)
const {verticalKey: categoryKey} = connectorConfigFilters

return (
<WithConnectConfig {...connectorConfigFilters}>
{({ccfgs}) => {
const [first, ...rest] = ccfgs
if (!first) {
return (
<div>
No connectors configured for {categoryKey}. Please check your
settings
</div>
)
}
const category = categoryKey ? VERTICAL_BY_KEY[categoryKey] : undefined
const content = (
<IntegrationSearch
connectorConfigs={rest.length === 0 ? [first] : ccfgs}
onEvent={(e) => {
if (e.type === 'close' || e.type === 'error') {
setOpen(false)
}
}}
/>
)

return (
<Dialog
open={open}
onOpenChange={(v) => {
console.log('onOpenChange', v)
setOpen(v)
}}
modal={false}>
{/* <DialogTrigger asChild>
</DialogTrigger> */}
<DialogContent className="flex max-h-screen flex-col sm:max-w-2xl">
<DialogHeader className="shrink-0">
<DialogTitle>New connection</DialogTitle>
<DialogDescription>
Choose a connector config to start
</DialogDescription>
</DialogHeader>
{category && (
<>
<h1>Select your first {category.name} integration</h1>
<p>{category.description}</p>
</>
)}
{content}
<DialogFooter className="shrink-0">
{/* Cancel here */}
</DialogFooter>
</DialogContent>
</Dialog>
)
}}
</WithConnectConfig>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ import type {
import {WithConnectConfig} from '../hocs/WithConnectConfig'
import {IntegrationSearch} from './IntegrationSearch'

interface ConnectButtonCommonProps {
interface ConnectDialogCommonProps {
className?: string
children?: React.ReactNode
}

// TODO: Refactor WithOpenConnect out of ConnectButton
// such that users can render their own trigger fully
export function ConnectButton({
export function ConnectDialog({
connectorNames = [],
connectorConfigFilters,
open: controlledOpen,
setOpen: controlledSetOpen,
onEvent,
...commonProps
}: {
connectorConfigFilters: ConnectorConfigFilters
connectorNames?: string[]
} & ConnectButtonCommonProps) {
open?: boolean
setOpen?: (open: boolean) => void
onEvent?: (event: any) => void
} & ConnectDialogCommonProps) {
const {verticalKey: categoryKey} = connectorConfigFilters
return (
<WithConnectConfig {...connectorConfigFilters}>
Expand All @@ -45,20 +51,30 @@ export function ConnectButton({
const [first, ...rest] = filteredCcfgs
if (!first) {
return (
<div>
No connectors configured for {categoryKey}. Please check your
settings
</div>
<Dialog open={true} onOpenChange={() => {}}>
<DialogContent>
<DialogHeader>
<DialogTitle>No Integrations Available</DialogTitle>
<DialogDescription>
You have no further integrations available. If you believe this is an error, please contact support.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={() => {}}>Close</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
// Render dialog for MultiConnector scenarios
// This would be the case for greenhouse + lever
const category = categoryKey ? VERTICAL_BY_KEY[categoryKey] : undefined
return (
<MultipleConnectButton
{...commonProps}
connectorConfigs={rest.length === 0 ? [first] : ccfgs}
category={category}
open={controlledOpen}
setOpen={controlledSetOpen}
onEvent={onEvent}
/>
)
}}
Expand All @@ -70,22 +86,30 @@ function MultipleConnectButton({
children,
className,
connectorConfigs,
open: controlledOpen,
setOpen: controlledSetOpen,
onEvent,
}: {
connectorConfigs: ConnectorConfig[]
/** Should correspond to connectorConfigs, but we can't guarantee that statically here... */
category?: Vertical
} & ConnectButtonCommonProps) {
const [open, setOpen] = React.useState(false)
open?: boolean
setOpen?: (open: boolean) => void
onEvent?: (event: any) => void
} & ConnectDialogCommonProps) {
const [internalOpen, setInternalOpen] = React.useState(false)

// Determine if the component is controlled or uncontrolled
const isControlled = controlledOpen !== undefined && controlledSetOpen !== undefined
const open = isControlled ? controlledOpen : internalOpen
const setOpen = isControlled ? controlledSetOpen : setInternalOpen

// Unconditional render to avoid delay when dialog is opened
const content = (
<IntegrationSearch
connectorConfigs={connectorConfigs}
onEvent={(e) => {
if (onEvent) onEvent(e);
if (e.type === 'close' || e.type === 'error') {
// Cannot close during open event otherwise whole thing becomes unmounted
// and we end up closing the connect dialog itself...
// Once we have a global UserInputDialog
setOpen(false)
}
}}
Expand All @@ -98,9 +122,11 @@ function MultipleConnectButton({
// as well as other modals introduced by things like Plaid
<Dialog open={open} onOpenChange={setOpen} modal={false}>
<DialogTrigger asChild>
<Button className={className} variant="default">
{children ?? 'Connect'}
</Button>
{!isControlled && (
<Button className={className} variant="default">
{children ?? 'Connect'}
</Button>
)}
</DialogTrigger>
<DialogContent className="flex max-h-screen flex-col sm:max-w-2xl">
<DialogHeader className="shrink-0">
Expand All @@ -110,7 +136,6 @@ function MultipleConnectButton({
</DialogDescription>
</DialogHeader>
{content}

<DialogFooter className="shrink-0">{/* Cancel here */}</DialogFooter>
</DialogContent>
</Dialog>
Expand Down
Loading

1 comment on commit 63664f8

@vercel
Copy link

@vercel vercel bot commented on 63664f8 Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.