feat(control-station): add configurable environment shell
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
Button,
|
||||
GlassSurface,
|
||||
Icon,
|
||||
Select,
|
||||
StatusBadge,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
@@ -1218,18 +1219,21 @@ function LaboratorySelector<T extends string>({
|
||||
<h2>{title}</h2>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
<label>
|
||||
<div className="laboratory-selector__control">
|
||||
<span>{label}</span>
|
||||
<select
|
||||
<Select
|
||||
label={`Выбрать: ${label}`}
|
||||
value={value}
|
||||
options={options.map((option) => ({
|
||||
value: option.id,
|
||||
label: option.label,
|
||||
}))}
|
||||
variant="split"
|
||||
menuWidth="anchor"
|
||||
disabled={disabled}
|
||||
onChange={(event) => onChange(event.currentTarget.value as T)}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<option key={option.id} value={option.id}>{option.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
onChange={(next) => onChange(next)}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1268,20 +1272,6 @@ function LaboratoryTask({
|
||||
}
|
||||
|
||||
function E29LaboratoryResult({ rigLabel }: { rigLabel: string }) {
|
||||
const semanticTotal = 19_625;
|
||||
const statuses = [
|
||||
{ id: "agree", label: "Камера + геометрия", value: 6_341 },
|
||||
{ id: "camera", label: "Только камера", value: 13_246 },
|
||||
{ id: "conflict", label: "Конфликт", value: 38 },
|
||||
] as const;
|
||||
const conflictEpisodes = [
|
||||
"track 115 · 69,799–71,398 с",
|
||||
"track 470 · 215,324–218,708 с",
|
||||
"track 679 · 282,569–283,281 с",
|
||||
"track 1011 · 354,937–355,242 с",
|
||||
"track 1276 · 402,606–402,995 с",
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<LaboratoryTask
|
||||
@@ -1296,61 +1286,6 @@ function E29LaboratoryResult({ rigLabel }: { rigLabel: string }) {
|
||||
]}
|
||||
/>
|
||||
|
||||
<section className="laboratory-visual-result" aria-label="Визуальный результат LAB E29">
|
||||
<header>
|
||||
<div>
|
||||
<span className="section-eyebrow">ВИЗУАЛЬНЫЙ РЕЗУЛЬТАТ</span>
|
||||
<h2>Покрытие семантических наблюдений геометрией</h2>
|
||||
<p>
|
||||
Это покрытие одного воспроизводимого replay, а не accuracy и не допуск
|
||||
планировщика. Конфликты сохранены для ручного покадрового разбора.
|
||||
</p>
|
||||
</div>
|
||||
<StatusBadge tone="warning">16 конфликтных эпизодов</StatusBadge>
|
||||
</header>
|
||||
|
||||
<div className="laboratory-e29-chart" role="img" aria-label="Распределение статусов геометрии">
|
||||
<div className="laboratory-e29-chart__bar">
|
||||
{statuses.map((status) => (
|
||||
<i
|
||||
key={status.id}
|
||||
data-status={status.id}
|
||||
style={{ width: `${(status.value / semanticTotal) * 100}%` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="laboratory-e29-chart__legend">
|
||||
{statuses.map((status) => (
|
||||
<div key={status.id}>
|
||||
<i data-status={status.id} />
|
||||
<span>{status.label}</span>
|
||||
<strong>{status.value.toLocaleString("ru-RU")}</strong>
|
||||
<small>{((status.value / semanticTotal) * 100).toLocaleString("ru-RU", {
|
||||
maximumFractionDigits: 2,
|
||||
})}%</small>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="laboratory-e29-evidence">
|
||||
<article>
|
||||
<span className="section-eyebrow">НЕЗАВИСИМАЯ ГЕОМЕТРИЯ</span>
|
||||
<strong>21 321 компонент</strong>
|
||||
<p>
|
||||
Незасемантизированные занятые компоненты сохранены отдельным слоем:
|
||||
им не назначается выдуманный класс и они не считаются свободным местом.
|
||||
</p>
|
||||
</article>
|
||||
<article>
|
||||
<span className="section-eyebrow">КОНФЛИКТЫ ДЛЯ РАЗБОРА</span>
|
||||
<div>
|
||||
{conflictEpisodes.map((episode) => <span key={episode}>{episode}</span>)}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="laboratory-result-summary">
|
||||
<header>
|
||||
<div>
|
||||
@@ -1575,7 +1510,7 @@ function LabArchiveWorkspace(props: WorkspaceRendererProps) {
|
||||
<LaboratorySelector
|
||||
eyebrow="ЛАБОРАТОРНАЯ РАБОТА"
|
||||
title={workOptions.find((work) => work.id === workId)?.label ?? "Работа не выбрана"}
|
||||
description="Выберите один зафиксированный эксперимент. Ниже откроются его задача, полноразмерное визуальное доказательство и структурированный результат."
|
||||
description="Выберите один зафиксированный эксперимент. Ниже откроются его задача и структурированный результат; viewer появляется только у опубликованного серверного доказательства."
|
||||
label="Работа"
|
||||
value={workId}
|
||||
options={workOptions}
|
||||
|
||||
Reference in New Issue
Block a user