Skip to content

Commit a6f3de4

Browse files
committed
remove duplication for jobs page
1 parent cc145b7 commit a6f3de4

8 files changed

Lines changed: 403 additions & 657 deletions

File tree

Lines changed: 2 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,6 @@
11
import React from 'react';
2-
import Box from '@mui/joy/Box';
3-
import Typography from '@mui/joy/Typography';
4-
import CircularProgress from '@mui/joy/CircularProgress';
5-
import Button from '@mui/joy/Button';
6-
import { DownloadIcon } from 'lucide-react';
7-
import { useSWRWithAuth, useAuth } from 'renderer/lib/authContext';
8-
import { useExperimentInfo } from 'renderer/lib/ExperimentInfoContext';
9-
import * as chatAPI from 'renderer/lib/transformerlab-api-sdk';
2+
import { JobArtifactsBody } from '../Tasks/JobArtifacts/JobArtifactsModal';
103

114
export default function ArtifactsSection({ jobId }: { jobId: string }) {
12-
const { experimentInfo } = useExperimentInfo();
13-
const { fetchWithAuth } = useAuth();
14-
15-
const { data, isLoading } = useSWRWithAuth(
16-
experimentInfo?.id && jobId
17-
? `${chatAPI.API_URL()}experiment/${experimentInfo.id}/jobs/${jobId}/artifacts`
18-
: null,
19-
);
20-
21-
if (isLoading) {
22-
return (
23-
<Box sx={{ display: 'flex', justifyContent: 'center', pt: 4 }}>
24-
<CircularProgress />
25-
</Box>
26-
);
27-
}
28-
29-
const artifacts: { filename: string; size?: number }[] =
30-
data?.artifacts ?? [];
31-
32-
if (artifacts.length === 0) {
33-
return <Typography level="body-sm">No artifacts available.</Typography>;
34-
}
35-
36-
async function downloadArtifact(filename: string) {
37-
if (!experimentInfo?.id) return;
38-
const url = `${chatAPI.API_URL()}experiment/${experimentInfo.id}/jobs/${jobId}/artifact/${filename}`;
39-
try {
40-
const res = await fetchWithAuth(url);
41-
if (!res.ok) {
42-
console.error(`Failed to download artifact: HTTP ${res.status}`);
43-
return;
44-
}
45-
const blob = await res.blob();
46-
const a = document.createElement('a');
47-
a.href = URL.createObjectURL(blob);
48-
a.download = filename;
49-
a.click();
50-
} catch (err) {
51-
console.error('Failed to download artifact:', err);
52-
}
53-
}
54-
55-
return (
56-
<Box>
57-
<Typography level="title-md" sx={{ mb: 2 }}>
58-
Artifacts
59-
</Typography>
60-
{artifacts.map((artifact) => (
61-
<Box
62-
key={artifact.filename}
63-
sx={{
64-
display: 'flex',
65-
justifyContent: 'space-between',
66-
alignItems: 'center',
67-
py: 1,
68-
borderBottom: '1px solid',
69-
borderColor: 'divider',
70-
}}
71-
>
72-
<Typography level="body-sm" sx={{ fontFamily: 'monospace' }}>
73-
{artifact.filename}
74-
</Typography>
75-
<Button
76-
size="sm"
77-
variant="plain"
78-
startDecorator={<DownloadIcon size={14} />}
79-
onClick={() => downloadArtifact(artifact.filename)}
80-
>
81-
Download
82-
</Button>
83-
</Box>
84-
))}
85-
</Box>
86-
);
5+
return <JobArtifactsBody jobId={jobId} showTitle={false} />;
876
}
Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,6 @@
11
import React from 'react';
2-
import Box from '@mui/joy/Box';
3-
import Typography from '@mui/joy/Typography';
4-
import CircularProgress from '@mui/joy/CircularProgress';
5-
import { useSWRWithAuth } from 'renderer/lib/authContext';
6-
import { useExperimentInfo } from 'renderer/lib/ExperimentInfoContext';
7-
import * as chatAPI from 'renderer/lib/transformerlab-api-sdk';
8-
import { formatBytes } from 'renderer/lib/utils';
2+
import { CheckpointsBody } from '../Tasks/ViewCheckpointsModal';
93

104
export default function CheckpointsSection({ jobId }: { jobId: string }) {
11-
const { experimentInfo } = useExperimentInfo();
12-
13-
const { data, isLoading } = useSWRWithAuth(
14-
experimentInfo?.id && jobId
15-
? `${chatAPI.API_URL()}experiment/${experimentInfo.id}/jobs/${jobId}/checkpoints`
16-
: null,
17-
);
18-
19-
if (isLoading) {
20-
return (
21-
<Box sx={{ display: 'flex', justifyContent: 'center', pt: 4 }}>
22-
<CircularProgress />
23-
</Box>
24-
);
25-
}
26-
27-
const checkpoints: { filename: string; date?: string; size?: number }[] =
28-
data?.checkpoints ?? [];
29-
30-
if (checkpoints.length === 0) {
31-
return <Typography level="body-sm">No checkpoints available.</Typography>;
32-
}
33-
34-
return (
35-
<Box>
36-
<Typography level="title-md" sx={{ mb: 2 }}>
37-
Checkpoints
38-
</Typography>
39-
{checkpoints.map((ckpt) => (
40-
<Box
41-
key={ckpt.filename}
42-
sx={{
43-
display: 'flex',
44-
justifyContent: 'space-between',
45-
alignItems: 'center',
46-
py: 1,
47-
borderBottom: '1px solid',
48-
borderColor: 'divider',
49-
}}
50-
>
51-
<Typography level="body-sm" sx={{ fontFamily: 'monospace' }}>
52-
{ckpt.filename}
53-
</Typography>
54-
<Box sx={{ display: 'flex', gap: 2 }}>
55-
{ckpt.size != null && (
56-
<Typography level="body-xs" color="neutral">
57-
{formatBytes(ckpt.size)}
58-
</Typography>
59-
)}
60-
{ckpt.date && (
61-
<Typography level="body-xs" color="neutral">
62-
{new Date(ckpt.date).toLocaleString()}
63-
</Typography>
64-
)}
65-
</Box>
66-
</Box>
67-
))}
68-
</Box>
69-
);
5+
return <CheckpointsBody jobId={jobId} onRestartSuccess={() => {}} />;
706
}
Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
1-
import React, { useState } from 'react';
2-
import Box from '@mui/joy/Box';
1+
import React from 'react';
32
import Typography from '@mui/joy/Typography';
4-
import CircularProgress from '@mui/joy/CircularProgress';
5-
import Select from '@mui/joy/Select';
6-
import Option from '@mui/joy/Option';
7-
import Table from '@mui/joy/Table';
8-
import { useSWRWithAuth } from 'renderer/lib/authContext';
9-
import { useExperimentInfo } from 'renderer/lib/ExperimentInfoContext';
10-
import * as chatAPI from 'renderer/lib/transformerlab-api-sdk';
3+
import { EvalResultsBody } from '../Tasks/ViewEvalResultsModal';
114

125
export default function EvalResultsSection({
136
jobId,
@@ -16,72 +9,9 @@ export default function EvalResultsSection({
169
jobId: string;
1710
evalFiles: string[];
1811
}) {
19-
const { experimentInfo } = useExperimentInfo();
20-
const [selectedFileIndex, setSelectedFileIndex] = useState(0);
21-
22-
const { data: reportData, isLoading: reportLoading } = useSWRWithAuth(
23-
experimentInfo?.id && evalFiles.length > 0
24-
? chatAPI.Endpoints.Experiment.GetEvalResults(
25-
experimentInfo.id,
26-
jobId,
27-
'view',
28-
selectedFileIndex,
29-
)
30-
: null,
31-
);
32-
3312
if (evalFiles.length === 0) {
3413
return <Typography level="body-sm">No eval results available.</Typography>;
3514
}
3615

37-
const headers: string[] = reportData?.header ?? [];
38-
const rows: unknown[][] = reportData?.body ?? [];
39-
40-
return (
41-
<Box>
42-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 2 }}>
43-
<Typography level="title-md">Eval Results</Typography>
44-
{evalFiles.length > 1 && (
45-
<Select
46-
size="sm"
47-
value={selectedFileIndex}
48-
onChange={(_, val) => setSelectedFileIndex(val ?? 0)}
49-
>
50-
{evalFiles.map((f, i) => (
51-
<Option key={i} value={i}>
52-
{f.split('/').pop()}
53-
</Option>
54-
))}
55-
</Select>
56-
)}
57-
</Box>
58-
59-
{reportLoading ? (
60-
<CircularProgress size="sm" />
61-
) : headers.length > 0 ? (
62-
<Box sx={{ overflowX: 'auto' }}>
63-
<Table size="sm" borderAxis="bothBetween">
64-
<thead>
65-
<tr>
66-
{headers.map((h) => (
67-
<th key={h}>{h}</th>
68-
))}
69-
</tr>
70-
</thead>
71-
<tbody>
72-
{rows.map((row, i) => (
73-
<tr key={i}>
74-
{(row as unknown[]).map((cell, j) => (
75-
<td key={j}>{String(cell)}</td>
76-
))}
77-
</tr>
78-
))}
79-
</tbody>
80-
</Table>
81-
</Box>
82-
) : (
83-
<Typography level="body-sm">No data in this file.</Typography>
84-
)}
85-
</Box>
86-
);
16+
return <EvalResultsBody jobId={jobId} enabled />;
8717
}
Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,6 @@
11
import React from 'react';
2-
import Box from '@mui/joy/Box';
3-
import Typography from '@mui/joy/Typography';
4-
import CircularProgress from '@mui/joy/CircularProgress';
5-
import Table from '@mui/joy/Table';
6-
import { useSWRWithAuth } from 'renderer/lib/authContext';
7-
import { useExperimentInfo } from 'renderer/lib/ExperimentInfoContext';
8-
import * as chatAPI from 'renderer/lib/transformerlab-api-sdk';
2+
import { SweepResultsBody } from '../Tasks/ViewSweepResultsModal';
93

104
export default function SweepResultsSection({ jobId }: { jobId: string }) {
11-
const { experimentInfo } = useExperimentInfo();
12-
13-
const { data, isLoading } = useSWRWithAuth(
14-
experimentInfo?.id && jobId
15-
? chatAPI.Endpoints.Experiment.GetSweepResults(experimentInfo.id, jobId)
16-
: null,
17-
);
18-
19-
if (isLoading) {
20-
return (
21-
<Box sx={{ display: 'flex', justifyContent: 'center', pt: 4 }}>
22-
<CircularProgress />
23-
</Box>
24-
);
25-
}
26-
27-
if (!data || data.status === 'error') {
28-
return (
29-
<Typography level="body-sm">
30-
{data?.message ?? 'No sweep results available.'}
31-
</Typography>
32-
);
33-
}
34-
35-
const results: Record<string, unknown>[] = Array.isArray(data) ? data : [];
36-
37-
if (results.length === 0) {
38-
return <Typography level="body-sm">No sweep results available.</Typography>;
39-
}
40-
41-
const headers = Object.keys(results[0]);
42-
43-
return (
44-
<Box>
45-
<Typography level="title-md" sx={{ mb: 2 }}>
46-
Sweep Results
47-
</Typography>
48-
<Box sx={{ overflowX: 'auto' }}>
49-
<Table size="sm" borderAxis="bothBetween">
50-
<thead>
51-
<tr>
52-
{headers.map((h) => (
53-
<th key={h}>{h}</th>
54-
))}
55-
</tr>
56-
</thead>
57-
<tbody>
58-
{results.map((row, i) => (
59-
<tr key={i}>
60-
{headers.map((h) => (
61-
<td key={h}>{String(row[h] ?? '')}</td>
62-
))}
63-
</tr>
64-
))}
65-
</tbody>
66-
</Table>
67-
</Box>
68-
</Box>
69-
);
5+
return <SweepResultsBody jobId={jobId} />;
706
}

0 commit comments

Comments
 (0)