Skip to content

Commit ab1bfa4

Browse files
author
mdatelle
committed
feat: create base Detail component and placeholder tab components
1 parent 18b9d39 commit ab1bfa4

File tree

8 files changed

+560
-69
lines changed

8 files changed

+560
-69
lines changed

web/components/Docker/Console.vue

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
import { UButton } from '#components';
4+
5+
interface Props {
6+
item: {
7+
id: string;
8+
label: string;
9+
icon?: string;
10+
badge?: string | number;
11+
};
12+
}
13+
14+
const props = defineProps<Props>();
15+
const command = ref('');
16+
const output = ref<string[]>([
17+
`root@${props.item.id}:/# echo "Welcome to ${props.item.label}"`,
18+
`Welcome to ${props.item.label}`,
19+
`root@${props.item.id}:/#`,
20+
]);
21+
22+
const executeCommand = () => {
23+
if (command.value.trim()) {
24+
output.value.push(`root@${props.item.id}:/# ${command.value}`);
25+
output.value.push(`${command.value}: command executed`);
26+
output.value.push(`root@${props.item.id}:/#`);
27+
command.value = '';
28+
}
29+
};
30+
</script>
31+
32+
<template>
33+
<div class="space-y-4">
34+
<div class="flex justify-between items-center">
35+
<h3 class="text-lg font-medium">Terminal</h3>
36+
<div class="flex gap-2">
37+
<UButton size="sm" color="primary" variant="outline" icon="i-lucide-maximize-2">
38+
Fullscreen
39+
</UButton>
40+
<UButton size="sm" color="primary" variant="outline" icon="i-lucide-refresh-cw">
41+
Restart
42+
</UButton>
43+
</div>
44+
</div>
45+
<div class="bg-black text-green-400 p-4 rounded-lg font-mono text-sm h-96 overflow-y-auto">
46+
<div v-for="(line, index) in output" :key="index">
47+
{{ line }}
48+
</div>
49+
<div class="flex items-center">
50+
<span>root@{{ item.id }}:/# </span>
51+
<input
52+
v-model="command"
53+
class="bg-transparent outline-none flex-1 ml-1"
54+
type="text"
55+
@keyup.enter="executeCommand"
56+
>
57+
</div>
58+
</div>
59+
</div>
60+
</template>

web/components/Docker/Edit.vue

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
import { UButton, UCard, UInput, USelectMenu, UIcon, UFormField } from '#components';
4+
5+
interface Props {
6+
item: {
7+
id: string;
8+
label: string;
9+
icon?: string;
10+
badge?: string | number;
11+
};
12+
}
13+
14+
const props = defineProps<Props>();
15+
16+
const config = ref({
17+
name: props.item.label,
18+
image: 'ghcr.io/imagegenius/immich:latest',
19+
network: 'bridge',
20+
restartPolicy: 'unless-stopped',
21+
cpuLimit: '',
22+
memoryLimit: '',
23+
ports: [{ container: '7878', host: '7878', protocol: 'tcp' }],
24+
volumes: [
25+
{ container: '/config', host: '/mnt/user/appdata/immich' },
26+
{ container: '/media', host: '/mnt/user/media' },
27+
],
28+
environment: [
29+
{ key: 'PUID', value: '99' },
30+
{ key: 'PGID', value: '100' },
31+
],
32+
});
33+
</script>
34+
35+
<template>
36+
<div class="space-y-6">
37+
<div class="flex justify-between items-center">
38+
<h3 class="text-lg font-medium">Container Configuration</h3>
39+
<div class="flex gap-2">
40+
<UButton color="primary" variant="outline">Cancel</UButton>
41+
<UButton color="primary">Save Changes</UButton>
42+
</div>
43+
</div>
44+
45+
<UCard>
46+
<template #header>
47+
<h4 class="font-medium">Basic Settings</h4>
48+
</template>
49+
<div class="space-y-4">
50+
<UFormField label="Container Name">
51+
<UInput v-model="config.name" />
52+
</UFormField>
53+
<UFormField label="Image">
54+
<UInput v-model="config.image" />
55+
</UFormField>
56+
<UFormField label="Network Mode">
57+
<USelectMenu v-model="config.network" :options="['bridge', 'host', 'none', 'custom']" />
58+
</UFormField>
59+
<UFormField label="Restart Policy">
60+
<USelectMenu
61+
v-model="config.restartPolicy"
62+
:options="['no', 'always', 'unless-stopped', 'on-failure']"
63+
/>
64+
</UFormField>
65+
</div>
66+
</UCard>
67+
68+
<UCard>
69+
<template #header>
70+
<h4 class="font-medium">Resource Limits</h4>
71+
</template>
72+
<div class="grid grid-cols-2 gap-4">
73+
<UFormField label="CPU Limit">
74+
<UInput v-model="config.cpuLimit" placeholder="e.g., 0.5 or 2" />
75+
</UFormField>
76+
<UFormField label="Memory Limit">
77+
<UInput v-model="config.memoryLimit" placeholder="e.g., 512m or 2g" />
78+
</UFormField>
79+
</div>
80+
</UCard>
81+
82+
<UCard>
83+
<template #header>
84+
<h4 class="font-medium">Port Mappings</h4>
85+
</template>
86+
<div class="space-y-2">
87+
<div v-for="(port, index) in config.ports" :key="index" class="flex gap-2 items-center">
88+
<UInput v-model="port.host" placeholder="Host Port" class="flex-1" />
89+
<UIcon name="i-lucide-arrow-right" class="text-gray-400" />
90+
<UInput v-model="port.container" placeholder="Container Port" class="flex-1" />
91+
<USelectMenu v-model="port.protocol" :options="['tcp', 'udp']" class="w-24" />
92+
<UButton icon="i-lucide-trash-2" color="primary" variant="ghost" size="sm" />
93+
</div>
94+
<UButton icon="i-lucide-plus" size="sm" variant="outline">Add Port</UButton>
95+
</div>
96+
</UCard>
97+
98+
<UCard>
99+
<template #header>
100+
<h4 class="font-medium">Volume Mappings</h4>
101+
</template>
102+
<div class="space-y-2">
103+
<div v-for="(volume, index) in config.volumes" :key="index" class="flex gap-2 items-center">
104+
<UInput v-model="volume.host" placeholder="Host Path" class="flex-1" />
105+
<UIcon name="i-lucide-arrow-right" class="text-gray-400" />
106+
<UInput v-model="volume.container" placeholder="Container Path" class="flex-1" />
107+
<UButton icon="i-lucide-trash-2" color="primary" variant="ghost" size="sm" />
108+
</div>
109+
<UButton icon="i-lucide-plus" size="sm" variant="outline">Add Volume</UButton>
110+
</div>
111+
</UCard>
112+
113+
<UCard>
114+
<template #header>
115+
<h4 class="font-medium">Environment Variables</h4>
116+
</template>
117+
<div class="space-y-2">
118+
<div v-for="(env, index) in config.environment" :key="index" class="flex gap-2 items-center">
119+
<UInput v-model="env.key" placeholder="Variable Name" class="flex-1" />
120+
<UInput v-model="env.value" placeholder="Value" class="flex-1" />
121+
<UButton icon="i-lucide-trash-2" color="primary" variant="ghost" size="sm" />
122+
</div>
123+
<UButton icon="i-lucide-plus" size="sm" variant="outline">Add Variable</UButton>
124+
</div>
125+
</UCard>
126+
</div>
127+
</template>

web/components/Docker/Logs.vue

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script setup lang="ts">
2+
import { UButton } from '#components';
3+
4+
interface Props {
5+
item: {
6+
id: string;
7+
label: string;
8+
icon?: string;
9+
badge?: string | number;
10+
};
11+
}
12+
13+
const props = defineProps<Props>();
14+
15+
const sampleLogs = [
16+
{ timestamp: '2024-01-22 10:15:23', message: `Starting ${props.item.label}...` },
17+
{ timestamp: '2024-01-22 10:15:24', message: 'Container initialized successfully' },
18+
{ timestamp: '2024-01-22 10:15:25', message: 'Listening on configured port' },
19+
{ timestamp: '2024-01-22 10:15:26', message: 'Health check passed' },
20+
{ timestamp: '2024-01-22 10:15:27', message: 'Ready to accept connections' },
21+
];
22+
</script>
23+
24+
<template>
25+
<div class="space-y-2">
26+
<div class="flex justify-between items-center mb-4">
27+
<h3 class="text-lg font-medium">Container Logs</h3>
28+
<UButton size="sm" color="primary" variant="outline" icon="i-lucide-download"> Export </UButton>
29+
</div>
30+
<div class="bg-gray-900 text-gray-100 p-4 rounded-lg font-mono text-sm overflow-x-auto">
31+
<div v-for="(log, index) in sampleLogs" :key="index" class="whitespace-nowrap">
32+
<span class="text-gray-500">[{{ log.timestamp }}]</span> {{ log.message }}
33+
</div>
34+
</div>
35+
</div>
36+
</template>

web/components/Docker/Overview.vue

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<script setup lang="ts">
2+
interface ContainerDetails {
3+
network: string;
4+
lanIpPort: string;
5+
containerIp: string;
6+
uptime: string;
7+
containerPort: string;
8+
creationDate: string;
9+
containerId: string;
10+
maintainer: string;
11+
}
12+
13+
interface Props {
14+
item: {
15+
id: string;
16+
label: string;
17+
icon?: string;
18+
badge?: string | number;
19+
};
20+
details?: ContainerDetails;
21+
}
22+
23+
defineProps<Props>();
24+
</script>
25+
26+
<template>
27+
<div v-if="details" class="space-y-4">
28+
<div class="grid grid-cols-2 gap-4">
29+
<div>
30+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Network:</p>
31+
<p class="mt-1">{{ details.network }}</p>
32+
</div>
33+
<div>
34+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">LAN IP:Port</p>
35+
<p class="mt-1">{{ details.lanIpPort }}</p>
36+
</div>
37+
<div>
38+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Container IP:</p>
39+
<p class="mt-1">{{ details.containerIp }}</p>
40+
</div>
41+
<div>
42+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Uptime:</p>
43+
<p class="mt-1">{{ details.uptime }}</p>
44+
</div>
45+
<div>
46+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Container Port:</p>
47+
<p class="mt-1">{{ details.containerPort }}</p>
48+
</div>
49+
<div>
50+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Creation Date:</p>
51+
<p class="mt-1">{{ details.creationDate }}</p>
52+
</div>
53+
<div>
54+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Container Id:</p>
55+
<p class="mt-1 font-mono text-sm">{{ details.containerId }}</p>
56+
</div>
57+
<div>
58+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Maintainer:</p>
59+
<p class="mt-1 text-sm">{{ details.maintainer }}</p>
60+
</div>
61+
</div>
62+
</div>
63+
<div v-else class="text-gray-500 dark:text-gray-400">
64+
No details available for {{ item.label }}
65+
</div>
66+
</template>

web/components/Docker/Preview.vue

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script setup lang="ts">
2+
import { UButton, UIcon } from '#components';
3+
4+
interface Props {
5+
item: {
6+
id: string;
7+
label: string;
8+
icon?: string;
9+
badge?: string | number;
10+
};
11+
port?: string;
12+
}
13+
14+
const props = defineProps<Props>();
15+
const previewUrl = props.port ? `http://localhost:${props.port}` : null;
16+
</script>
17+
18+
<template>
19+
<div class="space-y-4">
20+
<div class="flex justify-between items-center">
21+
<h3 class="text-lg font-medium">Web Preview</h3>
22+
<div class="flex gap-2">
23+
<UButton
24+
v-if="previewUrl"
25+
size="sm"
26+
color="primary"
27+
variant="outline"
28+
icon="i-lucide-external-link"
29+
:to="previewUrl"
30+
target="_blank"
31+
>
32+
Open in new tab
33+
</UButton>
34+
<UButton size="sm" color="primary" variant="outline" icon="i-lucide-refresh-cw"> Refresh </UButton>
35+
</div>
36+
</div>
37+
<div class="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
38+
<div v-if="previewUrl" class="bg-gray-100 dark:bg-gray-800 px-4 py-2 flex items-center gap-2">
39+
<UIcon name="i-lucide-lock" class="w-4 h-4 text-gray-500" />
40+
<span class="text-sm text-gray-600 dark:text-gray-400">{{ previewUrl }}</span>
41+
</div>
42+
<div class="p-8 text-center h-96 flex items-center justify-center">
43+
<div v-if="previewUrl" class="text-gray-500 dark:text-gray-400">
44+
<UIcon name="i-lucide-globe" class="w-16 h-16 mx-auto mb-4" />
45+
<p>Web interface preview for {{ item.label }}</p>
46+
<p class="text-sm mt-2">Container must be running and accessible on port {{ port }}</p>
47+
</div>
48+
<div v-else class="text-gray-500 dark:text-gray-400">
49+
<UIcon name="i-lucide-alert-circle" class="w-16 h-16 mx-auto mb-4" />
50+
<p>No web interface available for {{ item.label }}</p>
51+
<p class="text-sm mt-2">This container does not expose a web interface</p>
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
</template>

0 commit comments

Comments
 (0)