various model editor functions

This commit is contained in:
vabene1111
2024-10-02 20:33:35 +02:00
parent a3ee2fb69c
commit ddf977f665
44 changed files with 229 additions and 23 deletions

2
.idea/recipes.iml generated
View File

@@ -18,7 +18,7 @@
<excludeFolder url="file://$MODULE_DIR$/staticfiles" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.12 (recipes)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
@@ -40,7 +40,7 @@ import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
const props = defineProps({
item: {type: {} as PropType<AccessToken>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-tabs v-model="tab" :disabled="loading">
@@ -167,7 +167,7 @@ import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<Food>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
@@ -24,7 +24,7 @@
<script setup lang="ts">
import {VDateInput} from 'vuetify/labs/VDateInput' //TODO remove once component is out of labs
import { onMounted, PropType, ref} from "vue";
import {onMounted, PropType, ref} from "vue";
import {ApiApi, Group, InviteLink} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {DateTime} from "luxon";
@@ -34,7 +34,7 @@ import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<InviteLink>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -0,0 +1,55 @@
<template>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
: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-textarea :label="$t('Description')" v-model="editingObj.description"></v-textarea>
</v-form>
</v-card-text>
</model-editor-base>
</template>
<script setup lang="ts">
import {onMounted, PropType} from "vue";
import {Keyword} from "@/openapi";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import {useI18n} from "vue-i18n";
const {t} = useI18n()
const props = defineProps({
item: {type: {} as PropType<Keyword>, required: false, default: null},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Keyword>('Keyword', emit)
// object specific data (for selects/display)
onMounted(() => {
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
</script>
<style scoped>
</style>

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
@@ -47,7 +47,7 @@ import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<MealType>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -1,7 +1,7 @@
<template>
<v-card :loading="loading">
<v-card-title>
{{ modelName }}
<i :class="modelClass.model.icon"></i> {{ $t(modelClass.model.localizationKey) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
<v-card-subtitle class="pa-0">{{ objectName }}</v-card-subtitle>
</v-card-title>
@@ -11,10 +11,11 @@
</slot>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" :model-name="modelName" @delete="emit('delete')"></delete-confirm-dialog>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate && !modelClass.model.disableDelete">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" :model-name="$t(modelClass.model.localizationKey)" @delete="emit('delete')"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="emit('save')">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
<v-btn color="save" prepend-icon="$create" @click="emit('save')" v-if="!isUpdate && !modelClass.model.disableCreate">{{ $t('Create') }}</v-btn>
<v-btn color="save" prepend-icon="$save" @click="emit('save')" v-if="isUpdate && !modelClass.model.disableUpdate">{{ $t('Update') }}</v-btn>
</v-card-actions>
</v-card>
</template>
@@ -22,6 +23,7 @@
<script setup lang="ts">
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {GenericModel} from "@/types/Models";
const emit = defineEmits(['save', 'delete', 'close'])
@@ -29,7 +31,7 @@ const props = defineProps({
loading: {type: Boolean, default: false},
dialog: {type: Boolean, default: false},
objectName: {type: String, default: ''},
modelName: {type: String, default: ''},
modelClass: {type: GenericModel, default: null},
isUpdate: {type: Boolean, default: false}
})

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form>
@@ -36,7 +36,7 @@ import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<Property>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form>
@@ -56,7 +56,7 @@ import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
const props = defineProps({
item: {type: {} as PropType<UnitConversion>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -0,0 +1,80 @@
<template>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
: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>
</template>
<script setup lang="ts">
import {onMounted, PropType} from "vue";
import {Unit} from "@/openapi";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import {useI18n} from "vue-i18n";
const {t} = useI18n()
const props = defineProps({
item: {type: {} as PropType<Unit>, required: false, default: null},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Unit>('Unit', emit)
// object specific data (for selects/display)
const BASE_UNITS = [
{value: "g", title: t("g")},
{value: "kg", title: t("kg")},
{value: "ounce", title: t("ounce")},
{value: "pound", title: t("pound")},
{value: "ml", title: t("ml")},
{value: "l", title: t("l")},
{value: "fluid_ounce", title: t("fluid_ounce")},
{value: "us_cup", title: t("us_cup")},
{value: "pint", title: t("pint")},
{value: "quart", title: t("quart")},
{value: "gallon", title: t("gallon")},
{value: "tbsp", title: t("tbsp")},
{value: "tsp", title: t("tsp")},
{value: "imperial_fluid_ounce", title: t("imperial_fluid_ounce")},
{value: "imperial_pint", title: t("imperial_pint")},
{value: "imperial_quart", title: t("imperial_quart")},
{value: "imperial_gallon", title: t("imperial_gallon")},
{value: "imperial_tbsp", title: t("imperial_tbsp")},
{value: "imperial_tsp", title: t("imperial_tsp")},
]
onMounted(() => {
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
</script>
<style scoped>
</style>

View File

@@ -6,7 +6,7 @@
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form>
@@ -30,7 +30,7 @@ import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<UserSpace>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})

View File

@@ -27,7 +27,7 @@ export function useModelEditorFunctions<T>(modelName: string, emit: any) {
* @param item item object to set as editingObj
* @param itemId id of object to be retrieved and set as editingObj
*/
function setupState(item: T | null, itemId: number | undefined) {
function setupState(item: T | null, itemId: number|string | undefined) {
if (item === null && itemId === undefined) {
if (modelClass.value.model.disableCreate) {
throw Error('Trying to use a ModelEditor without an item and a model that does not allow object creation!')
@@ -37,6 +37,9 @@ export function useModelEditorFunctions<T>(modelName: string, emit: any) {
editingObj.value = item
} else if (itemId !== undefined) {
loading.value = true
if(typeof itemId == "string"){
itemId = Number(itemId)
}
modelClass.value.retrieve(itemId).then((r: T) => {
editingObj.value = r
}).catch((err: any) => {

View File

@@ -19,6 +19,8 @@
"Auto_Planner": "",
"Automate": "",
"Automation": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "",
"Calories": "",

View File

@@ -19,6 +19,8 @@
"Auto_Planner": "Автоматичен плановик",
"Automate": "Автоматизация",
"Automation": "Автоматизация",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Книжен пазар",
"Books": "Книги",
"Calories": "Калории",

View File

@@ -26,6 +26,8 @@
"Automate": "",
"Automation": "",
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "",
"Calculator": "",

View File

@@ -26,6 +26,8 @@
"Automate": "Automatizovat",
"Automation": "Automatizace",
"Back": "Zpět",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Skript v záložce",
"Books": "Kuchařky",
"Calculator": "Kalkulačka",

View File

@@ -26,6 +26,8 @@
"Automate": "Automatiser",
"Automation": "Automatisering",
"Back": "Tilbage",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Bogmærke",
"Books": "Bøger",
"Calories": "Kalorier",

View File

@@ -27,6 +27,8 @@
"Automate": "Automatisieren",
"Automation": "Automatisierung",
"Back": "Zurück",
"BaseUnit": "Basiseinheit",
"BaseUnitHelp": "Optionale Standardeinheit zur automatischen Umrechnung",
"Bookmarklet": "Lesezeichen",
"Books": "Kochbücher",
"Calculator": "Rechner",

View File

@@ -25,6 +25,8 @@
"Automate": "Αυτοματοποίηση",
"Automation": "Αυτοματισμός",
"Back": "Πίσω",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Bookmarklet",
"Books": "Βιβλία",
"Calories": "Θερμίδες",

View File

@@ -26,6 +26,8 @@
"Automate": "Automate",
"Automation": "Automation",
"Back": "Back",
"BaseUnit": "Base Unit",
"BaseUnitHelp": "Standard unit for automatic unit conversion",
"Bookmarklet": "Bookmarklet",
"Books": "Books",
"Calculator": "Calculator",

View File

@@ -26,6 +26,8 @@
"Automate": "Automatizar",
"Automation": "Automatización",
"Back": "Atrás",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Marcadores",
"Books": "Libros",
"Calculator": "Calculadora",

View File

@@ -12,6 +12,8 @@
"Auto_Planner": "Automaattinen Suunnittelija",
"Automate": "Automatisoi",
"Automation": "Automaatio",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "Kirjat",
"Calories": "Kalorit",
"Cancel": "Peruuta",

View File

@@ -27,6 +27,8 @@
"Automate": "Automatiser",
"Automation": "Automatisation",
"Back": "Retour",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Signet",
"Books": "Livres",
"Calculator": "Calculatrice",

View File

@@ -26,6 +26,8 @@
"Automate": "אוטומט",
"Automation": "אוטומטציה",
"Back": "חזור",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "סימניה",
"Books": "ספרים",
"Calculator": "מחשבון",

View File

@@ -26,6 +26,8 @@
"Automate": "Automatizálás",
"Automation": "Automatizálás",
"Back": "Vissza",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Könyvjelző",
"Books": "Könyvek",
"Calories": "Kalóriák",

View File

@@ -9,6 +9,8 @@
"Add_to_Shopping": "Ավելացնել գնումներին",
"Advanced Search Settings": "Ընդլայնված փնտրման կարգավորումներ",
"Automate": "Ավտոմատացնել",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "",
"Calories": "",
"Cancel": "",

View File

@@ -21,6 +21,8 @@
"Auto_Planner": "",
"Automate": "",
"Automation": "Automatis",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "Buku",
"Calories": "Kalori",

View File

@@ -26,6 +26,8 @@
"Automate": "",
"Automation": "",
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "",
"Calculator": "",

View File

@@ -25,6 +25,8 @@
"Auto_Sort_Help": "Sposta tutti gli ingredienti allo step più adatto.",
"Automate": "Automatizza",
"Automation": "Automazione",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Segnalibro",
"Books": "Libri",
"Calories": "Calorie",

View File

@@ -26,6 +26,8 @@
"Automate": "",
"Automation": "",
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "",
"Calories": "",

View File

@@ -25,6 +25,8 @@
"Auto_Sort_Help": "Flytt alle ingredienser til det mest passende steget.",
"Automate": "Automatiser",
"Automation": "Automatiser",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "Bøker",
"Calories": "Kalorier",

View File

@@ -27,6 +27,8 @@
"Automate": "Automatiseer",
"Automation": "Automatisering",
"Back": "Terug",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Bladwijzer",
"Books": "Boeken",
"Calories": "Calorieën",

View File

@@ -27,6 +27,8 @@
"Automate": "Automatyzacja",
"Automation": "Automatyzacja",
"Back": "Z powrotem",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Skryptozakładka",
"Books": "Książki",
"Calculator": "Kalkulator",

View File

@@ -20,6 +20,8 @@
"Auto_Sort_Help": "Mover todos os ingredientes para o passo mais indicado.",
"Automate": "Automatizar",
"Automation": "Automação",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "Livros",
"Calories": "Calorias",
"Cancel": "Cancelar",

View File

@@ -26,6 +26,8 @@
"Automate": "Automatizar",
"Automation": "Automação",
"Back": "Voltar",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "Livros",
"Calculator": "Calculadora",
"Calories": "Calorias",

View File

@@ -25,6 +25,8 @@
"Auto_Sort_Help": "Mutați toate ingredientele la cel mai potrivit pas.",
"Automate": "Automatizat",
"Automation": "Automatizare",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Marcaj",
"Books": "Cărți",
"Calories": "Calorii",

View File

@@ -19,6 +19,8 @@
"Auto_Planner": "Автопланировщик",
"Automate": "Автоматизировать",
"Automation": "Автоматизация",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "Книги",
"Calories": "Каллории",
"Cancel": "Отменить",

View File

@@ -18,6 +18,8 @@
"Auto_Sort_Help": "Vse sestavine prestavi v najprimernejši korak.",
"Automate": "Avtomatiziraj",
"Automation": "Avtomatizacija",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "Knjige",
"Calories": "Kalorije",
"Cancel": "Prekini",

View File

@@ -27,6 +27,8 @@
"Automate": "Automatisera",
"Automation": "Automatisering",
"Back": "Tillbaka",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Bokmärke",
"Books": "Böcker",
"Calculator": "Räknare",

View File

@@ -26,6 +26,8 @@
"Automate": "Otomatikleştir",
"Automation": "Otomasyon",
"Back": "Geri",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "Yer İmi",
"Books": "Kitaplar",
"Calculator": "Hesap Makinesi",

View File

@@ -22,6 +22,8 @@
"Auto_Sort_Help": "Перемістити всі інгредієнти до більш підходящого кроку.",
"Automate": "Автоматично",
"Automation": "Автоматизація",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "",
"Books": "Книжки",
"Calories": "Калорії",

View File

@@ -26,6 +26,8 @@
"Automate": "自动化",
"Automation": "自动化",
"Back": "后退",
"BaseUnit": "",
"BaseUnitHelp": "",
"Bookmarklet": "书签",
"Books": "书籍",
"Calories": "卡路里",

View File

@@ -6,6 +6,8 @@
"Add_nutrition_recipe": "為食譜添加營養資訊",
"Add_to_Plan": "加入計劃",
"Add_to_Shopping": "加入購物清單",
"BaseUnit": "",
"BaseUnitHelp": "",
"Books": "",
"Calories": "",
"Cancel": "",

View File

@@ -11,7 +11,9 @@
</v-row>
<v-row>
<v-col>
<food-editor :item-id="id"></food-editor>
<food-editor :item-id="id" v-if="model == 'Food'" @delete="router.go(-1)"></food-editor>
<unit-editor :item-id="id" v-if="model == 'Unit'" @delete="router.go(-1)"></unit-editor>
<keyword-editor :item-id="id" v-if="model == 'Keyword'" @delete="router.go(-1)"></keyword-editor>
</v-col>
</v-row>
</v-container>
@@ -23,6 +25,8 @@ import FoodEditor from "@/components/model_editors/FoodEditor.vue";
import {onMounted, ref} from "vue";
import {ApiApi, Food} from "@/openapi";
import {useRouter} from "vue-router";
import UnitEditor from "@/components/model_editors/UnitEditor.vue";
import KeywordEditor from "@/components/model_editors/KeywordEditor.vue";
const props = defineProps({
model: {type: String, default: 'Food'},