mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-07-18 05:30:18 -04:00
feat: Added sitewide statistics (#7322)
This commit is contained in:
committed by
GitHub
parent
16a0ba2e21
commit
31187b1a74
@@ -940,7 +940,10 @@
|
|||||||
"openai-ready": "OpenAI Ready",
|
"openai-ready": "OpenAI Ready",
|
||||||
"openai-not-ready": "OpenAI Not Ready",
|
"openai-not-ready": "OpenAI Not Ready",
|
||||||
"openai-ready-error-text": "Not all OpenAI Values are configured. This can be ignored if you are not using OpenAI features.",
|
"openai-ready-error-text": "Not all OpenAI Values are configured. This can be ignored if you are not using OpenAI features.",
|
||||||
"openai-ready-success-text": "Required OpenAI variables are all set."
|
"openai-ready-success-text": "Required OpenAI variables are all set.",
|
||||||
|
"site-statistics": "Site Statistics",
|
||||||
|
"uncategorized-recipes": "Uncategorized Recipes",
|
||||||
|
"untagged-recipes": "Untagged Recipes"
|
||||||
},
|
},
|
||||||
"shopping-list": {
|
"shopping-list": {
|
||||||
"all-lists": "All Lists",
|
"all-lists": "All Lists",
|
||||||
|
|||||||
@@ -157,6 +157,34 @@
|
|||||||
</v-alert>
|
</v-alert>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Site Statistics -->
|
||||||
|
<section>
|
||||||
|
<BaseCardSectionTitle
|
||||||
|
class="pt-2"
|
||||||
|
:icon="$globals.icons.chart"
|
||||||
|
:title="$t('settings.site-statistics')"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="d-flex flex-wrap justify-center align-center"
|
||||||
|
style="gap: 0.8rem"
|
||||||
|
>
|
||||||
|
<StatsCards
|
||||||
|
v-for="(value, key) in adminStats"
|
||||||
|
:key="`${key}-${value}`"
|
||||||
|
:min-width="$vuetify.display.xs ? '100%' : '158'"
|
||||||
|
:icon="getAdminStatsIcon(key)"
|
||||||
|
:to="getAdminStatsTo(key)"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ getAdminStatsTitle(key) }}
|
||||||
|
</template>
|
||||||
|
<template #value>
|
||||||
|
{{ value }}
|
||||||
|
</template>
|
||||||
|
</StatsCards>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- General App Info -->
|
<!-- General App Info -->
|
||||||
<section class="mt-4">
|
<section class="mt-4">
|
||||||
<BaseCardSectionTitle
|
<BaseCardSectionTitle
|
||||||
@@ -234,7 +262,8 @@ import type { TranslateResult } from "vue-i18n";
|
|||||||
import { useAdminApi, useUserApi } from "~/composables/api";
|
import { useAdminApi, useUserApi } from "~/composables/api";
|
||||||
import { validators } from "~/composables/use-validators";
|
import { validators } from "~/composables/use-validators";
|
||||||
import { useAsyncKey } from "~/composables/use-utils";
|
import { useAsyncKey } from "~/composables/use-utils";
|
||||||
import type { CheckAppConfig } from "~/lib/api/types/admin";
|
import StatsCards from "~/components/global/StatsCards.vue";
|
||||||
|
import type { AppStatistics, CheckAppConfig } from "~/lib/api/types/admin";
|
||||||
import AppLoader from "~/components/global/AppLoader.vue";
|
import AppLoader from "~/components/global/AppLoader.vue";
|
||||||
|
|
||||||
interface SimpleCheck {
|
interface SimpleCheck {
|
||||||
@@ -285,17 +314,68 @@ const appConfig = ref<CheckApp>({
|
|||||||
ldapReady: false,
|
ldapReady: false,
|
||||||
oidcReady: false,
|
oidcReady: false,
|
||||||
});
|
});
|
||||||
|
const adminStats = ref<AppStatistics>({
|
||||||
|
totalRecipes: 0,
|
||||||
|
totalUsers: 0,
|
||||||
|
totalHouseholds: 0,
|
||||||
|
totalGroups: 0,
|
||||||
|
uncategorizedRecipes: 0,
|
||||||
|
untaggedRecipes: 0,
|
||||||
|
});
|
||||||
function isLocalHostOrHttps() {
|
function isLocalHostOrHttps() {
|
||||||
return window.location.hostname === "localhost" || window.location.protocol === "https:";
|
return window.location.hostname === "localhost" || window.location.protocol === "https:";
|
||||||
}
|
}
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
const adminApi = useAdminApi();
|
const adminApi = useAdminApi();
|
||||||
|
|
||||||
|
const adminStatsText: { [key: string]: string } = {
|
||||||
|
totalRecipes: i18n.t("general.recipes"),
|
||||||
|
totalUsers: i18n.t("user.users"),
|
||||||
|
totalHouseholds: i18n.t("household.households"),
|
||||||
|
totalGroups: i18n.t("group.groups"),
|
||||||
|
uncategorizedRecipes: i18n.t("settings.uncategorized-recipes"),
|
||||||
|
untaggedRecipes: i18n.t("settings.untagged-recipes"),
|
||||||
|
};
|
||||||
|
|
||||||
|
function getAdminStatsTitle(key: string) {
|
||||||
|
return adminStatsText[key] ?? key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminStatsIcon: { [key: string]: string } = {
|
||||||
|
totalRecipes: $globals.icons.primary,
|
||||||
|
totalUsers: $globals.icons.user,
|
||||||
|
totalHouseholds: $globals.icons.household,
|
||||||
|
totalGroups: $globals.icons.group,
|
||||||
|
uncategorizedRecipes: $globals.icons.categories,
|
||||||
|
untaggedRecipes: $globals.icons.tags,
|
||||||
|
};
|
||||||
|
|
||||||
|
function getAdminStatsIcon(key: string) {
|
||||||
|
return adminStatsIcon[key] ?? $globals.icons.primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminStatsTo = computed<{ [key: string]: string }>(() => {
|
||||||
|
return {
|
||||||
|
totalUsers: "/admin/manage/users",
|
||||||
|
totalHouseholds: "/admin/manage/households",
|
||||||
|
totalGroups: "/admin/manage/groups",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function getAdminStatsTo(key: string) {
|
||||||
|
return adminStatsTo.value[key] ?? undefined;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { data } = await adminApi.about.checkApp();
|
const { data } = await adminApi.about.checkApp();
|
||||||
if (data) {
|
if (data) {
|
||||||
appConfig.value = { ...data, isSiteSecure: false };
|
appConfig.value = { ...data, isSiteSecure: false };
|
||||||
}
|
}
|
||||||
appConfig.value.isSiteSecure = isLocalHostOrHttps();
|
appConfig.value.isSiteSecure = isLocalHostOrHttps();
|
||||||
|
const { data: adminData } = await adminApi.about.statistics();
|
||||||
|
if (adminData) {
|
||||||
|
adminStats.value = adminData;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const simpleChecks = computed<SimpleCheck[]>(() => {
|
const simpleChecks = computed<SimpleCheck[]>(() => {
|
||||||
const goodIcon = $globals.icons.checkboxMarkedCircle;
|
const goodIcon = $globals.icons.checkboxMarkedCircle;
|
||||||
|
|||||||
Reference in New Issue
Block a user