Skip to content

Commit 4b24453

Browse files
committed
Refactor UI to use local state for pipeline / status change tracking
Refactor LitLytics class to always return new values on actions Move step addition logic to litlytics class
1 parent f2eafba commit 4b24453

16 files changed

+413
-285
lines changed

app/components/pipeline/GeneratePipeline.tsx

+12-11
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const tabClass = clsx(
2424
);
2525

2626
export default function GeneratePipeline() {
27-
const litlytics = useLitlytics();
27+
const { litlytics, pipeline, setPipeline, pipelineStatus } = useLitlytics();
2828
const [selectedTab, setSelectedTab] = useState(0);
2929
const [isOpen, setIsOpen] = useState(false);
3030
const [loading, setLoading] = useState(false);
@@ -36,8 +36,8 @@ export default function GeneratePipeline() {
3636
setError(undefined);
3737

3838
// generate plan from LLM
39-
await litlytics.generatePipeline();
40-
39+
const newPipeline = await litlytics.generatePipeline();
40+
setPipeline(newPipeline);
4141
setLoading(false);
4242
setSelectedTab(1);
4343
} catch (err) {
@@ -49,9 +49,9 @@ export default function GeneratePipeline() {
4949
const closeDialog = () => {
5050
if (
5151
loading ||
52-
litlytics.pipelineStatus.status === 'refine' ||
53-
litlytics.pipelineStatus.status === 'step' ||
54-
litlytics.pipelineStatus.status === 'sourcing'
52+
pipelineStatus.status === 'refine' ||
53+
pipelineStatus.status === 'step' ||
54+
pipelineStatus.status === 'sourcing'
5555
) {
5656
return;
5757
}
@@ -65,8 +65,8 @@ export default function GeneratePipeline() {
6565
outline
6666
onClick={() => setIsOpen(true)}
6767
disabled={
68-
litlytics.pipelineStatus.status === 'sourcing' ||
69-
litlytics.pipelineStatus.status === 'step'
68+
pipelineStatus.status === 'sourcing' ||
69+
pipelineStatus.status === 'step'
7070
}
7171
className="border-sky-500 dark:border-sky-500"
7272
>
@@ -83,7 +83,7 @@ export default function GeneratePipeline() {
8383
<TabGroup selectedIndex={selectedTab} onChange={setSelectedTab}>
8484
<TabList className="flex gap-4">
8585
<Tab className={tabClass}>Plan</Tab>
86-
{Boolean(litlytics.pipeline.pipelinePlan?.length) && (
86+
{Boolean(pipeline.pipelinePlan?.length) && (
8787
<Tab className={tabClass}>Refine plan</Tab>
8888
)}
8989
</TabList>
@@ -96,9 +96,10 @@ export default function GeneratePipeline() {
9696
rows={5}
9797
name="task"
9898
placeholder="Task description"
99-
value={litlytics.pipeline.pipelineDescription}
99+
value={pipeline.pipelineDescription ?? ''}
100100
onChange={(e) => {
101-
litlytics.setPipeline({
101+
setPipeline({
102+
...pipeline,
102103
pipelineDescription: e.target.value,
103104
});
104105
}}

app/components/pipeline/PipelineBuilder.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { SourceNode } from './nodes/source/SourceNode';
55
import { StepNode } from './nodes/StepNode';
66

77
export function PipelineBuilder() {
8-
const litlytics = useLitlytics();
8+
const { pipeline } = useLitlytics();
99

1010
return (
1111
<Background>
1212
<SourceNode />
13-
{litlytics.pipeline.steps
13+
{pipeline.steps
1414
.sort((a, b) => (a.connectsTo.includes(b.id) ? -1 : 1))
1515
.map((step) => (
1616
<StepNode data={step} key={step.id} />

app/components/pipeline/RefinePipeline.tsx

+34-22
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ import { Spinner } from '~/components/Spinner';
66
import { useLitlytics } from '~/store/WithLitLytics';
77

88
export function RefinePipeline({ hide }: { hide: () => void }) {
9-
const litlytics = useLitlytics();
9+
const {
10+
litlytics,
11+
pipeline,
12+
setPipeline,
13+
pipelineStatus,
14+
setPipelineStatus,
15+
} = useLitlytics();
1016
const [error, setError] = useState<Error>();
1117
const [refine, setRefine] = useState(``);
1218
const [progress, setProgress] = useState('');
@@ -18,48 +24,54 @@ export function RefinePipeline({ hide }: { hide: () => void }) {
1824

1925
try {
2026
// generate plan from LLM
21-
litlytics.setPipelineStatus({ status: 'refine' });
22-
await litlytics.refinePipeline({
27+
setPipelineStatus({ status: 'refine' });
28+
const newPipeline = await litlytics.refinePipeline({
2329
refineRequest: refine,
2430
});
25-
litlytics.setPipelineStatus({ status: 'init' });
31+
setPipeline(newPipeline);
32+
setPipelineStatus({ status: 'init' });
2633
setRefine('');
2734
} catch (err) {
2835
setError(err as Error);
29-
litlytics.setPipelineStatus({ status: 'error' });
36+
setPipelineStatus({ status: 'error' });
3037
}
3138
};
3239

3340
const doCreate = async () => {
3441
try {
42+
setPipelineStatus({ status: 'sourcing' });
3543
// generate plan from LLM
36-
await litlytics.pipelineFromText(({ step, totalSteps }) => {
37-
if (step > totalSteps) {
38-
setProgress('');
39-
return;
40-
}
44+
const newPipeline = await litlytics.pipelineFromText(
45+
({ step, totalSteps }) => {
46+
if (step > totalSteps) {
47+
setProgress('');
48+
return;
49+
}
4150

42-
setProgress(`Generating steps: ${step} / ${totalSteps}`);
43-
});
51+
setProgress(`Generating steps: ${step} / ${totalSteps}`);
52+
}
53+
);
54+
setPipeline(newPipeline);
55+
setPipelineStatus({ status: 'done' });
4456
hide();
4557
} catch (err) {
4658
setError(err as Error);
47-
litlytics.setPipelineStatus({ status: 'error' });
59+
setPipelineStatus({ status: 'error' });
4860
}
4961
};
5062

5163
const inProgress =
52-
litlytics.pipelineStatus.status === 'refine' ||
53-
litlytics.pipelineStatus.status === 'sourcing' ||
54-
litlytics.pipelineStatus.status === 'step';
64+
pipelineStatus.status === 'refine' ||
65+
pipelineStatus.status === 'sourcing' ||
66+
pipelineStatus.status === 'step';
5567

5668
return (
5769
<div className="w-full h-full p-4 prose prose-sm prose-no-nr dark:prose-invert ">
5870
<div className="flex w-full items-center justify-between">
5971
<h1 className="m-0">Suggested pipeline:</h1>
6072
</div>
6173

62-
<CustomMarkdown>{`${litlytics.pipeline.pipelinePlan}`}</CustomMarkdown>
74+
<CustomMarkdown>{`${pipeline.pipelinePlan}`}</CustomMarkdown>
6375
<div className="flex gap-1">
6476
<Textarea
6577
rows={2}
@@ -69,7 +81,7 @@ export function RefinePipeline({ hide }: { hide: () => void }) {
6981
onChange={(e) => setRefine(e.target.value)}
7082
/>
7183
<Button onClick={doRefine} disabled={inProgress}>
72-
{litlytics.pipelineStatus.status === 'refine' && (
84+
{pipelineStatus.status === 'refine' && (
7385
<Spinner className="h-5 w-5" />
7486
)}
7587
Refine
@@ -84,14 +96,14 @@ export function RefinePipeline({ hide }: { hide: () => void }) {
8496

8597
<div className="flex mt-8">
8698
<Button onClick={doCreate} disabled={inProgress}>
87-
{(litlytics.pipelineStatus.status === 'sourcing' ||
88-
litlytics.pipelineStatus.status === 'step') && (
99+
{(pipelineStatus.status === 'sourcing' ||
100+
pipelineStatus.status === 'step') && (
89101
<div className="flex items-center">
90102
<Spinner className="h-5 w-5" />
91103
</div>
92104
)}
93-
{litlytics.pipelineStatus.status === 'sourcing' ||
94-
litlytics.pipelineStatus.status === 'step'
105+
{pipelineStatus.status === 'sourcing' ||
106+
pipelineStatus.status === 'step'
95107
? progress.length > 0
96108
? progress
97109
: `Generating pipeline...`

app/components/pipeline/nodes/NodeConnector.tsx

+7-63
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { PlusIcon } from '@heroicons/react/24/solid';
22
import clsx from 'clsx';
33
import {
4-
OUTPUT_ID,
54
ProcessingStep,
65
ProcessingStepTypes,
76
SourceStep,
@@ -47,7 +46,7 @@ export function NodeConnector({
4746
currentStep?: SourceStep | ProcessingStep;
4847
showAuto?: boolean;
4948
}) {
50-
const litlytics = useLitlytics();
49+
const { litlytics, setPipeline } = useLitlytics();
5150
const [step, setStep] = useState<ProcessingStep>(
5251
structuredClone(defaultStep)
5352
);
@@ -66,68 +65,13 @@ export function NodeConnector({
6665
}
6766

6867
setLoading(true);
69-
// generate new ID and double-check that it doesn't overlap with other steps
70-
let id = litlytics.pipeline.steps.length;
71-
let existingStep = litlytics.pipeline.steps.find(
72-
(s) => s.id === `step_${id}`
73-
);
74-
while (existingStep) {
75-
id += 1;
76-
existingStep = litlytics.pipeline.steps.find(
77-
(s) => s.id === `step_${id}`
78-
);
79-
}
80-
// generate final id
81-
const idStr = `step_${id}`;
82-
83-
let newStep: ProcessingStep | undefined = undefined;
84-
if (manual) {
85-
newStep = structuredClone(step);
86-
newStep.id = idStr;
87-
} else {
88-
// generate new step
89-
newStep = await litlytics.generateStep({
90-
id: idStr,
91-
name: step.name,
92-
description: step.description,
93-
input: step.input as StepInput,
94-
type: step.type,
95-
});
96-
}
9768

98-
if (currentStep?.type === 'source') {
99-
// connect new step to next node
100-
const nextNodeId =
101-
litlytics.pipeline.source.connectsTo.at(0) ?? OUTPUT_ID;
102-
newStep.connectsTo = [nextNodeId];
103-
// add
104-
litlytics.setPipeline({
105-
source: {
106-
...litlytics.pipeline.source,
107-
connectsTo: [newStep.id],
108-
},
109-
steps: litlytics.pipeline.steps.concat(newStep),
110-
});
111-
} else {
112-
// connect new step to next node
113-
const nextNodeId =
114-
litlytics.pipeline.steps
115-
.find((s) => s.id === currentStep?.id)
116-
?.connectsTo.at(0) ?? OUTPUT_ID;
117-
newStep.connectsTo = [nextNodeId];
118-
// add
119-
litlytics.setPipeline({
120-
steps: litlytics.pipeline.steps
121-
.map((s) => {
122-
if (s.id === currentStep?.id) {
123-
s.connectsTo = [newStep.id];
124-
return s;
125-
}
126-
return s;
127-
})
128-
.concat(newStep),
129-
});
130-
}
69+
const newPipeline = await litlytics.addStep({
70+
step,
71+
sourceStep: currentStep,
72+
manual,
73+
});
74+
setPipeline(newPipeline);
13175

13276
setIsOpen(false);
13377
setLoading(false);

0 commit comments

Comments
 (0)