feat(lite): dynamic page title (#6853)
See #6793 ℹ️ This PR adds a `pageTitleStore` which allows defining the current page title according to 3 parts: an object, a string, and a count. Each part is optional. ⚡ The page title is **reactive** when function argument is a `Ref`, a `Computed` or a getter. For example, when updating a VM name, the page title will be updated in every tabs. 🪄 Each title part is automatically unset when the component that set it is unmounted.
This commit is contained in:
committed by
GitHub
parent
3b1bcc67ae
commit
20d04ba956
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
<title>XO Lite</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -41,8 +41,6 @@ if (link == null) {
|
||||
}
|
||||
link.href = favicon;
|
||||
|
||||
document.title = "XO Lite";
|
||||
|
||||
const xenApiStore = useXenApiStore();
|
||||
const { pool } = usePoolStore().subscribe();
|
||||
useChartTheme();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
@@ -33,6 +34,7 @@ import UiButton from "@/components/ui/UiButton.vue";
|
||||
import { useXenApiStore } from "@/stores/xen-api.store";
|
||||
|
||||
const { t } = useI18n();
|
||||
usePageTitleStore().setTitle(t("login"));
|
||||
const xenApiStore = useXenApiStore();
|
||||
const { isConnecting } = storeToRefs(xenApiStore);
|
||||
const login = ref("root");
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"news": "News",
|
||||
"news-name": "{name} news",
|
||||
"new-features-are-coming": "New features are coming soon!",
|
||||
"not-found": "Not found",
|
||||
"object": "Object",
|
||||
"object-not-found": "Object {id} can't be found…",
|
||||
"or": "Or",
|
||||
@@ -127,7 +128,6 @@
|
||||
"system": "System",
|
||||
"task": {
|
||||
"estimated-end": "Estimated end",
|
||||
"page-title": "Tasks | (1) Tasks | ({n}) Tasks",
|
||||
"progress": "Progress",
|
||||
"started": "Started"
|
||||
},
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"news": "Actualités",
|
||||
"news-name": "Actualités {name}",
|
||||
"new-features-are-coming": "De nouvelles fonctionnalités arrivent bientôt !",
|
||||
"not-found": "Non trouvé",
|
||||
"object": "Objet",
|
||||
"object-not-found": "L'objet {id} est introuvable…",
|
||||
"or": "Ou",
|
||||
@@ -127,7 +128,6 @@
|
||||
"system": "Système",
|
||||
"task": {
|
||||
"estimated-end": "Fin estimée",
|
||||
"page-title": "Tâches | (1) Tâches | ({n}) Tâches",
|
||||
"progress": "Progression",
|
||||
"started": "Démarré"
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@ const router = createRouter({
|
||||
},
|
||||
{
|
||||
path: "/:pathMatch(.*)*",
|
||||
name: "notFound",
|
||||
name: "not-found",
|
||||
component: () => import("@/views/PageNotFoundView.vue"),
|
||||
},
|
||||
],
|
||||
|
||||
92
@xen-orchestra/lite/src/stores/page-title.store.ts
Normal file
92
@xen-orchestra/lite/src/stores/page-title.store.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { useTitle } from "@vueuse/core";
|
||||
import { defineStore } from "pinia";
|
||||
import {
|
||||
computed,
|
||||
type MaybeRefOrGetter,
|
||||
onBeforeUnmount,
|
||||
reactive,
|
||||
toRef,
|
||||
watch,
|
||||
} from "vue";
|
||||
|
||||
const PAGE_TITLE_SUFFIX = "XO Lite";
|
||||
|
||||
interface PageTitleConfig {
|
||||
object: { name_label: string } | undefined;
|
||||
title: string | undefined;
|
||||
count: number | undefined;
|
||||
}
|
||||
|
||||
export const usePageTitleStore = defineStore("page-title", () => {
|
||||
const pageTitleConfig = reactive<PageTitleConfig>({
|
||||
count: undefined,
|
||||
title: undefined,
|
||||
object: undefined,
|
||||
});
|
||||
|
||||
const generatedPageTitle = computed(() => {
|
||||
const { object, title, count } = pageTitleConfig;
|
||||
const parts = [];
|
||||
|
||||
if (count !== undefined && count > 0) {
|
||||
parts.push(`(${count})`);
|
||||
}
|
||||
|
||||
if (title !== undefined && object !== undefined) {
|
||||
parts.push(`${title} - ${object.name_label}`);
|
||||
} else if (title !== undefined) {
|
||||
parts.push(title);
|
||||
} else if (object !== undefined) {
|
||||
parts.push(object.name_label);
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return parts.join(" ");
|
||||
});
|
||||
|
||||
useTitle(generatedPageTitle, {
|
||||
titleTemplate: computed(() =>
|
||||
generatedPageTitle.value === undefined
|
||||
? PAGE_TITLE_SUFFIX
|
||||
: `%s - ${PAGE_TITLE_SUFFIX}`
|
||||
),
|
||||
});
|
||||
|
||||
const setPageTitleConfig = <T extends keyof PageTitleConfig>(
|
||||
configKey: T,
|
||||
value: MaybeRefOrGetter<PageTitleConfig[T]>
|
||||
) => {
|
||||
const stop = watch(
|
||||
toRef(value),
|
||||
(newValue) =>
|
||||
(pageTitleConfig[configKey] = newValue as PageTitleConfig[T]),
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop();
|
||||
pageTitleConfig[configKey] = undefined;
|
||||
});
|
||||
};
|
||||
|
||||
const setObject = (
|
||||
object: MaybeRefOrGetter<{ name_label: string } | undefined>
|
||||
) => setPageTitleConfig("object", object);
|
||||
|
||||
const setTitle = (title: MaybeRefOrGetter<string | undefined>) =>
|
||||
setPageTitleConfig("title", title);
|
||||
|
||||
const setCount = (count: MaybeRefOrGetter<number | undefined>) =>
|
||||
setPageTitleConfig("count", count);
|
||||
|
||||
return {
|
||||
setObject,
|
||||
setTitle,
|
||||
setCount,
|
||||
};
|
||||
});
|
||||
@@ -9,6 +9,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
import UiButton from "@/components/ui/UiButton.vue";
|
||||
|
||||
@@ -16,6 +18,8 @@ defineProps<{
|
||||
id: string;
|
||||
}>();
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("not-found"));
|
||||
|
||||
const router = useRouter();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import UiButton from "@/components/ui/UiButton.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
usePageTitleStore().setTitle(useI18n().t("not-found"));
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { faBook } from "@fortawesome/free-solid-svg-icons";
|
||||
@@ -20,6 +21,8 @@ const title = computed(() => {
|
||||
|
||||
return `${currentRoute.value.meta.storyTitle} Story`;
|
||||
});
|
||||
|
||||
usePageTitleStore().setTitle(title);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped></style>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("dashboard"));
|
||||
</script>
|
||||
|
||||
@@ -8,17 +8,22 @@
|
||||
import ObjectNotFoundWrapper from "@/components/ObjectNotFoundWrapper.vue";
|
||||
import type { XenApiHost } from "@/libs/xen-api";
|
||||
import { useHostStore } from "@/stores/host.store";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useUiStore } from "@/stores/ui.store";
|
||||
import { watchEffect } from "vue";
|
||||
import { computed, watchEffect } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const { hasUuid, isReady, getByUuid } = useHostStore().subscribe();
|
||||
const route = useRoute();
|
||||
const uiStore = useUiStore();
|
||||
|
||||
const currentHost = computed(() =>
|
||||
getByUuid(route.params.uuid as XenApiHost["uuid"])
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
uiStore.currentHostOpaqueRef = getByUuid(
|
||||
route.params.uuid as XenApiHost["uuid"]
|
||||
)?.$ref;
|
||||
uiStore.currentHostOpaqueRef = currentHost.value?.$ref;
|
||||
});
|
||||
|
||||
usePageTitleStore().setObject(currentHost);
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("alarms"));
|
||||
</script>
|
||||
|
||||
@@ -31,8 +31,23 @@ export const N_ITEMS = 5;
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PoolCpuUsageChart from "@/components/pool/dashboard/cpuUsage/PoolCpuUsageChart.vue";
|
||||
import PoolDashboardCpuProvisioning from "@/components/pool/dashboard/PoolDashboardCpuProvisioning.vue";
|
||||
import PoolDashboardCpuUsage from "@/components/pool/dashboard/PoolDashboardCpuUsage.vue";
|
||||
import PoolDashboardNetworkChart from "@/components/pool/dashboard/PoolDashboardNetworkChart.vue";
|
||||
import PoolDashboardRamUsage from "@/components/pool/dashboard/PoolDashboardRamUsage.vue";
|
||||
import PoolDashboardStatus from "@/components/pool/dashboard/PoolDashboardStatus.vue";
|
||||
import PoolDashboardStorageUsage from "@/components/pool/dashboard/PoolDashboardStorageUsage.vue";
|
||||
import PoolDashboardRamUsageChart from "@/components/pool/dashboard/ramUsage/PoolRamUsage.vue";
|
||||
import UiCardComingSoon from "@/components/ui/UiCardComingSoon.vue";
|
||||
import UiCardGroup from "@/components/ui/UiCardGroup.vue";
|
||||
import useFetchStats from "@/composables/fetch-stats.composable";
|
||||
import { GRANULARITY, type HostStats, type VmStats } from "@/libs/xapi-stats";
|
||||
import type { XenApiHost, XenApiVm } from "@/libs/xen-api";
|
||||
import { useHostMetricsStore } from "@/stores/host-metrics.store";
|
||||
import { useHostStore } from "@/stores/host.store";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import {
|
||||
IK_HOST_LAST_WEEK_STATS,
|
||||
IK_HOST_STATS,
|
||||
@@ -40,20 +55,9 @@ import {
|
||||
} from "@/types/injection-keys";
|
||||
import { differenceBy } from "lodash-es";
|
||||
import { provide, watch } from "vue";
|
||||
import UiCardComingSoon from "@/components/ui/UiCardComingSoon.vue";
|
||||
import PoolCpuUsageChart from "@/components/pool/dashboard/cpuUsage/PoolCpuUsageChart.vue";
|
||||
import PoolDashboardCpuUsage from "@/components/pool/dashboard/PoolDashboardCpuUsage.vue";
|
||||
import PoolDashboardNetworkChart from "@/components/pool/dashboard/PoolDashboardNetworkChart.vue";
|
||||
import PoolDashboardCpuProvisioning from "@/components/pool/dashboard/PoolDashboardCpuProvisioning.vue";
|
||||
import PoolDashboardRamUsage from "@/components/pool/dashboard/PoolDashboardRamUsage.vue";
|
||||
import PoolDashboardRamUsageChart from "@/components/pool/dashboard/ramUsage/PoolRamUsage.vue";
|
||||
import PoolDashboardStatus from "@/components/pool/dashboard/PoolDashboardStatus.vue";
|
||||
import PoolDashboardStorageUsage from "@/components/pool/dashboard/PoolDashboardStorageUsage.vue";
|
||||
import useFetchStats from "@/composables/fetch-stats.composable";
|
||||
import { GRANULARITY, type HostStats, type VmStats } from "@/libs/xapi-stats";
|
||||
import type { XenApiHost, XenApiVm } from "@/libs/xen-api";
|
||||
import { useHostStore } from "@/stores/host.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("dashboard"));
|
||||
|
||||
const hostMetricsSubscription = useHostMetricsStore().subscribe();
|
||||
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("hosts"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("network"));
|
||||
</script>
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
<script lang="ts" setup>
|
||||
import PoolHeader from "@/components/pool/PoolHeader.vue";
|
||||
import PoolTabBar from "@/components/pool/PoolTabBar.vue";
|
||||
import { usePoolStore } from "@/stores/pool.store";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
|
||||
const { pool } = usePoolStore().subscribe();
|
||||
usePageTitleStore().setObject(pool);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped></style>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("stats"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("storage"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("system"));
|
||||
</script>
|
||||
|
||||
@@ -21,8 +21,7 @@ import useFilteredCollection from "@/composables/filtered-collection.composable"
|
||||
import useSortedCollection from "@/composables/sorted-collection.composable";
|
||||
import type { XenApiTask } from "@/libs/xen-api";
|
||||
import { useTaskStore } from "@/stores/task.store";
|
||||
import { useTitle } from "@vueuse/core";
|
||||
import { computed } from "vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { records, hasError } = useTaskStore().subscribe();
|
||||
@@ -53,9 +52,9 @@ const finishedTasks = useArrayRemovedItemsHistory(
|
||||
}
|
||||
);
|
||||
|
||||
useTitle(
|
||||
computed(() => t("task.page-title", { n: pendingTasks.value.length }))
|
||||
);
|
||||
const titleStore = usePageTitleStore();
|
||||
titleStore.setTitle(t("tasks"));
|
||||
titleStore.setCount(() => pendingTasks.value.length);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
|
||||
@@ -38,6 +38,7 @@ import UiCard from "@/components/ui/UiCard.vue";
|
||||
import UiCardTitle from "@/components/ui/UiCardTitle.vue";
|
||||
import VmsActionsBar from "@/components/vm/VmsActionsBar.vue";
|
||||
import { POWER_STATE } from "@/libs/xen-api";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useUiStore } from "@/stores/ui.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import type { Filters } from "@/types/filter";
|
||||
@@ -46,9 +47,13 @@ import { storeToRefs } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const titleStore = usePageTitleStore();
|
||||
titleStore.setTitle(t("vms"));
|
||||
|
||||
const { records: vms } = useVmStore().subscribe();
|
||||
const { isMobile, isDesktop } = storeToRefs(useUiStore());
|
||||
const { t } = useI18n();
|
||||
|
||||
const filters: Filters = {
|
||||
name_label: { label: t("name"), type: "string" },
|
||||
@@ -62,6 +67,8 @@ const filters: Filters = {
|
||||
};
|
||||
|
||||
const selectedVmsRefs = ref([]);
|
||||
|
||||
titleStore.setCount(() => selectedVmsRefs.value.length);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { computed } from "vue";
|
||||
import UiCardTitle from "@/components/ui/UiCardTitle.vue";
|
||||
import UiIcon from "@/components/ui/icon/UiIcon.vue";
|
||||
@@ -181,7 +182,9 @@ import UiKeyValueRow from "@/components/ui/UiKeyValueRow.vue";
|
||||
|
||||
const xoLiteVersion = XO_LITE_VERSION;
|
||||
const xoLiteGitHead = XO_LITE_GIT_HEAD;
|
||||
const { locale } = useI18n();
|
||||
const { t, locale } = useI18n();
|
||||
|
||||
usePageTitleStore().setTitle(() => t("settings"));
|
||||
|
||||
const { pool } = usePoolStore().subscribe();
|
||||
const { getByOpaqueRef: getHost } = useHostStore().subscribe();
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("alarms"));
|
||||
</script>
|
||||
|
||||
@@ -3,19 +3,21 @@
|
||||
<div v-else-if="!isVmRunning">Console is only available for running VMs.</div>
|
||||
<RemoteConsole
|
||||
v-else-if="vm && vmConsole"
|
||||
:location="vmConsole.location"
|
||||
:is-console-available="!isOperationsPending(vm, STOP_OPERATIONS)"
|
||||
:location="vmConsole.location"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { POWER_STATE, VM_OPERATION, type XenApiVm } from "@/libs/xen-api";
|
||||
import { computed } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import RemoteConsole from "@/components/RemoteConsole.vue";
|
||||
import { useConsoleStore } from "@/stores/console.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import { isOperationsPending } from "@/libs/utils";
|
||||
import { POWER_STATE, VM_OPERATION, type XenApiVm } from "@/libs/xen-api";
|
||||
import { useConsoleStore } from "@/stores/console.store";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const STOP_OPERATIONS = [
|
||||
VM_OPERATION.SHUTDOWN,
|
||||
@@ -27,6 +29,8 @@ const STOP_OPERATIONS = [
|
||||
VM_OPERATION.SUSPEND,
|
||||
];
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("console"));
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const { isReady: isVmReady, getByUuid: getVmByUuid } = useVmStore().subscribe();
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("dashboard"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("network"));
|
||||
</script>
|
||||
|
||||
@@ -11,6 +11,7 @@ import ObjectNotFoundWrapper from "@/components/ObjectNotFoundWrapper.vue";
|
||||
import VmHeader from "@/components/vm/VmHeader.vue";
|
||||
import VmTabBar from "@/components/vm/VmTabBar.vue";
|
||||
import type { XenApiVm } from "@/libs/xen-api";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useUiStore } from "@/stores/ui.store";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import { whenever } from "@vueuse/core";
|
||||
@@ -22,4 +23,5 @@ const { getByUuid, hasUuid, isReady } = useVmStore().subscribe();
|
||||
const uiStore = useUiStore();
|
||||
const vm = computed(() => getByUuid(route.params.uuid as XenApiVm["uuid"]));
|
||||
whenever(vm, (vm) => (uiStore.currentHostOpaqueRef = vm.resident_on));
|
||||
usePageTitleStore().setObject(vm);
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("stats"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("storage"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("system"));
|
||||
</script>
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PageUnderConstruction from "@/components/PageUnderConstruction.vue";
|
||||
import { usePageTitleStore } from "@/stores/page-title.store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
usePageTitleStore().setTitle(useI18n().t("tasks"));
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user