Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions apps/web/src/actions/workspaceOnboarding/calculateNavbarSteps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use server'

import { authProcedure } from '../procedures'
import { calculateAllSteps } from '@latitude-data/core/services/workspaceOnboarding/steps/calculateAllSteps'

/**
* Calculate all steps for the onboarding
*/
export const calculateNavbarStepsAction = authProcedure.action(
async ({ ctx }) => {
return await calculateAllSteps({
workspace: ctx.workspace,
}).then((r) => r.unwrap())
},
)
11 changes: 7 additions & 4 deletions apps/web/src/actions/workspaceOnboarding/moveNextStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@
import { getWorkspaceOnboarding } from '@latitude-data/core/services/workspaceOnboarding/get'
import { authProcedure } from '../procedures'
import { moveNextOnboardingStep } from '@latitude-data/core/services/workspaceOnboarding/steps/moveNextOnboardingStep'
import { z } from 'zod'
import { OnboardingStepKey } from '@latitude-data/constants/onboardingSteps'

/**
* Move to the next onboarding step
*/
export const moveNextOnboardingStepAction = authProcedure.action(
async ({ ctx }) => {
export const moveNextOnboardingStepAction = authProcedure
.inputSchema(z.object({ currentStep: z.nativeEnum(OnboardingStepKey) }))
.action(async ({ parsedInput, ctx }) => {
const onboarding = await getWorkspaceOnboarding({
workspace: ctx.workspace,
}).then((r) => r.unwrap())

const nextOnboardingStep = await moveNextOnboardingStep({
onboarding,
workspace: ctx.workspace,
currentStep: parsedInput.currentStep,
}).then((r) => r.unwrap())

return nextOnboardingStep
},
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,54 +13,54 @@ import { useCurrentProject } from '@latitude-data/web-ui/providers'
import { redirect } from 'next/navigation'

export default function NocodersNavbar({
onboardingSteps,
currentStep,
isLoadingOnboarding,
executeCompleteOnboarding,
}: {
onboardingSteps: OnboardingStepKey[]
executeCompleteOnboarding: () => void
currentStep: OnboardingStepKey | undefined | null // TODO(onboarding): remove null when data migration is done
isLoadingOnboarding: boolean
}) {
const project = useCurrentProject()
const { project } = useCurrentProject()

const skipOnboarding = useCallback(() => {
executeCompleteOnboarding()
redirect(ROUTES.dashboard.root)
}, [executeCompleteOnboarding])

const ONBOARDING_STEPS = Object.entries(ONBOARDING_STEP_CONTENT)
const isLast = ONBOARDING_STEPS.length - 1
const filteredNavbarSteps = ONBOARDING_STEPS.filter(([key]) =>
onboardingSteps.includes(key as OnboardingStepKey),
)

return (
<div className='flex flex-col p-6 items-start gap-8 h-full'>
<div className='flex flex-col justify-between p-6 flex-1 rounded-3xl bg-secondary'>
<div className='flex flex-col gap-6 items-start'>
<div className='flex flex-col gap-1'>
<Text.H5 color='foregroundMuted'>Create your first agent</Text.H5>
<Text.H3M color='foreground'>{project.project.name}</Text.H3M>
<Text.H3M color='foreground'>{project.name}</Text.H3M>
</div>
<div className='flex flex-col gap-4'>
{Object.entries(ONBOARDING_STEP_CONTENT).map(
([key, item], index) => (
<Fragment key={index}>
<div className={cn(currentStep === key ? '' : 'opacity-70')}>
<NavbarItem
title={item.title}
description={item.description}
state={
isLoadingOnboarding
? StatusFlagState.pending
: calculateState(
key as OnboardingStepKey,
currentStep,
)
}
/>
</div>
{index ===
Object.entries(ONBOARDING_STEP_CONTENT).length - 1 ? null : (
<Separator variant='dashed' />
)}
</Fragment>
),
)}
{filteredNavbarSteps.map(([key, item], index) => (
<Fragment key={index}>
<div className={cn(currentStep === key ? '' : 'opacity-70')}>
<NavbarItem
title={item.title}
description={item.description}
state={
isLoadingOnboarding
? StatusFlagState.pending
: calculateState(key as OnboardingStepKey, currentStep)
}
/>
</div>
{index === isLast ? null : <Separator variant='dashed' />}
</Fragment>
))}
</div>
</div>
<div className='flex flex-col gap-3'>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useMemo } from 'react'
import {
DocumentTrigger,
DocumentVersion,
IntegrationDto,
} from '@latitude-data/core/schema/types'
import { Text } from '@latitude-data/web-ui/atoms/Text'
import { cn } from '@latitude-data/web-ui/utils'
import { useTriggerInfo } from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/preview/_components/TriggersCard'
import useDocumentVersions from '$/stores/documentVersions'
import {
StatusFlag,
StatusFlagState,
} from '@latitude-data/web-ui/molecules/StatusFlag'
import { useCurrentCommit } from '@latitude-data/web-ui/providers'

export function ConfiguredTriggers({
trigger,
integrations,
}: {
trigger: DocumentTrigger
integrations: IntegrationDto[]
}) {
const { commit } = useCurrentCommit()
const { data: documents } = useDocumentVersions({
projectId: trigger.projectId,
commitUuid: commit.uuid,
})

const document = useMemo<DocumentVersion | undefined>(
() => documents?.find((d) => d.documentUuid === trigger.documentUuid),
[documents, trigger.documentUuid],
)

// Loading documents. Triggers always should have a document linked
if (!document) return null

return (
<ConfiguredTriggerWrapper
trigger={trigger}
document={document}
integrations={integrations}
/>
)
}

function ConfiguredTriggerWrapper({
trigger,
document,
integrations,
}: {
trigger: DocumentTrigger
document: DocumentVersion
integrations: IntegrationDto[]
}) {
const { image, title, integration } = useTriggerInfo({
trigger,
document,
integrations,
})

return (
<div className='flex flex-col rounded-lg w-full bg-secondary items-center min-h-[60px]'>
<div className={'w-full p-4 flex flex-row items-start gap-4'}>
<div className='relative'>
<div
className={cn(
'size-10 rounded-md bg-backgroundCode flex items-center justify-center overflow-hidden',
)}
>
{image}
</div>
<div className='absolute -top-1 -right-1'>
<StatusFlag
state={StatusFlagState.completed}
backgroundColor='successMutedForeground'
/>
</div>
</div>
<div className='flex flex-col min-w-0'>
<Text.H4M ellipsis noWrap>
{title}
</Text.H4M>
{integration && (
<Text.H5 color='foregroundMuted'>
{integration.configuration.metadata?.displayName} trigger
configured successfully
</Text.H5>
)}
</div>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useCallback, useMemo, useState } from 'react'
import {
DocumentTrigger,
DocumentVersion,
IntegrationDto,
} from '@latitude-data/core/schema/types'
import { Text } from '@latitude-data/web-ui/atoms/Text'
import { cn } from '@latitude-data/web-ui/utils'
import { useTriggerInfo } from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/preview/_components/TriggersCard'
import useDocumentVersions from '$/stores/documentVersions'
import { Button } from '@latitude-data/web-ui/atoms/Button'
import { EditTriggerModal } from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/preview/@modal/(.)triggers/[triggerUuid]/edit/EditTriggerModal'
import { useCurrentCommit } from '@latitude-data/web-ui/providers'

export function UnconfiguredTriggers({
trigger,
integrations,
}: {
trigger: DocumentTrigger
integrations: IntegrationDto[]
}) {
const { commit } = useCurrentCommit()
const { data: documents } = useDocumentVersions({
projectId: trigger.projectId,
commitUuid: commit.uuid,
})

const document = useMemo<DocumentVersion | undefined>(
() => documents?.find((d) => d.documentUuid === trigger.documentUuid),
[documents, trigger.documentUuid],
)

// Loading documents. Triggers always should have a document linked
if (!document) return null

return (
<ConfigureTriggerWrapper
trigger={trigger}
document={document}
integrations={integrations}
/>
)
}

function ConfigureTriggerWrapper({
trigger,
document,
integrations,
}: {
trigger: DocumentTrigger
document: DocumentVersion
integrations: IntegrationDto[]
}) {
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
const { image, title, integration } = useTriggerInfo({
trigger,
document,
integrations,
})

const onCloseModal = useCallback(() => {
setIsEditModalOpen(false)
}, [])

return (
<div className='flex flex-col relative border rounded-lg w-full'>
<div
className={'w-full p-4 flex flex-row items-start justify-between gap-4'}
>
<div
className={cn(
'size-10 rounded-md bg-backgroundCode flex items-center justify-center overflow-hidden',
)}
>
{image}
</div>
<div className='flex flex-col min-w-0'>
<Text.H4M ellipsis noWrap>
{title}
</Text.H4M>
{integration && (
<Text.H5 color='foregroundMuted'>
{integration.configuration.metadata?.displayName} trigger needs
configuring
</Text.H5>
)}
</div>
<div className='flex-1 flex flex-row justify-end gap-x-4'>
<Button
fancy
variant='outline'
onClick={() => setIsEditModalOpen(true)}
iconProps={{ name: 'wrench', placement: 'left' }}
>
Configure
</Button>
</div>
</div>
{isEditModalOpen && (
<EditTriggerModal
triggerUuid={trigger.uuid}
onClose={onCloseModal}
withDeleteButton={false}
/>
)}
</div>
)
}
Loading
Loading