Skip to content

Commit 93e20ce

Browse files
committed
layout improvments and fixes
1 parent 5078de1 commit 93e20ce

File tree

1 file changed

+92
-133
lines changed

1 file changed

+92
-133
lines changed

app/modules/compute/components/views/JobDetailsConsoleView.tsx

Lines changed: 92 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,18 @@ import EmbedPanelGrafana from '~/modules/compute/components/grafana/EmbedPanelGr
3838
interface JobDetailsPanelProps {
3939
job?: Job
4040
jobMetadata?: JobMetadata
41-
system?: System
41+
system?: System,
42+
stdoutFile?: File
43+
stderrFile?: File
4244
}
4345

44-
const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, system }) => {
46+
const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, system,stdoutFile,stderrFile }) => {
4547
const [cancelDialogOpen, setCancelDialogOpen] = useState(false)
48+
const [downloadkDialogOpen, setDownloadDialogOpen] = useState(false)
49+
const handleDownload = () => {
50+
setDownloadDialogOpen(true)
51+
}
52+
4653
return (
4754
<>
4855
<JobCancelDialog
@@ -62,7 +69,8 @@ const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, sys
6269
</button>
6370
</div>
6471
)}
65-
<h3 className='text-sm font-semibold mb-3'>Job details</h3>
72+
73+
<h3 className='font-semibold mb-3'>Job details</h3>
6674
<AttributesList>
6775
<AttributesListItem label='Job ID'>#{job?.jobId}</AttributesListItem>
6876
<AttributesListItem label='Name'>{job?.name}</AttributesListItem>
@@ -80,8 +88,8 @@ const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, sys
8088
)}
8189
</AttributesListItem>
8290
</AttributesList>
83-
<div className='mt-4 mb-6 border-b border-gray-900/10' />
84-
<h3 className='text-sm font-semibold mb-3'>Execution times</h3>
91+
92+
<h3 className='font-semibold mb-3 mt-9'>Execution times</h3>
8593
<AttributesList>
8694
<AttributesListItem label='Start time'>
8795
{formatDateTimeFromTimestamp({ timestamp: job?.time.start })}
@@ -93,8 +101,53 @@ const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, sys
93101
{formatTime({ time: job?.time.elapsed })}
94102
</AttributesListItem>
95103
</AttributesList>
96-
<div className='mt-4 mb-6 border-b border-gray-900/10' />
97-
<h3 className='text-sm font-semibold mb-3'>System and resource details</h3>
104+
105+
<h3 className='font-semibold mb-3 mt-9'>Files</h3>
106+
<AttributesList>
107+
<AttributesListItem label='StdOut'><div className='flex'>{jobMetadata?.standardOutput || 'N/A'}
108+
{stdoutFile && (
109+
<>
110+
<DownloadDialog
111+
system={system?.name || ''}
112+
file={stdoutFile}
113+
open={downloadkDialogOpen}
114+
onClose={() => setDownloadDialogOpen(false)}
115+
/>
116+
<button
117+
onClick={handleDownload}
118+
title='Download STDOUT log'
119+
className='w-8 h-8 flex items-center justify-center rounded-md border text-neutral-600 hover:text-neutral-800 hover:bg-neutral-100'
120+
>
121+
<ArrowDownCircleIcon className='w-4 h-4' />
122+
</button>
123+
</>
124+
)}
125+
</div>
126+
</AttributesListItem>
127+
<AttributesListItem label='StdErr'>{jobMetadata?.standardError || 'N/A'}
128+
{stderrFile && (
129+
<>
130+
<DownloadDialog
131+
system={system?.name || ''}
132+
file={stderrFile}
133+
open={downloadkDialogOpen}
134+
onClose={() => setDownloadDialogOpen(false)}
135+
/>
136+
<button
137+
onClick={handleDownload}
138+
title='Download STDOUT log'
139+
className='w-8 h-8 flex items-center justify-center rounded-md border text-neutral-600 hover:text-neutral-800 hover:bg-neutral-100'
140+
>
141+
<ArrowDownCircleIcon className='w-4 h-4' />
142+
</button>
143+
</>
144+
)}
145+
</AttributesListItem>
146+
<AttributesListItem label='StdIn'>{jobMetadata?.standardInput || 'N/A'}</AttributesListItem>
147+
<AttributesListItem label='Working directory'>{job?.workingDirectory || 'N/A'}</AttributesListItem>
148+
</AttributesList>
149+
150+
<h3 className='font-semibold mb-3 mt-9'>System and resource details</h3>
98151
<AttributesList>
99152
<AttributesListItem label='System name'>
100153
<LabelBadge color={LabelColor.YELLOW}>{system?.name}</LabelBadge>
@@ -104,7 +157,6 @@ const JobDetailsPanel: React.FC<JobDetailsPanelProps> = ({ job, jobMetadata, sys
104157
</AttributesListItem>
105158
<AttributesListItem label='Nodes'>{job?.nodes}</AttributesListItem>
106159
<AttributesListItem label='Partition'>{job?.partition}</AttributesListItem>
107-
<AttributesListItem label='Working directory'>{job?.workingDirectory}</AttributesListItem>
108160
</AttributesList>
109161
</>
110162
)
@@ -115,10 +167,10 @@ interface JobDetailCenterProps {
115167
jobMetadata?: JobMetadata
116168
system?: System
117169
activeTab: OutputTabId
118-
stdout: string
170+
stdout?: string
119171
stdoutFile?: File
120-
stdin: string
121-
stderr: string
172+
stdin?: string
173+
stderr?: string
122174
stderrFile?: File
123175
script?: string
124176
dashboards?: GrafanaDashboard[]
@@ -143,59 +195,49 @@ const JobDetailCenter: React.FC<JobDetailCenterProps> = ({
143195
OUTPUT_TABS.find((t) => t.id === 'resources')!.enabled = false
144196
}
145197
return (
146-
<div className='flex flex-1 rounded-xl border bg-white/70 shadow-sm'>
147-
<div className='flex-1 min-w-0 h-full min-h-0'>
198+
<div className='flex-1 rounded-xl border bg-white shadow-sm m-6 pt-2' style={{ marginTop: '20px' }} >
199+
<div className='sticky top-16 flex items-center justify-between bg-white p-4 px-3 py-2 shrink-0 z-9 '>
200+
<select name='datasource' value={activeTab} onChange={(e) => onChangeTab(e.target.value)} className='flex-none w-64 border-gray-300 focus:border-blue-300 focus:ring-blue-300 rounded-md border py-2 px-3 shadow-sm sm:text-sm focus:outline-none'>
201+
<option value='stdout'>Job StdOut</option>
202+
<option value='stderr'>Job StdErr</option>
203+
<option value='stdin'>Job StdIn</option>
204+
<option value='script'>Job Script</option>
205+
<option value='resources'>Dashboards</option>
206+
</select>
207+
</div>
208+
<div className='min-w-0 h-full min-h-0 pt-4 '>
148209
{activeTab === 'stdout' && (
149-
<ConsolePane
150-
title='Job output – STDOUT'
151-
content={stdout}
152-
system={system}
153-
filePath={jobMetadata?.standardOutput}
154-
stdFile={stdoutFile}
155-
/>
210+
<ConsolePane content={stdout}/>
156211
)}
157212
{activeTab === 'stdin' && (
158-
<ConsolePane
159-
title='Job input – STDIN'
160-
content={stdin}
161-
filePath={jobMetadata?.standardInput}
162-
/>
213+
<ConsolePane content={stdin}/>
163214
)}
164215
{activeTab === 'stderr' && (
165-
<ConsolePane
166-
title='Job output – STDERR'
167-
content={stderr}
168-
system={system}
169-
filePath={jobMetadata?.standardError}
170-
stdFile={stderrFile}
171-
/>
216+
<ConsolePane content={stderr}/>
172217
)}
173-
{activeTab === 'script' && <ScriptPane script={script} />}
218+
{activeTab === 'script' && <ConsolePane content={script} />}
174219
{activeTab === 'resources' && dashboards && dashboards.length > 0 && (
175220
<ResourcesPaneMulti job={job!} dashboards={dashboards} title='Resources' />
176221
)}
177222
</div>
178223
<aside className='fixed right-0 top-16 bottom-12 w-[30rem] border-l bg-white overflow-y-auto'>
179-
<RightTabs active={activeTab} onChange={onChangeTab} />
180224
<div className='p-4'>
181-
<JobDetailsPanel job={job} jobMetadata={jobMetadata} system={system} />
225+
<JobDetailsPanel job={job} jobMetadata={jobMetadata} system={system} stdoutFile={stdoutFile} stderrFile={stderrFile}/>
182226
</div>
183227
</aside>
184228
</div>
185229
)
186230
}
187231

188232
interface ConsolePaneProps {
189-
title: string
190-
content: string
191-
system?: System
192-
filePath?: string | null
193-
stdFile?: File
233+
234+
content?: string
235+
194236
}
195237

196-
const ConsolePane: React.FC<ConsolePaneProps> = ({ title, content, system, filePath, stdFile }) => {
238+
const ConsolePane: React.FC<ConsolePaneProps> = ({ content}) => {
197239
const scrollerRef = useRef<HTMLDivElement | null>(null)
198-
const [downloadkDialogOpen, setDownloadDialogOpen] = useState(false)
240+
199241

200242
useEffect(() => {
201243
const el = scrollerRef.current
@@ -204,59 +246,15 @@ const ConsolePane: React.FC<ConsolePaneProps> = ({ title, content, system, fileP
204246
if (nearBottom) el.scrollTop = el.scrollHeight
205247
}, [content])
206248

207-
const handleDownload = () => {
208-
setDownloadDialogOpen(true)
209-
}
210-
211249
return (
212250
<section className='h-full min-h-0 flex flex-col'>
213-
<div className='flex items-center justify-between border-b bg-white/60 backdrop-blur px-3 py-2 shrink-0'>
214-
<div className='text-sm font-medium'>{title}</div>
215-
<div className='flex items-center gap-2 text-xs'>
216-
{stdFile && (
217-
<>
218-
<DownloadDialog
219-
system={system?.name || ''}
220-
file={stdFile}
221-
open={downloadkDialogOpen}
222-
onClose={() => setDownloadDialogOpen(false)}
223-
/>
224-
<button
225-
onClick={handleDownload}
226-
title='Download STDOUT log'
227-
className='w-8 h-8 flex items-center justify-center rounded-md border text-neutral-600 hover:text-neutral-800 hover:bg-neutral-100'
228-
>
229-
<ArrowDownCircleIcon className='w-4 h-4' />
230-
</button>
231-
</>
232-
)}
233-
</div>
234-
</div>
235251
<div className='flex-1 bg-black text-neutral-100 font-mono text-[12px] leading-5'>
236-
<pre className='px-3 py-2 whitespace-pre-wrap'>{content}</pre>
252+
<pre className='px-3 py-2 whitespace-pre-wrap'>{content || '# No data available'}</pre>
237253
</div>
238254
</section>
239255
)
240256
}
241257

242-
interface ScriptPaneProps {
243-
script?: string
244-
}
245-
246-
const ScriptPane: React.FC<ScriptPaneProps> = ({ script }) => {
247-
return (
248-
<section className='h-full min-h-0 flex flex-col'>
249-
<div className='flex items-center justify-between border-b bg-white/60 backdrop-blur px-3 py-2 shrink-0'>
250-
<div className='text-sm font-medium'>Script</div>
251-
</div>
252-
<div className='flex-1 bg-neutral-50 text-neutral-800'>
253-
<pre className='px-4 py-3 text-xs leading-5 font-mono whitespace-pre'>
254-
{script || '# No script available'}
255-
</pre>
256-
</div>
257-
</section>
258-
)
259-
}
260258

261259
interface ResourcePaneProps {
262260
src?: string
@@ -427,45 +425,16 @@ let OUTPUT_TABS = [
427425

428426
type OutputTabId = (typeof OUTPUT_TABS)[number]['id']
429427

430-
interface RightTabsProps {
431-
active: OutputTabId
432-
onChange: (id: OutputTabId) => void
433-
}
434-
435-
const RightTabs: React.FC<RightTabsProps> = ({ active, onChange }) => {
436-
return (
437-
<div className='border-b bg-white/70 backdrop-blur p-4 sticky top-0 z-10'>
438-
<div className='flex flex-col w-full items-stretch gap-2'>
439-
{OUTPUT_TABS.map((t) => (
440-
<React.Fragment key={t.id}>
441-
{t.enabled && (
442-
<button
443-
key={t.id}
444-
type='button'
445-
onClick={() => onChange(t.id)}
446-
data-active={active === t.id}
447-
className='text-xs rounded-md border px-2.5 py-1.5 data-[active=true]:bg-neutral-900 data-[active=true]:text-white data-[active=true]:border-neutral-900 data-[active=false]:bg-white data-[active=false]:text-neutral-700 hover:bg-neutral-50'
448-
aria-pressed={active === t.id}
449-
>
450-
{t.label}
451-
</button>
452-
)}
453-
</React.Fragment>
454-
))}
455-
</div>
456-
</div>
457-
)
458-
}
459428

460429
interface JobDetailsLayoutProps {
461430
job?: Job
462431
jobMetadata?: JobMetadata
463432
system?: System
464433
activeTab: OutputTabId
465-
stdout: string
434+
stdout?: string
466435
stdoutFile?: File
467-
stdin: string
468-
stderr: string
436+
stdin?: string
437+
stderr?: string
469438
stderrFile?: File
470439
script?: string
471440
dashboards?: GrafanaDashboard[]
@@ -487,17 +456,7 @@ const JobDetailsLayout: React.FC<JobDetailsLayoutProps> = ({
487456
onChangeTab,
488457
}) => {
489458
return (
490-
<div className='flex flex-1 flex-col gap-4 pt-6 pb-20 px-8'>
491-
<div className='flex items-center justify-between'>
492-
<div className='text-sm text-neutral-500'>
493-
Clariden /{' '}
494-
<Link to={`/compute`} className='hover:text-gray-900'>
495-
Jobs
496-
</Link>{' '}
497-
/ <span className='text-neutral-800'>{job?.jobId}</span>
498-
</div>
499-
{/* <div className='text-xs text-neutral-500'>Last update: just now</div> */}
500-
</div>
459+
<div className='flex flex-1 flex-col gap-4 pb-20'>
501460
<div className='flex flex-1 h-full'>
502461
<JobDetailCenter
503462
job={job}
@@ -647,10 +606,10 @@ const JobDetailsConsoleView: React.FC<JobDetailsConsoleViewProps> = ({
647606
jobMetadata={jobMetadata || undefined}
648607
system={system}
649608
activeTab={activeTab}
650-
stdout={jobStandardOuput?.output?.content || '...'}
609+
stdout={jobStandardOuput?.output?.content }
651610
stdoutFile={jobStandardOutputFile || undefined}
652-
stdin={jobMetadata?.standardInput || ''}
653-
stderr={jobStandardError?.output?.content || '...'}
611+
stdin={jobMetadata?.standardInput || undefined}
612+
stderr={jobStandardError?.output?.content}
654613
stderrFile={jobStandardErrorFile || undefined}
655614
script={jobMetadata?.script || undefined}
656615
dashboards={dashboards}

0 commit comments

Comments
 (0)