mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 13:23:07 +01:00
feat: updates home dashboard to support mobile view (#2334)
* feat: updates home dashboard to support mobile view * updates created translation * adds ellipses
This commit is contained in:
@@ -4,14 +4,15 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
||||||
<th
|
<th
|
||||||
v-for="(label, field) in headers"
|
v-for="(value, key) in fields"
|
||||||
:key="field"
|
:key="key"
|
||||||
@click.prevent="sort(field)"
|
@click.prevent="sort(key)"
|
||||||
:class="{ 'selected-sort': field === sortField }"
|
:class="{ 'selected-sort': key === sortField }"
|
||||||
|
v-show="isVisible(key)"
|
||||||
>
|
>
|
||||||
<a>
|
<a>
|
||||||
<span class="icon-text">
|
<span class="icon-text">
|
||||||
<span>{{ $t(label) }}</span>
|
<span>{{ $t(value.label) }}</span>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<mdi:arrow-up />
|
<mdi:arrow-up />
|
||||||
</span>
|
</span>
|
||||||
@@ -22,17 +23,19 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="container in paginated" :key="container.id">
|
<tr v-for="container in paginated" :key="container.id">
|
||||||
<td>
|
<td v-if="isVisible('name')">
|
||||||
<router-link :to="{ name: 'container-id', params: { id: container.id } }" :title="container.name">
|
<router-link :to="{ name: 'container-id', params: { id: container.id } }" :title="container.name">
|
||||||
{{ container.name }}
|
{{ container.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ container.state }}</td>
|
<td v-if="isVisible('state')">{{ container.state }}</td>
|
||||||
<td><distance-time :date="container.created" strict :suffix="false"></distance-time></td>
|
<td v-if="isVisible('created')">
|
||||||
<td>
|
<distance-time :date="container.created" strict :suffix="false"></distance-time>
|
||||||
|
</td>
|
||||||
|
<td v-if="isVisible('cpu')">
|
||||||
{{ (container.movingAverage.cpu / 100).toLocaleString(undefined, { style: "percent" }) }}
|
{{ (container.movingAverage.cpu / 100).toLocaleString(undefined, { style: "percent" }) }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td v-if="isVisible('mem')">
|
||||||
{{ (container.movingAverage.memory / 100).toLocaleString(undefined, { style: "percent" }) }}
|
{{ (container.movingAverage.memory / 100).toLocaleString(undefined, { style: "percent" }) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -50,41 +53,55 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const headers = {
|
const fields = {
|
||||||
name: "label.container-name",
|
name: {
|
||||||
state: "label.status",
|
label: "label.container-name",
|
||||||
created: "label.last-started",
|
sortFunc: (a: Container, b: Container) => a.name.localeCompare(b.name) * direction.value,
|
||||||
cpu: "label.avg-cpu",
|
mobileVisible: true,
|
||||||
mem: "label.avg-mem",
|
},
|
||||||
|
state: {
|
||||||
|
label: "label.status",
|
||||||
|
sortFunc: (a: Container, b: Container) => a.state.localeCompare(b.state) * direction.value,
|
||||||
|
mobileVisible: false,
|
||||||
|
},
|
||||||
|
created: {
|
||||||
|
label: "label.created",
|
||||||
|
sortFunc: (a: Container, b: Container) => (a.created.getTime() - b.created.getTime()) * direction.value,
|
||||||
|
mobileVisible: true,
|
||||||
|
},
|
||||||
|
cpu: {
|
||||||
|
label: "label.avg-cpu",
|
||||||
|
sortFunc: (a: Container, b: Container) => (a.movingAverage.cpu - b.movingAverage.cpu) * direction.value,
|
||||||
|
mobileVisible: false,
|
||||||
|
},
|
||||||
|
mem: {
|
||||||
|
label: "label.avg-mem",
|
||||||
|
sortFunc: (a: Container, b: Container) => (a.movingAverage.memory - b.movingAverage.memory) * direction.value,
|
||||||
|
mobileVisible: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
type Container = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
state: string;
|
||||||
|
created: Date;
|
||||||
|
movingAverage: {
|
||||||
|
cpu: number;
|
||||||
|
memory: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const { containers, perPage = 15 } = defineProps<{
|
const { containers, perPage = 15 } = defineProps<{
|
||||||
containers: {
|
containers: Container[];
|
||||||
movingAverage: { cpu: number; memory: number };
|
|
||||||
created: Date;
|
|
||||||
state: string;
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
}[];
|
|
||||||
perPage?: number;
|
perPage?: number;
|
||||||
}>();
|
}>();
|
||||||
const sortField: Ref<keyof typeof headers> = ref("created");
|
const sortField: Ref<keyof typeof fields> = ref("created");
|
||||||
const direction = ref<1 | -1>(-1);
|
const direction = ref<1 | -1>(-1);
|
||||||
const sortedContainers = computedWithControl(
|
const sortedContainers = computedWithControl(
|
||||||
() => [containers.length, sortField.value, direction.value],
|
() => [containers.length, sortField.value, direction.value],
|
||||||
() => {
|
() => {
|
||||||
return containers.sort((a, b) => {
|
return containers.sort((a, b) => {
|
||||||
switch (sortField.value) {
|
return fields[sortField.value].sortFunc(a, b);
|
||||||
case "name":
|
|
||||||
return a.name.localeCompare(b.name) * direction.value;
|
|
||||||
case "state":
|
|
||||||
return a.state.localeCompare(b.state) * direction.value;
|
|
||||||
case "created":
|
|
||||||
return (a.created.getTime() - b.created.getTime()) * direction.value;
|
|
||||||
case "cpu":
|
|
||||||
return (a.movingAverage.cpu - b.movingAverage.cpu) * direction.value;
|
|
||||||
case "mem":
|
|
||||||
return (a.movingAverage.memory - b.movingAverage.memory) * direction.value;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -99,7 +116,7 @@ const paginated = computed(() => {
|
|||||||
return sortedContainers.value.slice(start, end);
|
return sortedContainers.value.slice(start, end);
|
||||||
});
|
});
|
||||||
|
|
||||||
function sort(field: keyof typeof headers) {
|
function sort(field: keyof typeof fields) {
|
||||||
if (sortField.value === field) {
|
if (sortField.value === field) {
|
||||||
direction.value *= -1;
|
direction.value *= -1;
|
||||||
} else {
|
} else {
|
||||||
@@ -107,6 +124,9 @@ function sort(field: keyof typeof headers) {
|
|||||||
direction.value = 1;
|
direction.value = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function isVisible(field: keyof typeof fields) {
|
||||||
|
return fields[field].mobileVisible || !isMobile.value;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -124,4 +144,11 @@ function sort(field: keyof typeof headers) {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tbody td {
|
||||||
|
max-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: Benutzername
|
username: Benutzername
|
||||||
container-name: Container Name
|
container-name: Container Name
|
||||||
status: Status
|
status: Status
|
||||||
last-started: Zuletzt gestartet
|
created: Erstellt
|
||||||
avg-cpu: Avg CPU (%)
|
avg-cpu: Avg CPU (%)
|
||||||
avg-mem: Avg MEM (%)
|
avg-mem: Avg MEM (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: Username
|
username: Username
|
||||||
container-name: Container Name
|
container-name: Container Name
|
||||||
status: Status
|
status: Status
|
||||||
last-started: Last started
|
created: Created
|
||||||
avg-cpu: Avg. CPU (%)
|
avg-cpu: Avg. CPU (%)
|
||||||
avg-mem: Avg. MEM (%)
|
avg-mem: Avg. MEM (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: Nombre de usuario
|
username: Nombre de usuario
|
||||||
container-name: Nombre del contenedor
|
container-name: Nombre del contenedor
|
||||||
status: Estado
|
status: Estado
|
||||||
last-started: Último inicio
|
created: Creado
|
||||||
avg-cpu: Promedio de CPU (%)
|
avg-cpu: Promedio de CPU (%)
|
||||||
avg-mem: Promedio de MEM (%)
|
avg-mem: Promedio de MEM (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: Nome de usuário
|
username: Nome de usuário
|
||||||
container-name: Nome do contentor
|
container-name: Nome do contentor
|
||||||
status: Estado
|
status: Estado
|
||||||
last-started: Última iniciada
|
created: Criado
|
||||||
avg-cpu: Média de CPU (%)
|
avg-cpu: Média de CPU (%)
|
||||||
avg-mem: Média de MEM (%)
|
avg-mem: Média de MEM (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: Имя пользователя
|
username: Имя пользователя
|
||||||
container-name: Имя контейнера
|
container-name: Имя контейнера
|
||||||
status: Статус
|
status: Статус
|
||||||
last-started: Последний запуск
|
created: Создан
|
||||||
avg-cpu: средний процессор (%)
|
avg-cpu: средний процессор (%)
|
||||||
avg-mem: средняя память (%)
|
avg-mem: средняя память (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ label:
|
|||||||
username: 用户名
|
username: 用户名
|
||||||
container-name: 容器名称
|
container-name: 容器名称
|
||||||
status: 状态
|
status: 状态
|
||||||
last-started: 最后启动
|
created: 创建时间
|
||||||
avg-cpu: 平均CPU (%)
|
avg-cpu: 平均CPU (%)
|
||||||
avg-mem: 平均MEM (%)
|
avg-mem: 平均MEM (%)
|
||||||
tooltip:
|
tooltip:
|
||||||
|
|||||||
Reference in New Issue
Block a user