diff --git a/coordinator/internal/transport/http/server_test.go b/coordinator/internal/transport/http/server_test.go
index 6199c51..01c299f 100644
--- a/coordinator/internal/transport/http/server_test.go
+++ b/coordinator/internal/transport/http/server_test.go
@@ -140,7 +140,7 @@ func TestUIRequiresDistinctCredentialAndRendersDashboard(t *testing.T) {
t.Fatalf("UI status: %d", resp.StatusCode)
}
body, _ := io.ReadAll(resp.Body)
- if !strings.Contains(string(body), "Панель оператора SciMesh") {
+ if !strings.Contains(string(body), "SciMesh operator dashboard") {
t.Errorf("dashboard body missing title")
}
}
diff --git a/coordinator/internal/transport/http/templates/dashboard.html b/coordinator/internal/transport/http/templates/dashboard.html
index 695c3c8..f4769ee 100644
--- a/coordinator/internal/transport/http/templates/dashboard.html
+++ b/coordinator/internal/transport/http/templates/dashboard.html
@@ -1,56 +1,22 @@
{{define "dashboard.html"}}
-
+
-
-
-
- Текущий этап — диагностика shard-задач.
- Worker загружает частичные CSV в coordinator. Пока reducer не реализован, эти файлы не являются единым финальным научным результатом.
- 1. Загрузить TSVCoordinator делит файл на shard-задачи.
2. Дождаться workerWorker берёт shard, вычисляет сходство и возвращает CSV.
3. Проверить артефактыСкачайте частичный результат из карточки задачи.
-
-
- Последние задания
-
-
- | Вычисление | Состояние | Прогресс | Создано |
- {{range .Jobs}}
-
- {{workloadLabel .Workload}} Открыть детали задачи |
- {{statusLabel .Status}} {{statusHint .Status}} |
- {{.Completed}} / {{.Total}} завершено{{if gt .Failed 0}} · ошибок: {{.Failed}}{{end}}
|
- {{time .CreatedAt}} |
-
- {{else}}
- Заданий пока нет. Нажмите «Запустить проверку», загрузите небольшой TSV и оставьте worker запущенным. |
- {{end}}
-
-
-
+
+ This screen currently diagnoses shard jobs.Workers upload partial CSVs to the coordinator. Until a reducer is implemented, those files are not one final scientific result.1. Upload TSVThe coordinator splits the file into shard tasks.
2. Wait for a workerA worker claims a shard, calculates similarity, and returns a CSV.
3. Inspect artifactsDownload a partial result from the job page.
+ Recent jobs
+ | Computation | State | Progress | Created |
{{range .Jobs}}{{workloadLabel .Workload}} Open job details | {{statusLabel .Status}} {{statusHint .Status}} | {{.Completed}} / {{.Total}} complete{{if gt .Failed 0}} · failed: {{.Failed}}{{end}}
| {{time .CreatedAt}} |
{{else}}No jobs yet. Click “Start a check”, upload a small TSV, and leave a worker running. |
{{end}}
Workers
-
- {{range .Workers}}
- {{.Name}}
{{.ID}}
{{workerStatusLabel .Status}}
{{range .Capabilities}}{{.}} {{end}}
Последний сигнал
{{time .LastHeartbeatAt}}
- {{else}}
- Worker ещё не зарегистрирован.
Запустите scimesh-worker с URL coordinator и worker token.
- {{end}}
-
+ {{range .Workers}}{{.Name}}
{{.ID}}
{{workerStatusLabel .Status}}
{{range .Capabilities}}{{.}} {{end}}
Last signal
{{time .LastHeartbeatAt}}
{{else}}No worker is registered yet.
Run scimesh-worker with the coordinator URL and worker token.
{{end}}
diff --git a/coordinator/internal/transport/http/templates/job.html b/coordinator/internal/transport/http/templates/job.html
index 1b0d2d1..3d744de 100644
--- a/coordinator/internal/transport/http/templates/job.html
+++ b/coordinator/internal/transport/http/templates/job.html
@@ -1,41 +1,27 @@
{{define "job.html"}}
-
+
- ← К списку заданий
- {{workloadLabel .Workload}}
- Ход выполнения
-
-
- {{statusLabel .Status}}{{statusHint .Status}}
Сводка обновляется автоматически каждые 2 секунды.
-
- {{.Completed}} из {{.Total}} задач завершено
- {{.Total}}всего shard
{{.Completed}}завершено
{{.Pending}}ожидает
{{add .Leased .Running}}у worker
{{.Failed}}ошибок
- Технические сведения
Job ID: {{.ID}}
Вычисление: {{.Workload}}
Создано: {{time .CreatedAt}}
-
-
- Что можно скачать сейчас?
Файлы partial_result — результат отдельных shards. Они полезны для проверки pipeline, но ещё не являются объединённым финальным CSV: reducer пока не реализован.
-
- Shard-задачи
- Если есть ошибки, в этой таблице видно код и сообщение. Подробные строки обновляются после обычного обновления страницы.
- | Shard | Состояние | Попытка | Worker / lease | Ошибка |
{{range .Tasks}}| #{{.ChunkIndex}} | {{statusLabel .Status}} | {{.Attempt}} / {{.MaxAttempts}} | {{if .LeaseOwner}}{{.LeaseOwner}}{{if .LeaseExpiresAt}} до {{time .LeaseExpiresAt}}{{end}}{{else}}—{{end}} | {{if .ErrorCode}}{{.ErrorCode}} {{.ErrorMessage}}{{else}}—{{end}} |
{{else}}| Задачи пока не появились. |
{{end}}
-
- Артефакты coordinator
- | Тип | Файл | Размер | Проверка целостности | |
{{range .Artifacts}}{{if .Diagnostic}}Частичный результат диагностический{{else}}{{.Kind}}{{end}} | {{.Filename}} | {{bytes .SizeBytes}} | {{.SHA256}} | {{if .Downloadable}}Скачать CSV{{else}}Недоступно{{end}} |
{{else}}| Артефактов ещё нет: worker загрузит CSV после выполнения shard. |
{{end}}
+ ← Back to jobs{{workloadLabel .Workload}}
Execution progress
+ {{statusLabel .Status}}{{statusHint .Status}}
Summary refreshes automatically every two seconds.
{{.Completed}} of {{.Total}} tasks complete
{{.Total}}total shards
{{.Completed}}complete
{{.Pending}}waiting
{{add .Leased .Running}}with workers
{{.Failed}}failed
Technical details
Job ID: {{.ID}}
Workload: {{.Workload}}
Created: {{time .CreatedAt}}
+ What can be downloaded now?
partial_result files come from individual shards. They are useful for checking the pipeline, but are not a merged final CSV because the reducer is not implemented yet.
+ Shard tasks
If a task fails, its code and message appear here. Refresh the page to update the detailed rows.
+ | Shard | State | Attempt | Worker / lease | Error |
{{range .Tasks}}| #{{.ChunkIndex}} | {{statusLabel .Status}} | {{.Attempt}} / {{.MaxAttempts}} | {{if .LeaseOwner}}{{.LeaseOwner}}{{if .LeaseExpiresAt}} until {{time .LeaseExpiresAt}}{{end}}{{else}}—{{end}} | {{if .ErrorCode}}{{.ErrorCode}} {{.ErrorMessage}}{{else}}—{{end}} |
{{else}}| No tasks have appeared yet. |
{{end}}
+ Coordinator artifacts
+ | Type | File | Size | Integrity check | |
{{range .Artifacts}}{{if .Diagnostic}}Partial result diagnostic{{else}}{{.Kind}}{{end}} | {{.Filename}} | {{bytes .SizeBytes}} | {{.SHA256}} | {{if .Downloadable}}Download CSV{{else}}Unavailable{{end}} |
{{else}}| No artifacts yet. The worker uploads a CSV after it completes a shard. |
{{end}}
diff --git a/coordinator/internal/transport/http/templates/new-job.html b/coordinator/internal/transport/http/templates/new-job.html
index 0a7cce7..5a28bf2 100644
--- a/coordinator/internal/transport/http/templates/new-job.html
+++ b/coordinator/internal/transport/http/templates/new-job.html
@@ -1,69 +1,29 @@
{{define "new-job.html"}}
-
+
- ← К списку заданий
- Пошаговый запуск
- Поиск похожих молекул
- Создаёт диагностическую задачу similarity-search: worker найдёт top-k молекул, похожих на заданный SMILES.
-
-
- Перед запуском
- - Оставьте хотя бы один
scimesh-worker запущенным. - Для ручной проверки используйте небольшой TSV.
- «Строк в shard» не ограничивает размер файла. Он делит весь загруженный файл на задачи: большой ChEMBL TSV при 1000 строках создаст тысячи задач.
-
-
+ ← Back to jobsGuided run
Search for similar molecules
Creates a diagnostic similarity-search job: a worker finds the top-k molecules most similar to a target SMILES.
+ Before starting- Keep at least one
scimesh-worker running. - Use a small TSV for a hands-on check.
- “Rows per shard” does not limit the file size. It splits the entire upload into tasks: a full ChEMBL TSV at 1,000 rows per shard creates thousands of tasks.
diff --git a/coordinator/internal/transport/http/ui.go b/coordinator/internal/transport/http/ui.go
index 3074e1a..e483ea8 100644
--- a/coordinator/internal/transport/http/ui.go
+++ b/coordinator/internal/transport/http/ui.go
@@ -40,15 +40,15 @@ func formatUITime(t time.Time) string {
func uiStatusLabel(status string) string {
switch status {
case "pending":
- return "Ожидает worker"
+ return "Waiting for a worker"
case "leased":
- return "Выдана worker"
+ return "Assigned to a worker"
case "running":
- return "Выполняется"
+ return "Running"
case "completed":
- return "Задачи завершены"
+ return "Tasks complete"
case "failed":
- return "Требует внимания"
+ return "Needs attention"
default:
return status
}
@@ -57,17 +57,17 @@ func uiStatusLabel(status string) string {
func uiStatusHint(status string) string {
switch status {
case "pending":
- return "Ожидает свободный worker с нужной возможностью."
+ return "Waiting for an available worker with the required capability."
case "leased":
- return "Worker уже забрал задачу и должен скоро начать вычисление."
+ return "A worker has claimed the task and should begin processing shortly."
case "running":
- return "Worker читает shard, считает fingerprints и загружает результат через coordinator."
+ return "A worker is reading a shard, calculating fingerprints, and uploading its result through the coordinator."
case "completed":
- return "Все shard-задачи завершены. Доступные ниже файлы пока являются частичными результатами."
+ return "Every shard task is complete. Files below are still partial results."
case "failed":
- return "Одна или несколько shard-задач завершились ошибкой. Откройте список задач ниже."
+ return "One or more shard tasks failed. Open the task list below for details."
default:
- return "Статус получен от coordinator."
+ return "Status reported by the coordinator."
}
}
@@ -87,9 +87,9 @@ func uiStatusClass(status string) string {
func uiWorkerStatusLabel(status string) string {
switch status {
case "online":
- return "Доступен"
+ return "Available"
case "offline":
- return "Нет связи"
+ return "Offline"
default:
return status
}
@@ -98,9 +98,9 @@ func uiWorkerStatusLabel(status string) string {
func uiWorkloadLabel(workload string) string {
switch workload {
case "similarity-search", "similarity_search":
- return "Поиск похожих молекул"
+ return "Molecule similarity search"
case "similarity-graph", "similarity_graph":
- return "Граф молекулярного сходства"
+ return "Molecular similarity graph"
default:
return workload
}
@@ -120,15 +120,15 @@ func uiProgressPercent(completed, failed, total int) int {
func uiBytes(n int64) string {
const kib = 1024
if n < kib {
- return fmt.Sprintf("%d Б", n)
+ return fmt.Sprintf("%d B", n)
}
if n < kib*kib {
- return fmt.Sprintf("%.1f КиБ", float64(n)/kib)
+ return fmt.Sprintf("%.1f KiB", float64(n)/kib)
}
if n < kib*kib*kib {
- return fmt.Sprintf("%.1f МиБ", float64(n)/(kib*kib))
+ return fmt.Sprintf("%.1f MiB", float64(n)/(kib*kib))
}
- return fmt.Sprintf("%.1f ГиБ", float64(n)/(kib*kib*kib))
+ return fmt.Sprintf("%.1f GiB", float64(n)/(kib*kib*kib))
}
func (s *Server) renderUI(w http.ResponseWriter, name string, data any) {
diff --git a/coordinator/internal/transport/http/ui_test.go b/coordinator/internal/transport/http/ui_test.go
index 993036d..cb56a88 100644
--- a/coordinator/internal/transport/http/ui_test.go
+++ b/coordinator/internal/transport/http/ui_test.go
@@ -8,10 +8,10 @@ func TestUIStatusPresentation(t *testing.T) {
label string
class string
}{
- {"pending", "Ожидает worker", "waiting"},
- {"running", "Выполняется", "active"},
- {"completed", "Задачи завершены", "success"},
- {"failed", "Требует внимания", "danger"},
+ {"pending", "Waiting for a worker", "waiting"},
+ {"running", "Running", "active"},
+ {"completed", "Tasks complete", "success"},
+ {"failed", "Needs attention", "danger"},
}
for _, test := range tests {
t.Run(test.status, func(t *testing.T) {