Merge branch 'mealie-next' into fix/meal-plan-settings-offscreen

This commit is contained in:
boc-the-git 2023-12-11 12:33:41 +11:00 committed by GitHub
commit 36b35caffb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 333 additions and 323 deletions

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Sleutelwoord",
"link-copied": "Skakel gekopieer",
"loading": "Loading",
"loading-events": "Besig om gebeurtenisse te laai",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "كلمة مفتاحية",
"link-copied": "تمّ نسْخ الرّابط",
"loading": "Loading",
"loading-events": "جاري تحميل الأحداث",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключова дума",
"link-copied": "Линкът е копиран",
"loading": "Loading",
"loading-events": "Зареждане на събития",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Paraula clau",
"link-copied": "S'ha copiat l'enllaç",
"loading": "Loading",
"loading-events": "Carregant esdeveniments",
"loading-recipe": "Carregant la recepta...",
"loading-ocr-data": "Carregant les dades OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Klíčové slovo",
"link-copied": "Odkaz zkopírován",
"loading": "Loading",
"loading-events": "Načítání událostí",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nøgleord",
"link-copied": "Link kopieret",
"loading": "Indlæser",
"loading-events": "Indlæser hændelser",
"loading-recipe": "Indlæser opskrift...",
"loading-ocr-data": "Indlæser OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Schlüsselwort",
"link-copied": "Link kopiert",
"loading": "Wird geladen...",
"loading-events": "Ereignisse werden geladen",
"loading-recipe": "Lade Rezept...",
"loading-ocr-data": "Lade OCR-Daten...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Λέξη-κλειδί",
"link-copied": "Ο Σύνδεσμος Αντιγράφηκε",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Etiqueta",
"link-copied": "Enlace copiado",
"loading": "Loading",
"loading-events": "Cargando Eventos",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Hakusana",
"link-copied": "Linkki kopioitu",
"loading": "Loading",
"loading-events": "Ladataan tapahtumia",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Mot-clé",
"link-copied": "Lien copié",
"loading": "Chargement",
"loading-events": "Chargement des événements",
"loading-recipe": "Chargement de la recette...",
"loading-ocr-data": "Chargement des données OCR...",
@ -875,7 +876,7 @@
"user-management": "Gestion des utilisateurs",
"reset-locked-users": "Réinitialiser les utilisateurs verrouillés",
"admin-user-creation": "Création d'un utilisateur admin",
"admin-user-management": "Admin User Management",
"admin-user-management": "Administration des utilisateurs",
"user-details": "Détails de l'utilisateur",
"user-name": "Nom d'utilisateur",
"authentication-method": "Méthode d'authentification",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Mot-clé",
"link-copied": "Lien copié",
"loading": "Chargement",
"loading-events": "Chargement des événements",
"loading-recipe": "Chargement de la recette...",
"loading-ocr-data": "Chargement des données OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "מילת מפתח",
"link-copied": "קישור הועתק",
"loading": "Loading",
"loading-events": "טוען",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna riječ",
"link-copied": "Poveznica kopirana",
"loading": "Loading",
"loading-events": "Učitavanje događaja",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -77,7 +77,7 @@
"tag-events": "Címke események",
"category-events": "Kategória események",
"when-a-new-user-joins-your-group": "Amikor egy új felhasználó csatlakozik a csoportodba",
"recipe-events": "Recipe Events"
"recipe-events": "Recept esemény"
},
"general": {
"cancel": "Mégsem",
@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Kulcsszó",
"link-copied": "Hivatkozás másolva",
"loading": "Loading",
"loading-events": "Események betöltése",
"loading-recipe": "Recept betöltése...",
"loading-ocr-data": "OCR adatok betöltése...",
@ -590,7 +591,7 @@
"import-summary": "Import összefoglaló",
"partial-backup": "Részleges biztonsági mentés",
"unable-to-delete-backup": "Nem lehetett létrehozni a biztonsági mentést.",
"experimental-description": "Backups a total snapshots of the database and data directory of the site. This includes all data and cannot be set to exclude subsets of data. You can think off this as a snapshot of Mealie at a specific time. Currently, {not-crossed-version} (data migrations are not done automatically). These serve as a database agnostic way to export and import data or backup the site to an external location.",
"experimental-description": "A biztonsági mentések az oldal adatbázisának és adatkönyvtárának teljes pillanatfelvételei. Ez az összes adatot tartalmazza, és nem lehet beállítani, hogy az adatok részhalmazait kizárja. Ezt úgy is elképzelheti, mint a Mealie egy adott időpontban készült pillanatfelvételét. Ezek adatbázis-független módon szolgálnak az adatok exportálására és importálására, vagy a webhely külső helyre történő mentésére.",
"backup-restore": "Biztonsági Mentés/Visszaállítás",
"back-restore-description": "A biztonsági mentés visszaállítása felülírja az adatbázisban és az adatkönyvtárban lévő összes aktuális adatot, és a biztonsági mentés tartalmával helyettesíti azokat. {cannot-be-undone} Ha a visszaállítás sikeres, akkor a rendszer kilépteti Önt.",
"cannot-be-undone": "Ezt a műveletet visszavonható - óvatosan használja.",
@ -1056,8 +1057,8 @@
"click": "Kattintson bármelyik mezőre a jobb oldalon, majd kattintson vissza a kép feletti téglalapra.",
"result": "A kiválasztott szöveg a korábban kiválasztott mezőben jelenik meg."
},
"pan-and-zoom-mode": "Pan and Zoom Mode",
"pan-and-zoom-desc": "Select pan and zoom by clicking the icon. This mode allows to zoom inside the image and move around to make using big images easier.",
"pan-and-zoom-mode": "Pásztázás és nagyítás mód",
"pan-and-zoom-desc": "Válassza ki a pásztázást és a nagyítást az ikonra kattintva. Ez a mód lehetővé teszi a kép nagyítását és mozgását a nagy képek használatának megkönnyítése érdekében.",
"split-text-mode": "Szöveg felosztási módok",
"split-modes": {
"line-mode": "Vonal mód (alapértelmezett)",
@ -1113,7 +1114,7 @@
"show-individual-confidence": "",
"ingredient-text": "Hozzávaló szöveg",
"average-confident": "{0} Confident",
"try-an-example": "Próbáld ki",
"try-an-example": "Próbáljon ki egy példát",
"parser": "Szintaxis elemző",
"background-tasks": "Háttér folyamatok",
"background-tasks-description": "Itt megtekintheti az összes futó háttérfeladatot és azok állapotát",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Parola chiave",
"link-copied": "Link Copiato",
"loading": "Loading",
"loading-events": "Caricamento eventi",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "キーワード",
"link-copied": "リンクをコピーしました。",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "키워드",
"link-copied": "링크 복사됨",
"loading": "Loading",
"loading-events": "이벤트를 불러오는 중",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Raktažodis",
"link-copied": "Nuoroda nukopijuota",
"loading": "Loading",
"loading-events": "Užkrovimo įvykiai",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Trefwoord",
"link-copied": "Link Gekopieerd",
"loading": "Bezig met laden",
"loading-events": "Gebeurtenis laden",
"loading-recipe": "Recepten ophalen...",
"loading-ocr-data": "OCR gegevens laden...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nøkkelord",
"link-copied": "Lenke kopiert",
"loading": "Loading",
"loading-events": "Laster hendelser",
"loading-recipe": "Laster oppskrift...",
"loading-ocr-data": "Laster OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Słowo kluczowe",
"link-copied": "Odnośnik skopiowany",
"loading": "Loading",
"loading-events": "Ładowanie wydarzeń",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Palavra chave",
"link-copied": "Link Copiado",
"loading": "Loading",
"loading-events": "Carregando eventos",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Palavra-chave",
"link-copied": "Ligação copiada",
"loading": "Loading",
"loading-events": "A carregar Eventos",
"loading-recipe": "A carregar receita...",
"loading-ocr-data": "A carregar dados OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Cuvânt cheie",
"link-copied": "Link copiat",
"loading": "Loading",
"loading-events": "Se încarcă evenimentele",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключевое слово",
"link-copied": "Ссылка скопирована",
"loading": "Loading",
"loading-events": "Загрузка событий",
"loading-recipe": "Загрузка рецепта...",
"loading-ocr-data": "Загрузка данных OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Kľučové slovo",
"link-copied": "Odkaz bol skopírovaný",
"loading": "Loading",
"loading-events": "Načítanie udalostí",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna beseda",
"link-copied": "Povezava kopirana",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna reč",
"link-copied": "Линк је копиран",
"loading": "Loading",
"loading-events": "Учитавање догађаја",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nyckelord",
"link-copied": "Länk kopierad",
"loading": "Loading",
"loading-events": "Laddar händelser",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Anahtar Kelime",
"link-copied": "Bağlantı Kopyalandı",
"loading": "Loading",
"loading-events": "Etkinlikler yükleniyor",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "OCR verileri yükleniyor...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключове слово",
"link-copied": "Посилання скопійовано",
"loading": "Завантаження",
"loading-events": "Завантаження подій",
"loading-recipe": "Завантаження рецепта...",
"loading-ocr-data": "Завантаження даних OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "关键字",
"link-copied": "链接已复制",
"loading": "Loading",
"loading-events": "正在加载事件",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "關鍵字",
"link-copied": "已複製連結",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -130,40 +130,47 @@
<section class="mt-4">
<BaseCardSectionTitle class="pb-0" :icon="$globals.icons.cog" :title="$tc('settings.general-about')"> </BaseCardSectionTitle>
<v-card class="mb-4">
<template v-for="(property, idx) in appInfo">
<v-list-item :key="property.name">
<v-list-item-icon>
<v-icon> {{ property.icon || $globals.icons.user }} </v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
<div>{{ property.name }}</div>
</v-list-item-title>
<template v-if="property.slot === 'recipe-scraper'">
<v-list-item-subtitle>
<a
target="_blank"
:href="`https://github.com/hhursev/recipe-scrapers/releases/tag/${property.value}`"
>
<template v-if="appInfo && appInfo.length">
<template v-for="(property, idx) in appInfo">
<v-list-item :key="property.name">
<v-list-item-icon>
<v-icon> {{ property.icon || $globals.icons.user }} </v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
<div>{{ property.name }}</div>
</v-list-item-title>
<template v-if="property.slot === 'recipe-scraper'">
<v-list-item-subtitle>
<a
target="_blank"
:href="`https://github.com/hhursev/recipe-scrapers/releases/tag/${property.value}`"
>
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else-if="property.slot === 'build'">
<v-list-item-subtitle>
<a target="_blank" :href="`https://github.com/hay-kot/mealie/commit/${property.value}`">
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else>
<v-list-item-subtitle>
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else-if="property.slot === 'build'">
<v-list-item-subtitle>
<a target="_blank" :href="`https://github.com/hay-kot/mealie/commit/${property.value}`">
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else>
<v-list-item-subtitle>
{{ property.value }}
</v-list-item-subtitle>
</template>
</v-list-item-content>
</v-list-item>
<v-divider v-if="appInfo && idx !== appInfo.length - 1" :key="`divider-${property.name}`"></v-divider>
</v-list-item-subtitle>
</template>
</v-list-item-content>
</v-list-item>
<v-divider v-if="appInfo && idx !== appInfo.length - 1" :key="`divider-${property.name}`"></v-divider>
</template>
</template>
<template v-else>
<div class="mb-3 text-center">
<AppLoader :waiting-text="$tc('general.loading')" />
</div>
</template>
</v-card>
</section>
@ -186,6 +193,7 @@ import { useAdminApi, useUserApi } from "~/composables/api";
import { validators } from "~/composables/use-validators";
import { useAsyncKey } from "~/composables/use-utils";
import { CheckAppConfig } from "~/lib/api/types/admin";
import AppLoader from "~/components/global/AppLoader.vue";
enum DockerVolumeState {
Unknown = "unknown",
@ -208,294 +216,257 @@ interface CheckApp extends CheckAppConfig {
}
export default defineComponent({
layout: "admin",
setup() {
// ==========================================================
// Docker Volume Validation
const docker = reactive({
loading: false,
state: DockerVolumeState.Unknown,
});
async function dockerValidate() {
docker.loading = true;
// Do API Check
const { data } = await adminApi.about.checkDocker();
if (data == null) {
docker.state = DockerVolumeState.Error;
return;
}
// Get File Contents
const { data: fileContents } = await adminApi.about.getDockerValidateFileContents();
if (data.text === fileContents) {
docker.state = DockerVolumeState.Success;
} else {
docker.state = DockerVolumeState.Error;
}
docker.loading = false;
}
const state = reactive({
loading: false,
address: "",
success: false,
error: "",
tested: false,
});
const appConfig = ref<CheckApp>({
emailReady: true,
baseUrlSet: true,
isSiteSecure: true,
isUpToDate: false,
ldapReady: false,
});
function isLocalHostOrHttps() {
return window.location.hostname === "localhost" || window.location.protocol === "https:";
}
const api = useUserApi();
const adminApi = useAdminApi();
onMounted(async () => {
const { data } = await adminApi.about.checkApp();
if (data) {
appConfig.value = { ...data, isSiteSecure: false };
}
appConfig.value.isSiteSecure = isLocalHostOrHttps();
});
const simpleChecks = computed<SimpleCheck[]>(() => {
const goodIcon = $globals.icons.checkboxMarkedCircle;
const badIcon = $globals.icons.alert;
const warningIcon = $globals.icons.alertCircle;
const goodColor = "success";
const badColor = "error";
const warningColor = "warning";
const data: SimpleCheck[] = [
{
id: "application-version",
text: i18n.t("settings.application-version"),
status: appConfig.value.isUpToDate,
errorText: i18n.t("settings.application-version-error-text", [rawAppInfo.value.version, rawAppInfo.value.versionLatest]),
successText: i18n.t("settings.mealie-is-up-to-date"),
color: appConfig.value.isUpToDate ? goodColor : warningColor,
icon: appConfig.value.isUpToDate ? goodIcon : warningIcon,
},
{
id: "secure-site",
text: i18n.t("settings.secure-site"),
status: appConfig.value.isSiteSecure,
errorText: i18n.t("settings.secure-site-error-text"),
successText: i18n.t("settings.secure-site-success-text"),
color: appConfig.value.isSiteSecure ? goodColor : badColor,
icon: appConfig.value.isSiteSecure ? goodIcon : badIcon,
},
{
id: "server-side-base-url",
text: i18n.t("settings.server-side-base-url"),
status: appConfig.value.baseUrlSet,
errorText:
i18n.t("settings.server-side-base-url-error-text"),
successText: i18n.t("settings.server-side-base-url-success-text"),
color: appConfig.value.baseUrlSet ? goodColor : badColor,
icon: appConfig.value.baseUrlSet ? goodIcon : badIcon,
},
{
id: "ldap-ready",
text: i18n.t("settings.ldap-ready"),
status: appConfig.value.ldapReady,
errorText:
i18n.t("settings.ldap-ready-error-text"),
successText: i18n.t("settings.ldap-ready-success-text"),
color: appConfig.value.ldapReady ? goodColor : warningColor,
icon: appConfig.value.ldapReady ? goodIcon : warningIcon,
},
];
return data;
});
async function testEmail() {
state.loading = true;
state.tested = false;
const { data } = await api.email.test({ email: state.address });
if (data) {
if (data.success) {
state.success = true;
} else {
state.error = data.error ?? "";
state.success = false;
layout: "admin",
setup() {
// ==========================================================
// Docker Volume Validation
const docker = reactive({
loading: false,
state: DockerVolumeState.Unknown,
});
async function dockerValidate() {
docker.loading = true;
// Do API Check
const { data } = await adminApi.about.checkDocker();
if (data == null) {
docker.state = DockerVolumeState.Error;
return;
}
// Get File Contents
const { data: fileContents } = await adminApi.about.getDockerValidateFileContents();
if (data.text === fileContents) {
docker.state = DockerVolumeState.Success;
}
else {
docker.state = DockerVolumeState.Error;
}
docker.loading = false;
}
}
state.loading = false;
state.tested = true;
}
const validEmail = computed(() => {
if (state.address === "") {
return false;
}
const valid = validators.email(state.address);
// Explicit bool check because validators.email sometimes returns a string
if (valid === true) {
return true;
}
return false;
});
// ============================================================
// General About Info
const { $globals, i18n } = useContext();
const rawAppInfo = ref({
version: "null",
versionLatest: "null",
});
function getAppInfo() {
const statistics = useAsync(async () => {
const { data } = await adminApi.about.about();
if (data) {
rawAppInfo.value.version = data.version;
rawAppInfo.value.versionLatest = data.versionLatest;
const prettyInfo = [
{
name: i18n.t("about.version"),
icon: $globals.icons.information,
value: data.version,
},
{
slot: "build",
name: i18n.t("settings.build"),
icon: $globals.icons.information,
value: data.buildId,
},
{
name: i18n.t("about.application-mode"),
icon: $globals.icons.devTo,
value: data.production ? i18n.t("about.production") : i18n.t("about.development"),
},
{
name: i18n.t("about.demo-status"),
icon: $globals.icons.testTube,
value: data.demoStatus ? i18n.t("about.demo") : i18n.t("about.not-demo"),
},
{
name: i18n.t("about.api-port"),
icon: $globals.icons.api,
value: data.apiPort,
},
{
name: i18n.t("about.api-docs"),
icon: $globals.icons.file,
value: data.apiDocs ? i18n.t("general.enabled") : i18n.t("general.disabled"),
},
{
name: i18n.t("about.database-type"),
icon: $globals.icons.database,
value: data.dbType,
},
{
name: i18n.t("about.database-url"),
icon: $globals.icons.database,
value: data.dbUrl,
},
{
name: i18n.t("about.default-group"),
icon: $globals.icons.group,
value: data.defaultGroup,
},
{
slot: "recipe-scraper",
name: i18n.t("settings.recipe-scraper-version"),
icon: $globals.icons.primary,
value: data.recipeScraperVersion,
},
];
return prettyInfo;
const state = reactive({
loading: false,
address: "",
success: false,
error: "",
tested: false,
});
const appConfig = ref<CheckApp>({
emailReady: true,
baseUrlSet: true,
isSiteSecure: true,
isUpToDate: false,
ldapReady: false,
});
function isLocalHostOrHttps() {
return window.location.hostname === "localhost" || window.location.protocol === "https:";
}
return data;
}, useAsyncKey());
return statistics;
}
const appInfo = getAppInfo();
const bugReportDialog = ref(false);
const bugReportText = computed(() => {
const ignore = {
[i18n.tc("about.database-url")]: true,
[i18n.tc("about.default-group")]: true,
};
let text = "**Details**\n";
appInfo.value?.forEach((item) => {
if (ignore[item.name as string]) {
return;
const api = useUserApi();
const adminApi = useAdminApi();
onMounted(async () => {
const { data } = await adminApi.about.checkApp();
if (data) {
appConfig.value = { ...data, isSiteSecure: false };
}
appConfig.value.isSiteSecure = isLocalHostOrHttps();
});
const simpleChecks = computed<SimpleCheck[]>(() => {
const goodIcon = $globals.icons.checkboxMarkedCircle;
const badIcon = $globals.icons.alert;
const warningIcon = $globals.icons.alertCircle;
const goodColor = "success";
const badColor = "error";
const warningColor = "warning";
const data: SimpleCheck[] = [
{
id: "application-version",
text: i18n.t("settings.application-version"),
status: appConfig.value.isUpToDate,
errorText: i18n.t("settings.application-version-error-text", [rawAppInfo.value.version, rawAppInfo.value.versionLatest]),
successText: i18n.t("settings.mealie-is-up-to-date"),
color: appConfig.value.isUpToDate ? goodColor : warningColor,
icon: appConfig.value.isUpToDate ? goodIcon : warningIcon,
},
{
id: "secure-site",
text: i18n.t("settings.secure-site"),
status: appConfig.value.isSiteSecure,
errorText: i18n.t("settings.secure-site-error-text"),
successText: i18n.t("settings.secure-site-success-text"),
color: appConfig.value.isSiteSecure ? goodColor : badColor,
icon: appConfig.value.isSiteSecure ? goodIcon : badIcon,
},
{
id: "server-side-base-url",
text: i18n.t("settings.server-side-base-url"),
status: appConfig.value.baseUrlSet,
errorText: i18n.t("settings.server-side-base-url-error-text"),
successText: i18n.t("settings.server-side-base-url-success-text"),
color: appConfig.value.baseUrlSet ? goodColor : badColor,
icon: appConfig.value.baseUrlSet ? goodIcon : badIcon,
},
{
id: "ldap-ready",
text: i18n.t("settings.ldap-ready"),
status: appConfig.value.ldapReady,
errorText: i18n.t("settings.ldap-ready-error-text"),
successText: i18n.t("settings.ldap-ready-success-text"),
color: appConfig.value.ldapReady ? goodColor : warningColor,
icon: appConfig.value.ldapReady ? goodIcon : warningIcon,
},
];
return data;
});
async function testEmail() {
state.loading = true;
state.tested = false;
const { data } = await api.email.test({ email: state.address });
if (data) {
if (data.success) {
state.success = true;
}
else {
state.error = data.error ?? "";
state.success = false;
}
}
state.loading = false;
state.tested = true;
}
text += `${item.name as string}: ${item.value as string}\n`;
});
const ignoreChecks: { [key: string]: boolean } = {
"application-version": true,
};
text += "\n**Checks**\n";
simpleChecks.value.forEach((item) => {
if (ignoreChecks[item.id]) {
return;
const validEmail = computed(() => {
if (state.address === "") {
return false;
}
const valid = validators.email(state.address);
// Explicit bool check because validators.email sometimes returns a string
if (valid === true) {
return true;
}
return false;
});
// ============================================================
// General About Info
const { $globals, i18n } = useContext();
const rawAppInfo = ref({
version: "null",
versionLatest: "null",
});
function getAppInfo() {
const statistics = useAsync(async () => {
const { data } = await adminApi.about.about();
if (data) {
rawAppInfo.value.version = data.version;
rawAppInfo.value.versionLatest = data.versionLatest;
const prettyInfo = [
{
name: i18n.t("about.version"),
icon: $globals.icons.information,
value: data.version,
},
{
slot: "build",
name: i18n.t("settings.build"),
icon: $globals.icons.information,
value: data.buildId,
},
{
name: i18n.t("about.application-mode"),
icon: $globals.icons.devTo,
value: data.production ? i18n.t("about.production") : i18n.t("about.development"),
},
{
name: i18n.t("about.demo-status"),
icon: $globals.icons.testTube,
value: data.demoStatus ? i18n.t("about.demo") : i18n.t("about.not-demo"),
},
{
name: i18n.t("about.api-port"),
icon: $globals.icons.api,
value: data.apiPort,
},
{
name: i18n.t("about.api-docs"),
icon: $globals.icons.file,
value: data.apiDocs ? i18n.t("general.enabled") : i18n.t("general.disabled"),
},
{
name: i18n.t("about.database-type"),
icon: $globals.icons.database,
value: data.dbType,
},
{
name: i18n.t("about.database-url"),
icon: $globals.icons.database,
value: data.dbUrl,
},
{
name: i18n.t("about.default-group"),
icon: $globals.icons.group,
value: data.defaultGroup,
},
{
slot: "recipe-scraper",
name: i18n.t("settings.recipe-scraper-version"),
icon: $globals.icons.primary,
value: data.recipeScraperVersion,
},
];
return prettyInfo;
}
return data;
}, useAsyncKey());
return statistics;
}
const status = item.status ? i18n.tc("general.yes") : i18n.tc("general.no");
text += `${item.text.toString()}: ${status}\n`;
});
text += `${i18n.tc("settings.email-configured")}: ${appConfig.value.emailReady ? i18n.tc("general.yes") : i18n.tc("general.no")}\n`;
text += `${i18n.tc("settings.docker-volume")}: ${docker.state}`;
return text;
});
return {
bugReportDialog,
bugReportText,
DockerVolumeState,
docker,
dockerValidate,
simpleChecks,
appConfig,
validEmail,
validators,
...toRefs(state),
testEmail,
appInfo,
};
},
head() {
return {
title: this.$t("settings.site-settings") as string,
};
},
const appInfo = getAppInfo();
const bugReportDialog = ref(false);
const bugReportText = computed(() => {
const ignore = {
[i18n.tc("about.database-url")]: true,
[i18n.tc("about.default-group")]: true,
};
let text = "**Details**\n";
appInfo.value?.forEach((item) => {
if (ignore[item.name as string]) {
return;
}
text += `${item.name as string}: ${item.value as string}\n`;
});
const ignoreChecks: {
[key: string]: boolean;
} = {
"application-version": true,
};
text += "\n**Checks**\n";
simpleChecks.value.forEach((item) => {
if (ignoreChecks[item.id]) {
return;
}
const status = item.status ? i18n.tc("general.yes") : i18n.tc("general.no");
text += `${item.text.toString()}: ${status}\n`;
});
text += `${i18n.tc("settings.email-configured")}: ${appConfig.value.emailReady ? i18n.tc("general.yes") : i18n.tc("general.no")}\n`;
text += `${i18n.tc("settings.docker-volume")}: ${docker.state}`;
return text;
});
return {
bugReportDialog,
bugReportText,
DockerVolumeState,
docker,
dockerValidate,
simpleChecks,
appConfig,
validEmail,
validators,
...toRefs(state),
testEmail,
appInfo,
};
},
head() {
return {
title: this.$t("settings.site-settings") as string,
};
},
components: { AppLoader }
});
</script>