Skip to content

Commit 925472f

Browse files
ravwojdylagithub-actions[bot]rjpowerclaude
authored
iris: add IP cp buttons (#3655)
Add Iris copy IP buttons, to make it easier to SSH into stuff. --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Russell Power <rjpower@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d0df187 commit 925472f

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

lib/iris/dashboard/src/components/controller/EndpointsTab.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useControllerRpc } from '@/composables/useRpc'
55
import { useAutoRefresh } from '@/composables/useAutoRefresh'
66
import type { EndpointInfo, ListEndpointsResponse } from '@/types/rpc'
77
import EmptyState from '@/components/shared/EmptyState.vue'
8+
import CopyButton from '@/components/shared/CopyButton.vue'
89
910
const SHOW_ALL_THRESHOLD = 100
1011
@@ -143,7 +144,13 @@ function jobIdFromTaskId(taskId?: string): string | null {
143144
class="border-b border-surface-border-subtle hover:bg-surface-raised transition-colors"
144145
>
145146
<td class="px-3 py-2 text-[13px] font-mono">{{ ep.name }}</td>
146-
<td class="px-3 py-2 text-[13px] font-mono text-text-secondary">{{ ep.address }}</td>
147+
<td class="px-3 py-2 text-[13px] font-mono text-text-secondary">
148+
<span v-if="ep.address" class="group/addr inline-flex items-center gap-1">
149+
{{ ep.address }}
150+
<CopyButton :value="ep.address" />
151+
</span>
152+
<span v-else>-</span>
153+
</td>
147154
<td class="px-3 py-2 text-[13px]">
148155
<RouterLink
149156
v-if="ep.taskId && jobIdFromTaskId(ep.taskId)"

lib/iris/dashboard/src/components/controller/FleetTab.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { timestampMs, formatRelativeTime, formatBytes, formatWorkerDevice } from
88
99
import DataTable, { type Column } from '@/components/shared/DataTable.vue'
1010
import EmptyState from '@/components/shared/EmptyState.vue'
11+
import CopyButton from '@/components/shared/CopyButton.vue'
1112
1213
const { data, loading, error, refresh } = useControllerRpc<ListWorkersResponse>('ListWorkers')
1314
@@ -70,7 +71,11 @@ const columns: Column[] = [
7071
</template>
7172

7273
<template #cell-address="{ row }">
73-
{{ (row as WorkerHealthStatus).address ?? '-' }}
74+
<span v-if="(row as WorkerHealthStatus).address" class="group/addr inline-flex items-center gap-1">
75+
{{ (row as WorkerHealthStatus).address }}
76+
<CopyButton :value="(row as WorkerHealthStatus).address!" />
77+
</span>
78+
<span v-else>-</span>
7479
</template>
7580

7681
<template #cell-device="{ row }">

lib/iris/dashboard/src/components/controller/WorkerDetail.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import InfoRow from '@/components/shared/InfoRow.vue'
1919
import MetricCard from '@/components/shared/MetricCard.vue'
2020
import Sparkline from '@/components/shared/Sparkline.vue'
2121
import DataTable, { type Column } from '@/components/shared/DataTable.vue'
22+
import CopyButton from '@/components/shared/CopyButton.vue'
2223
2324
const props = defineProps<{
2425
workerId: string
@@ -118,8 +119,9 @@ function attributeDisplay(val: { stringValue?: string; intValue?: string; floatV
118119
/>
119120
{{ worker?.healthy ? 'Healthy' : 'Unhealthy' }}
120121
</span>
121-
<span v-if="worker?.address" class="text-sm text-text-muted font-mono">
122+
<span v-if="worker?.address" class="group/addr text-sm text-text-muted font-mono inline-flex items-center gap-1">
122123
{{ worker.address }}
124+
<CopyButton :value="worker.address" />
123125
</span>
124126
<button
125127
class="ml-auto px-3 py-1.5 text-xs border border-surface-border rounded hover:bg-surface-sunken"
@@ -148,7 +150,11 @@ function attributeDisplay(val: { stringValue?: string; intValue?: string; floatV
148150
<span class="font-mono">{{ worker?.workerId }}</span>
149151
</InfoRow>
150152
<InfoRow label="Address">
151-
<span class="font-mono">{{ worker?.address ?? '-' }}</span>
153+
<span v-if="worker?.address" class="group/addr inline-flex items-center gap-1">
154+
<CopyButton :value="worker.address" />
155+
<span class="font-mono">{{ worker.address }}</span>
156+
</span>
157+
<span v-else class="font-mono">-</span>
152158
</InfoRow>
153159
<InfoRow v-if="worker?.metadata?.attributes?.zone" label="Zone">
154160
<span class="font-mono">{{ worker.metadata.attributes.zone.stringValue }}</span>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
4+
const props = defineProps<{
5+
/** The raw value to copy (e.g. "https://10.0.0.1:8080"). Protocol and port are stripped before copying. */
6+
value: string
7+
/** Tooltip text shown on hover. */
8+
title?: string
9+
}>()
10+
11+
const copied = ref(false)
12+
13+
async function copy() {
14+
const ip = props.value.replace(/^https?:\/\//, '').replace(/:\d+$/, '')
15+
await navigator.clipboard.writeText(ip)
16+
copied.value = true
17+
setTimeout(() => { copied.value = false }, 1500)
18+
}
19+
</script>
20+
21+
<template>
22+
<button
23+
class="text-text-muted hover:text-text opacity-0 group-hover/addr:opacity-100 transition-opacity"
24+
:title="title ?? 'Copy IP'"
25+
@click="copy"
26+
>
27+
<svg v-if="copied" class="w-3.5 h-3.5 text-status-success" viewBox="0 0 20 20" fill="currentColor">
28+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
29+
</svg>
30+
<svg v-else class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
31+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
32+
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" />
33+
</svg>
34+
</button>
35+
</template>

0 commit comments

Comments
 (0)