Skip to content

Commit

Permalink
display block list used in template
Browse files Browse the repository at this point in the history
  • Loading branch information
breeg554 committed Oct 10, 2024
1 parent d30c8b1 commit 55419a2
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from 'zod';

import { KnowledgeBaseCollectionCost } from '~/api/knowledgeBase/knowledgeApi.contracts';
import { PipelineCost } from '~/api/pipeline/pipeline.contracts';
import { Pipeline, PipelineCost } from '~/api/pipeline/pipeline.contracts';
import { PaginationMeta } from '~/components/pagination/pagination.types';

export const Organization = z.object({
Expand Down Expand Up @@ -86,6 +86,11 @@ export const WorkflowTemplate = z.object({
template_name: z.string(),
template_description: z.string(),
groups: z.array(z.string()),
template_config: Pipeline.pick({
config: true,
name: true,
interface_config: true,
}),
});

export type IWorkflowTemplate = z.TypeOf<typeof WorkflowTemplate>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';
import { ClientOnly } from 'remix-utils/client-only';

import { resolveBlockTypeIconPath } from '~/components/pages/pipelines/blockTypes.utils';
import type { IBlockConfig } from '~/components/pages/pipelines/pipeline.types';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '~/components/ui/tooltip';
import { cn } from '~/utils/cn';

interface WorkflowBlockListProps {
blocks: IBlockConfig[];
}

export function WorkflowBlockList({ blocks }: WorkflowBlockListProps) {
return (
<ul className="flex -space-x-2">
{blocks.map((block) => (
<WorkflowBlockListItem block={block} key={block.name} />
))}
</ul>
);
}

interface WorkflowBlockListItemProps {
block: IBlockConfig;
}
function WorkflowBlockListItem({ block }: WorkflowBlockListItemProps) {
const imageRef = React.useRef<HTMLImageElement>(null);

const onImageError = () => {
if (!imageRef.current) return;

imageRef.current.src = resolveBlockTypeIconPath('default');
};

return (
<TooltipProvider>
<Tooltip delayDuration={500}>
<TooltipTrigger asChild>
<li className="w-6 h-6 rounded-full bg-white border border-input flex justify-center items-center">
<ClientOnly
fallback={
<div className="w-3.5 h-3.5 bg-secondary rounded-full" />
}
>
{() => (
<img
src={resolveBlockTypeIconPath(`type/${block.type}`)}
alt={block.type}
onError={onImageError}
className="w-3.5 h-3.5"
ref={imageRef}
/>
)}
</ClientOnly>
</li>
</TooltipTrigger>

<TooltipContent side="top" className="text-xs">
{block.type}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

export function WorkflowBlockListOverflow({
className,
...rest
}: Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>) {
return (
<div
className={cn(
'absolute h-6 w-8 right-0 bottom-2 bg-gradient-to-r from-transparent to-white pointer-events-none xl:bottom-0',
className,
)}
{...rest}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {
LockOpen,
Trash,
} from 'lucide-react';
import { ClientOnly } from 'remix-utils/client-only';
import { ValidatedForm } from 'remix-validated-form';

import { CreatePipelineSchema } from '~/api/pipeline/pipeline.contracts';
import { HiddenField } from '~/components/form/fields/field.context';
import { IconButton } from '~/components/iconButton';
import { resolveBlockTypeIconPath } from '~/components/pages/pipelines/blockTypes.utils';
import {
WorkflowBlockList,
WorkflowBlockListOverflow,
} from '~/components/pages/pipelines/components/WorkflowBlockList';
import type { BadgeProps } from '~/components/ui/badge';
import { Badge } from '~/components/ui/badge';
import { Button } from '~/components/ui/button';
Expand Down Expand Up @@ -47,11 +49,7 @@ import { cn } from '~/utils/cn';
import { MonetaryValue } from '~/utils/MonetaryValue';
import { routes } from '~/utils/routes.utils';

import type {
IBlockConfig,
IInterfaceConfigForm,
IPipeline,
} from '../pipeline.types';
import type { IInterfaceConfigForm, IPipeline } from '../pipeline.types';

interface PipelinesListItemProps extends PropsWithChildren {
className?: string;
Expand Down Expand Up @@ -195,14 +193,14 @@ export const PipelineListItemContent = ({
<CardContentColumnTitle>Blocks</CardContentColumnTitle>

{pipeline.config.blocks.length > 0 ? (
<PipelineItemBlockList pipeline={pipeline} />
<WorkflowBlockList blocks={pipeline.config.blocks} />
) : (
<CardContentBooleanValue value={false}>
None
</CardContentBooleanValue>
)}

<div className="absolute h-6 w-8 right-0 bottom-2 bg-gradient-to-r from-transparent to-white pointer-events-none xl:bottom-0" />
<WorkflowBlockListOverflow />
</CardContentColumnWrapper>
</div>
</CardContent>
Expand All @@ -215,7 +213,7 @@ interface DuplicateFormProps {

function DuplicateForm({ pipeline }: DuplicateFormProps) {
const validator = useMemo(() => withZod(CreatePipelineSchema), []);
console.log(pipeline);

return (
<ValidatedForm
method="POST"
Expand Down Expand Up @@ -296,64 +294,6 @@ function PipelineItemInterfaceBadge({
);
}

interface PipelineItemBlockListProps {
pipeline: IPipeline;
}

function PipelineItemBlockList({ pipeline }: PipelineItemBlockListProps) {
return (
<ul className="flex -space-x-2">
{pipeline.config.blocks.map((block) => (
<PipelineItemBlockListBlock block={block} key={block.name} />
))}
</ul>
);
}
interface PipelineItemBlockListBlockProps {
block: IBlockConfig;
}
function PipelineItemBlockListBlock({
block,
}: PipelineItemBlockListBlockProps) {
const imageRef = React.useRef<HTMLImageElement>(null);

const onImageError = () => {
if (!imageRef.current) return;

imageRef.current.src = resolveBlockTypeIconPath('default');
};

return (
<TooltipProvider>
<Tooltip delayDuration={500}>
<TooltipTrigger asChild>
<li className="w-6 h-6 rounded-full bg-white border border-input flex justify-center items-center">
<ClientOnly
fallback={
<div className="w-3.5 h-3.5 bg-secondary rounded-full" />
}
>
{() => (
<img
src={resolveBlockTypeIconPath(`type/${block.type}`)}
alt={block.type}
onError={onImageError}
className="w-3.5 h-3.5"
ref={imageRef}
/>
)}
</ClientOnly>
</li>
</TooltipTrigger>

<TooltipContent side="top" className="text-xs">
{block.type}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

function isInterfaceInitialized(config: IInterfaceConfigForm) {
return config.outputs.length > 0 && config.inputs.length > 0;
}
38 changes: 27 additions & 11 deletions apps/web-remix/app/components/pages/pipelines/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { TextInputField } from '~/components/form/fields/text.field';
import { SubmitButton } from '~/components/form/submit';
import { BasicLink } from '~/components/link/BasicLink';
import { ItemList } from '~/components/list/ItemList';
import {
WorkflowBlockList,
WorkflowBlockListOverflow,
} from '~/components/pages/pipelines/components/WorkflowBlockList';
import {
getTemplateImageColor,
resolveTemplateImageUrl,
Expand Down Expand Up @@ -119,7 +123,7 @@ function NameFormStep() {

function TemplatesStep() {
const { templates, organizationId } = useLoaderData<typeof loader>();

console.log(templates);
return (
<>
<div className="flex justify-between gap-2 items-center mb-2">
Expand Down Expand Up @@ -219,13 +223,15 @@ export function TemplateList({ items, action, children }: TemplateListProps) {
[items],
);
return (
<ItemList
className="grid grid-cols-1 md:grid-cols-2 gap-3"
items={formattedTemplates}
renderItem={(item) => <TemplateListItem action={action} item={item} />}
>
{children}
</ItemList>
<div className="max-h-[600px] overflow-y-auto">
<ItemList
className="grid grid-cols-1 md:grid-cols-2 gap-3"
items={formattedTemplates}
renderItem={(item) => <TemplateListItem action={action} item={item} />}
>
{children}
</ItemList>
</div>
);
}

Expand All @@ -236,14 +242,15 @@ interface ITemplateItem {
function TemplateListItem({ item, action }: ITemplateItem) {
const ref = useRef<HTMLFormElement>(null);
const validator = useMemo(() => withZod(CreateFromTemplateSchema), []);

return (
<ValidatedForm
formRef={ref}
action={action}
method="POST"
validator={validator}
onClick={() => ref.current?.submit()}
className="group p-2 bg-white border border-neutral-100 min-h-[90px] rounded-xl transition hover:border-blue-200 cursor-pointer md:p-3 md:min-h-[98px]"
className="group p-2 bg-white border border-neutral-100 min-h-[90px] rounded-xl transition hover:border-blue-200 cursor-pointer md:p-3 md:min-h-[98px] h-full"
>
<div className="flex flex-col gap-2">
<div className="flex gap-2 items-center">
Expand All @@ -265,11 +272,20 @@ function TemplateListItem({ item, action }: ITemplateItem) {
</h4>
</div>

<div className="grow">
<p className="text-xs text-muted-foreground line-clamp-2">
<div className="grow min-h-[32px]">
<p
className="text-xs text-muted-foreground line-clamp-2"
title={item.template_description}
>
{item.template_description}
</p>
</div>

<div className="relative overflow-x-hidden w-full flex">
<WorkflowBlockList blocks={item.template_config.config.blocks} />

<WorkflowBlockListOverflow className="bottom-0" />
</div>
</div>

<HiddenField name="template_name" value={item.template_name} />
Expand Down

0 comments on commit 55419a2

Please sign in to comment.