Skip to content

Commit 5a7e27b

Browse files
authored
Merge branch 'main' into fix/async-context-fsspec
2 parents eb3f326 + effc324 commit 5a7e27b

8 files changed

Lines changed: 113 additions & 124 deletions

File tree

src/renderer/components/Experiment/Interactive/Interactive.tsx

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ import {
1313
} from '@mui/joy';
1414
import dayjs from 'dayjs';
1515
import relativeTime from 'dayjs/plugin/relativeTime';
16-
import { PlusIcon, TerminalIcon, PlayIcon, Trash2Icon } from 'lucide-react';
16+
import {
17+
PlusIcon,
18+
TerminalIcon,
19+
PlayIcon,
20+
Trash2Icon,
21+
LogsIcon,
22+
} from 'lucide-react';
1723
import { useSWRWithAuth as useSWR, useAPI } from 'renderer/lib/authContext';
1824

1925
import * as chatAPI from 'renderer/lib/transformerlab-api-sdk';
@@ -813,16 +819,28 @@ export default function Interactive() {
813819
interactiveType === 'vllm' ||
814820
interactiveType === 'ollama' ||
815821
interactiveType === 'ssh') && (
816-
<Button
817-
variant="soft"
818-
color="primary"
819-
size="sm"
820-
onClick={() =>
821-
handleViewInteractive(parseInt(job.id))
822-
}
823-
>
824-
Interactive Setup
825-
</Button>
822+
<>
823+
<Button
824+
variant="plain"
825+
size="sm"
826+
startDecorator={<LogsIcon size={16} />}
827+
onClick={() =>
828+
setViewOutputFromJob(parseInt(job.id))
829+
}
830+
>
831+
Output
832+
</Button>
833+
<Button
834+
variant="soft"
835+
color="primary"
836+
size="sm"
837+
onClick={() =>
838+
handleViewInteractive(parseInt(job.id))
839+
}
840+
>
841+
Interactive Setup
842+
</Button>
843+
</>
826844
)}
827845
<IconButton
828846
variant="plain"

src/renderer/components/Experiment/Tasks/InteractiveJupyterModal.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import { fetcher } from 'renderer/lib/transformerlab-api-sdk';
2222
type InteractiveJupyterModalProps = {
2323
jobId: number;
2424
setJobId: (jobId: number) => void;
25+
onOpenOutput?: (jobId: number) => void;
2526
};
2627

2728
export default function InteractiveJupyterModal({
2829
jobId,
2930
setJobId,
31+
onOpenOutput,
3032
}: InteractiveJupyterModalProps) {
3133
const { experimentInfo } = useExperimentInfo();
3234

@@ -179,27 +181,6 @@ export default function InteractiveJupyterModal({
179181
logs to ensure Jupyter and ngrok started correctly.
180182
</Typography>
181183
</Box>
182-
183-
<Divider />
184-
185-
<Stack direction="row" spacing={1}>
186-
<Button
187-
size="sm"
188-
variant="outlined"
189-
startDecorator={<LogsIcon size={16} />}
190-
onClick={() => {
191-
// Reuse the existing output modal via the main Tasks page
192-
window.dispatchEvent(
193-
new CustomEvent('tflab-open-job-output', {
194-
detail: { jobId },
195-
}),
196-
);
197-
}}
198-
>
199-
Open Output & Provider Logs
200-
</Button>
201-
<Box flex={1} />
202-
</Stack>
203184
</Box>
204185
</ModalDialog>
205186
</Modal>

src/renderer/components/Experiment/Tasks/InteractiveOllamaModal.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ import { fetcher } from 'renderer/lib/transformerlab-api-sdk';
2121
type InteractiveOllamaModalProps = {
2222
jobId: number;
2323
setJobId: (jobId: number) => void;
24+
onOpenOutput?: (jobId: number) => void;
2425
};
2526

2627
export default function InteractiveOllamaModal({
2728
jobId,
2829
setJobId,
30+
onOpenOutput,
2931
}: InteractiveOllamaModalProps) {
3032
const { experimentInfo } = useExperimentInfo();
3133

@@ -203,27 +205,6 @@ export default function InteractiveOllamaModal({
203205
logs to ensure Ollama and ngrok started correctly.
204206
</Typography>
205207
</Box>
206-
207-
<Divider />
208-
209-
<Stack direction="row" spacing={1}>
210-
<Button
211-
size="sm"
212-
variant="outlined"
213-
startDecorator={<LogsIcon size={16} />}
214-
onClick={() => {
215-
// Reuse the existing output modal via the main Tasks page
216-
window.dispatchEvent(
217-
new CustomEvent('tflab-open-job-output', {
218-
detail: { jobId },
219-
}),
220-
);
221-
}}
222-
>
223-
Open Output & Provider Logs
224-
</Button>
225-
<Box flex={1} />
226-
</Stack>
227208
</Box>
228209
</ModalDialog>
229210
</Modal>

src/renderer/components/Experiment/Tasks/InteractiveSshModal.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ import { fetcher } from 'renderer/lib/transformerlab-api-sdk';
2121
type InteractiveSshModalProps = {
2222
jobId: number;
2323
setJobId: (jobId: number) => void;
24+
onOpenOutput?: (jobId: number) => void;
2425
};
2526

2627
export default function InteractiveSshModal({
2728
jobId,
2829
setJobId,
30+
onOpenOutput,
2931
}: InteractiveSshModalProps) {
3032
const { experimentInfo } = useExperimentInfo();
3133

@@ -226,27 +228,6 @@ export default function InteractiveSshModal({
226228
provider logs to ensure ngrok started correctly.
227229
</Typography>
228230
</Box>
229-
230-
<Divider />
231-
232-
<Stack direction="row" spacing={1}>
233-
<Button
234-
size="sm"
235-
variant="outlined"
236-
startDecorator={<LogsIcon size={16} />}
237-
onClick={() => {
238-
// Reuse the existing output modal via the main Tasks page
239-
window.dispatchEvent(
240-
new CustomEvent('tflab-open-job-output', {
241-
detail: { jobId },
242-
}),
243-
);
244-
}}
245-
>
246-
Open Output & Provider Logs
247-
</Button>
248-
<Box flex={1} />
249-
</Stack>
250231
</Box>
251232
</ModalDialog>
252233
</Modal>

src/renderer/components/Experiment/Tasks/InteractiveVSCodeModal.tsx

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import { fetcher } from 'renderer/lib/transformerlab-api-sdk';
2222
type InteractiveVSCodeModalProps = {
2323
jobId: number;
2424
setJobId: (jobId: number) => void;
25+
onOpenOutput?: (jobId: number) => void;
2526
};
2627

2728
export default function InteractiveVSCodeModal({
2829
jobId,
2930
setJobId,
31+
onOpenOutput,
3032
}: InteractiveVSCodeModalProps) {
3133
const { experimentInfo } = useExperimentInfo();
3234

@@ -218,28 +220,6 @@ export default function InteractiveVSCodeModal({
218220
)}
219221
</Box>
220222
</Box>
221-
222-
<Divider />
223-
224-
<Stack direction="row" spacing={1}>
225-
<Button
226-
size="sm"
227-
variant="outlined"
228-
startDecorator={<LogsIcon size={16} />}
229-
onClick={() => {
230-
// Reuse the existing output modal via the main Tasks page
231-
// This just nudges the user to open the standard Output modal.
232-
window.dispatchEvent(
233-
new CustomEvent('tflab-open-job-output', {
234-
detail: { jobId },
235-
}),
236-
);
237-
}}
238-
>
239-
Open Output & Provider Logs
240-
</Button>
241-
<Box flex={1} />
242-
</Stack>
243223
</Box>
244224
</ModalDialog>
245225
</Modal>

src/renderer/components/Experiment/Tasks/InteractiveVllmModal.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ import { fetcher } from 'renderer/lib/transformerlab-api-sdk';
2121
type InteractiveVllmModalProps = {
2222
jobId: number;
2323
setJobId: (jobId: number) => void;
24+
onOpenOutput?: (jobId: number) => void;
2425
};
2526

2627
export default function InteractiveVllmModal({
2728
jobId,
2829
setJobId,
30+
onOpenOutput,
2931
}: InteractiveVllmModalProps) {
3032
const { experimentInfo } = useExperimentInfo();
3133

@@ -204,27 +206,6 @@ export default function InteractiveVllmModal({
204206
logs to ensure vLLM and ngrok started correctly.
205207
</Typography>
206208
</Box>
207-
208-
<Divider />
209-
210-
<Stack direction="row" spacing={1}>
211-
<Button
212-
size="sm"
213-
variant="outlined"
214-
startDecorator={<LogsIcon size={16} />}
215-
onClick={() => {
216-
// Reuse the existing output modal via the main Tasks page
217-
window.dispatchEvent(
218-
new CustomEvent('tflab-open-job-output', {
219-
detail: { jobId },
220-
}),
221-
);
222-
}}
223-
>
224-
Open Output & Provider Logs
225-
</Button>
226-
<Box flex={1} />
227-
</Stack>
228209
</Box>
229210
</ModalDialog>
230211
</Modal>

src/renderer/components/Experiment/Tasks/JobsList.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,33 @@ const JobsList: React.FC<JobsListProps> = ({
310310
job?.job_data?.interactive_type === 'vllm' ||
311311
job?.job_data?.interactive_type === 'ollama' ||
312312
job?.job_data?.interactive_type === 'ssh') && (
313-
<Button
314-
size="sm"
315-
variant="plain"
316-
onClick={() => onViewInteractive?.(job?.id)}
317-
>
318-
Interactive Setup
319-
</Button>
313+
<>
314+
<Button
315+
size="sm"
316+
variant="plain"
317+
onClick={() => onViewInteractive?.(job?.id)}
318+
>
319+
Interactive Setup
320+
</Button>
321+
<Button
322+
size="sm"
323+
variant="plain"
324+
onClick={() => onViewOutput?.(job?.id)}
325+
startDecorator={<LogsIcon />}
326+
>
327+
<Box
328+
sx={{
329+
display: {
330+
xs: 'none',
331+
sm: 'none',
332+
md: 'inline-flex',
333+
},
334+
}}
335+
>
336+
Output
337+
</Box>
338+
</Button>
339+
</>
320340
)}
321341
{job?.job_data?.checkpoints && (
322342
<Button

src/renderer/components/Experiment/Tasks/Tasks.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,46 @@ export default function Tasks({ subtype }: { subtype?: string }) {
135135
};
136136
}, [pendingJobsStorageKey]);
137137

138+
// Listen for custom event to open job output modal from interactive modals
139+
useEffect(() => {
140+
const handleOpenJobOutput = (e: Event) => {
141+
const customEvent = e as CustomEvent<{ jobId: number }>;
142+
const jobId = customEvent.detail?.jobId;
143+
if (jobId && jobId !== -1) {
144+
// Close the interactive modal first
145+
setInteractiveJobForModal(-1);
146+
// Wait for the modal to close (MUI modals have transition animations)
147+
// Use a longer delay to ensure the interactive modal fully closes
148+
// before opening the output modal to avoid z-index/stacking issues
149+
setTimeout(() => {
150+
setViewOutputFromJob(jobId);
151+
}, 300); // 300ms should be enough for modal close animation
152+
}
153+
};
154+
155+
const eventName = 'tflab-open-job-output';
156+
window.addEventListener(eventName, handleOpenJobOutput);
157+
158+
return () => {
159+
window.removeEventListener(eventName, handleOpenJobOutput);
160+
};
161+
}, []);
162+
138163
const isInteractivePage = subtype === 'interactive';
139164

165+
// Define the callback outside the IIFE to ensure it's always available
166+
const handleOpenOutputFromInteractive = useCallback(
167+
(outputJobId: number) => {
168+
// Close the interactive modal first
169+
setInteractiveJobForModal(-1);
170+
// Wait for modal close animation, then open output modal
171+
setTimeout(() => {
172+
setViewOutputFromJob(outputJobId);
173+
}, 300);
174+
},
175+
[interactiveJobForModal],
176+
);
177+
140178
const handleOpen = () => {
141179
if (isInteractivePage) {
142180
setInteractiveModalOpen(true);
@@ -1092,6 +1130,7 @@ export default function Tasks({ subtype }: { subtype?: string }) {
10921130
<InteractiveJupyterModal
10931131
jobId={interactiveJobForModal}
10941132
setJobId={(jobId: number) => setInteractiveJobForModal(jobId)}
1133+
onOpenOutput={handleOpenOutputFromInteractive}
10951134
/>
10961135
);
10971136
}
@@ -1101,15 +1140,21 @@ export default function Tasks({ subtype }: { subtype?: string }) {
11011140
<InteractiveVllmModal
11021141
jobId={interactiveJobForModal}
11031142
setJobId={(jobId: number) => setInteractiveJobForModal(jobId)}
1143+
onOpenOutput={handleOpenOutputFromInteractive}
11041144
/>
11051145
);
11061146
}
11071147

11081148
if (interactiveType === 'ssh') {
1149+
console.log(
1150+
'[Tasks] Rendering InteractiveSshModal with onOpenOutput:',
1151+
handleOpenOutputFromInteractive,
1152+
);
11091153
return (
11101154
<InteractiveSshModal
11111155
jobId={interactiveJobForModal}
11121156
setJobId={(jobId: number) => setInteractiveJobForModal(jobId)}
1157+
onOpenOutput={handleOpenOutputFromInteractive}
11131158
/>
11141159
);
11151160
}
@@ -1119,6 +1164,7 @@ export default function Tasks({ subtype }: { subtype?: string }) {
11191164
<InteractiveOllamaModal
11201165
jobId={interactiveJobForModal}
11211166
setJobId={(jobId: number) => setInteractiveJobForModal(jobId)}
1167+
onOpenOutput={handleOpenOutputFromInteractive}
11221168
/>
11231169
);
11241170
}
@@ -1127,6 +1173,7 @@ export default function Tasks({ subtype }: { subtype?: string }) {
11271173
<InteractiveVSCodeModal
11281174
jobId={interactiveJobForModal}
11291175
setJobId={(jobId: number) => setInteractiveJobForModal(jobId)}
1176+
onOpenOutput={handleOpenOutputFromInteractive}
11301177
/>
11311178
);
11321179
})()}

0 commit comments

Comments
 (0)