Skip to content

Commit bf08330

Browse files
authored
Bug fixes for new Connect UX (#2113)
* fix: fixed major connect bugs * feat: fixed start/stop pipeline button and removed refresh from heading * fix: lint * feat: PR comments and removed extra ui state for hiding header
1 parent 87f55ef commit bf08330

File tree

11 files changed

+421
-220
lines changed

11 files changed

+421
-220
lines changed

frontend/src/components/layout/header.tsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { computed } from 'mobx';
1414
import { observer } from 'mobx-react';
1515
import { Link as ReactRouterLink, useMatch } from 'react-router-dom';
1616

17-
import { isEmbedded } from '../../config';
17+
import { isEmbedded, isFeatureFlagEnabled } from '../../config';
1818
import { api } from '../../state/backend-api';
1919
import { type BreadcrumbEntry, uiState } from '../../state/ui-state';
2020
import { IsDev } from '../../utils/env';
@@ -42,7 +42,7 @@ const AppPageHeader = observer(() => {
4242

4343
const lastBreadcrumb = breadcrumbItems.pop();
4444

45-
if (shouldHideHeader) {
45+
if (shouldHideHeader || uiState.shouldHidePageHeader) {
4646
return null;
4747
}
4848

@@ -144,6 +144,16 @@ function useShouldShowRefresh() {
144144
end: true,
145145
});
146146

147+
const connectWizardPagesMatch = useMatch({
148+
path: '/rp-connect/wizard',
149+
end: false,
150+
});
151+
152+
const getStartedApiMatch = useMatch({
153+
path: '/get-started/api',
154+
end: false,
155+
});
156+
147157
// matches acls
148158
const aclCreateMatch = useMatch('/security/acls/create');
149159
const aclUpdateMatch = useMatch('/security/acls/:id/update');
@@ -174,6 +184,12 @@ function useShouldShowRefresh() {
174184
if (isRoleRelated) {
175185
return false;
176186
}
187+
if (connectWizardPagesMatch) {
188+
return false;
189+
}
190+
if (getStartedApiMatch) {
191+
return false;
192+
}
177193

178194
return true;
179195
}
@@ -199,10 +215,23 @@ function useShouldHideHeader() {
199215
end: false,
200216
});
201217

218+
const pipelineDetailsMatch = useMatch({
219+
path: '/rp-connect/:pipelineId',
220+
end: true,
221+
});
222+
223+
const pipelineEditMatch = useMatch({
224+
path: '/rp-connect/:pipelineId/edit',
225+
end: false,
226+
});
227+
const isNewRpcnUX = isFeatureFlagEnabled('enableRpcnTiles') && isEmbedded();
228+
202229
return (
203230
remoteMcpPagesMatch !== null ||
204231
aiAgentPagesMatch !== null ||
205232
knowledgeBasePagesMatch !== null ||
206-
secretPagesMatch !== null
233+
secretPagesMatch !== null ||
234+
(pipelineDetailsMatch !== null && isNewRpcnUX) ||
235+
(pipelineEditMatch !== null && isNewRpcnUX)
207236
);
208237
}

frontend/src/components/pages/rp-connect/pipeline/details.tsx

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
AccordionTrigger,
1717
} from 'components/redpanda-ui/components/accordion';
1818
import { Card, CardContent } from 'components/redpanda-ui/components/card';
19+
import { CopyButton } from 'components/redpanda-ui/components/copy-button';
1920
import {
2021
FormControl,
2122
FormDescription,
@@ -25,49 +26,70 @@ import {
2526
FormMessage,
2627
} from 'components/redpanda-ui/components/form';
2728
import { Input } from 'components/redpanda-ui/components/input';
28-
import { Label } from 'components/redpanda-ui/components/label';
29+
import { SkeletonCard } from 'components/redpanda-ui/components/skeleton';
2930
import { Slider } from 'components/redpanda-ui/components/slider';
3031
import { Textarea } from 'components/redpanda-ui/components/textarea';
32+
import { Tooltip, TooltipContent, TooltipTrigger } from 'components/redpanda-ui/components/tooltip';
3133
import { Text } from 'components/redpanda-ui/components/typography';
34+
import { InfoIcon } from 'lucide-react';
35+
import type { Pipeline } from 'protogen/redpanda/api/dataplane/v1/pipeline_pb';
36+
import React from 'react';
3237
import { useFormContext } from 'react-hook-form';
3338

34-
import { MAX_TASKS, MIN_TASKS } from '../tasks';
39+
import { cpuToTasks, MAX_TASKS, MIN_TASKS } from '../tasks';
3540

3641
type DetailsProps = {
3742
readonly?: boolean;
43+
pipeline?: Pipeline;
3844
};
3945

40-
export function Details({ readonly = false }: DetailsProps) {
41-
const { control, watch } = useFormContext();
42-
const name = watch('name');
43-
const description = watch('description');
44-
const computeUnits = watch('computeUnits');
46+
const DetailRow = ({
47+
label,
48+
value,
49+
copyable = false,
50+
}: {
51+
label: React.ReactNode;
52+
value?: string;
53+
copyable?: boolean;
54+
}) => (
55+
<div className="grid h-7 min-w-0 grid-cols-[minmax(0,1.5fr)_minmax(0,2fr)_30px] gap-1">
56+
{typeof label === 'string' ? <Text variant="label">{label}</Text> : (label ?? null)}
57+
<Text className="truncate">{value ?? ''}</Text>
58+
{copyable && value ? <CopyButton content={value} size="sm" variant="ghost" /> : null}
59+
</div>
60+
);
61+
62+
export function Details({ readonly = false, pipeline }: DetailsProps) {
63+
const { control } = useFormContext();
4564

4665
if (readonly) {
66+
if (!pipeline) {
67+
return <SkeletonCard />;
68+
}
4769
return (
4870
<Card size="full">
4971
<CardContent>
50-
<div className="flex items-center gap-4">
51-
<Label>Pipeline Name</Label>
52-
<Text>{name}</Text>
72+
<div className="flex flex-col gap-4">
73+
<DetailRow copyable label="ID" value={pipeline.id} />
74+
<DetailRow label="Description" value={pipeline.description} />
75+
<div className="flex flex-col">
76+
<DetailRow
77+
label={
78+
<Tooltip>
79+
<Text className="flex items-center gap-1" variant="label">
80+
Compute units
81+
<TooltipTrigger>
82+
<InfoIcon className="-mt-0.5 size-3 cursor-pointer text-muted-foreground" />
83+
</TooltipTrigger>
84+
</Text>
85+
<TooltipContent>One compute unit = 0.1 CPU and 400 MB memory</TooltipContent>
86+
</Tooltip>
87+
}
88+
value={`${cpuToTasks(pipeline.resources?.cpuShares) ?? 0}`}
89+
/>
90+
</div>
91+
<DetailRow copyable label="URL" value={pipeline.url} />
5392
</div>
54-
55-
<Accordion collapsible type="single">
56-
<AccordionItem value="advanced" variant="outlined">
57-
<AccordionTrigger>Advanced Settings</AccordionTrigger>
58-
<AccordionContent className="space-y-4">
59-
<div className="space-y-2">
60-
<Label>Description</Label>
61-
<Text>{description || '-'}</Text>
62-
</div>
63-
64-
<div className="space-y-2">
65-
<Label>Compute Units: {computeUnits}</Label>
66-
<Text variant="muted">One compute unit = 0.1 CPU and 400 MB memory</Text>
67-
</div>
68-
</AccordionContent>
69-
</AccordionItem>
70-
</Accordion>
7193
</CardContent>
7294
</Card>
7395
);
@@ -81,7 +103,7 @@ export function Details({ readonly = false }: DetailsProps) {
81103
name="name"
82104
render={({ field }) => (
83105
<FormItem>
84-
<FormLabel required>Pipeline Name</FormLabel>
106+
<FormLabel required>Pipeline name</FormLabel>
85107
<FormControl>
86108
<Input {...field} placeholder="Enter pipeline name" />
87109
</FormControl>
@@ -91,9 +113,9 @@ export function Details({ readonly = false }: DetailsProps) {
91113
/>
92114

93115
<Accordion collapsible type="single">
94-
<AccordionItem value="advanced" variant="outlined">
95-
<AccordionTrigger>Advanced Settings</AccordionTrigger>
96-
<AccordionContent className="space-y-4">
116+
<AccordionItem value="advanced" variant="contained">
117+
<AccordionTrigger>Advanced settings</AccordionTrigger>
118+
<AccordionContent className="space-y-4 pt-4">
97119
<FormField
98120
control={control}
99121
name="description"
@@ -113,7 +135,7 @@ export function Details({ readonly = false }: DetailsProps) {
113135
name="computeUnits"
114136
render={({ field }) => (
115137
<FormItem>
116-
<FormLabel>Compute Units: {field.value}</FormLabel>
138+
<FormLabel>Compute units</FormLabel>
117139
<FormControl>
118140
<div className="flex items-center gap-2">
119141
<Slider

frontend/src/components/pages/rp-connect/pipeline/index.tsx

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { Form } from 'components/redpanda-ui/components/form';
1818
import { Skeleton, SkeletonGroup } from 'components/redpanda-ui/components/skeleton';
1919
import { Spinner } from 'components/redpanda-ui/components/spinner';
2020
import { Tabs, TabsContent, TabsContents, TabsList, TabsTrigger } from 'components/redpanda-ui/components/tabs';
21+
import { Heading } from 'components/redpanda-ui/components/typography';
22+
import { cn } from 'components/redpanda-ui/lib/utils';
2123
import { LintHintList } from 'components/ui/lint-hint/lint-hint-list';
2224
import { YamlEditorCard } from 'components/ui/yaml/yaml-editor-card';
2325
import { useDebounce } from 'hooks/use-debounce';
@@ -171,7 +173,10 @@ const PipelinePageSkeleton = memo(({ mode }: { mode: PipelineMode }) => {
171173
});
172174

173175
const pipelineFormSchema = z.object({
174-
name: z.string().min(1, 'Pipeline name is required').max(100, 'Pipeline name must be less than 100 characters'),
176+
name: z
177+
.string()
178+
.min(3, 'Pipeline name must be at least 3 characters')
179+
.max(100, 'Pipeline name must be less than 100 characters'),
175180
description: z.string().optional(),
176181
computeUnits: z.number().min(MIN_TASKS).int(),
177182
});
@@ -192,6 +197,7 @@ export default function PipelinePage() {
192197

193198
const form = useForm<PipelineFormValues>({
194199
resolver: zodResolver(pipelineFormSchema),
200+
mode: 'onChange',
195201
defaultValues: {
196202
name: '',
197203
description: '',
@@ -482,7 +488,7 @@ export default function PipelinePage() {
482488
const content = (
483489
<>
484490
<Form {...form}>
485-
<Details readonly={mode === 'view'} />
491+
<Details pipeline={pipeline} readonly={mode === 'view'} />
486492
</Form>
487493

488494
<YamlEditorCard
@@ -544,22 +550,30 @@ export default function PipelinePage() {
544550
};
545551

546552
return (
547-
<div className="grid grid-cols-[minmax(auto,_950px)_260px] gap-4">
548-
<div className="flex flex-1 flex-col gap-4">
549-
{mode === 'view' && pipelineId && (
550-
<Toolbar pipelineId={pipelineId} pipelineName={form.getValues('name')} pipelineState={pipeline?.state} />
553+
<div>
554+
{mode === 'edit' && (
555+
<div className="mt-12 mb-4">
556+
<Heading level={1}>Edit pipeline</Heading>
557+
</div>
558+
)}
559+
<div className={cn((mode === 'create' || mode === 'edit') && 'grid grid-cols-[minmax(auto,950px)_260px] gap-4')}>
560+
<div className="flex flex-1 flex-col gap-4">
561+
{mode === 'view' && pipelineId && (
562+
<Toolbar pipelineId={pipelineId} pipelineName={form.getValues('name')} pipelineState={pipeline?.state} />
563+
)}
564+
565+
{renderContent()}
566+
</div>
567+
{(mode === 'create' || mode === 'edit') && (
568+
<CreatePipelineSidebar
569+
componentList={componentListResponse?.components}
570+
editorContent={yamlContent}
571+
editorInstance={editorInstance}
572+
isComponentListLoading={isComponentListLoading}
573+
setYamlContent={handleSetYamlContent}
574+
/>
551575
)}
552-
{renderContent()}
553576
</div>
554-
{(mode === 'create' || mode === 'edit') && (
555-
<CreatePipelineSidebar
556-
componentList={componentListResponse?.components}
557-
editorContent={yamlContent}
558-
editorInstance={editorInstance}
559-
isComponentListLoading={isComponentListLoading}
560-
setYamlContent={handleSetYamlContent}
561-
/>
562-
)}
563577
</div>
564578
);
565579
}

0 commit comments

Comments
 (0)