0.10.2-25 Fixes
This commit is contained in:
@@ -774,42 +774,43 @@ export default function JobDetailDialog({
|
||||
</div>
|
||||
|
||||
<section className="job-meta-block job-meta-block-full">
|
||||
<h4>Job-Infos</h4>
|
||||
<div className="job-meta-grid job-meta-grid-compact">
|
||||
<div>
|
||||
<strong>Status:</strong>{' '}
|
||||
<span
|
||||
className={`job-status-icon tone-${statusMeta.tone}`}
|
||||
title={statusMeta.label}
|
||||
aria-label={statusMeta.label}
|
||||
>
|
||||
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
||||
<div className="job-infos-header">
|
||||
<h4>Job-Infos</h4>
|
||||
<div className="job-infos-badges">
|
||||
<span>
|
||||
<strong>Status:</strong>{' '}
|
||||
<span
|
||||
className={`job-status-icon tone-${statusMeta.tone}`}
|
||||
title={statusMeta.label}
|
||||
aria-label={statusMeta.label}
|
||||
>
|
||||
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
||||
</span>
|
||||
</span>
|
||||
{' '}<span className="job-meta-subtle">{statusMeta.label}</span>
|
||||
<span className="job-infos-sep">|</span>
|
||||
{isCd ? (
|
||||
<>
|
||||
<span><strong>Rip:</strong> <BoolState value={job?.ripSuccessful} /></span>
|
||||
<span className="job-infos-sep">|</span>
|
||||
<span><strong>Backup:</strong> <BoolState value={job?.backupSuccess} /></span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span><strong>{isAudiobook ? 'Import:' : 'Backup:'}</strong> <BoolState value={job?.backupSuccess} /></span>
|
||||
<span className="job-infos-sep">|</span>
|
||||
<span><strong>Encode:</strong> <BoolState value={job?.encodeSuccess} /></span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Start:</strong> {job.start_time || '-'}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Ende:</strong> {job.end_time || '-'}
|
||||
</div>
|
||||
{isCd ? (
|
||||
<div>
|
||||
<strong>Rip:</strong> <BoolState value={job?.ripSuccessful} />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<strong>{isAudiobook ? 'Import:' : 'Backup:'}</strong> <BoolState value={job?.backupSuccess} />
|
||||
</div>
|
||||
<div>
|
||||
<strong>Encode:</strong> <BoolState value={job?.encodeSuccess} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="job-infos-layout">
|
||||
{/* Zeile 1: Start | Ende */}
|
||||
<div><strong>Start:</strong> {job.start_time || '-'}</div>
|
||||
<div><strong>Ende:</strong> {job.end_time || '-'}</div>
|
||||
{/* Zeile 3+4: Pfade */}
|
||||
<PathField
|
||||
label={isCd ? 'WAV:' : 'RAW:'}
|
||||
value={job.raw_path}
|
||||
value={isCd ? (job.raw_path || job.output_path) : job.raw_path}
|
||||
onDownload={canDownloadRaw ? () => onDownloadArchive?.(job, 'raw') : null}
|
||||
downloadDisabled={!canDownloadRaw}
|
||||
downloadLoading={downloadBusyTarget === 'raw'}
|
||||
@@ -822,12 +823,10 @@ export default function JobDetailDialog({
|
||||
downloadLoading={downloadBusyTarget === 'output'}
|
||||
/>
|
||||
{job.error_message ? (
|
||||
<div className="job-meta-col-span-2">
|
||||
<strong>Fehler:</strong> {job.error_message}
|
||||
</div>
|
||||
<div><strong>Fehler:</strong> {job.error_message}</div>
|
||||
) : null}
|
||||
{expertMode ? (
|
||||
<div className="job-meta-col-span-2">
|
||||
<div>
|
||||
<Link to={`/database?table=jobs&id=${job.id}`} className="job-db-link" onClick={onHide}>
|
||||
<i className="pi pi-database" /> DB-Eintrag ansehen
|
||||
</Link>
|
||||
@@ -885,50 +884,51 @@ export default function JobDetailDialog({
|
||||
return (
|
||||
<div key={title.id} className="track-title-block">
|
||||
<div className="track-title-row">
|
||||
<span>#{title.id} | {title.fileName} | {title.durationMinutes != null ? `${Number(title.durationMinutes).toFixed(2)} min` : '-'} | {trackSizeFormat(title.sizeBytes)}</span>
|
||||
{title.encodeInput ? <span className="track-input-badge">Encode-Input</span> : null}
|
||||
<span>#{title.id} | {title.fileName} | {title.durationMinutes != null ? `${Number(title.durationMinutes).toFixed(2)} min` : '-'}</span>
|
||||
</div>
|
||||
<div className="track-groups-row">
|
||||
{audioTracks.length > 0 ? (
|
||||
<div className="track-group">
|
||||
<div className="track-group-label">Tonspuren (Titel #{title.id})</div>
|
||||
{audioTracks.map((track) => {
|
||||
const lang = trackLang(track.language || track.languageLabel);
|
||||
const codec = trackCodec('audio', track.format, track.description || track.title);
|
||||
const chLayout = trackChLayout(track.channels);
|
||||
let displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||
if (chLayout) displayText += ` | ${chLayout}`;
|
||||
const actionInfo = track.selectedForEncode
|
||||
? (String(track.encodePreviewSummary || track.encodeActionSummary || '').trim() || 'Copy')
|
||||
: 'Nicht übernommen';
|
||||
return (
|
||||
<div key={track.id} className="track-item">
|
||||
<span>{displayText}</span>
|
||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
{subtitleTracks.length > 0 ? (
|
||||
<div className="track-group">
|
||||
<div className="track-group-label">Subtitles (Titel #{title.id})</div>
|
||||
{subtitleTracks.map((track) => {
|
||||
const lang = trackLang(track.language || track.languageLabel);
|
||||
const codec = trackCodec('subtitle', track.format);
|
||||
const displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||
const rawAction = String(track.subtitlePreviewSummary || track.subtitleActionSummary || '').trim();
|
||||
const actionInfo = track.selectedForEncode
|
||||
? (/^nicht übernommen$/i.test(rawAction) ? 'Übernehmen' : (rawAction || 'Übernehmen'))
|
||||
: 'Nicht übernommen';
|
||||
return (
|
||||
<div key={track.id} className="track-item">
|
||||
<span>{displayText}</span>
|
||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{audioTracks.length > 0 ? (
|
||||
<div className="track-group">
|
||||
<div className="track-group-label">Tonspuren (Titel #{title.id})</div>
|
||||
{audioTracks.map((track) => {
|
||||
const lang = trackLang(track.language || track.languageLabel);
|
||||
const codec = trackCodec('audio', track.format, track.description || track.title);
|
||||
const chLayout = trackChLayout(track.channels);
|
||||
let displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||
if (chLayout) displayText += ` | ${chLayout}`;
|
||||
const actionInfo = track.selectedForEncode
|
||||
? (String(track.encodePreviewSummary || track.encodeActionSummary || '').trim() || 'Copy')
|
||||
: 'Nicht übernommen';
|
||||
return (
|
||||
<div key={track.id} className="track-item">
|
||||
<span>{displayText}</span>
|
||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
{subtitleTracks.length > 0 ? (
|
||||
<div className="track-group">
|
||||
<div className="track-group-label">Subtitles (Titel #{title.id})</div>
|
||||
{subtitleTracks.map((track) => {
|
||||
const lang = trackLang(track.language || track.languageLabel);
|
||||
const codec = trackCodec('subtitle', track.format);
|
||||
const displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||
const rawAction = String(track.subtitlePreviewSummary || track.subtitleActionSummary || '').trim();
|
||||
const actionInfo = track.selectedForEncode
|
||||
? (/^nicht übernommen$/i.test(rawAction) ? 'Übernehmen' : (rawAction || 'Übernehmen'))
|
||||
: 'Nicht übernommen';
|
||||
return (
|
||||
<div key={track.id} className="track-item">
|
||||
<span>{displayText}</span>
|
||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
@@ -938,14 +938,99 @@ export default function JobDetailDialog({
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{(isCd || isAudiobook) && job.encodePlan ? (
|
||||
<section className="job-meta-block job-meta-block-full">
|
||||
<h4>{isCd ? 'Titelauswahl' : 'Kapitelauswahl'}</h4>
|
||||
{isCd ? (() => {
|
||||
const tracksRaw = Array.isArray(job.makemkvInfo?.tracks) && job.makemkvInfo.tracks.length > 0
|
||||
? job.makemkvInfo.tracks
|
||||
: (Array.isArray(job.encodePlan?.tracks) ? job.encodePlan.tracks : []);
|
||||
const selectedSet = Array.isArray(job.encodePlan?.selectedTracks) && job.encodePlan.selectedTracks.length > 0
|
||||
? new Set(job.encodePlan.selectedTracks.map(Number))
|
||||
: null;
|
||||
if (tracksRaw.length === 0) return <p className="job-meta-subtle">Keine Tracks vorhanden.</p>;
|
||||
return (
|
||||
<div className="track-group">
|
||||
{tracksRaw.map((track, i) => {
|
||||
const pos = Number(track.position ?? (i + 1));
|
||||
const label = String(track.title || track.name || `Track ${pos}`).trim();
|
||||
const artist = String(track.artist || '').trim();
|
||||
const durationSec = Number(track.durationMs || 0) > 0
|
||||
? Number(track.durationMs) / 1000
|
||||
: Number(track.durationSec || 0);
|
||||
const durLabel = durationSec > 0
|
||||
? `${Math.floor(durationSec / 60)}:${String(Math.floor(durationSec % 60)).padStart(2, '0')} min`
|
||||
: '-';
|
||||
const selected = selectedSet ? selectedSet.has(pos) : track.selected !== false;
|
||||
const ripDone = job?.ripSuccessful != null;
|
||||
const encodeLabel = !selected ? 'Nicht übernommen'
|
||||
: ripDone ? (job.ripSuccessful ? 'Erfolgreich' : 'Fehler')
|
||||
: 'Übernommen';
|
||||
const encodeClass = !selected ? '' : ripDone ? (job.ripSuccessful ? 'tone-ok' : 'tone-no') : '';
|
||||
return (
|
||||
<div key={pos} className="track-item">
|
||||
<span>#{pos} | {label}{artist ? ` | ${artist}` : ''} | {durLabel}</span>
|
||||
<small className={`track-action-note ${encodeClass}`}>Encode: {encodeLabel}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})() : (() => {
|
||||
const chapters = Array.isArray(job.handbrakeInfo?.metadata?.chapters) && job.handbrakeInfo.metadata.chapters.length > 0
|
||||
? job.handbrakeInfo.metadata.chapters
|
||||
: (Array.isArray(job.makemkvInfo?.chapters) && job.makemkvInfo.chapters.length > 0
|
||||
? job.makemkvInfo.chapters
|
||||
: (Array.isArray(job.encodePlan?.metadata?.chapters) ? job.encodePlan.metadata.chapters : []));
|
||||
const stepsByIndex = new Map(
|
||||
(Array.isArray(job.handbrakeInfo?.steps) ? job.handbrakeInfo.steps : [])
|
||||
.map((s) => [Number(s.chapterIndex), s])
|
||||
);
|
||||
if (chapters.length === 0) return <p className="job-meta-subtle">Keine Kapitelinformationen vorhanden.</p>;
|
||||
return (
|
||||
<div className="track-group">
|
||||
{chapters.map((chapter, i) => {
|
||||
const id = Number(chapter.id ?? chapter.index ?? chapter.position ?? (i + 1));
|
||||
const label = String(chapter.title || chapter.name || `Kapitel ${id}`).trim();
|
||||
const durationSec = Number(chapter.durationMs || 0) > 0
|
||||
? Number(chapter.durationMs) / 1000
|
||||
: Number(chapter.durationSec || 0);
|
||||
const durLabel = durationSec > 0
|
||||
? `${Math.floor(durationSec / 60)}:${String(Math.floor(durationSec % 60)).padStart(2, '0')} min`
|
||||
: '-';
|
||||
const step = stepsByIndex.get(id);
|
||||
const stepStatus = step ? String(step.status || '').toUpperCase() : null;
|
||||
const encodeLabel = stepStatus === 'SUCCESS' ? 'Erfolgreich'
|
||||
: stepStatus === 'ERROR' ? 'Fehler'
|
||||
: stepStatus === 'CANCELLED' ? 'Abgebrochen'
|
||||
: stepStatus ? stepStatus
|
||||
: 'Übernommen';
|
||||
const encodeClass = stepStatus === 'SUCCESS' ? 'tone-ok'
|
||||
: stepStatus === 'ERROR' ? 'tone-no'
|
||||
: '';
|
||||
return (
|
||||
<div key={id} className="track-item">
|
||||
<span>#{id} | {label} | {durLabel}</span>
|
||||
<small className={`track-action-note ${encodeClass}`}>Encode: {encodeLabel}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
<section className="job-meta-block job-meta-block-full">
|
||||
<h4>Rohdaten</h4>
|
||||
<h4>Logs</h4>
|
||||
<div className="job-json-grid">
|
||||
{!isCd && !isAudiobook ? <JsonView title="OMDb Info" value={job.omdbInfo} /> : null}
|
||||
{isCd ? <JsonView title="MusicBrainz" value={job.makemkvInfo?.selectedMetadata ?? null} /> : null}
|
||||
{isAudiobook ? <JsonView title="Metadaten" value={job.handbrakeInfo?.metadata ?? job.makemkvInfo?.selectedMetadata ?? null} /> : null}
|
||||
<JsonView title={isCd ? 'cdparanoia Info' : (isAudiobook ? 'Audiobook Info' : 'MakeMKV Info')} value={job.makemkvInfo} />
|
||||
{!isCd && !isAudiobook ? <JsonView title="Mediainfo Info" value={job.mediainfoInfo} /> : null}
|
||||
<JsonView title={isCd ? 'Rip-Plan' : 'Encode Plan'} value={job.encodePlan} />
|
||||
{!isCd ? <JsonView title={isAudiobook ? 'FFmpeg Info' : 'HandBrake Info'} value={job.handbrakeInfo} /> : null}
|
||||
<JsonView title={isCd ? 'Rip-Info' : (isAudiobook ? 'FFmpeg Info' : 'HandBrake Info')} value={job.handbrakeInfo} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -867,9 +867,8 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
||||
const renderPoster = (row, className = 'history-dv-poster') => {
|
||||
const mediaMeta = resolveMediaTypeMeta(row);
|
||||
const isAudioSquare = ['cd', 'audiobook'].includes(mediaMeta.mediaType);
|
||||
const imgClass = className === 'history-dv-poster-grid' && isAudioSquare
|
||||
? 'history-dv-poster-grid-audio'
|
||||
: className;
|
||||
const audioClass = className === 'history-dv-poster-grid' ? 'history-dv-poster-grid-audio' : 'history-dv-poster-audio';
|
||||
const imgClass = isAudioSquare ? audioClass : className;
|
||||
const title = row?.title || row?.detected_title || 'Poster';
|
||||
if (row?.poster_url && row.poster_url !== 'N/A') {
|
||||
return <img src={row.poster_url} alt={title} className={imgClass} loading="lazy" />;
|
||||
@@ -903,9 +902,6 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
||||
if (cdDetails.totalDurationLabel) {
|
||||
infoItems.push({ key: 'duration', label: 'Dauer', value: cdDetails.totalDurationLabel });
|
||||
}
|
||||
if (cdDetails.mbId) {
|
||||
infoItems.push({ key: 'mb', label: 'MusicBrainz', value: 'gesetzt' });
|
||||
}
|
||||
if (infoItems.length === 0) {
|
||||
return <span className="history-dv-subtle">Keine CD-Details</span>;
|
||||
}
|
||||
@@ -1013,35 +1009,15 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
||||
</div>
|
||||
|
||||
<div className="history-dv-flags-row">
|
||||
{isCdJob ? (
|
||||
<>
|
||||
{renderPresenceChip('Audio', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Rip', Boolean(row?.ripSuccessful))}
|
||||
{renderPresenceChip('Metadaten', Boolean(cdDetails?.artist || cdDetails?.mbId))}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||
{renderPresenceChip('Movie', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Encode', Boolean(row?.encodeSuccess))}
|
||||
</>
|
||||
)}
|
||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||
{renderPresenceChip(isCdJob || mediaMeta.mediaType === 'audiobook' ? 'Audio' : 'Movie', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Encode', isCdJob || mediaMeta.mediaType === 'audiobook' ? Boolean(row?.ripSuccessful) : Boolean(row?.encodeSuccess))}
|
||||
</div>
|
||||
|
||||
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
||||
</div>
|
||||
|
||||
<div className="history-dv-actions">
|
||||
<Button
|
||||
label="Details"
|
||||
icon="pi pi-search"
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
void openDetail(row);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -1096,35 +1072,13 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
||||
</div>
|
||||
|
||||
<div className="history-dv-flags-row">
|
||||
{isCdJob ? (
|
||||
<>
|
||||
{renderPresenceChip('Audio', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Rip', Boolean(row?.ripSuccessful))}
|
||||
{renderPresenceChip('Metadaten', Boolean(cdDetails?.artist || cdDetails?.mbId))}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||
{renderPresenceChip('Movie', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Encode', Boolean(row?.encodeSuccess))}
|
||||
</>
|
||||
)}
|
||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||
{renderPresenceChip(isCdJob || mediaMeta.mediaType === 'audiobook' ? 'Audio' : 'Movie', Boolean(row?.outputStatus?.exists))}
|
||||
{renderPresenceChip('Encode', isCdJob || mediaMeta.mediaType === 'audiobook' ? Boolean(row?.ripSuccessful) : Boolean(row?.encodeSuccess))}
|
||||
</div>
|
||||
|
||||
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
||||
</div>
|
||||
|
||||
<div className="history-dv-actions history-dv-actions-grid">
|
||||
<Button
|
||||
label="Details"
|
||||
icon="pi pi-search"
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
void openDetail(row);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+69
-14
@@ -2334,6 +2334,7 @@ body {
|
||||
}
|
||||
|
||||
.history-dv-poster,
|
||||
.history-dv-poster-audio,
|
||||
.history-dv-poster-grid,
|
||||
.history-dv-poster-grid-audio {
|
||||
display: block;
|
||||
@@ -2348,9 +2349,13 @@ body {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.history-dv-poster-audio {
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.history-dv-poster-grid {
|
||||
height: 164px;
|
||||
object-fit: contain;
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
.history-dv-poster-grid-audio {
|
||||
@@ -2360,7 +2365,7 @@ body {
|
||||
|
||||
.history-dv-grid-poster-wrap {
|
||||
width: min(120px, 100%);
|
||||
height: 164px;
|
||||
height: 180px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -2517,6 +2522,7 @@ body {
|
||||
|
||||
.job-film-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
@@ -2572,16 +2578,18 @@ body {
|
||||
|
||||
.job-path-field {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
gap: 0.2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 0.15rem 0.4rem;
|
||||
}
|
||||
|
||||
.job-path-field-value {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.35rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.job-path-field-value > span {
|
||||
@@ -2598,6 +2606,47 @@ body {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.job-infos-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.job-infos-header h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.job-infos-badges {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.84rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.job-infos-sep {
|
||||
color: var(--rip-border);
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.job-infos-layout {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.84rem;
|
||||
}
|
||||
|
||||
.job-infos-layout strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.job-infos-row-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-downloads-row {
|
||||
border-top: 1px solid var(--surface-border);
|
||||
padding-top: 0.75rem;
|
||||
@@ -2762,7 +2811,7 @@ body {
|
||||
color: #f8e2b8;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
max-height: 16rem;
|
||||
height: 16rem;
|
||||
overflow: auto;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
@@ -2847,7 +2896,7 @@ body {
|
||||
color: #f6ddb2;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
max-height: 25rem;
|
||||
height: 25rem;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
@@ -3050,10 +3099,6 @@ body {
|
||||
}
|
||||
|
||||
.track-title-block {
|
||||
border: 1px solid var(--rip-border);
|
||||
border-radius: 0.45rem;
|
||||
padding: 0.55rem 0.65rem;
|
||||
background: var(--rip-panel-soft);
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
@@ -3077,6 +3122,16 @@ body {
|
||||
border: 1px solid var(--rip-success, #2d7a3a);
|
||||
}
|
||||
|
||||
.track-groups-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 0.5rem;
|
||||
align-items: start;
|
||||
border-top: 1px solid var(--rip-border);
|
||||
padding-top: 0.5rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.track-group {
|
||||
display: grid;
|
||||
gap: 0.25rem;
|
||||
|
||||
Reference in New Issue
Block a user