Skip to content

Commit 41987b5

Browse files
author
Lasim
committed
feat(frontend): enhance device detail view with i18n support
1 parent 5344c1a commit 41987b5

File tree

4 files changed

+59
-107
lines changed

4 files changed

+59
-107
lines changed

services/frontend/src/composables/useDeviceDetail.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,43 +42,38 @@ export function useDeviceDetail() {
4242

4343
return [
4444
{
45-
label: 'Device ID',
45+
label: t('devices.detail.fields.deviceId'),
4646
value: device.value.id,
4747
icon: 'Monitor'
4848
},
4949
{
50-
label: 'Hostname',
51-
value: device.value.hostname || 'Unknown',
50+
label: t('devices.detail.fields.hostname'),
51+
value: device.value.hostname || t('devices.detail.fields.unknown'),
5252
icon: 'Globe'
5353
},
5454
{
55-
label: 'Operating System',
55+
label: t('devices.detail.fields.operatingSystem'),
5656
value: `${getOSDisplayName(device.value.os_type)} ${device.value.os_version || ''}`.trim(),
5757
icon: 'HardDrive'
5858
},
5959
{
60-
label: 'Architecture',
61-
value: device.value.arch || 'Unknown',
60+
label: t('devices.detail.fields.architecture'),
61+
value: device.value.arch || t('devices.detail.fields.unknown'),
6262
icon: 'Cpu'
6363
},
6464
{
65-
label: 'Node.js Version',
66-
value: device.value.node_version || 'Unknown',
65+
label: t('devices.detail.fields.nodeVersion'),
66+
value: device.value.node_version || t('devices.detail.fields.unknown'),
6767
icon: 'Cpu'
6868
},
6969
{
70-
label: 'Last IP Address',
71-
value: device.value.last_ip || 'Unknown',
72-
icon: 'Globe'
73-
},
74-
{
75-
label: 'Hardware ID',
76-
value: device.value.hardware_id || 'Unknown',
70+
label: t('devices.detail.fields.hardwareId'),
71+
value: device.value.hardware_id || t('devices.detail.fields.unknown'),
7772
icon: 'Monitor'
7873
},
7974
{
80-
label: 'User Agent',
81-
value: device.value.user_agent || 'Unknown',
75+
label: t('devices.detail.fields.userAgent'),
76+
value: device.value.user_agent || t('devices.detail.fields.unknown'),
8277
icon: 'Globe'
8378
}
8479
]
@@ -89,22 +84,22 @@ export function useDeviceDetail() {
8984

9085
return [
9186
{
92-
label: 'Device Registered',
87+
label: t('devices.detail.fields.deviceRegistered'),
9388
value: device.value.created_at,
9489
icon: 'Calendar'
9590
},
9691
{
97-
label: 'Last Updated',
92+
label: t('devices.detail.fields.lastUpdated'),
9893
value: device.value.updated_at,
9994
icon: 'Calendar'
10095
},
10196
{
102-
label: 'Last Login',
97+
label: t('devices.detail.fields.lastLogin'),
10398
value: device.value.last_login_at,
10499
icon: 'Calendar'
105100
},
106101
{
107-
label: 'Last Activity',
102+
label: t('devices.detail.fields.lastActivity'),
108103
value: device.value.last_activity_at,
109104
icon: 'Calendar'
110105
}

services/frontend/src/i18n/locales/en/devices.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ export default {
6969

7070
// Dialogs
7171
editDialog: {
72-
title: 'Edit Device',
73-
description: 'Update your device name and settings',
72+
title: 'Edit Device Friendly Name',
73+
description: 'Update your device friendly name',
7474
fields: {
7575
deviceName: {
7676
label: 'Device Name',
@@ -118,5 +118,35 @@ export default {
118118
title: 'No devices registered',
119119
description: 'You have no registered devices. Devices are automatically registered when you login with the DeployStack CLI.',
120120
action: 'Learn about device management'
121+
},
122+
123+
// Device detail view
124+
detail: {
125+
title: 'Device Details',
126+
backToDevices: 'Back to Devices',
127+
loadingMessage: 'Loading device details...',
128+
loadError: 'Failed to load device',
129+
systemInformation: {
130+
title: 'System Information',
131+
description: 'Hardware and system details for this device'
132+
},
133+
activityInformation: {
134+
title: 'Activity Information',
135+
description: 'Registration and usage timestamps for this device'
136+
},
137+
fields: {
138+
deviceId: 'Device ID',
139+
hostname: 'Hostname',
140+
operatingSystem: 'Operating System',
141+
architecture: 'Architecture',
142+
nodeVersion: 'Node.js Version',
143+
hardwareId: 'Hardware ID',
144+
userAgent: 'User Agent',
145+
deviceRegistered: 'Device Registered',
146+
lastUpdated: 'Last Updated',
147+
lastLogin: 'Last Login',
148+
lastActivity: 'Last Activity',
149+
unknown: 'Unknown'
150+
}
121151
}
122152
}

services/frontend/src/views/devices/index.vue

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
AlertDialogTitle,
2626
} from '@/components/ui/alert-dialog'
2727
import { Button } from '@/components/ui/button'
28-
import { Badge } from '@/components/ui/badge'
2928
import { Input } from '@/components/ui/input'
3029
import { Label } from '@/components/ui/label'
3130
import DashboardLayout from '@/components/DashboardLayout.vue'
@@ -34,10 +33,7 @@ import {
3433
MoreHorizontal,
3534
Edit,
3635
Trash2,
37-
Shield,
38-
ShieldOff,
3936
Monitor,
40-
CheckCircle,
4137
Laptop
4238
} from 'lucide-vue-next'
4339
import { useDevices } from '@/composables/useDevices'
@@ -140,14 +136,6 @@ onMounted(() => {
140136
<Monitor class="h-4 w-4" />
141137
<span>{{ deviceStats.total }} {{ t('devices.stats.total') }}</span>
142138
</div>
143-
<div class="flex items-center gap-1">
144-
<CheckCircle class="h-4 w-4 text-green-600" />
145-
<span>{{ deviceStats.active }} {{ t('devices.stats.active') }}</span>
146-
</div>
147-
<div class="flex items-center gap-1">
148-
<Shield class="h-4 w-4 text-blue-600" />
149-
<span>{{ deviceStats.trusted }} {{ t('devices.stats.trusted') }}</span>
150-
</div>
151139
</div>
152140
</div>
153141
</div>
@@ -160,15 +148,13 @@ onMounted(() => {
160148
<TableHead>{{ t('devices.table.columns.deviceName') }}</TableHead>
161149
<TableHead>{{ t('devices.table.columns.operatingSystem') }}</TableHead>
162150
<TableHead>{{ t('devices.table.columns.lastActivity') }}</TableHead>
163-
<TableHead>{{ t('devices.table.columns.status') }}</TableHead>
164-
<TableHead>{{ t('devices.table.columns.trustStatus') }}</TableHead>
165151
<TableHead class="w-[100px]">{{ t('devices.table.columns.actions') }}</TableHead>
166152
</TableRow>
167153
</TableHeader>
168154
<TableBody>
169155
<!-- Loading state -->
170156
<TableRow v-if="isLoading">
171-
<TableCell :colspan="6" class="h-24 text-center">
157+
<TableCell :colspan="4" class="h-24 text-center">
172158
<div class="flex items-center justify-center">
173159
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
174160
<span class="ml-2">Loading devices...</span>
@@ -178,7 +164,7 @@ onMounted(() => {
178164

179165
<!-- Empty State -->
180166
<TableRow v-else-if="sortedDevices.length === 0">
181-
<TableCell :colspan="6" class="h-32 text-center">
167+
<TableCell :colspan="4" class="h-32 text-center">
182168
<div class="flex flex-col items-center justify-center space-y-2">
183169
<Laptop class="h-12 w-12 text-muted-foreground" />
184170
<div class="text-lg font-medium">{{ t('devices.emptyState.title') }}</div>
@@ -211,18 +197,6 @@ onMounted(() => {
211197
<TableCell class="text-sm text-muted-foreground">
212198
{{ device.lastActivityDisplay }}
213199
</TableCell>
214-
<TableCell>
215-
<Badge :variant="device.statusBadgeVariant">
216-
{{ device.is_active ? t('devices.status.active') : t('devices.status.inactive') }}
217-
</Badge>
218-
</TableCell>
219-
<TableCell>
220-
<div class="flex items-center gap-1">
221-
<Shield v-if="device.is_trusted" class="h-4 w-4 text-green-600" />
222-
<ShieldOff v-else class="h-4 w-4 text-yellow-600" />
223-
<span class="text-sm">{{ device.trustStatusDisplay }}</span>
224-
</div>
225-
</TableCell>
226200
<TableCell>
227201
<DropdownMenu>
228202
<DropdownMenuTrigger as-child>

services/frontend/src/views/devices/view/[id].vue

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ import { ref, computed, onMounted } from 'vue'
33
import { useRoute, useRouter } from 'vue-router'
44
import { useI18n } from 'vue-i18n'
55
import { Button } from '@/components/ui/button'
6-
import { Badge } from '@/components/ui/badge'
76
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
87
import { Alert, AlertDescription } from '@/components/ui/alert'
98
import DashboardLayout from '@/components/DashboardLayout.vue'
109
import ContentWrapper from '@/components/ContentWrapper.vue'
1110
import {
1211
ArrowLeft,
1312
Monitor,
14-
Shield,
15-
ShieldOff,
1613
Calendar,
1714
Globe,
1815
Cpu,
@@ -57,20 +54,20 @@ onMounted(async () => {
5754
try {
5855
await fetchDevice(deviceId.value)
5956
} catch (err) {
60-
error.value = err instanceof Error ? err.message : 'Failed to load device'
57+
error.value = err instanceof Error ? err.message : t('devices.detail.loadError')
6158
}
6259
})
6360
</script>
6461

6562
<template>
66-
<DashboardLayout :title="device?.device_name || 'Device Details'">
63+
<DashboardLayout :title="device?.device_name || t('devices.detail.title')">
6764
<ContentWrapper>
6865
<div class="space-y-6">
6966
<!-- Back Navigation -->
7067
<div class="flex items-center gap-4">
7168
<Button variant="ghost" @click="handleBack" class="flex items-center gap-2">
7269
<ArrowLeft class="h-4 w-4" />
73-
Back to Devices
70+
{{ t('devices.detail.backToDevices') }}
7471
</Button>
7572
</div>
7673

@@ -83,7 +80,7 @@ onMounted(async () => {
8380
<!-- Loading State -->
8481
<div v-if="isLoading" class="flex items-center justify-center h-32">
8582
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
86-
<span class="ml-3">Loading device details...</span>
83+
<span class="ml-3">{{ t('devices.detail.loadingMessage') }}</span>
8784
</div>
8885

8986
<!-- Device Details -->
@@ -100,18 +97,6 @@ onMounted(async () => {
10097
<span v-if="device.arch"> • {{ device.arch }}</span>
10198
</p>
10299
</div>
103-
<div class="flex items-center gap-2">
104-
<Badge :variant="device.is_active ? 'default' : 'secondary'">
105-
{{ device.is_active ? t('devices.status.active') : t('devices.status.inactive') }}
106-
</Badge>
107-
<div class="flex items-center gap-1">
108-
<Shield v-if="device.is_trusted" class="h-4 w-4 text-green-600" />
109-
<ShieldOff v-else class="h-4 w-4 text-yellow-600" />
110-
<Badge variant="outline">
111-
{{ device.is_trusted ? t('devices.status.trusted') : t('devices.status.untrusted') }}
112-
</Badge>
113-
</div>
114-
</div>
115100
</div>
116101

117102
<!-- Device Information Cards -->
@@ -121,10 +106,10 @@ onMounted(async () => {
121106
<CardHeader>
122107
<CardTitle class="flex items-center gap-2">
123108
<Monitor class="h-5 w-5" />
124-
System Information
109+
{{ t('devices.detail.systemInformation.title') }}
125110
</CardTitle>
126111
<CardDescription>
127-
Hardware and system details for this device
112+
{{ t('devices.detail.systemInformation.description') }}
128113
</CardDescription>
129114
</CardHeader>
130115
<CardContent class="space-y-4">
@@ -146,10 +131,10 @@ onMounted(async () => {
146131
<CardHeader>
147132
<CardTitle class="flex items-center gap-2">
148133
<Calendar class="h-5 w-5" />
149-
Activity Information
134+
{{ t('devices.detail.activityInformation.title') }}
150135
</CardTitle>
151136
<CardDescription>
152-
Registration and usage timestamps for this device
137+
{{ t('devices.detail.activityInformation.description') }}
153138
</CardDescription>
154139
</CardHeader>
155140
<CardContent class="space-y-4">
@@ -164,43 +149,11 @@ onMounted(async () => {
164149
</Card>
165150
</div>
166151

167-
<!-- Security Status -->
168-
<Card>
169-
<CardHeader>
170-
<CardTitle class="flex items-center gap-2">
171-
<Shield class="h-5 w-5" />
172-
Security Status
173-
</CardTitle>
174-
<CardDescription>
175-
Trust status and security information for this device
176-
</CardDescription>
177-
</CardHeader>
178-
<CardContent>
179-
<div class="flex items-center gap-4">
180-
<div class="flex items-center gap-2">
181-
<Shield v-if="device.is_trusted" class="h-5 w-5 text-green-600" />
182-
<ShieldOff v-else class="h-5 w-5 text-yellow-600" />
183-
<div>
184-
<div class="font-medium">
185-
{{ device.is_trusted ? 'Trusted Device' : 'Untrusted Device' }}
186-
</div>
187-
<div class="text-sm text-muted-foreground">
188-
{{ device.is_trusted
189-
? 'This device is marked as trusted and has full access to your MCP configurations'
190-
: 'This device requires additional verification for sensitive operations'
191-
}}
192-
</div>
193-
</div>
194-
</div>
195-
</div>
196-
</CardContent>
197-
</Card>
198-
199152
<!-- Actions -->
200153
<div class="flex items-center gap-4 pt-4 border-t">
201154
<Button variant="destructive" class="flex items-center gap-2">
202155
<Trash2 class="h-4 w-4" />
203-
Remove Device
156+
{{ t('devices.actions.removeDevice') }}
204157
</Button>
205158
</div>
206159
</div>

0 commit comments

Comments
 (0)