model related stuff

This commit is contained in:
vabene1111
2024-09-26 15:02:07 +02:00
parent ddaeb054d0
commit 9a94c650da
42 changed files with 320 additions and 94 deletions

View File

@@ -18,18 +18,18 @@
</v-card>
</v-list-item>
<v-divider></v-divider>
<v-list-item :to="{ name: 'view_settings', params: {} }"><template #prepend><v-icon icon="fa-solid fa-sliders"></v-icon></template>Settings</v-list-item>
<v-list-item :to="{ name: 'ModelListPage', params: {} }"><template #prepend><v-icon icon="fa-solid fa-folder-tree"></v-icon></template>Database</v-list-item>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-user-shield"></v-icon></template>Admin</v-list-item>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-question"></v-icon></template>Help</v-list-item>
<v-list-item :to="{ name: 'view_settings', params: {} }"><template #prepend><v-icon icon="fa-solid fa-sliders"></v-icon></template>{{$t('Settings')}}</v-list-item>
<v-list-item :to="{ name: 'ModelListPage', params: {model: 'Food'} }"><template #prepend><v-icon icon="fa-solid fa-folder-tree"></v-icon></template>{{$t('Database')}}</v-list-item>
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-user-shield"></v-icon></template>Admin</v-list-item>-->
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-question"></v-icon></template>Help</v-list-item>-->
<v-divider></v-divider>
<v-list-subheader>Spaces</v-list-subheader>
<v-list-item>Space 1</v-list-item>
<v-list-item>Space 2</v-list-item>
<v-list-item>Space 3</v-list-item>
<v-divider></v-divider>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-database"></v-icon></template>Messages<message-list-dialog></message-list-dialog></v-list-item>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-arrow-right-from-bracket"></v-icon></template>Logout</v-list-item>
<v-list-item link><template #prepend><v-icon icon="fa-solid fa-database"></v-icon></template>{{$t('Messages')}}<message-list-dialog></message-list-dialog></v-list-item>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-arrow-right-from-bracket"></v-icon></template>{{$t('Logout')}}</v-list-item>
</v-list>
</v-menu>
</v-avatar>

View File

@@ -1,7 +1,7 @@
<template>
<!-- TODO label is not showing for some reason, for now in placeholder -->
<!-- TODO support density prop -->
<v-input :hint="hint" persistent-hint :label="label" class="">
<v-input :hint="props.hint" persistent-hint :label="props.label" class="">
<!-- TODO resolve-on-load false for now, race condition with model class, make prop once better solution is found -->
<!-- TODO strange behavior/layering issues with appendTo body, find solution to make it work -->
@@ -28,6 +28,7 @@
:placeholder="label"
:noOptionsText="$t('No_Results')"
:noResultsText="$t('No_Results')"
:loading="loading"
/>
</v-input>
@@ -81,7 +82,8 @@ const props = defineProps({
})
const model = defineModel()
const modelClass = ref({} as GenericModel<any>)
const modelClass = ref({} as GenericModel)
const loading = ref(false)
/**
* create instance of model class when mounted
@@ -95,16 +97,17 @@ onMounted(() => {
* @param query input to search for on the API
*/
function search(query: string) {
return modelClass.value.list({query: query}).then((r) => {
loading.value = true
return modelClass.value.list({query: query, page: 1, pageSize: 25}).then((r: any) => {
if (modelClass.value.model.isPaginated) {
return r.results
} else {
return r
}
}).catch((err) => {
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
}).finally(() => {
loading.value = false
})
}
@@ -115,11 +118,11 @@ function search(query: string) {
* @param select$ reference to multiselect instance
*/
async function createObject(object: any, select$: Multiselect) {
return await modelClass.value.create({name: object[props.itemLabel]}).then((createdObj) => {
return await modelClass.value.create({name: object[props.itemLabel]}).then((createdObj : any) => {
useMessageStore().addMessage(MessageType.SUCCESS, 'Created', 5000, createdObj)
emit('create', object)
return createdObj
}).catch((err) => {
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}

View File

@@ -1,10 +1,10 @@
<template>
<v-card>
<v-card :loading="loading">
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }} <span class="text-disabled">{{ editingObj.name }}</span>
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<v-tabs v-model="tab">
<v-tabs v-model="tab" :disabled="loading">
<v-tab value="food">{{ $t('Food') }}</v-tab>
<v-tab value="properties">{{ $t('Properties') }}</v-tab>
<v-tab value="conversions">{{ $t('Conversion') }}</v-tab>
@@ -14,7 +14,7 @@
<v-card-text>
<v-tabs-window v-model="tab">
<v-tabs-window-item value="food">
<v-form>
<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>
@@ -64,7 +64,7 @@
<template #append>
<v-btn color="edit">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="Property" :item="p"></model-editor-dialog>
<model-edit-dialog model="Property" :item="p"></model-edit-dialog>
</v-btn>
</template>
</v-list-item>
@@ -88,7 +88,7 @@
</v-btn>
<v-btn color="edit" class="float-right d-md-none">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="UnitConversion" :item="uc" @delete="deleteUnitConversion(uc, false)" :disabled-fields="['food']"></model-editor-dialog>
<model-edit-dialog model="UnitConversion" :item="uc" @delete="deleteUnitConversion(uc, false)" :disabled-fields="['food']"></model-edit-dialog>
</v-btn>
</v-card-title>
<v-card-text class="d-none d-md-block">
@@ -138,7 +138,7 @@
</v-tabs-window>
</v-card-text>
<v-card-actions>
<v-card-actions class="float-right">
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
@@ -156,7 +156,7 @@ import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {VNumberInput} from 'vuetify/labs/VNumberInput'
import ModelEditorDialog from "@/components/dialogs/ModelEditorDialog.vue"; //TODO remove once component is out of labs
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
const {t} = useI18n()
@@ -173,7 +173,7 @@ const editingObj = ref({} as Food)
const loading = ref(false)
// object specific data (for selects/display)
const tab = ref("misc")
const tab = ref("food")
const unitConversions = ref([] as UnitConversion[])
@@ -196,7 +196,7 @@ const isUpdate = computed(() => {
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.name}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
@@ -204,10 +204,13 @@ onMounted(() => {
editingObj.value = props.item
} else if (props.itemId != null) {
const api = new ApiApi()
loading.value = true
api.apiFoodRetrieve({id: props.itemId}).then(r => {
editingObj.value = r
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
}).finally(() => {
loading.value = false
})
} else {
// functions to populate defaults for new item

View File

@@ -26,7 +26,7 @@
<v-alert color="warning" variant="tonal">Make sure to save your token after creation as they cannot be viewed afterwards.</v-alert>
<v-btn prepend-icon="$create" color="create" class="mt-2">{{ $t('New') }}
<model-editor-dialog model="AccessToken" @create="loadAccessTokens()" :close-after-create="false"></model-editor-dialog>
<model-edit-dialog model="AccessToken" @create="loadAccessTokens()" :close-after-create="false"></model-edit-dialog>
</v-btn>
<v-list class="mt-2" border>
@@ -39,7 +39,7 @@
<v-chip color="error" class="me-2" v-if="at.expires < DateTime.now().toJSDate()">Expired</v-chip>
<v-btn color="edit">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="AccessToken" :item="at" class="mt-2" @delete="loadAccessTokens()"></model-editor-dialog>
<model-edit-dialog model="AccessToken" :item="at" class="mt-2" @delete="loadAccessTokens()"></model-edit-dialog>
</v-btn>
</template>
</v-list-item>
@@ -53,14 +53,12 @@
<script setup lang="ts">
import {onMounted, ref} from "vue";
import {ApiApi} from "@/openapi";
import {AccessToken, ApiApi} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {DateTime} from "luxon";
import AccessTokenEditor from "@/components/model_editors/AccessTokenEditor.vue";
import ModelEditorDialog from "@/components/dialogs/ModelEditorDialog.vue";
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
const accessTokenList = ref([] as AccessToken[])
const accessToken = ref({} as AccessToken)
onMounted(() => {
loadAccessTokens()

View File

@@ -27,7 +27,7 @@
<p class="text-h6 mt-2">{{ $t('Meal_Types') }}
<v-btn prepend-icon="$create" color="create" size="small" class="float-right">
{{ $t('New') }}
<model-editor-dialog model="MealType" @create="item => mealTypes.push(item)" @delete="deleteMealType"></model-editor-dialog>
<model-edit-dialog model="MealType" @create="item => mealTypes.push(item)" @delete="deleteMealType"></model-edit-dialog>
</v-btn>
</p>
@@ -41,7 +41,7 @@
<v-chip class="me-2">{{ mt.time}}</v-chip>
<v-btn color="edit">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="MealType" :item="mt" @delete="deleteMealType"></model-editor-dialog>
<model-edit-dialog model="MealType" :item="mt" @delete="deleteMealType"></model-edit-dialog>
</v-btn>
</template>
</v-list-item>
@@ -58,7 +58,7 @@ import {useI18n} from "vue-i18n";
import {onMounted, ref} from "vue";
import {ApiApi, MealType} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import ModelEditorDialog from "@/components/dialogs/ModelEditorDialog.vue";
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
const {t} = useI18n()

View File

@@ -2,7 +2,7 @@
<v-form>
<p class="text-h6">{{ $t('SpaceMembers') }}</p>
<v-divider></v-divider>
<p class="text-subtitle-2">{{$t('SpaceMemberHelp')}}</p>
<p class="text-subtitle-2">{{ $t('SpaceMemberHelp') }}</p>
<v-data-table :items="spaceUserSpaces" :headers="userTableHeaders" density="compact" :hide-default-footer="spaceUserSpaces.length < 10" class="mt-3">
<template #item.groups="{item}">
@@ -12,16 +12,16 @@
<template #item.edit="{item}">
<v-btn color="edit" size="small" v-if="item.user.id != useUserPreferenceStore().activeSpace.createdBy.id">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="UserSpace" :item="item" @delete="deleteUserSpace(item)" class="mt-2"></model-editor-dialog>
<model-edit-dialog model="UserSpace" :item="item" @delete="deleteUserSpace(item)" class="mt-2"></model-edit-dialog>
</v-btn>
<v-chip color="edit" v-else>{{$t('Owner')}}</v-chip>
<v-chip color="edit" v-else>{{ $t('Owner') }}</v-chip>
</template>
</v-data-table>
<p class="text-h6 mt-3">{{ $t('Invites') }}
<v-btn size="small" class="float-right" prepend-icon="$create" color="create">
{{ $t('New') }}
<model-editor-dialog model="InviteLink" @delete="deleteInviteLink" @create="item => spaceInviteLinks.push(item)" class="mt-2"></model-editor-dialog>
<model-edit-dialog model="InviteLink" @delete="deleteInviteLink" @create="item => spaceInviteLinks.push(item)" class="mt-2"></model-edit-dialog>
</v-btn>
</p>
<v-divider class="mb-3"></v-divider>
@@ -31,7 +31,7 @@
<btn-copy size="small" :copy-value="inviteLinkUrl(item)" class="me-1"></btn-copy>
<v-btn color="edit" size="small">
<v-icon icon="$edit"></v-icon>
<model-editor-dialog model="InviteLink" :item="item" @delete="deleteInviteLink(item)" class="mt-2"></model-editor-dialog>
<model-edit-dialog model="InviteLink" :item="item" @delete="deleteInviteLink(item)" class="mt-2"></model-edit-dialog>
</v-btn>
</template>
</v-data-table>
@@ -43,14 +43,12 @@
import {onMounted, ref} from "vue";
import {ApiApi, Group, InviteLink, UserSpace} from "@/openapi";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {ApiApi, InviteLink, UserSpace} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {useI18n} from "vue-i18n";
import {DateTime} from "luxon";
import {useClipboard} from "@vueuse/core";
import ModelEditorDialog from "@/components/dialogs/ModelEditorDialog.vue";
import BtnCopy from "@/components/buttons/BtnCopy.vue";
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
const {t} = useI18n()

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "",
"AddAll": "",
"AddFoodToShopping": "",
@@ -55,6 +56,7 @@
"Create_New_Unit": "",
"Current_Period": "",
"Custom Filter": "",
"Database": "",
"Date": "",
"DelayFor": "",
"DelayUntil": "",
@@ -139,6 +141,7 @@
"Load_More": "",
"Log_Cooking": "",
"Log_Recipe_Cooking": "",
"Logout": "",
"Make_Header": "",
"Make_Ingredient": "",
"ManageSubscription": "",
@@ -151,6 +154,7 @@
"Merge": "",
"Merge_Keyword": "",
"Message": "",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Добави",
"AddAll": "",
"AddFoodToShopping": "Добавете {food} към списъка си за пазаруване",
@@ -52,6 +53,7 @@
"Create_New_Unit": "Добавяне на нова единица",
"Current_Period": "Текущ период",
"Custom Filter": "Персонализиран филтър",
"Database": "",
"Date": "Дата",
"DelayFor": "Закъснение за {hours} часа",
"DelayUntil": "Забавяне до",
@@ -134,6 +136,7 @@
"Load_More": "Зареди още",
"Log_Cooking": "Дневник на Готвене",
"Log_Recipe_Cooking": "Дневник на Рецепта за готвене",
"Logout": "",
"Make_Header": "Направете заглавие",
"Make_Ingredient": "Направете съставка",
"ManageSubscription": "",
@@ -145,6 +148,7 @@
"Meal_Types": "Видове хранене",
"Merge": "Обединяване",
"Merge_Keyword": "Обединяване на ключова дума",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Месец",

View File

@@ -2,6 +2,7 @@
"API": "",
"Access_Token": "",
"Account": "",
"Actions": "",
"Add": "",
"AddAll": "",
"AddFoodToShopping": "",
@@ -78,6 +79,7 @@
"CustomTheme": "",
"CustomThemeHelp": "",
"Data_Import_Info": "",
"Database": "",
"Datatype": "",
"Date": "",
"Day": "",
@@ -188,6 +190,7 @@
"Log_Cooking": "Registreu el que s'ha cuinat",
"Log_Recipe_Cooking": "Registre de receptes",
"Logo": "",
"Logout": "",
"Make_Header": "Establiu capçalera",
"Make_Ingredient": "Establiu ingredient",
"ManageSubscription": "",
@@ -201,6 +204,7 @@
"Merge": "",
"Merge_Keyword": "Fusioneu paraula clau",
"Message": "",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Účet",
"Actions": "",
"Add": "Přidat",
"AddAll": "",
"AddFoodToShopping": "Přidat {food} na váš nákupní seznam",
@@ -77,6 +78,7 @@
"CustomTheme": "Vlastní téma",
"CustomThemeHelp": "Přepsat styly vybraného motivu nahráním vlastního souboru CSS.",
"Data_Import_Info": "Rozšiřte svůj prostor o seznamy potravin, jednotek a dalších položek spravovaných komunitou, a vylepšete tak svoji sbírku receptů.",
"Database": "",
"Datatype": "Datový typ",
"Date": "Datum",
"Day": "Den",
@@ -187,6 +189,7 @@
"Log_Cooking": "Zaznamenat vaření",
"Log_Recipe_Cooking": "Záznam vaření receptu",
"Logo": "Logo",
"Logout": "",
"Make_Header": "Použij jako nadpis",
"Make_Ingredient": "Použij jako ingredienci",
"ManageSubscription": "",
@@ -200,6 +203,7 @@
"Merge": "Spojit",
"Merge_Keyword": "Sloučit štítek",
"Message": "Zpráva",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Měsíc",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Bruger",
"Actions": "",
"Add": "Tilføj",
"AddAll": "",
"AddFoodToShopping": "Tilføj {food} til indkøbsliste",
@@ -70,6 +71,7 @@
"Current_Period": "Nuværende periode",
"Custom Filter": "Tilpasset filter",
"Data_Import_Info": "Udbyg dit Space og gør din opskriftsamling bedre ved at importere en netværkskurateret liste af ingredienser, enheder og mere.",
"Database": "",
"Datatype": "Datatype",
"Date": "Dato",
"Day": "Dag",
@@ -174,6 +176,7 @@
"Load_More": "Indlæs mere",
"Log_Cooking": "Noter tilberedning",
"Log_Recipe_Cooking": "Noter tilberedning af opskrift",
"Logout": "",
"Make_Header": "Opret rubrik",
"Make_Ingredient": "Opret ingredient",
"ManageSubscription": "",
@@ -187,6 +190,7 @@
"Merge": "Sammenflet",
"Merge_Keyword": "Sammenflet nøgleord",
"Message": "Besked",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Måned",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "Zugriffstoken",
"Account": "Konto",
"Actions": "Aktionen",
"Add": "Hinzufügen",
"AddAll": "Alle Hinzufügen",
"AddFoodToShopping": "Fügen Sie {food} zur Einkaufsliste hinzu",
@@ -79,6 +80,7 @@
"CustomTheme": "Benutzerdefiniertes Theme",
"CustomThemeHelp": "Überschreiben Sie die Stile des ausgewählten Themes, indem Sie eine eigene CSS-Datei hochladen.",
"Data_Import_Info": "Verbessern Sie Ihren Space, indem Sie eine von der Community kuratierte Liste von Lebensmitteln, Einheiten und mehr importieren, um Ihre Rezeptsammlung zu verbessern.",
"Database": "Datenbank",
"Datatype": "Datentyp",
"Date": "Datum",
"Day": "Tag",
@@ -190,6 +192,7 @@
"Log_Cooking": "Kochen protokollieren",
"Log_Recipe_Cooking": "Kochen protokollieren",
"Logo": "Logo",
"Logout": "Ausloggen",
"Make_Header": "In Überschrift wandeln",
"Make_Ingredient": "In Zutat umwandeln",
"ManageSubscription": "Tarfi verwalten",
@@ -203,6 +206,7 @@
"Merge": "Zusammenführen",
"Merge_Keyword": "Schlagworte zusammenführen",
"Message": "Nachricht",
"Messages": "Nachrichten",
"Miscellaneous": "Sonstige",
"Monday": "Montag",
"Month": "Monat",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Λογαριασμός",
"Actions": "",
"Add": "Προσθήκη",
"AddAll": "",
"AddFoodToShopping": "Προσθήκη του φαγητού {food} στη λίστα αγορών σας",
@@ -69,6 +70,7 @@
"Current_Period": "Τρέχουσα περίοδος",
"Custom Filter": "Προσαρμοσμένο φίλτρο",
"Data_Import_Info": "Βελτιώστε τον χώρο και τη συλλογή συνταγών σας κάνοντας εισαγωγή μιας λίστας από φαγητά, μονάδες μέτρησης κ.α., επιμελημένη από την κοινότητα.",
"Database": "",
"Datatype": "Τύπος δεδομένων",
"Date": "Ημερομηνία",
"Day": "Ημέρα",
@@ -169,6 +171,7 @@
"Load_More": "Φόρτωση περισσότερων",
"Log_Cooking": "Καταγραφή μαγειρέματος",
"Log_Recipe_Cooking": "Καταγραφή εκτέλεσης συνταγής",
"Logout": "",
"Make_Header": "Δημιουργία κεφαλίδας",
"Make_Ingredient": "Δημιουργία υλικού",
"ManageSubscription": "",
@@ -182,6 +185,7 @@
"Merge": "Συγχώνευση",
"Merge_Keyword": "Συγχώνευση λέξης-κλειδί",
"Message": "Μήνυμα",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Μήνας",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "Access Token",
"Account": "Account",
"Actions": "Actions",
"Add": "Add",
"AddAll": "Add all",
"AddFoodToShopping": "Add {food} to your shopping list",
@@ -78,6 +79,7 @@
"CustomTheme": "Custom Theme",
"CustomThemeHelp": "Override styles of the selected theme by uploading a custom CSS file.",
"Data_Import_Info": "Enhance your Space by importing a community curated list of foods, units and more to improve your recipe collection.",
"Database": "Database",
"Datatype": "Datatype",
"Date": "Date",
"Day": "Day",
@@ -190,6 +192,7 @@
"Log_Cooking": "Log Cooking",
"Log_Recipe_Cooking": "Log Recipe Cooking",
"Logo": "Logo",
"Logout": "Logout",
"Make_Header": "Make Header",
"Make_Ingredient": "Make Ingredient",
"ManageSubscription": "Manage subscription",
@@ -203,6 +206,7 @@
"Merge": "Merge",
"Merge_Keyword": "Merge Keyword",
"Message": "Message",
"Messages": "Messages",
"Miscellaneous": "Miscellaneous",
"Monday": "Monday",
"Month": "Month",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Cuenta",
"Actions": "",
"Add": "Añadir",
"AddAll": "",
"AddFoodToShopping": "Añadir {food} a la lista de la compra",
@@ -78,6 +79,7 @@
"CustomTheme": "Tema Personalizado",
"CustomThemeHelp": "Anular los estilos del tema seleccionado cargando un archivo CSS personalizado.",
"Data_Import_Info": "Mejora tu Espacio importando listas de alimentos, unidades y más seleccionados por la comunidad, para mejorar tu colección de recetas.",
"Database": "",
"Datatype": "Tipo de Datos",
"Date": "Fecha",
"Day": "Día",
@@ -189,6 +191,7 @@
"Log_Cooking": "Registrar Cocinada",
"Log_Recipe_Cooking": "Registro de recetas",
"Logo": "Logotipo",
"Logout": "",
"Make_Header": "Establecer Cabecera",
"Make_Ingredient": "Establecer Ingrediente",
"ManageSubscription": "",
@@ -202,6 +205,7 @@
"Merge": "Unificar",
"Merge_Keyword": "Fusionar palabra clave",
"Message": "Mensaje",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mes",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Lisää",
"AddAll": "",
"Add_Step": "Lisää Vaihe",
@@ -35,6 +36,7 @@
"Create_New_Shopping Category": "Luo Uusi Ostoskategoria",
"Create_New_Unit": "Lisää Uusi Yksikkö",
"Current_Period": "Nykyinen Jakso",
"Database": "",
"Date": "Päivämäärä",
"Delete": "Poista",
"DeleteConfirmQuestion": "",
@@ -89,6 +91,7 @@
"Load_More": "Lataa Lisää",
"Log_Cooking": "Kirjaa kokkaus",
"Log_Recipe_Cooking": "Kirjaa Reseptin Kokkaus",
"Logout": "",
"Make_Header": "Valmista Otsikko",
"Make_Ingredient": "Valmista Ainesosa",
"ManageSubscription": "",
@@ -100,6 +103,7 @@
"Meal_Types": "Ateriatyypit",
"Merge": "Yhdistä",
"Merge_Keyword": "Yhdistä Avainsana",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Kuukausi",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Compte",
"Actions": "",
"Add": "Ajouter",
"AddAll": "",
"AddFoodToShopping": "Ajouter laliment {food} à votre liste de courses",
@@ -77,6 +78,7 @@
"CustomTheme": "Thème personnalisé",
"CustomThemeHelp": "Remplacer les styles du thème sélectionné en téléchargeant un fichier CSS personnalisé.",
"Data_Import_Info": "Améliorez votre groupe en important des données partagées par la communauté afin d'améliorer vos collections de recettes : listes d'aliments, unités et plus encore.",
"Database": "",
"Datatype": "Type de donnée",
"Date": "Date",
"Day": "Jour",
@@ -188,6 +190,7 @@
"Log_Cooking": "Marquer comme cuisiné",
"Log_Recipe_Cooking": "Marquer la recette comme cuisinée",
"Logo": "Logo",
"Logout": "",
"Make_Header": "Créer un en-tête",
"Make_Ingredient": "Créer un ingrédient",
"ManageSubscription": "",
@@ -201,6 +204,7 @@
"Merge": "Fusionner",
"Merge_Keyword": "Fusionner le mot-clé",
"Message": "Message",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mois",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "חשבון",
"Actions": "",
"Add": "הוספה",
"AddAll": "",
"AddFoodToShopping": "הוסף {מזון} לרשימת הקניות",
@@ -78,6 +79,7 @@
"CustomTheme": "ערכת נושא מותאמת אישית",
"CustomThemeHelp": "העלאה של קובץ CSS מותאם אישית תדרוס את העיצוב של הערכת נושא שנבחרה.",
"Data_Import_Info": "שפר את המרחב שלך ע\"י ייבוא רשימת משאבים קהילתית כמו מאכלים, ערכים ועוד.",
"Database": "",
"Datatype": "סוג מידע",
"Date": "תאריך",
"Day": "יום",
@@ -189,6 +191,7 @@
"Log_Cooking": "רשום הכנת מתכון",
"Log_Recipe_Cooking": "רשום בישול מתכון",
"Logo": "לוגו",
"Logout": "",
"Make_Header": "הפוך לכותרת",
"Make_Ingredient": "הפוך למרכיב",
"ManageSubscription": "",
@@ -202,6 +205,7 @@
"Merge": "איחוד",
"Merge_Keyword": "איחוד מילת מפתח",
"Message": "הודעה",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "חודש",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Fiók",
"Actions": "",
"Add": "Hozzáadás",
"AddAll": "",
"AddFoodToShopping": "{food} hozzáadása bevásárlólistához",
@@ -69,6 +70,7 @@
"Current_Period": "Jelenlegi periódus",
"Custom Filter": "Egyéni szűrő",
"Data_Import_Info": "Bővítse Terét alapanyagok, mértékegységek és egyebek közösség által összeállított listájának importálásával, hogy ezzel is javítsa a receptgyűjteményét.",
"Database": "",
"Datatype": "Adattípus",
"Date": "Dátum",
"Day": "Nap",
@@ -170,6 +172,7 @@
"Load_More": "Továbbiak betöltése",
"Log_Cooking": "Főzés naplózása",
"Log_Recipe_Cooking": "Főzés naplózása",
"Logout": "",
"Make_Header": "Átalakítás címsorra",
"Make_Ingredient": "Összetevő létrehozása",
"ManageSubscription": "",
@@ -183,6 +186,7 @@
"Merge": "Összefűzés",
"Merge_Keyword": "Kulcsszó összevonása",
"Message": "Üzenet",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Hónap",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "",
"AddAll": "",
"Add_nutrition_recipe": "Ավելացնել սննդայնություն բաղադրատոմսին",
@@ -22,6 +23,7 @@
"Create_New_Food": "Ավելացնել նոր սննդամթերք",
"Create_New_Keyword": "Ավելացնել նոր բանալի բառ",
"Create_New_Shopping Category": "Ստեղծել գնումների նոր կատեգորիա",
"Database": "",
"Date": "",
"Delete": "",
"DeleteConfirmQuestion": "",
@@ -60,11 +62,13 @@
"Load_More": "",
"Log_Cooking": "Գրանցել եփելը",
"Log_Recipe_Cooking": "Գրանցել բաղադրատոմսի օգտագործում",
"Logout": "",
"ManageSubscription": "",
"Manage_Books": "Կարգավորել Գրքերը",
"Meal_Plan": "Ճաշացուցակ",
"Merge": "Միացնել",
"Merge_Keyword": "Միացնել բանալի բառը",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Move": "Տեղափոխել",

View File

@@ -2,6 +2,7 @@
"API": "",
"Access_Token": "",
"Account": "",
"Actions": "",
"Add": "Tambahkan",
"AddAll": "",
"AddFoodToShopping": "",
@@ -60,6 +61,7 @@
"Create_New_Unit": "",
"Current_Period": "",
"Custom Filter": "",
"Database": "",
"Date": "Tanggal",
"Day": "",
"Days": "",
@@ -155,6 +157,7 @@
"Load_More": "Muat lebih banyak",
"Log_Cooking": "Log Memasak",
"Log_Recipe_Cooking": "Log Resep Memasak",
"Logout": "",
"Make_Header": "Buat Header",
"Make_Ingredient": "Buat bahan",
"ManageSubscription": "",
@@ -168,6 +171,7 @@
"Merge": "Menggabungkan",
"Merge_Keyword": "Gabungkan Kata Kunci",
"Message": "",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "",

View File

@@ -2,6 +2,7 @@
"API": "",
"Access_Token": "",
"Account": "",
"Actions": "",
"Add": "",
"AddAll": "",
"AddFoodToShopping": "",
@@ -78,6 +79,7 @@
"CustomTheme": "",
"CustomThemeHelp": "",
"Data_Import_Info": "",
"Database": "",
"Datatype": "",
"Date": "",
"Day": "",
@@ -188,6 +190,7 @@
"Log_Cooking": "",
"Log_Recipe_Cooking": "",
"Logo": "",
"Logout": "",
"Make_Header": "",
"Make_Ingredient": "",
"ManageSubscription": "",
@@ -201,6 +204,7 @@
"Merge": "",
"Merge_Keyword": "",
"Message": "",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Account",
"Actions": "",
"Add": "Aggiungi",
"AddAll": "",
"AddFoodToShopping": "Aggiungi {food} alla tua lista della spesa",
@@ -64,6 +65,7 @@
"Create_New_Unit": "Aggiungi nuova unità",
"Current_Period": "Periodo attuale",
"Custom Filter": "Filtro personalizzato",
"Database": "",
"Date": "Data",
"Day": "Giorno",
"Days": "Giorni",
@@ -160,6 +162,7 @@
"Load_More": "Carica di più",
"Log_Cooking": "Registro ricette cucinate",
"Log_Recipe_Cooking": "Aggiungi a ricette cucinate",
"Logout": "",
"Make_Header": "Crea Intestazione",
"Make_Ingredient": "Crea Ingrediente",
"ManageSubscription": "",
@@ -173,6 +176,7 @@
"Merge": "Unisci",
"Merge_Keyword": "Unisci parola chiave",
"Message": "Messaggio",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mese",

View File

@@ -2,6 +2,7 @@
"API": "",
"Access_Token": "",
"Account": "",
"Actions": "",
"Add": "",
"AddAll": "",
"AddFoodToShopping": "",
@@ -70,6 +71,7 @@
"Current_Period": "",
"Custom Filter": "",
"Data_Import_Info": "",
"Database": "",
"Datatype": "",
"Date": "",
"Day": "",
@@ -172,6 +174,7 @@
"Load_More": "Įkelti daugiau",
"Log_Cooking": "Užregistruoti patiekalo gaminimą",
"Log_Recipe_Cooking": "Užregistruoti recepto pagaminimą",
"Logout": "",
"Make_Header": "Padaryti antraštę",
"Make_Ingredient": "Padaryti ingredientą",
"ManageSubscription": "",
@@ -185,6 +188,7 @@
"Merge": "",
"Merge_Keyword": "Sujungti raktažodį",
"Message": "",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "",
"Actions": "",
"Add": "Legg til",
"AddAll": "",
"AddFoodToShopping": "Legg til {food] i handlelisten din",
@@ -67,6 +68,7 @@
"Create_New_Unit": "Opprett ny enhet",
"Current_Period": "Gjeldende periode",
"Custom Filter": "Egendefinert Filter",
"Database": "",
"Datatype": "Data-type",
"Date": "Dato",
"Day": "Dag",
@@ -167,6 +169,7 @@
"Load_More": "Last inn flere",
"Log_Cooking": "Loggfør tilbereding",
"Log_Recipe_Cooking": "Logg oppskriftsbruk",
"Logout": "",
"Make_Header": "Bruk som overskrift",
"Make_Ingredient": "Bruk som ingrediens",
"ManageSubscription": "",
@@ -180,6 +183,7 @@
"Merge": "Slå sammen",
"Merge_Keyword": "Slå sammen nøkkelord",
"Message": "Melding",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Måned",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Account",
"Actions": "",
"Add": "Voeg toe",
"AddAll": "",
"AddFoodToShopping": "Voeg {food} toe aan je boodschappenlijst",
@@ -71,6 +72,7 @@
"Current_Period": "Huidige periode",
"Custom Filter": "Aangepast filter",
"Data_Import_Info": "Verbeter je Space door een door de community samengestelde lijst van voedingsmiddelen, eenheden en meer te importeren om je receptenverzameling te verbeteren.",
"Database": "",
"Datatype": "Datatype",
"Date": "Datum",
"Day": "Dag",
@@ -171,6 +173,7 @@
"Load_More": "Laad meer",
"Log_Cooking": "Log Bereiding",
"Log_Recipe_Cooking": "Bereiding loggen",
"Logout": "",
"Make_Header": "Maak Koptekst",
"Make_Ingredient": "Maak Ingrediënt",
"ManageSubscription": "",
@@ -184,6 +187,7 @@
"Merge": "Samenvoegen",
"Merge_Keyword": "Voeg Etiket samen",
"Message": "Bericht",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Maand",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Konto",
"Actions": "",
"Add": "Dodaj",
"AddAll": "",
"AddFoodToShopping": "Dodaj {food} do swojej listy zakupów",
@@ -79,6 +80,7 @@
"CustomTheme": "Własny motyw",
"CustomThemeHelp": "Zastąp style wybranego motywu, przesyłając własny plik CSS.",
"Data_Import_Info": "Wzbogać swoją Przestrzeń, importując wyselekcjonowaną przez społeczność listę żywności, jednostek i nie tylko, aby ulepszyć swoją kolekcję przepisów.",
"Database": "",
"Datatype": "Typ danych",
"Date": "Data",
"Day": "Dzień",
@@ -190,6 +192,7 @@
"Log_Cooking": "Zanotuj ugotowanie",
"Log_Recipe_Cooking": "Zaloguj gotowanie przepisu",
"Logo": "Logo",
"Logout": "",
"Make_Header": "Utwórz nagłówek",
"Make_Ingredient": "Utwórz składnik",
"ManageSubscription": "",
@@ -203,6 +206,7 @@
"Merge": "Scal",
"Merge_Keyword": "Scal słowa kluczowe",
"Message": "Wiadomość",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Miesiąc",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Adicionar",
"AddAll": "",
"AddFoodToShopping": "Adicionar {food} à sua lista de compras",
@@ -54,6 +55,7 @@
"Create_New_Unit": "Adicionar nova unidade",
"Current_Period": "Período atual",
"Custom Filter": "",
"Database": "",
"Date": "Data",
"Decimals": "Casas decimais",
"Default_Unit": "Unidade padrão",
@@ -131,6 +133,7 @@
"Load_More": "Carregar Mais",
"Log_Cooking": "Registrar Culinária",
"Log_Recipe_Cooking": "Registrar Receitas de Culinária",
"Logout": "",
"Make_Header": "Tornar cabeçalho",
"Make_Ingredient": "Fazer ingrediente",
"ManageSubscription": "",
@@ -142,6 +145,7 @@
"Meal_Types": "Tipos de refeições",
"Merge": "Juntar",
"Merge_Keyword": "Unir palavra-chave",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mês",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Conta",
"Actions": "",
"Add": "Adicionar",
"AddAll": "",
"AddFoodToShopping": "Incluir {food} na sua lista de compras",
@@ -76,6 +77,7 @@
"CustomTheme": "Tema Personalizado",
"CustomThemeHelp": "Substituir estilos do tema selecionado fazendo upload de um arquivo CSS personalizado.",
"Data_Import_Info": "Enriqueça seu espaço importando uma lista comunitariamente curada de alimentos, unidades e mais para melhorar sua coleção de receitas.",
"Database": "",
"Datatype": "Tipo Dado",
"Date": "Data",
"Day": "Dia",
@@ -182,6 +184,7 @@
"Load_More": "Carregar mais",
"Log_Cooking": "Registro de Cozinha",
"Log_Recipe_Cooking": "Registrar receitas feitas",
"Logout": "",
"Make_Header": "Criar cabeçalho",
"Make_Ingredient": "Criar Ingrediente",
"ManageSubscription": "",
@@ -195,6 +198,7 @@
"Merge": "Mesclar",
"Merge_Keyword": "Mesclar palavra-chave",
"Message": "Mensagem",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mês",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Cont",
"Actions": "",
"Add": "Adaugă",
"AddAll": "",
"AddFoodToShopping": "Adăugă {food} în lista de cumpărături",
@@ -66,6 +67,7 @@
"Create_New_Unit": "Adaugă unitate nouă",
"Current_Period": "Perioada curentă",
"Custom Filter": "Filtru personalizat",
"Database": "",
"Date": "Dată",
"Day": "Zi",
"Days": "Zile",
@@ -164,6 +166,7 @@
"Load_More": "Încărcați mai mult",
"Log_Cooking": "Jurnal de pregătire",
"Log_Recipe_Cooking": "Jurnalul rețetelor de pregătire",
"Logout": "",
"Make_Header": "Creare antet",
"Make_Ingredient": "Create ingredient",
"ManageSubscription": "",
@@ -177,6 +180,7 @@
"Merge": "Unire",
"Merge_Keyword": "Unește cuvânt cheie",
"Message": "Mesaj",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Lună",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Добавить",
"AddAll": "",
"AddFoodToShopping": "Добавить {food} в ваш список покупок",
@@ -46,6 +47,7 @@
"Create_New_Unit": "Добавить единицу измерения",
"Current_Period": "Текущий период",
"Custom Filter": "Пользовательский фильтр",
"Database": "",
"Date": "Дата",
"DelayFor": "Отложить на {hours} часов",
"Delete": "Удалить",
@@ -120,6 +122,7 @@
"Load_More": "Загрузить еще",
"Log_Cooking": "Журнал приготовления",
"Log_Recipe_Cooking": "Журнал приготовления",
"Logout": "",
"Make_Header": "Создание Заголовка",
"Make_Ingredient": "Создание инградиента",
"ManageSubscription": "",
@@ -131,6 +134,7 @@
"Meal_Types": "Типы питания",
"Merge": "Объединить",
"Merge_Keyword": "Объеденить ключевые слова",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Месяц",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Dodaj",
"AddAll": "",
"AddFoodToShopping": "Dodaj {food} v nakupovalni listek",
@@ -46,6 +47,7 @@
"Create_New_Unit": "Dodaj novo enoto",
"Current_Period": "Trenutno obdobje",
"Data_Import_Info": "Izboljšajte svoj prostor z uvozom seznama živil, enot in drugega, ker je pripravila skupnost, ter s tem izboljšajte svojo zbirko receptov.",
"Database": "",
"Date": "Datum",
"DelayFor": "Zamakni za {hours} ur",
"DelayUntil": "Zamakni do",
@@ -116,6 +118,7 @@
"Load_More": "Naloži več",
"Log_Cooking": "Zgodovina kuhanja",
"Log_Recipe_Cooking": "Logiraj recept za kuhanje",
"Logout": "",
"Make_Header": "Ustvari glavo",
"Make_Ingredient": "Ustvari sestavino",
"ManageSubscription": "",
@@ -127,6 +130,7 @@
"Meal_Types": "Tipi obroka",
"Merge": "Združi",
"Merge_Keyword": "Združi ključno besedo",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Mesec",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Konto",
"Actions": "",
"Add": "Lägg till",
"AddAll": "",
"AddFoodToShopping": "Lägg till {food} på din inköpslista",
@@ -79,6 +80,7 @@
"CustomTheme": "Anpassat tema",
"CustomThemeHelp": "Skriv över nuvarande tema genom att ladda upp en anpassad CSS-fil.",
"Data_Import_Info": "Förbättra din samling genom att importera en framtagen lista av livsmedel, enheter och mer för att förbättra din recept-samling.",
"Database": "",
"Datatype": "Datatyp",
"Date": "Datum",
"Day": "Dag",
@@ -190,6 +192,7 @@
"Log_Cooking": "Logga tillagning",
"Log_Recipe_Cooking": "Logga tillagningen av receptet",
"Logo": "Logga",
"Logout": "",
"Make_Header": "Skapa rubrik",
"Make_Ingredient": "Skapa ingrediens",
"ManageSubscription": "",
@@ -203,6 +206,7 @@
"Merge": "Slå samman",
"Merge_Keyword": "Slå samman nyckelord",
"Message": "Meddelande",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Månad",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "Hesap",
"Actions": "",
"Add": "Ekle",
"AddAll": "",
"AddFoodToShopping": "{food}'ı alışveriş listenize ekleyin",
@@ -78,6 +79,7 @@
"CustomTheme": "Özel Tema",
"CustomThemeHelp": "Özel bir CSS dosyası yükleyerek seçilen temanın stillerini geçersiz kılın.",
"Data_Import_Info": "Tarif koleksiyonunuzu geliştirmek için topluluk tarafından oluşturulmuş yiyecek, birim ve daha fazlasını olduğu listeleri içeri aktararak Alanlarınızı genişletin.",
"Database": "",
"Datatype": "Veri tipi",
"Date": "Tarih",
"Day": "Gün",
@@ -189,6 +191,7 @@
"Log_Cooking": "Günlük Pişirme",
"Log_Recipe_Cooking": "Günlük Tarif Pişirme",
"Logo": "Logo",
"Logout": "",
"Make_Header": "Başlık Oluştur",
"Make_Ingredient": "Malzeme Oluştur",
"ManageSubscription": "",
@@ -202,6 +205,7 @@
"Merge": "Birleştir",
"Merge_Keyword": "Anahtar Kelimeyi Birleştir",
"Message": "Mesaj",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Ay",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "Додати",
"AddAll": "",
"AddFoodToShopping": "Додати {food} до вашого списку покупок",
@@ -58,6 +59,7 @@
"Create_New_Unit": "Додати Нову Одиницю",
"Current_Period": "Теперішній Період",
"Custom Filter": "",
"Database": "",
"Date": "Дата",
"Decimals": "Десятки",
"Default_Unit": "Одиниця замовчуванням",
@@ -145,6 +147,7 @@
"Load_More": "Завантажити більше",
"Log_Cooking": "",
"Log_Recipe_Cooking": "",
"Logout": "",
"Make_Header": "",
"Make_Ingredient": "",
"ManageSubscription": "",
@@ -156,6 +159,7 @@
"Meal_Types": "Типи страви",
"Merge": "Об'єднати",
"Merge_Keyword": "Об'єднати Ключове слово",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "Місяць",

View File

@@ -2,6 +2,7 @@
"API": "API",
"Access_Token": "",
"Account": "账户",
"Actions": "",
"Add": "添加",
"AddAll": "",
"AddFoodToShopping": "添加 {food} 到购物清单",
@@ -76,6 +77,7 @@
"CustomTheme": "自定义主题",
"CustomThemeHelp": "通过上传自定义 CSS 文件覆盖所选主题的样式。",
"Data_Import_Info": "通过导入社区精选的食物、单位等列表来增强您的空间,以提升您的食谱收藏。",
"Database": "",
"Datatype": "数据类型",
"Date": "日期",
"Day": "天",
@@ -185,6 +187,7 @@
"Log_Cooking": "烹饪记录",
"Log_Recipe_Cooking": "食谱烹饪记录",
"Logo": "徽标",
"Logout": "",
"Make_Header": "显示注意事项",
"Make_Ingredient": "制作食材",
"ManageSubscription": "",
@@ -198,6 +201,7 @@
"Merge": "合并",
"Merge_Keyword": "合并关键词",
"Message": "信息",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"Month": "月份",

View File

@@ -1,5 +1,6 @@
{
"Access_Token": "",
"Actions": "",
"Add": "",
"AddAll": "",
"Add_nutrition_recipe": "為食譜添加營養資訊",
@@ -17,6 +18,7 @@
"Copy": "",
"Copy_template_reference": "複製參考模板",
"Create": "",
"Database": "",
"Date": "",
"Delete": "",
"DeleteConfirmQuestion": "",
@@ -45,9 +47,11 @@
"Load_More": "",
"Log_Cooking": "",
"Log_Recipe_Cooking": "記錄食譜烹飪",
"Logout": "",
"ManageSubscription": "",
"Manage_Books": "管理書籍",
"Meal_Plan": "膳食計劃",
"Messages": "",
"Miscellaneous": "",
"Monday": "",
"New": "",

View File

@@ -1,5 +1,14 @@
<template>
<v-container>
<v-row>
<v-col>
<v-card >
<v-card-text class="pt-2 pb-2">
<v-btn variant="flat" @click="router.go(-1)" prepend-icon="fa-solid fa-arrow-left">{{ $t('Back')}}</v-btn>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row>
<v-col>
<food-editor :item-id="id"></food-editor>
@@ -13,12 +22,14 @@
import FoodEditor from "@/components/model_editors/FoodEditor.vue";
import {onMounted, ref} from "vue";
import {ApiApi, Food} from "@/openapi";
import {useRouter} from "vue-router";
const props = defineProps({
model: {type: String, default: 'Food'},
id: {type: String, required: true},
})
const router = useRouter()
</script>

View File

@@ -31,8 +31,7 @@
:items-length="itemCount"
:loading="loading"
:search="searchQuery"
:headers="tableHeaders"
:headers="genericModel.getTableHeaders()"
:items-per-page-options="itemsPerPageOptions"
:show-select="tableShowSelect"
>
@@ -44,10 +43,7 @@
</v-data-table-server>
</v-col>
</v-row>
</v-container>
</template>
<script setup lang="ts">
@@ -69,10 +65,9 @@ import {
TAutomation,
TUserFile, TCookLog, TViewLog
} from "@/types/Models";
import {ca} from "vuetify/locale";
import {ApiApi} from "@/openapi";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import ModelEditorDialog from "@/components/dialogs/ModelEditorDialog.vue";
import {VDataTable} from "vuetify/components";
type VDataTableProps = InstanceType<typeof VDataTable>['$props']
const {t} = useI18n()
@@ -87,10 +82,10 @@ const itemsPerPageOptions = [
{value: 50, title: '50'},
]
const tableHeaders = [
const tableHeaders : VDataTableProps['headers'] = [
{title: t('Name'), key: 'name'},
{title: t('Category'), key: 'supermarketCategory.name'},
{title: t('Edit'), key: 'action', align: 'end'},
{title: t('Actions'), key: 'action', align: 'end'},
]
const tableShowSelect = ref(true)
@@ -107,7 +102,7 @@ const genericModel = ref({} as GenericModel)
// watch for changes to the prop in case its changed
watch(() => props.model, () => {
console.log('loading model ', props.model)
genericModel.value = getGenericModelFromString(props.model)
genericModel.value = getGenericModelFromString(props.model, t)
loadItems({page: 1, itemsPerPage: 10})
})
@@ -117,10 +112,10 @@ watch(() => props.model, () => {
onBeforeMount(() => {
try {
genericModel.value = getGenericModelFromString(props.model)
genericModel.value = getGenericModelFromString(props.model, t)
} catch (Error) {
console.error('Invalid model passed to ModelListPage, loading Food instead')
genericModel.value = getGenericModelFromString('Food')
genericModel.value = getGenericModelFromString('Food', t)
}
})

View File

@@ -11,17 +11,21 @@ import {
SupermarketCategory as ISupermarketCategory,
PropertyType as IPropertyType, ApiFoodListRequest, ApiUnitListRequest,
} from "@/openapi";
import {VDataTable} from "vuetify/components";
import {useI18n} from "vue-i18n";
type VDataTableProps = InstanceType<typeof VDataTable>['$props']
/**
* returns a GenericModel instance with the given model type
* throws and error if no model with the given name exist
* @param modelName name of the model
* @param t translation function from calling context
* @return instance of GenericModel
*/
export function getGenericModelFromString(modelName: String) {
export function getGenericModelFromString(modelName: string, t: any) {
if (SUPPORTED_MODELS.has(modelName)) {
return new GenericModel(SUPPORTED_MODELS.get(modelName))
return new GenericModel(SUPPORTED_MODELS.get(modelName), t)
} else {
throw Error(`Model ${modelName} not in SUPPORTED_MODELS`)
}
@@ -36,6 +40,20 @@ type GenericListRequestParameter = {
query: string,
}
/**
* if a model is shown in a table, these are the table headers
* structure similar to the VDataTableHeaders but simplified and
* extended by a "hidden" attribute to allow custom table configuration for users
*
* converted to VDataTableHeaders by the GenericModel instance
*/
type ModelTableHeaders = {
title: string,
key: string,
align: 'end'|'start',
hidden?: boolean,
}
/**
* custom type containing all attributes needed by the generic model system to properly handle all functions
*/
@@ -44,16 +62,14 @@ type Model = {
localizationKey: string,
icon: string,
disableList: boolean | undefined,
disableRetrieve: boolean | undefined,
disableCreate: boolean | undefined,
disableDelete: boolean | undefined,
disableList?: boolean | undefined,
disableRetrieve?: boolean | undefined,
disableCreate?: boolean | undefined,
disableDelete?: boolean | undefined,
isPaginated: boolean | undefined,
// table headers
// canCreate
// canDelete
tableHeaders: ModelTableHeaders[],
}
export let SUPPORTED_MODELS = new Map<string, Model>()
@@ -63,6 +79,13 @@ export const TFood = {
icon: 'fa-solid fa-carrot',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Category', key: 'supermarketCategory.name'},
{title: 'Plural', key: 'plural', hidden: true},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TFood.name, TFood)
@@ -72,6 +95,12 @@ export const TUnit = {
icon: 'fa-solid fa-scale-balanced',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Plural', key: 'plural', hidden: true},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TUnit.name, TUnit)
@@ -81,6 +110,11 @@ export const TKeyword = {
icon: 'fa-solid fa-tags',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TKeyword.name, TKeyword)
@@ -90,6 +124,11 @@ export const TRecipe = {
icon: 'fa-solid fa-book',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TRecipe.name, TRecipe)
@@ -99,6 +138,11 @@ export const TMealType = {
icon: 'fa-solid fa-utensils',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TMealType.name, TMealType)
@@ -111,6 +155,11 @@ export const TUser = {
disableDelete: true,
isPaginated: false,
tableHeaders: [
{title: 'Name', key: 'displayName'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TUser.name, TUser)
@@ -120,6 +169,11 @@ export const TSupermarket = {
icon: 'fa-solid fa-store',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TSupermarket.name, TSupermarket)
@@ -129,6 +183,11 @@ export const TSupermarketCategory = {
icon: 'fa-solid fa-boxes-stacked',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TSupermarketCategory.name, TSupermarketCategory)
@@ -138,6 +197,11 @@ export const TPropertyType = {
icon: 'fa-solid fa-database',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TPropertyType.name, TPropertyType)
@@ -147,6 +211,15 @@ export const TUnitConversion = {
icon: 'fa-solid fa-exchange-alt',
isPaginated: true,
tableHeaders: [
{title: 'Food', key: 'food.name'},
{title: 'base_amount', key: 'baseAmount'},
{title: 'base_unit', key: 'baseUnit.name'},
{title: 'converted_amount', key: 'convertedAmount'},
{title: 'converted_unit', key: 'convertedUnit.name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TUnitConversion.name, TUnitConversion)
@@ -156,6 +229,11 @@ export const TUserFile = {
icon: 'fa-solid fa-file',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TUserFile.name, TUserFile)
@@ -165,6 +243,11 @@ export const TAutomation = {
icon: 'fa-solid fa-robot',
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TAutomation.name, TAutomation)
@@ -174,6 +257,12 @@ export const TCookLog = {
icon: 'fa-solid fa-table-list',
isPaginated: true,
tableHeaders: [
{title: 'Recipe', key: 'recipe'},
{title: 'Created', key: 'createdAt'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TCookLog.name, TCookLog)
@@ -183,6 +272,12 @@ export const TViewLog = {
icon: 'fa-solid fa-clock-rotate-left',
isPaginated: true,
tableHeaders: [
{title: 'Recipe', key: 'recipe'},
{title: 'Created', key: 'createdAt'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TViewLog.name, TViewLog)
@@ -208,10 +303,29 @@ export class GenericModel {
api: Object
model: Model
// TODO find out the type of the t useI18n object and use it here
t: any
constructor(model: Model) {
/**
* create a new generic model based on the given Model type
* @param model instance of Model type
* @param t translation function from calling context
*/
constructor(model: Model, t: any) {
this.model = model
this.api = new ApiApi()
this.t = t
}
getTableHeaders(): VDataTableProps['headers'][]{
let tableHeaders: VDataTableProps['headers'][] = []
this.model.tableHeaders.forEach(header => {
if(!header.hidden){
header.title = this.t(header.title)
tableHeaders.push(header as unknown as VDataTableProps['headers'])
}
})
return tableHeaders
}
/**
@@ -237,7 +351,7 @@ export class GenericModel {
if (this.model.disableCreate) {
throw new Error('Cannot create on this model!')
} else {
let createRequestParams = {}
let createRequestParams: any = {}
createRequestParams[this.model.name.toLowerCase()] = obj
return this.api[`api${this.model.name}Create`](createRequestParams)
}
@@ -254,7 +368,7 @@ export class GenericModel {
if (this.model.disableCreate) {
throw new Error('Cannot update on this model!')
} else {
let updateRequestParams = {}
let updateRequestParams: any = {}
updateRequestParams['id'] = id
updateRequestParams[this.model.name.toLowerCase()] = obj
return this.api[`api${this.model.name}Update`](updateRequestParams)
@@ -271,34 +385,10 @@ export class GenericModel {
if (this.model.disableDelete) {
throw new Error('Cannot delete on this model!')
} else {
let destroyRequestParams = {}
let destroyRequestParams: any = {}
destroyRequestParams['id'] = id
return this.api[`api${this.model.name}Destroy`](createRequestParams)
return this.api[`api${this.model.name}Destroy`](destroyRequestParams)
}
}
}
export class PropertyType extends GenericModel<IPropertyType> {
create(name: string) {
const api = new ApiApi()
return api.apiPropertyTypeCreate({propertyType: {name: name} as IPropertyType}).then(r => {
return r as unknown as IPropertyType
})
}
list(query: string) {
const api = new ApiApi()
return api.apiPropertyTypeList({query: query}).then(r => {
if (r.results) {
return r.results
} else {
return []
}
})
}
}

View File

@@ -11,7 +11,11 @@ export default createVuetify({
// disabled as this leads to cards overflowing if not careful, manually set on cards containing a multiselect until proper solution is found
// VCard: {
// class: 'overflow-visible' // this is needed so that vue-multiselect options show above a card, vuetify uses overlay container to avoid this
// }
// },
// without this action buttons are left aligned in normal cards but right aligned in dialogs (I think)
VCardActions: {
class: 'float-right'
}
},
theme: {
defaultTheme: 'light',