warn before leaving model edit page

This commit is contained in:
vabene1111
2025-01-01 10:07:27 +01:00
parent 60f2494eae
commit 8159838fc3
52 changed files with 177 additions and 30 deletions

View File

@@ -1,13 +1,13 @@
<template>
<v-card-title class="pb-0">
<v-row align="center" >
<v-row align="center">
<v-col cols="10" md="11" class="text-truncate">
<i :class="props.icon" v-if="props.icon != ''"></i>
{{ props.title }}
<v-card-subtitle class="pa-0" v-if="props.subTitle != ''">{{ props.subTitle}}</v-card-subtitle>
<v-card-subtitle class="pa-0" v-if="props.subTitle != ''">{{ props.subTitle }}</v-card-subtitle>
</v-col>
<v-col cols="2" md="1" v-if="!props.hideClose">
<v-btn class="float-right pr-2" icon="$close" variant="plain" @click="model = false; emit('close')"></v-btn>
<v-col cols="2" md="1">
<v-btn class="float-right pr-2" icon="$close" variant="plain" @click="model = false; emit('close')" v-if="!props.hideClose"></v-btn>
</v-col>
</v-row>
</v-card-title>
@@ -26,7 +26,7 @@ const props = defineProps({
title: {type: String, default: ''},
icon: {type: String, default: ''},
subTitle: {type: String, default: ''},
hideClose: {type:Boolean, default: false},
hideClose: {type: Boolean, default: false},
})
const model = defineModel<Boolean>()

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -45,7 +46,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<AccessToken>('AccessToken', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<AccessToken>('AccessToken', emit)
onMounted(() => {

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -47,7 +48,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Automation>('Automation', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Automation>('Automation', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
@@ -133,7 +134,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Food>('Food', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Food>('Food', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -39,7 +40,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<InviteLink>('InviteLink', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<InviteLink>('InviteLink', emit)
// object specific data (for selects/display)
const groups = ref([] as Group[])

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -38,7 +39,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Keyword>('Keyword', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Keyword>('Keyword', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
@@ -120,7 +121,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, applyItemDefaults, loading, editingObj, modelClass} = useModelEditorFunctions<MealPlan>('MealPlan', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, applyItemDefaults, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<MealPlan>('MealPlan', emit)
// object specific data (for selects/display)
const tab = ref('plan')

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -55,7 +56,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<MealType>('MealType', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<MealType>('MealType', emit)
// object specific data (for selects/display)
const timePickerMenu = ref(false)

View File

@@ -1,13 +1,19 @@
<template>
<v-card :loading="loading">
<v-closable-card-title :title="$t(modelClass.model.localizationKey)" :sub-title="objectName" :icon="modelClass.model.icon" @close="emit('close');" :hide-close="!dialog"></v-closable-card-title>
<v-closable-card-title
:title="$t(modelClass.model.localizationKey) + ((isChanged) ? '*' : '')"
:sub-title="objectName"
:icon="modelClass.model.icon"
@close="emit('close');"
:hide-close="!dialog"
></v-closable-card-title>
<v-divider></v-divider>
<slot name="default">
</slot>
<v-divider></v-divider>
<v-card-actions >
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate && !modelClass.model.disableDelete" :disabled="loading">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" :model-name="$t(modelClass.model.localizationKey)" @delete="emit('delete')"></delete-confirm-dialog>
</v-btn>
@@ -15,6 +21,20 @@
<v-btn color="save" prepend-icon="$save" @click="emit('save')" v-if="isUpdate && !modelClass.model.disableUpdate" :disabled="loading">{{ $t('Save') }}</v-btn>
</v-card-actions>
</v-card>
<v-dialog width="600px" v-model="leaveConfirmDialog">
<v-card>
<v-closable-card-title v-model="leaveConfirmDialog" :title="$t('Confirm')"></v-closable-card-title>
<v-card-text>
{{$t('WarnPageLeave')}}
</v-card-text>
<v-card-actions>
<v-btn @click="leaveConfirmDialog = false; leaveGoTo = null">{{ $t('Cancel') }}</v-btn>
<v-btn :to="leaveGoTo" color="warning">{{ $t('Confirm') }}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
@@ -22,6 +42,8 @@
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {GenericModel} from "@/types/Models";
import VClosableCardTitle from "@/components/dialogs/VClosableCardTitle.vue";
import {onBeforeRouteLeave, RouteLocationNormalized} from "vue-router";
import {ref} from "vue";
const emit = defineEmits(['save', 'delete', 'close'])
@@ -30,7 +52,20 @@ const props = defineProps({
dialog: {type: Boolean, default: false},
objectName: {type: String, default: ''},
modelClass: {type: GenericModel, default: null},
isUpdate: {type: Boolean, default: false}
isUpdate: {type: Boolean, default: false},
isChanged: {type: Boolean, default: false},
})
const leaveConfirmDialog = ref(false)
const leaveGoTo = ref<RouteLocationNormalized | null>(null)
onBeforeRouteLeave((to, from) => {
if (props.isChanged && !leaveConfirmDialog.value) {
leaveConfirmDialog.value = true
leaveGoTo.value = to
return false
}
return true
})
</script>

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -41,7 +42,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Property>('Property', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Property>('Property', emit)
onMounted(() => {

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -39,7 +40,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<PropertyType>('PropertyType', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<PropertyType>('PropertyType', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
@@ -145,7 +146,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Recipe>('Recipe', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Recipe>('Recipe', emit)
// object specific data (for selects/display)
const tab = ref("recipe")

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -47,7 +48,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<ShoppingListEntry>('ShoppingListEntry', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<ShoppingListEntry>('ShoppingListEntry', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -37,7 +38,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<SupermarketCategory>('SupermarketCategory', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<SupermarketCategory>('SupermarketCategory', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
@@ -115,7 +116,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Supermarket>('Supermarket', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Supermarket>('Supermarket', emit)
// object specific data (for selects/display)
const tab = ref("supermarket")

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -61,7 +62,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<UnitConversion>('UnitConversion', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<UnitConversion>('UnitConversion', emit)
onMounted(() => {

View File

@@ -6,17 +6,16 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
<v-text-field :label="$t('Name')" v-model="editingObj.name"></v-text-field>
<v-text-field :label="$t('Plural')" v-model="editingObj.pluralName"></v-text-field>
<v-textarea :label="$t('Description')" v-model="editingObj.description"></v-textarea>
<v-select :label="$t('BaseUnit')" :hint="$t('BaseUnitHelp')" :items="BASE_UNITS" v-model="editingObj.baseUnit"></v-select>
<v-text-field :label="$t('Open_Data_Slug')" :hint="$t('open_data_help_text')" persistent-hint v-model="editingObj.openDataSlug" disabled></v-text-field>
</v-form>
</v-card-text>
</model-editor-base>
@@ -40,7 +39,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Unit>('Unit', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Unit>('Unit', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -62,7 +63,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<UserFile>('UserFile', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<UserFile>('UserFile', emit)
// object specific data (for selects/display)

View File

@@ -6,6 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
@@ -35,7 +36,7 @@ const props = defineProps({
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<UserSpace>('UserSpace', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<UserSpace>('UserSpace', emit)
// object specific data (for selects/display)
const groups = ref([] as Group[])

View File

@@ -1,5 +1,5 @@
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {onBeforeMount, ref} from "vue";
import {onBeforeMount, onMounted, ref, watch} from "vue";
import {EditorSupportedModels, GenericModel, getGenericModelFromString} from "@/types/Models";
import {useI18n} from "vue-i18n";
import {ResponseError} from "@/openapi";
@@ -15,8 +15,16 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
const editingObj = ref({} as T)
const modelClass = ref({} as GenericModel)
const editingObjChanged = ref(false)
const {t} = useI18n()
watch(() => editingObj.value, (newValue, oldValue) => {
if (Object.keys(oldValue).length > 0) {
editingObjChanged.value = true
}
}, {deep: true})
/**
* before mounting the component UI set the model class based on the given model name
*/
@@ -24,6 +32,26 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
modelClass.value = getGenericModelFromString(modelName, t)
})
onMounted(() => {
setupPageLeaveWarning()
})
/**
* add event listener to page unload event (also triggered by router) to prevent accidentally closing with unsaved changes
*/
function setupPageLeaveWarning() {
window.onbeforeunload = (event) => {
if (editingObjChanged.value) {
event.returnValue = "this_string_cant_be_empty_because_of_firefox"
return "this_string_cant_be_empty_because_of_firefox"
}
}
}
/**
* apply the defaults to the item given in the itemsDefaults value of the setupState function
* @param itemDefaults
*/
function applyItemDefaults(itemDefaults: T) {
if (Object.keys(itemDefaults).length > 0) {
Object.keys(itemDefaults).forEach(k => {
@@ -156,6 +184,7 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
console.error(err)
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
}).finally(() => {
editingObjChanged.value = false
loading.value = false
})
} else {
@@ -168,6 +197,7 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
console.error(err)
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
}).finally(() => {
editingObjChanged.value = false
loading.value = false
})
}
@@ -177,13 +207,18 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
* deletes the editing object from the database
*/
function deleteObject() {
loading.value = true
modelClass.value.destroy(editingObj.value.id).then((r: any) => {
emit('delete', editingObj.value)
editingObj.value = {} as T
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
}).finally(() => {
editingObjChanged.value = false
loading.value = false
})
}
return {setupState, saveObject, deleteObject, isUpdate, editingObjName, applyItemDefaults, loading, editingObj, modelClass}
return {setupState, saveObject, deleteObject, isUpdate, editingObjName, applyItemDefaults, loading, editingObj, editingObjChanged, modelClass}
}

View File

@@ -44,6 +44,7 @@
"Color": "",
"Coming_Soon": "",
"Completed": "",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -352,6 +353,7 @@
"View_Recipes": "",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -44,6 +44,7 @@
"Color": "Цвят",
"Coming_Soon": "Очаквайте скоро",
"Completed": "Завършено",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -343,6 +344,7 @@
"View_Recipes": "Вижте рецепти",
"Waiting": "Очакване",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Внимание",
"Warning_Delete_Supermarket_Category": "Изтриването на категория супермаркет ще изтрие и всички връзки с храни. Сигурен ли си?",
"Website": "уебсайт",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "",
"Comments_setting": "",
"Completed": "",
"Confirm": "",
"Continue": "",
"Conversion": "",
"ConversionsHelp": "",
@@ -448,6 +449,7 @@
"View_Recipes": "Mostreu les receptes",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "Již brzy",
"Comments_setting": "Zobrazit komentáře",
"Completed": "Dokončeno",
"Confirm": "",
"Continue": "",
"Conversion": "Převod",
"ConversionsHelp": "",
@@ -441,6 +442,7 @@
"View_Recipes": "Zobrazit recepty",
"Waiting": "Čekající",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Varování",
"Warning_Delete_Supermarket_Category": "Vymazáním kategorie obchodu dojde k odstranění všech vazeb na potraviny. Jste si jistí?",
"Website": "Web",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "Kommer snart",
"Comments_setting": "Vis kommentarer",
"Completed": "Afsluttet",
"Confirm": "",
"Continue": "",
"Conversion": "Konversion",
"ConversionsHelp": "",
@@ -419,6 +420,7 @@
"View_Recipes": "Vis opskrifter",
"Waiting": "Vente",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Advarsel",
"Warning_Delete_Supermarket_Category": "At slette en supermarkedskategori vil også slette alle relationer til mad. Er du sikker?",
"Website": "Hjemmeside",

View File

@@ -57,6 +57,7 @@
"Coming_Soon": "Bald verfügbar",
"Comments_setting": "Kommentare anzeigen",
"Completed": "Fertig",
"Confirm": "Bestätigen",
"Continue": "Weiter",
"Conversion": "Umrechnung",
"ConversionsHelp": "Mit Umrechnungen kann die Menge einens Lebensmittels in verschiedenen Einheiten ausgerechnet werden. Aktuell wird dies nur zur berechnung von Eigenschaften verwendet, später jedoch sollen auch andere Funktionen von Tandoor davon profitieren.",
@@ -451,6 +452,7 @@
"View_Recipes": "Rezepte Ansehen",
"Waiting": "Wartezeit",
"WaitingTime": "Wartezeit",
"WarnPageLeave": "Deine Änderungen wurden noch nicht gespeichert und gehen verloren. Seite wirklich verlassen?",
"Warning": "Warnung",
"Warning_Delete_Supermarket_Category": "Die Löschung einer Supermarktkategorie werden auch alle Beziehungen zu Lebensmitteln gelöscht. Bist du dir sicher?",
"Website": "Webseite",

View File

@@ -54,6 +54,7 @@
"Coming_Soon": "Σύντομα διαθέσιμο",
"Comments_setting": "Εμφάνιση σχολίων",
"Completed": "Ολοκληρωμένο",
"Confirm": "",
"Continue": "",
"Conversion": "Μετατροπή",
"ConversionsHelp": "",
@@ -408,6 +409,7 @@
"View_Recipes": "Προβολή συνταγών",
"Waiting": "Αναμονή",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Προειδοποίηση",
"Warning_Delete_Supermarket_Category": "Η διαγραφή μιας κατηγορίας supermarket θα διαγράψει και όλες τις σχέσεις της με φαγητά. Είστε σίγουροι;",
"Website": "Ιστοσελίδα",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "Coming-Soon",
"Comments_setting": "Show Comments",
"Completed": "Completed",
"Confirm": "Confirm",
"Continue": "Continue",
"Conversion": "Conversion",
"ConversionsHelp": "With conversions you can calculate the amount of a food in different units. Currently this is only used for property calculation, later it might also be used in other parts of tandoor. ",
@@ -450,6 +451,7 @@
"View_Recipes": "View Recipes",
"Waiting": "Waiting",
"WaitingTime": "Waiting Time",
"WarnPageLeave": "There are unsaved changes that will get lost. Leave page anyway?",
"Warning": "Warning",
"Warning_Delete_Supermarket_Category": "Deleting a supermarket category will also delete all relations to foods. Are you sure?",
"Website": "Website",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "Próximamente",
"Comments_setting": "Mostrar Comentarios",
"Completed": "Completado",
"Confirm": "",
"Continue": "",
"Conversion": "Conversión",
"ConversionsHelp": "",
@@ -447,6 +448,7 @@
"View_Recipes": "Mostrar recetas",
"Waiting": "esperando",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Advertencia",
"Warning_Delete_Supermarket_Category": "Borrar una categoría de supermercado borrará también todas las relaciones con alimentos. ¿Está seguro?",
"Website": "Sitio Web",

View File

@@ -30,6 +30,7 @@
"Close": "Sulje",
"Color": "Väri",
"Coming_Soon": "Tulossa pian",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -263,6 +264,7 @@
"View_Recipes": "Näytä Reseptit",
"Waiting": "Odottaa",
"WaitingTime": "",
"WarnPageLeave": "",
"Wednesday": "",
"Week": "Viikko",
"Week_Numbers": "Viikkonumerot",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "Bientôt disponible",
"Comments_setting": "Montrer les commentaires",
"Completed": "Achevé",
"Confirm": "",
"Continue": "",
"Conversion": "Conversion",
"ConversionsHelp": "",
@@ -447,6 +448,7 @@
"View_Recipes": "Voir les recettes",
"Waiting": "Attente",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Avertissement",
"Warning_Delete_Supermarket_Category": "Supprimer une catégorie de supermarché supprimera également toutes les relations avec les aliments. Êtes-vous sûr ?",
"Website": "Site",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "בקרוב",
"Comments_setting": "הצג תגובות",
"Completed": "הושלם",
"Confirm": "",
"Continue": "",
"Conversion": "עברית",
"ConversionsHelp": "",
@@ -449,6 +450,7 @@
"View_Recipes": "הצג מתכונים",
"Waiting": "המתנה",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "אזהרה",
"Warning_Delete_Supermarket_Category": "מחיקת קטגורית סופרמרקט תמחוק גם את המאכלים הקשורים. האם אתה בטוח ?",
"Website": "אתר",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "Hamarosan",
"Comments_setting": "Hozzászólások megjelenítése",
"Completed": "Kész",
"Confirm": "",
"Continue": "",
"Conversion": "Konverzió",
"ConversionsHelp": "",
@@ -410,6 +411,7 @@
"View_Recipes": "Receptek megjelenítése",
"Waiting": "Várakozás",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Figyelmeztetés",
"Warning_Delete_Supermarket_Category": "Egy szupermarket-kategória törlése az alapanyagokkal való összes kapcsolatot is törli. Biztos vagy benne?",
"Website": "Weboldal",

View File

@@ -22,6 +22,7 @@
"Categories": "",
"Category": "",
"Close": "",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -193,6 +194,7 @@
"View_Recipes": "Դիտել բաղադրատոմսերը",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Wednesday": "",
"WorkingTime": "",
"YourSpaces": "",

View File

@@ -48,6 +48,7 @@
"Coming_Soon": "",
"Comments_setting": "",
"Completed": "",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -377,6 +378,7 @@
"View_Recipes": "Lihat Resep",
"Waiting": "Menunggu",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "",
"Comments_setting": "",
"Completed": "",
"Confirm": "",
"Continue": "",
"Conversion": "",
"ConversionsHelp": "",
@@ -447,6 +448,7 @@
"View_Recipes": "",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -52,6 +52,7 @@
"Coming_Soon": "In-Arrivo",
"Comments_setting": "Mostra commenti",
"Completed": "Completato",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -392,6 +393,7 @@
"View_Recipes": "Mostra ricette",
"Waiting": "Attesa",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Attenzione",
"Warning_Delete_Supermarket_Category": "L'eliminazione di una categoria di supermercato comporta anche l'eliminazione di tutte le relazioni con gli alimenti. Sei sicuro?",
"Website": "Sito web",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "",
"Comments_setting": "",
"Completed": "",
"Confirm": "",
"Continue": "",
"Conversion": "",
"ConversionsHelp": "",
@@ -417,6 +418,7 @@
"View_Recipes": "Žiūrėti receptus",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -53,6 +53,7 @@
"Coming_Soon": "Kommer snart",
"Comments_setting": "",
"Completed": "Fullført",
"Confirm": "",
"Continue": "",
"Conversion": "Omregn enhet",
"ConversionsHelp": "",
@@ -406,6 +407,7 @@
"View_Recipes": "Vis oppskrifter",
"Waiting": "Venter",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Advarsel",
"Warning_Delete_Supermarket_Category": "",
"Website": "Nettside",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "Binnenkort beschikbaar",
"Comments_setting": "Commentaar weergeven",
"Completed": "Voltooid",
"Confirm": "",
"Continue": "",
"Conversion": "Omrekening",
"ConversionsHelp": "",
@@ -410,6 +411,7 @@
"View_Recipes": "Bekijk Recepten",
"Waiting": "Wachten",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Waarschuwing",
"Warning_Delete_Supermarket_Category": "Een supermarktcategorie verwijderen verwijdert ook alle relaties naar ingrediënten. Weet je het zeker?",
"Website": "Website",

View File

@@ -57,6 +57,7 @@
"Coming_Soon": "Dostępne wkrótce",
"Comments_setting": "Pokaż komentarze",
"Completed": "Zakończone",
"Confirm": "",
"Continue": "",
"Conversion": "Konwersja",
"ConversionsHelp": "",
@@ -450,6 +451,7 @@
"View_Recipes": "Przeglądaj przepisy",
"Waiting": "Oczekiwanie",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Ostrzeżenie",
"Warning_Delete_Supermarket_Category": "Usunięcie kategorii supermarketu spowoduje również usunięcie wszystkich relacji z żywnością. Jesteś pewny?",
"Website": "Strona internetowa",

View File

@@ -43,6 +43,7 @@
"Color": "Cor",
"Coming_Soon": "",
"Completed": "Completo",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -339,6 +340,7 @@
"View_Recipes": "Ver Receitas",
"Waiting": "Em espera",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Aviso",
"Wednesday": "",
"Week": "Semana",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "Em breve",
"Comments_setting": "Mostrar Comentários",
"Completed": "Finalizado",
"Confirm": "",
"Continue": "",
"Conversion": "Conversão",
"ConversionsHelp": "",
@@ -426,6 +427,7 @@
"View_Recipes": "Ver Receitas",
"Waiting": "Espera",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Alerta",
"Website": "Website",
"Wednesday": "",

View File

@@ -53,6 +53,7 @@
"Coming_Soon": "În curând",
"Comments_setting": "Afișează comentarii",
"Completed": "Completat",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -396,6 +397,7 @@
"View_Recipes": "Vizionare rețete",
"Waiting": "Așteptare",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Atenționare",
"Warning_Delete_Supermarket_Category": "Ștergerea unei categorii de supermarketuri va șterge, de asemenea, toate relațiile cu alimentele. Sunteți sigur?",
"Website": "Site web",

View File

@@ -38,6 +38,7 @@
"Color": "Цвет",
"Coming_Soon": "Скоро",
"Completed": "Завершено",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -314,6 +315,7 @@
"View_Recipes": "Просмотр рецепта",
"Waiting": "Ожидание",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Предупреждение",
"Warning_Delete_Supermarket_Category": "Удаление категории супермаркета также приведет к удалению всех связей с продуктами. Вы уверены?",
"Wednesday": "",

View File

@@ -39,6 +39,7 @@
"Color": "Barva",
"Coming_Soon": "Kmalu",
"Completed": "Končano",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -309,6 +310,7 @@
"View_Recipes": "Preglej recepte",
"Waiting": "Čakanje",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Opozorilo",
"Wednesday": "",
"Week": "Teden",

View File

@@ -57,6 +57,7 @@
"Coming_Soon": "Kommer snart",
"Comments_setting": "Visa Kommentarer",
"Completed": "Avslutad",
"Confirm": "",
"Continue": "",
"Conversion": "Omvandling",
"ConversionsHelp": "",
@@ -450,6 +451,7 @@
"View_Recipes": "Visa recept",
"Waiting": "Väntan",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Varning",
"Warning_Delete_Supermarket_Category": "Om du tar bort en mataffärskategori raderas också alla relationer till livsmedel. Är du säker?",
"Website": "Hemsida",

View File

@@ -56,6 +56,7 @@
"Coming_Soon": "Yakında Gelecek",
"Comments_setting": "Yorumları Göster",
"Completed": "Tamamlandı",
"Confirm": "",
"Continue": "",
"Conversion": "Dönüşüm",
"ConversionsHelp": "",
@@ -449,6 +450,7 @@
"View_Recipes": "Tarifleri Görüntüle",
"Waiting": "Bekleniyor",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Uyarı",
"Warning_Delete_Supermarket_Category": "Bir market kategorisinin silinmesi, gıdalarla olan tüm ilişkileri de silecektir. Emin misiniz?",
"Website": "Website",

View File

@@ -47,6 +47,7 @@
"Color": "Колір",
"Coming_Soon": "",
"Completed": "Виконано",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -361,6 +362,7 @@
"View_Recipes": "Подивитися Рецепт",
"Waiting": "Очікування",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "Увага",
"Warning_Delete_Supermarket_Category": "",
"Website": "",

View File

@@ -55,6 +55,7 @@
"Coming_Soon": "即将到来",
"Comments_setting": "显示评论",
"Completed": "完成",
"Confirm": "",
"Continue": "",
"Conversion": "转换",
"ConversionsHelp": "",
@@ -440,6 +441,7 @@
"View_Recipes": "查看食谱",
"Waiting": "等待",
"WaitingTime": "",
"WarnPageLeave": "",
"Warning": "警告",
"Warning_Delete_Supermarket_Category": "删除超市类别也会删除与食品的所有关系。 你确定吗?",
"Website": "网站",

View File

@@ -19,6 +19,7 @@
"Categories": "",
"Category": "",
"Close": "",
"Confirm": "",
"Continue": "",
"ConversionsHelp": "",
"CookLog": "",
@@ -162,6 +163,7 @@
"View_Recipes": "",
"Waiting": "",
"WaitingTime": "",
"WarnPageLeave": "",
"Wednesday": "",
"WorkingTime": "",
"YourSpaces": "",

View File

@@ -21,7 +21,7 @@
import {useRouter} from "vue-router";
import {EditorSupportedModels, getGenericModelFromString} from "@/types/Models";
import {defineAsyncComponent, PropType, shallowRef} from "vue";
import {defineAsyncComponent, onMounted, PropType, shallowRef} from "vue";
import {useI18n} from "vue-i18n";
const {t} = useI18n()