worker: separate display metadata
This commit is contained in:
parent
ff905d4a22
commit
006762f900
|
|
@ -141,11 +141,17 @@ pub struct BackendWorkerSummary {
|
|||
pub runtime_id: String,
|
||||
pub worker_id: String,
|
||||
pub host_id: String,
|
||||
#[serde(default)]
|
||||
pub display_name: String,
|
||||
pub label: String,
|
||||
#[serde(default)]
|
||||
pub role: Option<String>,
|
||||
#[serde(default)]
|
||||
pub profile: Option<String>,
|
||||
#[serde(default)]
|
||||
pub singleton_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
pub workspace: BackendWorkerWorkspaceSummary,
|
||||
pub state: String,
|
||||
#[serde(default)]
|
||||
|
|
|
|||
|
|
@ -192,6 +192,8 @@ pub struct WorkspaceApiRef {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CreateWorkerRequest {
|
||||
pub profile: ProfileSelector,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub display_name: Option<String>,
|
||||
pub profile_source: ProfileSourceArchiveSource,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub config_bundle: Option<ConfigBundleRef>,
|
||||
|
|
@ -228,6 +230,8 @@ pub struct WorkerSummary {
|
|||
pub status: WorkerStatus,
|
||||
pub execution: WorkerExecutionStatus,
|
||||
pub profile: ProfileSelector,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub display_name: Option<String>,
|
||||
pub profile_source: ProfileSourceArchiveRef,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub config_bundle: Option<ConfigBundleRef>,
|
||||
|
|
@ -242,6 +246,8 @@ pub struct WorkerDetail {
|
|||
pub status: WorkerStatus,
|
||||
pub execution: WorkerExecutionStatus,
|
||||
pub profile: ProfileSelector,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub display_name: Option<String>,
|
||||
pub profile_source: ProfileSourceArchiveRef,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub config_bundle: Option<ConfigBundleRef>,
|
||||
|
|
|
|||
|
|
@ -887,6 +887,7 @@ mod tests {
|
|||
let bundle = test_bundle(profile.clone());
|
||||
CreateWorkerRequest {
|
||||
profile,
|
||||
display_name: None,
|
||||
profile_source: crate::catalog::ProfileSourceArchiveSource::Http {
|
||||
location: crate::catalog::ProfileSourceArchiveHttpRef {
|
||||
url: "http://127.0.0.1/profile-source.tar".to_string(),
|
||||
|
|
@ -1210,6 +1211,7 @@ mod ws_tests {
|
|||
let bundle = ws_test_bundle(ProfileSelector::RuntimeDefault);
|
||||
CreateWorkerRequest {
|
||||
profile: ProfileSelector::RuntimeDefault,
|
||||
display_name: None,
|
||||
profile_source: crate::catalog::ProfileSourceArchiveSource::Http {
|
||||
location: crate::catalog::ProfileSourceArchiveHttpRef {
|
||||
url: "http://127.0.0.1/profile-source.tar".to_string(),
|
||||
|
|
|
|||
|
|
@ -1860,6 +1860,7 @@ impl WorkerRecord {
|
|||
.clone()
|
||||
.with_restore_dry_check(restore_dry_check),
|
||||
profile: self.request.profile.clone(),
|
||||
display_name: self.request.display_name.clone(),
|
||||
profile_source: self.request.profile_source.reference(),
|
||||
config_bundle: self.request.config_bundle.clone(),
|
||||
last_event_id: self.last_event_id,
|
||||
|
|
@ -1873,6 +1874,7 @@ impl WorkerRecord {
|
|||
status: self.status,
|
||||
execution: self.execution.clone(),
|
||||
profile: self.request.profile.clone(),
|
||||
display_name: self.request.display_name.clone(),
|
||||
profile_source: self.request.profile_source.reference(),
|
||||
config_bundle: self.request.config_bundle.clone(),
|
||||
last_event_id: self.last_event_id,
|
||||
|
|
@ -2008,6 +2010,7 @@ mod tests {
|
|||
let bundle = test_bundle_for_profile(profile.clone());
|
||||
CreateWorkerRequest {
|
||||
profile,
|
||||
display_name: None,
|
||||
profile_source: crate::catalog::ProfileSourceArchiveSource::Http {
|
||||
location: crate::catalog::ProfileSourceArchiveHttpRef {
|
||||
url: "http://127.0.0.1/profile-source.tar".to_string(),
|
||||
|
|
|
|||
|
|
@ -1559,6 +1559,7 @@ mod tests {
|
|||
let bundle = test_bundle();
|
||||
CreateWorkerRequest {
|
||||
profile: ProfileSelector::RuntimeDefault,
|
||||
display_name: None,
|
||||
profile_source: crate::catalog::ProfileSourceArchiveSource::Embedded {
|
||||
archive: bundle.profile_source_archive.clone().unwrap(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -230,9 +230,15 @@ pub struct WorkerSummary {
|
|||
pub runtime_id: String,
|
||||
pub worker_id: String,
|
||||
pub host_id: String,
|
||||
/// Human-readable display name. This is not identity and may be duplicated.
|
||||
pub display_name: String,
|
||||
/// Backward-compatible display label. New UI should prefer `display_name`.
|
||||
pub label: String,
|
||||
pub role: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub singleton_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
pub workspace: WorkerWorkspaceSummary,
|
||||
pub state: String,
|
||||
pub last_seen_at: Option<String>,
|
||||
|
|
@ -1334,13 +1340,24 @@ impl EmbeddedWorkerRuntime {
|
|||
}
|
||||
|
||||
fn map_worker_summary(&self, summary: worker_runtime::catalog::WorkerSummary) -> WorkerSummary {
|
||||
let worker_id = summary.worker_ref.worker_id.to_string();
|
||||
let profile = embedded_profile_label(&summary.profile);
|
||||
let display = worker_display_metadata(
|
||||
&worker_id,
|
||||
profile.as_deref(),
|
||||
summary.display_name.as_deref(),
|
||||
true,
|
||||
);
|
||||
WorkerSummary {
|
||||
runtime_id: self.runtime_id.clone(),
|
||||
worker_id: summary.worker_ref.worker_id.to_string(),
|
||||
worker_id,
|
||||
host_id: self.host_id.clone(),
|
||||
label: safe_display_hint(&summary.worker_ref.worker_id.to_string()),
|
||||
role: embedded_profile_label(&summary.profile),
|
||||
profile: embedded_profile_label(&summary.profile),
|
||||
display_name: display.display_name.clone(),
|
||||
label: display.display_name,
|
||||
role: profile.clone(),
|
||||
profile,
|
||||
singleton_key: display.singleton_key,
|
||||
tags: display.tags,
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "backend_internal".to_string(),
|
||||
identity: "runtime_registry_worker".to_string(),
|
||||
|
|
@ -1368,13 +1385,24 @@ impl EmbeddedWorkerRuntime {
|
|||
}
|
||||
|
||||
fn map_worker_detail(&self, detail: EmbeddedWorkerDetail) -> WorkerSummary {
|
||||
let worker_id = detail.worker_id.to_string();
|
||||
let profile = embedded_profile_label(&detail.profile);
|
||||
let display = worker_display_metadata(
|
||||
&worker_id,
|
||||
profile.as_deref(),
|
||||
detail.display_name.as_deref(),
|
||||
true,
|
||||
);
|
||||
WorkerSummary {
|
||||
runtime_id: self.runtime_id.clone(),
|
||||
worker_id: detail.worker_id.to_string(),
|
||||
worker_id,
|
||||
host_id: self.host_id.clone(),
|
||||
label: safe_display_hint(&detail.worker_id.to_string()),
|
||||
role: embedded_profile_label(&detail.profile),
|
||||
profile: embedded_profile_label(&detail.profile),
|
||||
display_name: display.display_name.clone(),
|
||||
label: display.display_name,
|
||||
role: profile.clone(),
|
||||
profile,
|
||||
singleton_key: display.singleton_key,
|
||||
tags: display.tags,
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "backend_internal".to_string(),
|
||||
identity: "runtime_registry_worker".to_string(),
|
||||
|
|
@ -1579,9 +1607,9 @@ impl WorkspaceWorkerRuntime for EmbeddedWorkerRuntime {
|
|||
}
|
||||
if request.requested_worker_name.is_some() {
|
||||
diagnostics.push(diagnostic(
|
||||
"embedded_worker_name_ignored",
|
||||
"embedded_worker_name_display_only",
|
||||
DiagnosticSeverity::Info,
|
||||
"Embedded Runtime v0 allocates opaque runtime-local worker ids; requested display names are not authority".to_string(),
|
||||
"requested_worker_name is used only as display_name; embedded Runtime allocates opaque runtime-local worker ids".to_string(),
|
||||
));
|
||||
}
|
||||
if matches!(request.acceptance, WorkerSpawnAcceptanceRequirement::RunAccepted { expected_segments } if expected_segments > 0)
|
||||
|
|
@ -1615,6 +1643,7 @@ impl WorkspaceWorkerRuntime for EmbeddedWorkerRuntime {
|
|||
};
|
||||
let create_request = CreateWorkerRequest {
|
||||
profile,
|
||||
display_name: request.requested_worker_name.clone(),
|
||||
config_bundle: None,
|
||||
profile_source,
|
||||
initial_input: request.initial_input.clone(),
|
||||
|
|
@ -2174,13 +2203,24 @@ impl RemoteWorkerRuntime {
|
|||
}
|
||||
|
||||
fn map_worker_summary(&self, summary: worker_runtime::catalog::WorkerSummary) -> WorkerSummary {
|
||||
let worker_id = summary.worker_ref.worker_id.to_string();
|
||||
let profile = embedded_profile_label(&summary.profile);
|
||||
let display = worker_display_metadata(
|
||||
&worker_id,
|
||||
profile.as_deref(),
|
||||
summary.display_name.as_deref(),
|
||||
false,
|
||||
);
|
||||
WorkerSummary {
|
||||
runtime_id: self.runtime_id.clone(),
|
||||
worker_id: summary.worker_ref.worker_id.to_string(),
|
||||
worker_id,
|
||||
host_id: self.host_id.clone(),
|
||||
label: safe_display_hint(&summary.worker_ref.worker_id.to_string()),
|
||||
role: None,
|
||||
profile: embedded_profile_label(&summary.profile),
|
||||
display_name: display.display_name.clone(),
|
||||
label: display.display_name,
|
||||
role: profile.clone(),
|
||||
profile,
|
||||
singleton_key: display.singleton_key,
|
||||
tags: display.tags,
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "remote_runtime".to_string(),
|
||||
identity: "runtime_registry_worker".to_string(),
|
||||
|
|
@ -2208,13 +2248,24 @@ impl RemoteWorkerRuntime {
|
|||
}
|
||||
|
||||
fn map_worker_detail(&self, detail: EmbeddedWorkerDetail) -> WorkerSummary {
|
||||
let worker_id = detail.worker_id.to_string();
|
||||
let profile = embedded_profile_label(&detail.profile);
|
||||
let display = worker_display_metadata(
|
||||
&worker_id,
|
||||
profile.as_deref(),
|
||||
detail.display_name.as_deref(),
|
||||
false,
|
||||
);
|
||||
WorkerSummary {
|
||||
runtime_id: self.runtime_id.clone(),
|
||||
worker_id: detail.worker_id.to_string(),
|
||||
worker_id,
|
||||
host_id: self.host_id.clone(),
|
||||
label: safe_display_hint(&detail.worker_id.to_string()),
|
||||
role: None,
|
||||
profile: embedded_profile_label(&detail.profile),
|
||||
display_name: display.display_name.clone(),
|
||||
label: display.display_name,
|
||||
role: profile.clone(),
|
||||
profile,
|
||||
singleton_key: display.singleton_key,
|
||||
tags: display.tags,
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "remote_runtime".to_string(),
|
||||
identity: "runtime_registry_worker".to_string(),
|
||||
|
|
@ -2473,6 +2524,7 @@ impl WorkspaceWorkerRuntime for RemoteWorkerRuntime {
|
|||
};
|
||||
let create = CreateWorkerRequest {
|
||||
profile,
|
||||
display_name: request.requested_worker_name.clone(),
|
||||
config_bundle: None,
|
||||
profile_source,
|
||||
initial_input: request.initial_input.clone(),
|
||||
|
|
@ -3000,10 +3052,83 @@ fn ticket_role_profile_slug(role: &TicketWorkerRole) -> &'static str {
|
|||
fn embedded_profile_label(profile: &ProfileSelector) -> Option<String> {
|
||||
Some(match profile {
|
||||
ProfileSelector::RuntimeDefault => "runtime_default".to_string(),
|
||||
ProfileSelector::Builtin(name) | ProfileSelector::Named(name) => safe_display_hint(name),
|
||||
ProfileSelector::Builtin(name) | ProfileSelector::Named(name) => {
|
||||
if name.strip_prefix("builtin:").unwrap_or(name) == MEMORY_CONSOLIDATION_PROFILE {
|
||||
MEMORY_CONSOLIDATION_PROFILE.to_string()
|
||||
} else {
|
||||
safe_display_hint(name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const MEMORY_CONSOLIDATION_PROFILE: &str = "memory-consolidation";
|
||||
const MEMORY_CONSOLIDATION_SINGLETON_KEY: &str = "workspace-memory-consolidation";
|
||||
|
||||
struct WorkerDisplayMetadata {
|
||||
display_name: String,
|
||||
singleton_key: Option<String>,
|
||||
tags: Vec<String>,
|
||||
}
|
||||
|
||||
fn worker_display_metadata(
|
||||
worker_id: &str,
|
||||
profile_label: Option<&str>,
|
||||
requested_display_name: Option<&str>,
|
||||
internal: bool,
|
||||
) -> WorkerDisplayMetadata {
|
||||
if profile_label == Some(MEMORY_CONSOLIDATION_PROFILE) {
|
||||
let mut tags = vec![
|
||||
"memory".to_string(),
|
||||
"consolidation".to_string(),
|
||||
"singleton".to_string(),
|
||||
];
|
||||
if internal {
|
||||
tags.insert(0, "internal".to_string());
|
||||
}
|
||||
return WorkerDisplayMetadata {
|
||||
display_name: "Memory Consolidation".to_string(),
|
||||
singleton_key: Some(MEMORY_CONSOLIDATION_SINGLETON_KEY.to_string()),
|
||||
tags,
|
||||
};
|
||||
}
|
||||
let display_name = requested_display_name
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.map(safe_display_hint)
|
||||
.or_else(|| profile_label.map(profile_display_name))
|
||||
.unwrap_or_else(|| format!("Worker {worker_id}"));
|
||||
let mut tags = Vec::new();
|
||||
if internal {
|
||||
tags.push("internal".to_string());
|
||||
}
|
||||
if let Some(profile_label) = profile_label {
|
||||
tags.push(format!("profile:{profile_label}"));
|
||||
}
|
||||
WorkerDisplayMetadata {
|
||||
display_name,
|
||||
singleton_key: None,
|
||||
tags,
|
||||
}
|
||||
}
|
||||
|
||||
fn profile_display_name(profile_label: &str) -> String {
|
||||
match profile_label {
|
||||
"runtime_default" => "Default Worker".to_string(),
|
||||
value => value
|
||||
.split(['-', '_'])
|
||||
.filter(|part| !part.is_empty())
|
||||
.map(|part| {
|
||||
let mut chars = part.chars();
|
||||
match chars.next() {
|
||||
Some(first) => first.to_uppercase().chain(chars).collect::<String>(),
|
||||
None => String::new(),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" "),
|
||||
}
|
||||
}
|
||||
|
||||
fn embedded_input_rejected(
|
||||
runtime_id: &str,
|
||||
worker_id: &str,
|
||||
|
|
@ -3389,9 +3514,12 @@ pub fn placeholder_worker(host_id: impl Into<String>) -> WorkerSummary {
|
|||
runtime_id: "placeholder".to_string(),
|
||||
worker_id: "worker-placeholder".to_string(),
|
||||
host_id,
|
||||
display_name: "Worker runtime actions are not implemented".to_string(),
|
||||
label: "Worker runtime actions are not implemented".to_string(),
|
||||
role: None,
|
||||
profile: None,
|
||||
singleton_key: None,
|
||||
tags: Vec::new(),
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "none".to_string(),
|
||||
identity: "unsupported".to_string(),
|
||||
|
|
@ -3720,9 +3848,12 @@ mod tests {
|
|||
runtime_id: runtime_id.to_string(),
|
||||
worker_id: worker_id.to_string(),
|
||||
host_id: host_id.to_string(),
|
||||
display_name: label.to_string(),
|
||||
label: label.to_string(),
|
||||
role: None,
|
||||
profile: None,
|
||||
singleton_key: None,
|
||||
tags: Vec::new(),
|
||||
workspace: WorkerWorkspaceSummary {
|
||||
visibility: "opaque".to_string(),
|
||||
identity: host_id.to_string(),
|
||||
|
|
|
|||
|
|
@ -1514,6 +1514,7 @@ async fn scoped_memory_backend_operation(
|
|||
}
|
||||
|
||||
const MEMORY_CONSOLIDATION_PROFILE: &str = "memory-consolidation";
|
||||
const MEMORY_CONSOLIDATION_SINGLETON_KEY: &str = "workspace-memory-consolidation";
|
||||
const MEMORY_CONSOLIDATION_WORKER_SCAN_LIMIT: usize = 100;
|
||||
|
||||
async fn scoped_memory_consolidation(
|
||||
|
|
@ -1699,7 +1700,8 @@ fn try_reuse_memory_consolidation_worker(
|
|||
}
|
||||
|
||||
fn is_memory_consolidation_worker(worker: &WorkerSummary) -> bool {
|
||||
[worker.profile.as_deref(), worker.role.as_deref()]
|
||||
worker.singleton_key.as_deref() == Some(MEMORY_CONSOLIDATION_SINGLETON_KEY)
|
||||
|| [worker.profile.as_deref(), worker.role.as_deref()]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.any(|value| value == MEMORY_CONSOLIDATION_PROFILE)
|
||||
|
|
@ -5723,7 +5725,10 @@ fn worker_summary_from_registry(record: &WorkerRegistryRecord) -> WorkerSummary
|
|||
runtime_id: record.runtime_id.clone(),
|
||||
host_id: "backend-registry".to_string(),
|
||||
role: None,
|
||||
display_name: record.display_name.clone(),
|
||||
label: record.display_name.clone(),
|
||||
singleton_key: None,
|
||||
tags: Vec::new(),
|
||||
state: "missing".to_string(),
|
||||
last_seen_at: Some(record.updated_at.clone()),
|
||||
pinned: record.retention_state == "pinned",
|
||||
|
|
@ -7395,6 +7400,13 @@ mod tests {
|
|||
.worker(EMBEDDED_WORKER_RUNTIME_ID, &worker_id)
|
||||
.unwrap();
|
||||
assert_eq!(worker.state, "idle");
|
||||
assert_eq!(worker.display_name, "Memory Consolidation");
|
||||
assert_eq!(
|
||||
worker.singleton_key.as_deref(),
|
||||
Some(MEMORY_CONSOLIDATION_SINGLETON_KEY)
|
||||
);
|
||||
assert!(worker.tags.iter().any(|tag| tag == "memory"));
|
||||
assert!(worker.tags.iter().any(|tag| tag == "consolidation"));
|
||||
|
||||
let second = match start_memory_staging_consolidation(
|
||||
api.clone(),
|
||||
|
|
@ -7942,6 +7954,7 @@ mod tests {
|
|||
let bundle = runtime_test_bundle();
|
||||
worker_runtime::catalog::CreateWorkerRequest {
|
||||
profile: worker_runtime::catalog::ProfileSelector::RuntimeDefault,
|
||||
display_name: None,
|
||||
profile_source: worker_runtime::catalog::ProfileSourceArchiveSource::Http {
|
||||
location: worker_runtime::catalog::ProfileSourceArchiveHttpRef {
|
||||
url: "http://127.0.0.1/profile-source.tar".to_string(),
|
||||
|
|
|
|||
|
|
@ -114,13 +114,16 @@ Deno.test("workspace Worker list lives on the dedicated Workers page", async ()
|
|||
assert(
|
||||
workersPage.includes("workerConsoleHref(worker, data.workspaceId)") &&
|
||||
workersPage.includes('<table class="workers-table">') &&
|
||||
workersPage.includes('class="icon-action"') &&
|
||||
workersPage.includes("Delete ${worker.label}"),
|
||||
workersPage.includes("workerDisplayName = worker.display_name || worker.label") &&
|
||||
workersPage.includes("worker <code>{worker.worker_id}</code>") &&
|
||||
workersPage.includes("Delete ${workerDisplayName}"),
|
||||
"dedicated Workers page should expose a table, console link target, and icon actions per Worker",
|
||||
);
|
||||
assert(
|
||||
workersNav.includes("href={`/w/${workspaceId}/workers`}") &&
|
||||
workersNav.includes("filter(canShowWorkerInSidebar)") &&
|
||||
workersNav.includes("worker.display_name || worker.label") &&
|
||||
workersNav.includes("worker {worker.worker_id}") &&
|
||||
!workersNav.includes('aria-disabled="true"'),
|
||||
"Workers sidebar should link to the Worker list page and omit registry-only Workers",
|
||||
);
|
||||
|
|
|
|||
|
|
@ -105,11 +105,11 @@
|
|||
<li>
|
||||
<a href={href} class="nav-item worker-nav-item" class:active={currentPath === href} aria-current={currentPath === href ? 'page' : undefined}>
|
||||
<span class="worker-title-row">
|
||||
<span class="item-title">{worker.label}</span>
|
||||
<span class="item-title">{worker.display_name || worker.label}</span>
|
||||
<span class="worker-task-title">-</span>
|
||||
</span>
|
||||
<span class="item-meta">
|
||||
{worker.role ? `${worker.role} · ` : ''}{worker.state} · 🖥 {worker.host_id}
|
||||
worker {worker.worker_id} · {worker.role ? `${worker.role} · ` : ''}{worker.state} · 🖥 {worker.host_id}
|
||||
{worker.working_directory ? ` · wd:${worker.working_directory.repository_id}@${worker.working_directory.resolved_commit.slice(0, 8)}` : ''}
|
||||
</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -77,9 +77,12 @@ export type Worker = {
|
|||
runtime_id: string;
|
||||
worker_id: string;
|
||||
host_id: string;
|
||||
display_name: string;
|
||||
label: string;
|
||||
role?: string | null;
|
||||
profile?: string | null;
|
||||
singleton_key?: string | null;
|
||||
tags: string[];
|
||||
workspace: { visibility: string; identity: string };
|
||||
state: string;
|
||||
pinned?: boolean;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,12 @@ function worker(overrides: Partial<Worker>): Worker {
|
|||
runtime_id: "arc",
|
||||
worker_id: "1",
|
||||
host_id: "host",
|
||||
label: "worker-1",
|
||||
display_name: "Worker 1",
|
||||
label: "Worker 1",
|
||||
role: null,
|
||||
profile: null,
|
||||
singleton_key: null,
|
||||
tags: [],
|
||||
workspace: { visibility: "workspace", identity: "workspace" },
|
||||
state: "running",
|
||||
pinned: false,
|
||||
|
|
|
|||
|
|
@ -190,14 +190,15 @@
|
|||
{@const cleanup = cleanupCandidate(worker)}
|
||||
{@const canDelete = cleanup && !cleanup.blocking_reason}
|
||||
{@const anyActionDisabled = actionsDisabled()}
|
||||
{@const workerDisplayName = worker.display_name || worker.label}
|
||||
<tr>
|
||||
<td>
|
||||
{#if canOpenWorkerConsole(worker)}
|
||||
<a class="worker-title-link" href={workerConsoleHref(worker, data.workspaceId)}><strong>{worker.label}</strong></a>
|
||||
<a class="worker-title-link" href={workerConsoleHref(worker, data.workspaceId)}><strong>{workerDisplayName}</strong></a>
|
||||
{:else}
|
||||
<strong>{worker.label}</strong>
|
||||
<strong>{workerDisplayName}</strong>
|
||||
{/if}
|
||||
<small><code>{worker.worker_id}</code></small>
|
||||
<small>worker <code>{worker.worker_id}</code></small>
|
||||
</td>
|
||||
<td><code>{worker.runtime_id}</code></td>
|
||||
<td>{workerProfile(worker)}</td>
|
||||
|
|
@ -205,12 +206,12 @@
|
|||
<td><span class="pill {worker.pinned ? 'success' : 'muted'}">{worker.retention_state ?? 'normal'}</span></td>
|
||||
<td>{workerDirectory(worker)}</td>
|
||||
<td>
|
||||
<div class="worker-actions" aria-label={`Actions for ${worker.label}`}>
|
||||
<div class="worker-actions" aria-label={`Actions for ${workerDisplayName}`}>
|
||||
<button
|
||||
class="icon-action"
|
||||
type="button"
|
||||
disabled={anyActionDisabled}
|
||||
aria-label={worker.pinned ? `Unpin ${worker.label}` : `Pin ${worker.label}`}
|
||||
aria-label={worker.pinned ? `Unpin ${workerDisplayName}` : `Pin ${workerDisplayName}`}
|
||||
title={worker.pinned ? 'Unpin' : 'Pin'}
|
||||
onclick={() => setPinned(worker, !worker.pinned)}
|
||||
>
|
||||
|
|
@ -227,7 +228,7 @@
|
|||
class="icon-action danger"
|
||||
type="button"
|
||||
disabled={!canDelete || anyActionDisabled}
|
||||
aria-label={`Delete ${worker.label}`}
|
||||
aria-label={`Delete ${workerDisplayName}`}
|
||||
title={cleanup.blocking_reason ?? cleanup.reason}
|
||||
onclick={() => deleteWorker(worker, cleanup)}
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user