baisc implementation of books WIP

This commit is contained in:
vabene1111
2025-02-10 17:35:14 +01:00
parent 4a9bd3626e
commit 9c0dc64a47
45 changed files with 223 additions and 1907 deletions

View File

@@ -1073,6 +1073,7 @@ class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerialize
class RecipeBookSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
created_by = UserSerializer(read_only=True)
shared = UserSerializer(many=True)
filter = CustomFilterSerializer(allow_null=True, required=False)

View File

@@ -114,10 +114,11 @@
<v-list-item-subtitle>{{ useUserPreferenceStore().activeSpace.name }}</v-list-item-subtitle>
</v-list-item>
<v-divider></v-divider>
<v-list-item prepend-icon="fas fa-book" title="Home" :to="{ name: 'view_home', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-calendar-alt" :title="$t('Meal_Plan')" :to="{ name: 'view_mealplan', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-shopping-cart" :title="$t('Shopping_list')" :to="{ name: 'view_shopping', params: {} }"></v-list-item>
<v-list-item prepend-icon="$recipes" title="Home" :to="{ name: 'view_home', params: {} }"></v-list-item>
<v-list-item prepend-icon="$mealplan" :title="$t('Meal_Plan')" :to="{ name: 'view_mealplan', params: {} }"></v-list-item>
<v-list-item prepend-icon="$shopping" :title="$t('Shopping_list')" :to="{ name: 'view_shopping', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-globe" :title="$t('Import')" :to="{ name: 'RecipeImportPage', params: {} }"></v-list-item>
<v-list-item prepend-icon="$books" :title="$t('Books')" :to="{ name: 'BooksPage', params: {} }"></v-list-item>
<v-list-item prepend-icon="fa-solid fa-folder-tree" :title="$t('Database')" :to="{ name: 'ModelListPage', params: {model: 'food'} }"></v-list-item>
<navigation-drawer-context-menu></navigation-drawer-context-menu>

View File

@@ -28,6 +28,7 @@ import ModelListPage from "@/pages/ModelListPage.vue";
import ModelEditPage from "@/pages/ModelEditPage.vue";
import RecipeImportPage from "@/pages/RecipeImportPage.vue";
import IngredientEditorPage from "@/pages/IngredientEditorPage.vue";
import BooksPage from "@/pages/BooksPage.vue";
const routes = [
{path: '/', component: StartPage, name: 'view_home'},
@@ -49,7 +50,7 @@ const routes = [
{path: '/search', component: SearchPage, name: 'view_search'},
{path: '/shopping', component: ShoppingListPage, name: 'view_shopping'},
{path: '/mealplan', component: MealPlanPage, name: 'view_mealplan'},
{path: '/books', component: ShoppingListPage, name: 'view_books'},
{path: '/books', component: BooksPage, name: 'BooksPage'},
{path: '/recipe/import', component: RecipeImportPage, name: 'RecipeImportPage'},
{path: '/recipe/:id', component: RecipeViewPage, name: 'view_recipe', props: true},

View File

@@ -9,55 +9,139 @@
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
<v-row>
<v-col cols="10">
<v-text-field label="Token" v-model="editingObj.token" disabled></v-text-field>
</v-col>
<v-col cols="2">
<btn-copy :copy-value="editingObj.token" class="me-1"></btn-copy>
</v-col>
</v-row>
<v-text-field label="Scope" v-model="editingObj.scope"></v-text-field>
<v-date-input :label="$t('Valid Until')" v-model="editingObj.expires"></v-date-input>
</v-form>
<v-tabs v-model="tab" :disabled="loading" grow>
<v-tab value="book">{{ $t('Book') }}</v-tab>
<v-tab value="recipes" :disabled="!isUpdate()">{{ $t('Recipes') }}</v-tab>
</v-tabs>
<v-card-text>
<v-tabs-window v-model="tab">
<v-tabs-window-item value="book">
<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" rows="3"></v-textarea>
<model-select model="User" v-model="editingObj.shared" mode="tags"></model-select>
<model-select model="CustomFilter" v-model="editingObj.filter"></model-select>
<v-number-input :label="$t('Order')" :hint="$t('OrderInformation')" v-model="editingObj.order"></v-number-input>
</v-form>
</v-tabs-window-item>
<v-tabs-window-item value="recipes">
<model-select model="Recipe" v-model="selectedRecipe">
<template #append>
<v-btn @click="addRecipeToBook()">
<v-icon icon="$create"></v-icon>
</v-btn>
</template>
</model-select>
<v-data-table-server
@update:options="loadRecipeBookEntries"
:items="recipeBookEntries"
:headers="tableHeaders"
:items-length="itemCount"
>
</v-data-table-server>
</v-tabs-window-item>
</v-tabs-window>
</v-card-text>
</model-editor-base>
</template>
<script setup lang="ts">
import {VDateInput} from 'vuetify/labs/VDateInput' //TODO remove once component is out of labs
import {onMounted, PropType} from "vue";
import {AccessToken} from "@/openapi";
import {DateTime} from "luxon";
import BtnCopy from "@/components/buttons/BtnCopy.vue";
import {VNumberInput} from 'vuetify/labs/VNumberInput'
import {onMounted, PropType, ref} from "vue";
import {ApiApi, Recipe, RecipeBook, RecipeBookEntry, User} from "@/openapi";
import {VDataTableUpdateOptions} from "@/vuetify";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import {useI18n} from "vue-i18n";
const props = defineProps({
item: {type: {} as PropType<AccessToken>, required: false, default: null},
item: {type: {} as PropType<RecipeBook>, 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, editingObjChanged, modelClass} = useModelEditorFunctions<AccessToken>('AccessToken', emit)
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<RecipeBook>('RecipeBook', emit)
const {t} = useI18n()
const tab = ref("book")
const recipeBookEntries = ref([] as RecipeBookEntry[])
const selectedRecipe = ref({} as Recipe)
const tablePage = ref(1)
const itemCount = ref(0)
const tableHeaders = [
{title: t('Name'), key: 'recipeContent.name', },
{key: 'action', width: '1%', noBreak: true, align: 'end'},
]
onMounted(() => {
setupState(props.item, props.itemId, {
newItemFunction: () => {
editingObj.value.expires = DateTime.now().plus({year: 1}).toJSDate()
editingObj.value.scope = 'read write'
editingObj.value.shared = [] as User[]
recipeBookEntries.value = []
},
existingItemFunction: () => {
recipeBookEntries.value = []
}
})
})
function addRecipeToBook() {
let api = new ApiApi()
// TODO check both for null, handle errors
api.apiRecipeBookEntryCreate({recipeBookEntry: {book: editingObj.value.id!, recipe: selectedRecipe.value.id!}}).then(r => {
recipeBookEntries.value.push(r) // TODO or reload ?
selectedRecipe.value = {} as Recipe
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
/**
* load items from API whenever the table calls for it
* parameters defined by vuetify
* @param options
*/
function loadRecipeBookEntries(options: VDataTableUpdateOptions) {
let api = new ApiApi()
loading.value = true
window.scrollTo({top: 0, behavior: 'smooth'})
if (tablePage.value != options.page) {
tablePage.value = options.page
}
useUserPreferenceStore().deviceSettings.general_tableItemsPerPage = options.itemsPerPage
api.apiRecipeBookEntryList({page: options.page, pageSize: options.itemsPerPage,}).then((r: any) => {
recipeBookEntries.value = r.results
itemCount.value = r.count
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
}).finally(() => {
loading.value = false
})
}
</script>
<style scoped>

View File

@@ -26,6 +26,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "",
"Calories": "",

View File

@@ -26,6 +26,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Книжен пазар",
"Books": "Книги",
"Calories": "Калории",

View File

@@ -33,6 +33,7 @@
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "",
"Calculator": "",

View File

@@ -33,6 +33,7 @@
"Back": "Zpět",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Skript v záložce",
"Books": "Kuchařky",
"Calculator": "Kalkulačka",

View File

@@ -33,6 +33,7 @@
"Back": "Tilbage",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Bogmærke",
"Books": "Bøger",
"Calories": "Kalorier",

View File

@@ -34,6 +34,7 @@
"Back": "Zurück",
"BaseUnit": "Basiseinheit",
"BaseUnitHelp": "Optionale Standardeinheit zur automatischen Umrechnung",
"Book": "Buch",
"Bookmarklet": "Lesezeichen",
"Books": "Kochbücher",
"Calculator": "Rechner",

View File

@@ -32,6 +32,7 @@
"Back": "Πίσω",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Bookmarklet",
"Books": "Βιβλία",
"Calories": "Θερμίδες",

View File

@@ -33,6 +33,7 @@
"Back": "Back",
"BaseUnit": "Base Unit",
"BaseUnitHelp": "Standard unit for automatic unit conversion",
"Book": "Book",
"Bookmarklet": "Bookmarklet",
"Books": "Books",
"Calculator": "Calculator",

View File

@@ -33,6 +33,7 @@
"Back": "Atrás",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Marcadores",
"Books": "Libros",
"Calculator": "Calculadora",

View File

@@ -19,6 +19,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "Kirjat",
"Calories": "Kalorit",
"Cancel": "Peruuta",

View File

@@ -34,6 +34,7 @@
"Back": "Retour",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Signet",
"Books": "Livres",
"Calculator": "Calculatrice",

View File

@@ -33,6 +33,7 @@
"Back": "חזור",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "סימניה",
"Books": "ספרים",
"Calculator": "מחשבון",

View File

@@ -33,6 +33,7 @@
"Back": "Vissza",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Könyvjelző",
"Books": "Könyvek",
"Calories": "Kalóriák",

View File

@@ -16,6 +16,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "",
"Calories": "",
"Cancel": "",

View File

@@ -28,6 +28,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "Buku",
"Calories": "Kalori",

View File

@@ -33,6 +33,7 @@
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "",
"Calculator": "",

View File

@@ -32,6 +32,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Segnalibro",
"Books": "Libri",
"Calories": "Calorie",

View File

@@ -33,6 +33,7 @@
"Back": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "",
"Calories": "",

View File

@@ -32,6 +32,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "Bøker",
"Calories": "Kalorier",

View File

@@ -34,6 +34,7 @@
"Back": "Terug",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Bladwijzer",
"Books": "Boeken",
"Calories": "Calorieën",

View File

@@ -34,6 +34,7 @@
"Back": "Z powrotem",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Skryptozakładka",
"Books": "Książki",
"Calculator": "Kalkulator",

View File

@@ -27,6 +27,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "Livros",
"Calories": "Calorias",
"Cancel": "Cancelar",

View File

@@ -33,6 +33,7 @@
"Back": "Voltar",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "Livros",
"Calculator": "Calculadora",
"Calories": "Calorias",

View File

@@ -32,6 +32,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Marcaj",
"Books": "Cărți",
"Calories": "Calorii",

View File

@@ -26,6 +26,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "Книги",
"Calories": "Каллории",
"Cancel": "Отменить",

View File

@@ -25,6 +25,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "Knjige",
"Calories": "Kalorije",
"Cancel": "Prekini",

View File

@@ -34,6 +34,7 @@
"Back": "Tillbaka",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Bokmärke",
"Books": "Böcker",
"Calculator": "Räknare",

View File

@@ -33,6 +33,7 @@
"Back": "Geri",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "Yer İmi",
"Books": "Kitaplar",
"Calculator": "Hesap Makinesi",

View File

@@ -29,6 +29,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "",
"Books": "Книжки",
"Calories": "Калорії",

View File

@@ -33,6 +33,7 @@
"Back": "后退",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Bookmarklet": "书签",
"Books": "书籍",
"Calories": "卡路里",

View File

@@ -13,6 +13,7 @@
"AvailableCategories": "",
"BaseUnit": "",
"BaseUnitHelp": "",
"Book": "",
"Books": "",
"Calories": "",
"Cancel": "",

View File

@@ -7,8 +7,6 @@ models/AccessToken.ts
models/AuthToken.ts
models/AutoMealPlan.ts
models/Automation.ts
models/AutomationTypeEnum.ts
models/BaseUnitEnum.ts
models/BookmarkletImport.ts
models/BookmarkletImportList.ts
models/ConnectorConfigConfig.ts
@@ -33,16 +31,6 @@ models/MealPlan.ts
models/MealType.ts
models/MethodEnum.ts
models/NutritionInformation.ts
models/OpenDataCategory.ts
models/OpenDataConversion.ts
models/OpenDataFood.ts
models/OpenDataFoodProperty.ts
models/OpenDataProperty.ts
models/OpenDataStore.ts
models/OpenDataStoreCategory.ts
models/OpenDataUnit.ts
models/OpenDataUnitTypeEnum.ts
models/OpenDataVersion.ts
models/PaginatedAutomationList.ts
models/PaginatedBookmarkletImportListList.ts
models/PaginatedCookLogList.ts
@@ -89,13 +77,6 @@ models/PatchedInviteLink.ts
models/PatchedKeyword.ts
models/PatchedMealPlan.ts
models/PatchedMealType.ts
models/PatchedOpenDataCategory.ts
models/PatchedOpenDataConversion.ts
models/PatchedOpenDataFood.ts
models/PatchedOpenDataProperty.ts
models/PatchedOpenDataStore.ts
models/PatchedOpenDataUnit.ts
models/PatchedOpenDataVersion.ts
models/PatchedProperty.ts
models/PatchedPropertyType.ts
models/PatchedRecipe.ts
@@ -155,6 +136,7 @@ models/SupermarketCategoryRelation.ts
models/Sync.ts
models/SyncLog.ts
models/ThemeEnum.ts
models/TypeEnum.ts
models/Unit.ts
models/UnitConversion.ts
models/User.ts

File diff suppressed because it is too large Load Diff

View File

@@ -13,13 +13,13 @@
*/
import { mapValues } from '../runtime';
import type { AutomationTypeEnum } from './AutomationTypeEnum';
import type { TypeEnum } from './TypeEnum';
import {
AutomationTypeEnumFromJSON,
AutomationTypeEnumFromJSONTyped,
AutomationTypeEnumToJSON,
AutomationTypeEnumToJSONTyped,
} from './AutomationTypeEnum';
TypeEnumFromJSON,
TypeEnumFromJSONTyped,
TypeEnumToJSON,
TypeEnumToJSONTyped,
} from './TypeEnum';
/**
*
@@ -35,10 +35,10 @@ export interface Automation {
id?: number;
/**
*
* @type {AutomationTypeEnum}
* @type {TypeEnum}
* @memberof Automation
*/
type: AutomationTypeEnum;
type: TypeEnum;
/**
*
* @type {string}
@@ -111,7 +111,7 @@ export function AutomationFromJSONTyped(json: any, ignoreDiscriminator: boolean)
return {
'id': json['id'] == null ? undefined : json['id'],
'type': AutomationTypeEnumFromJSON(json['type']),
'type': TypeEnumFromJSON(json['type']),
'name': json['name'] == null ? undefined : json['name'],
'description': json['description'] == null ? undefined : json['description'],
'param1': json['param_1'] == null ? undefined : json['param_1'],
@@ -135,7 +135,7 @@ export function AutomationToJSONTyped(value?: Omit<Automation, 'created_by'> | n
return {
'id': value['id'],
'type': AutomationTypeEnumToJSON(value['type']),
'type': TypeEnumToJSON(value['type']),
'name': value['name'],
'description': value['description'],
'param_1': value['param1'],

View File

@@ -13,13 +13,13 @@
*/
import { mapValues } from '../runtime';
import type { AutomationTypeEnum } from './AutomationTypeEnum';
import type { TypeEnum } from './TypeEnum';
import {
AutomationTypeEnumFromJSON,
AutomationTypeEnumFromJSONTyped,
AutomationTypeEnumToJSON,
AutomationTypeEnumToJSONTyped,
} from './AutomationTypeEnum';
TypeEnumFromJSON,
TypeEnumFromJSONTyped,
TypeEnumToJSON,
TypeEnumToJSONTyped,
} from './TypeEnum';
/**
*
@@ -35,10 +35,10 @@ export interface PatchedAutomation {
id?: number;
/**
*
* @type {AutomationTypeEnum}
* @type {TypeEnum}
* @memberof PatchedAutomation
*/
type?: AutomationTypeEnum;
type?: TypeEnum;
/**
*
* @type {string}
@@ -109,7 +109,7 @@ export function PatchedAutomationFromJSONTyped(json: any, ignoreDiscriminator: b
return {
'id': json['id'] == null ? undefined : json['id'],
'type': json['type'] == null ? undefined : AutomationTypeEnumFromJSON(json['type']),
'type': json['type'] == null ? undefined : TypeEnumFromJSON(json['type']),
'name': json['name'] == null ? undefined : json['name'],
'description': json['description'] == null ? undefined : json['description'],
'param1': json['param_1'] == null ? undefined : json['param_1'],
@@ -133,7 +133,7 @@ export function PatchedAutomationToJSONTyped(value?: Omit<PatchedAutomation, 'cr
return {
'id': value['id'],
'type': AutomationTypeEnumToJSON(value['type']),
'type': TypeEnumToJSON(value['type']),
'name': value['name'],
'description': value['description'],
'param_1': value['param1'],

View File

@@ -60,10 +60,10 @@ export interface PatchedRecipeBook {
shared?: Array<User>;
/**
*
* @type {number}
* @type {User}
* @memberof PatchedRecipeBook
*/
readonly createdBy?: number;
readonly createdBy?: User;
/**
*
* @type {CustomFilter}
@@ -99,7 +99,7 @@ export function PatchedRecipeBookFromJSONTyped(json: any, ignoreDiscriminator: b
'name': json['name'] == null ? undefined : json['name'],
'description': json['description'] == null ? undefined : json['description'],
'shared': json['shared'] == null ? undefined : ((json['shared'] as Array<any>).map(UserFromJSON)),
'createdBy': json['created_by'] == null ? undefined : json['created_by'],
'createdBy': json['created_by'] == null ? undefined : UserFromJSON(json['created_by']),
'filter': json['filter'] == null ? undefined : CustomFilterFromJSON(json['filter']),
'order': json['order'] == null ? undefined : json['order'],
};

View File

@@ -60,10 +60,10 @@ export interface RecipeBook {
shared: Array<User>;
/**
*
* @type {number}
* @type {User}
* @memberof RecipeBook
*/
readonly createdBy: number;
readonly createdBy: User;
/**
*
* @type {CustomFilter}
@@ -102,7 +102,7 @@ export function RecipeBookFromJSONTyped(json: any, ignoreDiscriminator: boolean)
'name': json['name'],
'description': json['description'] == null ? undefined : json['description'],
'shared': ((json['shared'] as Array<any>).map(UserFromJSON)),
'createdBy': json['created_by'],
'createdBy': UserFromJSON(json['created_by']),
'filter': json['filter'] == null ? undefined : CustomFilterFromJSON(json['filter']),
'order': json['order'] == null ? undefined : json['order'],
};

View File

@@ -4,8 +4,6 @@ export * from './AccessToken';
export * from './AuthToken';
export * from './AutoMealPlan';
export * from './Automation';
export * from './AutomationTypeEnum';
export * from './BaseUnitEnum';
export * from './BookmarkletImport';
export * from './BookmarkletImportList';
export * from './ConnectorConfigConfig';
@@ -30,16 +28,6 @@ export * from './MealPlan';
export * from './MealType';
export * from './MethodEnum';
export * from './NutritionInformation';
export * from './OpenDataCategory';
export * from './OpenDataConversion';
export * from './OpenDataFood';
export * from './OpenDataFoodProperty';
export * from './OpenDataProperty';
export * from './OpenDataStore';
export * from './OpenDataStoreCategory';
export * from './OpenDataUnit';
export * from './OpenDataUnitTypeEnum';
export * from './OpenDataVersion';
export * from './PaginatedAutomationList';
export * from './PaginatedBookmarkletImportListList';
export * from './PaginatedCookLogList';
@@ -86,13 +74,6 @@ export * from './PatchedInviteLink';
export * from './PatchedKeyword';
export * from './PatchedMealPlan';
export * from './PatchedMealType';
export * from './PatchedOpenDataCategory';
export * from './PatchedOpenDataConversion';
export * from './PatchedOpenDataFood';
export * from './PatchedOpenDataProperty';
export * from './PatchedOpenDataStore';
export * from './PatchedOpenDataUnit';
export * from './PatchedOpenDataVersion';
export * from './PatchedProperty';
export * from './PatchedPropertyType';
export * from './PatchedRecipe';
@@ -152,6 +133,7 @@ export * from './SupermarketCategoryRelation';
export * from './Sync';
export * from './SyncLog';
export * from './ThemeEnum';
export * from './TypeEnum';
export * from './Unit';
export * from './UnitConversion';
export * from './User';

View File

@@ -1,40 +1,61 @@
<template>
<v-container>
<horizontal-meal-plan-window></horizontal-meal-plan-window>
<v-card v-if="totalRecipes == 0" class="mt-5 mb-5">
<v-card-title><i class="fa-solid fa-eye-slash"></i> {{ $t('search_no_recipes') }}</v-card-title>
<v-card-text>
<v-btn-group divided>
<v-btn size="large" color="success" prepend-icon="$create" :to="{ name: 'ModelEditPage', params: {model: 'recipe'} }">{{ $t('Create Recipe') }}</v-btn>
<v-btn size="large" color="primary" prepend-icon="fa-solid fa-globe" :to="{ name: 'RecipeImportPage', params: {} }">{{ $t('Import Recipe') }}</v-btn>
</v-btn-group>
</v-card-text>
</v-card>
<horizontal-recipe-scroller :skeletons="4" mode="recent"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="new"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="random"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="2" mode="rating"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
<v-row>
<v-col cols="12" md="6" offset-md="3">
<v-text-field>
<template #append>
<v-btn icon color="create">
<v-icon icon="$create"></v-icon>
<model-edit-dialog model="RecipeBook" @create="(arg: RecipeBook) => {books.push(arg)}"></model-edit-dialog>
</v-btn>
</template>
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="3" v-for="(b, i) in books">
<v-card>
<v-card-title>
<v-icon icon="$books" size="small"></v-icon>
{{ b.name }}
</v-card-title>
<v-card-subtitle>{{ b.createdBy.displayName }}</v-card-subtitle>
<v-card-text>
{{ b.description }}
</v-card-text>
<v-card-actions>
<v-btn>
{{ $t('Edit') }}
<model-edit-dialog model="RecipeBook" :item="books[i]"
@delete="(arg: RecipeBook) => { books.splice(books.findIndex((value: RecipeBook) => value.id == arg.id!),1)}"></model-edit-dialog>
</v-btn>
<v-btn>
{{ $t('View') }}
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup lang="ts">
import {onMounted, ref} from "vue"
import {ApiApi} from "@/openapi"
import HorizontalRecipeScroller from "@/components/display/HorizontalRecipeWindow.vue"
import HorizontalMealPlanWindow from "@/components/display/HorizontalMealPlanWindow.vue"
const totalRecipes = ref(-1)
import {onMounted, ref} from "vue";
import {ApiApi, RecipeBook} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
const books = ref([] as RecipeBook[])
onMounted(() => {
const api = new ApiApi()
api.apiRecipeList({pageSize: 1}).then((r) => {
totalRecipes.value = r.count
api.apiRecipeBookList().then(r => {
books.value = r.results
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR)
})
})
</script>

View File

@@ -302,7 +302,7 @@ registerModel(TMealPlan)
export const TRecipeBook = {
name: 'RecipeBook',
localizationKey: 'Recipe_Book',
icon: 'fa-solid fa-book-open',
icon: 'fa-solid fa-book-bookmark',
isPaginated: true,
toStringKeys: ['name'],
@@ -319,7 +319,7 @@ registerModel(TRecipeBook)
export const TRecipeBookEntry = {
name: 'RecipeBookEntry',
localizationKey: 'Recipe_Book',
icon: 'fa-solid fa-book-open',
icon: 'fa-solid fa-book-bookmark',
isPaginated: true,
toStringKeys: ['book.name', 'recipe.name'],

View File

@@ -81,7 +81,7 @@ export default createVuetify({
shopping: 'fa-solid fa-cart-shopping',
mealplan: 'fa-solid fa-calendar-days',
recipes: 'fa-solid fa-book',
books: 'fa-solid fa-book-open',
books: 'fa-solid fa-book-bookmark',
menu: 'fa-solid fa-ellipsis-vertical'
},
sets: {