Merge remote-tracking branch 'upstream/dev' into localization

This commit is contained in:
Florian Dupret 2021-04-29 08:52:13 +02:00
commit a7f7a742bb
73 changed files with 1330 additions and 1004 deletions

2
.gitignore vendored
View file

@ -9,6 +9,7 @@ mealie/temp/*
mealie/temp/api.html mealie/temp/api.html
.temp/ .temp/
.secret .secret
!*/components/Recipe/Parts
dev/data/backups/* dev/data/backups/*
dev/data/debug/* dev/data/debug/*
@ -159,3 +160,4 @@ scratch.py
dev/data/backups/dev_sample_data*.zip dev/data/backups/dev_sample_data*.zip
dev/data/backups/dev_sample_data*.zip dev/data/backups/dev_sample_data*.zip
!dev/data/backups/test*.zip !dev/data/backups/test*.zip
dev/data/recipes/*

View file

@ -16,6 +16,7 @@ const recipeURLs = {
delete: slug => prefix + slug, delete: slug => prefix + slug,
recipeImage: slug => `${prefix}${slug}/image`, recipeImage: slug => `${prefix}${slug}/image`,
updateImage: slug => `${prefix}${slug}/image`, updateImage: slug => `${prefix}${slug}/image`,
createAsset: slug => `${prefix}${slug}/asset`,
}; };
export const recipeAPI = { export const recipeAPI = {
@ -78,26 +79,16 @@ export const recipeAPI = {
); );
}, },
updateImagebyURL(slug, url) { async updateImagebyURL(slug, url) {
return apiReq.post( const response = apiReq.post(recipeURLs.updateImage(slug), { url: url });
recipeURLs.updateImage(slug), return response;
{ url: url },
function() { return i18n.t('general.image-upload-failed'); },
function() { return i18n.t('recipe.recipe-image-updated'); }
);
}, },
async update(data) { async update(data) {
let response = await apiReq.put( console.log(data)
recipeURLs.update(data.slug), let response = await apiReq.put(recipeURLs.update(data.slug), data);
data, store.dispatch("patchRecipe", response.data);
function() { return i18n.t('recipe.recipe-update-failed'); }, return response.data.slug; // ! Temporary until I rewrite to refresh page without additional request
function() { return i18n.t('recipe.recipe-updated'); }
);
if(response) {
store.dispatch("patchRecipe", response.data);
return response.data.slug; // ! Temporary until I rewrite to refresh page without additional request
}
}, },
async patch(data) { async patch(data) {

View file

@ -0,0 +1,160 @@
<template>
<div v-if="value.length > 0 || edit">
<v-card class="mt-2">
<v-card-title class="py-2">
{{ $t("recipe.assets") }}
</v-card-title>
<v-divider class="mx-2"></v-divider>
<v-list :flat="!edit" v-if="value.length > 0">
<v-list-item v-for="(item, i) in value" :key="i">
<v-list-item-icon class="ma-auto">
<v-icon v-text="item.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title
class="pl-2"
v-text="item.name"
></v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn
v-if="!edit"
color="primary"
icon
:href="`/api/recipes/${slug}/asset?file_name=${item.fileName}`"
target="_blank"
top
>
<v-icon> mdi-download</v-icon>
</v-btn>
<v-btn v-else color="error" icon @click="deleteAsset(i)" top>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</v-card>
<div class="d-flex ml-auto mt-2">
<v-spacer></v-spacer>
<base-dialog
@submit="addAsset"
title="New Asset"
:title-icon="newAsset.icon"
>
<template v-slot:open="{ open }">
<v-btn color="secondary" dark @click="open" v-if="edit">
<v-icon>mdi-plus</v-icon>
</v-btn>
</template>
<v-card-text class="pt-2">
<v-text-field
dense
v-model="newAsset.name"
:label="$t('general.name')"
></v-text-field>
<div class="d-flex justify-space-between">
<v-select
dense
:prepend-icon="newAsset.icon"
v-model="newAsset.icon"
:items="iconOptions"
class="mr-2"
>
<template v-slot:item="{ item }">
<v-list-item-avatar>
<v-icon class="mr-auto">
{{ item }}
</v-icon>
</v-list-item-avatar>
{{ item }}
</template>
</v-select>
<TheUploadBtn
@uploaded="setFileObject"
:post="false"
file-name="file"
:text-btn="false"
/>
</div>
{{ fileObject.name }}
</v-card-text>
</base-dialog>
</div>
</div>
</template>
<script>
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
import BaseDialog from "@/components/UI/Dialogs/BaseDialog";
import { api } from "@/api";
export default {
components: {
BaseDialog,
TheUploadBtn,
},
props: {
slug: String,
value: {
type: Array,
},
edit: {
type: Boolean,
default: true,
},
},
data() {
return {
fileObject: {},
newAsset: {
name: "",
icon: "mdi-file",
},
iconOptions: [
"mdi-file",
"mdi-file-pdf-box",
"mdi-file-image",
"mdi-code-json",
"mdi-silverware-fork-knife",
],
menu: [
{
title: "Link 1",
icon: "mdi-file",
action: "Do Something",
},
{
title: "Link 1",
icon: "mdi-file",
action: "Do Something",
},
{
title: "Link 1",
icon: "mdi-file",
action: "Do Something",
},
],
};
},
methods: {
setFileObject(obj) {
this.fileObject = obj;
},
async addAsset() {
const serverAsset = await api.recipes.createAsset(
this.slug,
this.fileObject,
this.newAsset.name,
this.newAsset.icon
);
this.value.push(serverAsset.data);
this.newAsset = { name: "", icon: "mdi-file" };
},
deleteAsset(index) {
this.value.splice(index, 1);
},
},
};
</script>
<style scoped>
</style>

View file

@ -3,7 +3,7 @@
<v-dialog v-model="dialog" width="600"> <v-dialog v-model="dialog" width="600">
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn
text
color="secondary lighten-2" color="secondary lighten-2"
dark dark
v-bind="attrs" v-bind="attrs"

View file

@ -3,13 +3,16 @@
<v-menu offset-y top nudge-top="6" :close-on-content-click="false"> <v-menu offset-y top nudge-top="6" :close-on-content-click="false">
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn color="accent" dark v-bind="attrs" v-on="on"> <v-btn color="accent" dark v-bind="attrs" v-on="on">
{{$t('general.image')}} <v-icon left>
mdi-image
</v-icon>
{{ $t("general.image") }}
</v-btn> </v-btn>
</template> </template>
<v-card width="400"> <v-card width="400">
<v-card-title class="headline flex mb-0"> <v-card-title class="headline flex mb-0">
<div> <div>
{{$t('recipe.recipe-image')}} {{ $t("recipe.recipe-image") }}
</div> </div>
<TheUploadBtn <TheUploadBtn
class="ml-auto" class="ml-auto"
@ -22,7 +25,12 @@
</v-card-title> </v-card-title>
<v-card-text class="mt-n5"> <v-card-text class="mt-n5">
<div> <div>
<v-text-field :label="$t('general.url')" class="pt-5" clearable v-model="url"> <v-text-field
:label="$t('general.url')"
class="pt-5"
clearable
v-model="url"
>
<template v-slot:append-outer> <template v-slot:append-outer>
<v-btn <v-btn
class="ml-2" class="ml-2"
@ -30,7 +38,7 @@
@click="getImageFromURL" @click="getImageFromURL"
:loading="loading" :loading="loading"
> >
{{$t('general.get')}} {{ $t("general.get") }}
</v-btn> </v-btn>
</template> </template>
</v-text-field> </v-text-field>

View file

@ -0,0 +1,137 @@
<template>
<div>
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
<div v-if="edit">
<draggable
:value="value"
@input="updateIndex"
@start="drag = true"
@end="drag = false"
handle=".handle"
>
<transition-group type="transition" :name="!drag ? 'flip-list' : null">
<div
v-for="(ingredient, index) in value"
:key="generateKey('ingredient', index)"
>
<v-row align="center">
<v-textarea
class="mr-2"
:label="$t('recipe.ingredient')"
v-model="value[index]"
mdi-move-resize
auto-grow
solo
dense
rows="1"
>
<template slot="append-outer">
<v-icon class="handle">mdi-arrow-up-down</v-icon>
</template>
<v-icon
class="mr-n1"
slot="prepend"
color="error"
@click="removeByIndex(value, index)"
>
mdi-delete
</v-icon>
</v-textarea>
</v-row>
</div>
</transition-group>
</draggable>
<div class="d-flex row justify-end">
<BulkAdd @bulk-data="addIngredient" class="mr-2" />
<v-btn color="secondary" dark @click="addIngredient" class="mr-4">
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
</div>
<div v-else>
<v-list-item
dense
v-for="(ingredient, index) in value"
:key="generateKey('ingredient', index)"
@click="toggleChecked(index)"
>
<v-checkbox
hide-details
:value="checked[index]"
class="pt-0 my-auto py-auto"
color="secondary"
>
</v-checkbox>
<v-list-item-content>
<vue-markdown
class="ma-0 pa-0 text-subtitle-1 dense-markdown"
:source="ingredient"
>
</vue-markdown>
</v-list-item-content>
</v-list-item>
</div>
</div>
</template>
<script>
import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd";
import VueMarkdown from "@adapttive/vue-markdown";
import draggable from "vuedraggable";
import utils from "@/utils";
export default {
components: {
BulkAdd,
draggable,
VueMarkdown,
},
props: {
value: {
type: Array,
},
edit: {
type: Boolean,
default: true,
},
},
data() {
return {
drag: false,
checked: [],
};
},
mounted() {
this.checked = this.value.map(() => false);
},
methods: {
addIngredient(ingredients = null) {
if (ingredients.length) {
this.value.push(...ingredients);
} else {
this.value.push("");
}
},
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
updateIndex(data) {
this.$emit("input", data);
},
toggleChecked(index) {
this.$set(this.checked, index, !this.checked[index]);
},
removeByIndex(list, index) {
list.splice(index, 1);
},
},
};
</script>
<style >
.dense-markdown p {
margin: auto !important;
}
</style>

View file

@ -0,0 +1,148 @@
<template>
<div>
<h2 class="mb-4">{{ $t("recipe.instructions") }}</h2>
<div>
<div v-for="(step, index) in value" :key="index">
<v-app-bar
v-if="showTitleEditor[index]"
class="primary mx-1 mt-6"
dark
dense
rounded
>
<v-toolbar-title class="headline" v-if="!edit">
<v-app-bar-title v-text="step.title"> </v-app-bar-title>
</v-toolbar-title>
<v-text-field
v-if="edit"
class="headline pa-0 mt-5"
v-model="step.title"
dense
solo
flat
placeholder="Section Title"
background-color="primary"
>
</v-text-field>
</v-app-bar>
<v-hover v-slot="{ hover }">
<v-card
class="ma-1"
:class="[{ 'on-hover': hover }, isDisabled(index)]"
:elevation="hover ? 12 : 2"
:ripple="!edit"
@click="toggleDisabled(index)"
>
<v-card-title>
<v-btn
v-if="edit"
fab
x-small
color="white"
class="mr-2"
elevation="0"
@click="removeByIndex(value, index)"
>
<v-icon size="24" color="error">mdi-delete</v-icon>
</v-btn>
{{ $t("recipe.step-index", { step: index + 1 }) }}
<v-btn
v-if="edit"
text
color="primary"
class="ml-auto"
@click="toggleShowTitle(index)"
>
{{
!showTitleEditor[index] ? "Insert Section" : "Remove Section"
}}
</v-btn>
</v-card-title>
<v-card-text v-if="edit">
<v-textarea
auto-grow
dense
v-model="value[index]['text']"
:key="generateKey('instructions', index)"
rows="4"
>
</v-textarea>
</v-card-text>
<v-card-text v-else>
<vue-markdown :source="step.text"> </vue-markdown>
</v-card-text>
</v-card>
</v-hover>
</div>
</div>
</div>
</template>
<script>
import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils";
export default {
components: {
VueMarkdown,
},
props: {
value: {
type: Array,
},
edit: {
type: Boolean,
default: true,
},
},
data() {
return {
disabledSteps: [],
showTitleEditor: [],
};
},
mounted() {
this.showTitleEditor = this.value.map(x => this.validateTitle(x.title));
},
methods: {
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
removeByIndex(list, index) {
list.splice(index, 1);
},
validateTitle(title) {
return !(title === null || title === "");
},
toggleDisabled(stepIndex) {
if (this.edit) return;
if (this.disabledSteps.includes(stepIndex)) {
let index = this.disabledSteps.indexOf(stepIndex);
if (index !== -1) {
this.disabledSteps.splice(index, 1);
}
} else {
this.disabledSteps.push(stepIndex);
}
},
isDisabled(stepIndex) {
if (this.disabledSteps.includes(stepIndex) && !this.edit) {
return "disabled-card";
} else {
return;
}
},
toggleShowTitle(index) {
const newVal = !this.showTitleEditor[index];
if (!newVal) {
this.value[index].title = "";
}
this.$set(this.showTitleEditor, index, newVal);
},
},
};
</script>
<style scoped>
</style>

View file

@ -0,0 +1,87 @@
<template>
<div v-if="value.length > 0 || edit">
<h2 class="my-4">{{ $t("recipe.note") }}</h2>
<v-card
class="mt-1"
v-for="(note, index) in value"
:key="generateKey('note', index)"
>
<div v-if="edit">
<v-card-text>
<v-row align="center">
<v-btn
fab
x-small
color="white"
class="mr-2"
elevation="0"
@click="removeByIndex(value, index)"
>
<v-icon color="error">mdi-delete</v-icon>
</v-btn>
<v-text-field
:label="$t('recipe.title')"
v-model="value[index]['title']"
></v-text-field>
</v-row>
<v-textarea
auto-grow
:placeholder="$t('recipe.note')"
v-model="value[index]['text']"
>
</v-textarea>
</v-card-text>
</div>
<div v-else>
<v-card-title class="py-2">
{{ note.title }}
</v-card-title>
<v-divider class="mx-2"></v-divider>
<v-card-text>
<vue-markdown :source="note.text"> </vue-markdown>
</v-card-text>
</div>
</v-card>
<div class="d-flex justify-end" v-if="edit">
<v-btn class="mt-1" color="secondary" dark @click="addNote">
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
</div>
</template>
<script>
import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils";
export default {
components: {
VueMarkdown,
},
props: {
value: {
type: Array,
},
edit: {
type: Boolean,
default: true,
},
},
methods: {
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
addNote() {
this.value.push({ text: "" });
},
removeByIndex(list, index) {
list.splice(index, 1);
},
},
};
</script>
<style>
</style>

View file

@ -0,0 +1,101 @@
<template>
<div v-if="valueNotNull || edit">
<v-card class="mt-2">
<v-card-title class="py-2">
{{ $t("recipe.nutrition") }}
</v-card-title>
<v-divider class="mx-2"></v-divider>
<v-card-text v-if="edit">
<div v-for="(item, key, index) in value" :key="index">
<v-text-field
dense
:value="value[key]"
:label="labels[key].label"
:suffix="labels[key].suffix"
type="number"
autocomplete="off"
@input="updateValue(key, $event)"
></v-text-field>
</div>
</v-card-text>
<v-list dense v-if="showViewer" class="mt-0 pt-0">
<v-list-item v-for="(item, key, index) in labels" :key="index">
<v-list-item-content>
<v-list-item-title class="pl-4 text-subtitle-1 flex row ">
<div>{{ item.label }}</div>
<div class="ml-auto mr-1">{{ value[key] }}</div>
<div>{{ item.suffix }}</div>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-card>
</div>
</template>
<script>
export default {
props: {
value: {},
edit: {
type: Boolean,
default: true,
},
},
data() {
return {
labels: {
calories: {
label: this.$t("recipe.calories"),
suffix: this.$t("recipe.calories-suffix"),
},
fatContent: {
label: this.$t("recipe.fat-content"),
suffix: this.$t("recipe.grams"),
},
fiberContent: {
label: this.$t("recipe.fiber-content"),
suffix: this.$t("recipe.grams"),
},
proteinContent: {
label: this.$t("recipe.protein-content"),
suffix: this.$t("recipe.grams"),
},
sodiumContent: {
label: this.$t("recipe.sodium-content"),
suffix: this.$t("recipe.milligrams"),
},
sugarContent: {
label: this.$t("recipe.sugar-content"),
suffix: this.$t("recipe.grams"),
},
carbohydrateContent: {
label: this.$t("recipe.carbohydrate-content"),
suffix: this.$t("recipe.grams"),
},
},
};
},
computed: {
showViewer() {
return !this.edit && this.valueNotNull;
},
valueNotNull() {
for (const property in this.value) {
const valueProperty = this.value[property];
if (valueProperty && valueProperty !== "") return true;
}
return false;
},
},
methods: {
updateValue(key, value) {
this.$emit("input", { ...this.value, [key]: value });
},
},
};
</script>
<style lang="scss" scoped>
</style>

View file

@ -1,81 +0,0 @@
<template>
<div v-if="valueNotNull || edit">
<h2 class="my-4">{{$t('recipe.nutrition')}}</h2>
<div v-if="edit">
<div v-for="(item, key, index) in value" :key="index">
<v-text-field
dense
:value="value[key]"
:label="labels[key].label"
:suffix="labels[key].suffix"
type="number"
autocomplete="off"
@input="updateValue(key, $event)"
></v-text-field>
</div>
</div>
<div v-if="showViewer">
<v-list dense>
<v-list-item-group color="primary">
<v-list-item v-for="(item, key, index) in labels" :key="index">
<v-list-item-content>
<v-list-item-title class="pl-4 text-subtitle-1 flex row ">
<div>{{ item.label }}</div>
<div class="ml-auto mr-1">{{ value[key] }}</div>
<div>{{ item.suffix }}</div>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</div>
</div>
</template>
<script>
export default {
props: {
value: {},
edit: {
type: Boolean,
default: true,
},
},
data() {
return {
labels: {
calories: {
label: this.$t('recipe.calories'),
suffix:this.$t('recipe.calories-suffix'),
},
fatContent: { label: this.$t('recipe.fat-content'), suffix: this.$t('recipe.grams') },
fiberContent: { label: this.$t('recipe.fiber-content'), suffix: this.$t('recipe.grams') },
proteinContent: { label: this.$t('recipe.protein-content'), suffix: this.$t('recipe.grams') },
sodiumContent: { label: this.$t('recipe.sodium-content'), suffix: this.$t('recipe.milligrams') },
sugarContent: { label: this.$t('recipe.sugar-content'), suffix: this.$t('recipe.grams') },
},
};
},
computed: {
showViewer() {
return !this.edit && this.valueNotNull;
},
valueNotNull() {
for (const property in this.value) {
const valueProperty = this.value[property];
if (valueProperty && valueProperty !== "") return true;
}
return false;
},
},
methods: {
updateValue(key, value) {
this.$emit("input", { ...this.value, [key]: value });
},
},
};
</script>
<style lang="scss" scoped>
</style>

View file

@ -3,7 +3,7 @@
<v-card-text> <v-card-text>
<v-row dense> <v-row dense>
<ImageUploadBtn <ImageUploadBtn
class="mt-2" class="my-1"
@upload="uploadImage" @upload="uploadImage"
:slug="value.slug" :slug="value.slug"
@refresh="$emit('upload')" @refresh="$emit('upload')"
@ -64,50 +64,7 @@
</v-row> </v-row>
<v-row> <v-row>
<v-col cols="12" sm="12" md="4" lg="4"> <v-col cols="12" sm="12" md="4" lg="4">
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2> <Ingredients :edit="true" v-model="value.recipeIngredient" />
<draggable
v-model="value.recipeIngredient"
@start="drag = true"
@end="drag = false"
>
<transition-group
type="transition"
:name="!drag ? 'flip-list' : null"
>
<div
v-for="(ingredient, index) in value.recipeIngredient"
:key="generateKey('ingredient', index)"
>
<v-row align="center">
<v-textarea
class="mr-2"
:label="$t('recipe.ingredient')"
v-model="value.recipeIngredient[index]"
append-outer-icon="mdi-menu"
mdi-move-resize
auto-grow
solo
dense
rows="1"
>
<v-icon
class="mr-n1"
slot="prepend"
color="error"
@click="removeByIndex(value.recipeIngredient, index)"
>
mdi-delete
</v-icon>
</v-textarea>
</v-row>
</div>
</transition-group>
</draggable>
<v-btn color="secondary" fab dark small @click="addIngredient">
<v-icon>mdi-plus</v-icon>
</v-btn>
<BulkAdd @bulk-data="addIngredient" />
<h2 class="mt-6">{{ $t("recipe.categories") }}</h2> <h2 class="mt-6">{{ $t("recipe.categories") }}</h2>
<CategoryTagSelector <CategoryTagSelector
@ -125,87 +82,23 @@
:tag-selector="true" :tag-selector="true"
:show-label="false" :show-label="false"
/> />
<Nutrition v-model="value.nutrition" :edit="true" />
<h2 class="my-4">{{ $t("recipe.notes") }}</h2> <Assets v-model="value.assets" :edit="true" :slug="value.slug" />
<v-card
class="mt-1"
v-for="(note, index) in value.notes"
:key="generateKey('note', index)"
>
<v-card-text>
<v-row align="center">
<v-btn
fab
x-small
color="white"
class="mr-2"
elevation="0"
@click="removeByIndex(value.notes, index)"
>
<v-icon color="error">mdi-delete</v-icon>
</v-btn>
<v-text-field
:label="$t('recipe.title')"
v-model="value.notes[index]['title']"
></v-text-field>
</v-row>
<v-textarea
auto-grow
:label="$t('recipe.note')"
v-model="value.notes[index]['text']"
>
</v-textarea>
</v-card-text>
</v-card>
<v-btn class="mt-1" color="secondary" fab dark small @click="addNote">
<v-icon>mdi-plus</v-icon>
</v-btn>
<NutritionEditor v-model="value.nutrition" :edit="true" />
<ExtrasEditor :extras="value.extras" @save="saveExtras" /> <ExtrasEditor :extras="value.extras" @save="saveExtras" />
</v-col> </v-col>
<v-divider class="my-divider" :vertical="true"></v-divider> <v-divider class="my-divider" :vertical="true"></v-divider>
<v-col cols="12" sm="12" md="8" lg="8"> <v-col cols="12" sm="12" md="8" lg="8">
<h2 class="mb-4">{{ $t("recipe.instructions") }}</h2> <Instructions v-model="value.recipeInstructions" :edit="true" />
<div v-for="(step, index) in value.recipeInstructions" :key="index"> <div class="d-flex row justify-end mt-2">
<v-hover v-slot="{ hover }"> <BulkAdd @bulk-data="appendSteps" class="mr-2" />
<v-card <v-btn color="secondary" dark @click="addStep" class="mr-4">
class="ma-1" <v-icon>mdi-plus</v-icon>
:class="[{ 'on-hover': hover }]" </v-btn>
:elevation="hover ? 12 : 2"
>
<v-card-title>
<v-btn
fab
x-small
color="white"
class="mr-2"
elevation="0"
@click="removeByIndex(value.recipeInstructions, index)"
>
<v-icon size="24" color="error">mdi-delete</v-icon>
</v-btn>
{{ $t("recipe.step-index", { step: index + 1 }) }}
</v-card-title>
<v-card-text>
<v-textarea
auto-grow
dense
v-model="value.recipeInstructions[index]['text']"
:key="generateKey('instructions', index)"
rows="4"
>
</v-textarea>
</v-card-text>
</v-card>
</v-hover>
</div> </div>
<v-btn color="secondary" fab dark small @click="addStep"> <Notes :edit="true" v-model="value.notes" />
<v-icon>mdi-plus</v-icon>
</v-btn>
<BulkAdd @bulk-data="appendSteps" />
<v-text-field <v-text-field
v-model="value.orgURL" v-model="value.orgURL"
class="mt-10" class="mt-10"
@ -219,22 +112,27 @@
<script> <script>
const UPLOAD_EVENT = "upload"; const UPLOAD_EVENT = "upload";
import draggable from "vuedraggable"; import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd";
import utils from "@/utils"; import ExtrasEditor from "@/components/Recipe/Parts/Helpers/ExtrasEditor";
import BulkAdd from "./BulkAdd";
import ExtrasEditor from "./ExtrasEditor";
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector"; import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
import NutritionEditor from "./NutritionEditor"; import ImageUploadBtn from "@/components/Recipe/Parts/Helpers/ImageUploadBtn";
import ImageUploadBtn from "./ImageUploadBtn.vue";
import { validators } from "@/mixins/validators"; import { validators } from "@/mixins/validators";
import Nutrition from "@/components/Recipe/Parts/Nutrition";
import Instructions from "@/components/Recipe/Parts/Instructions";
import Ingredients from "@/components/Recipe/Parts/Ingredients";
import Assets from "@/components/Recipe/Parts/Assets.vue";
import Notes from "@/components/Recipe/Parts/Notes.vue";
export default { export default {
components: { components: {
BulkAdd, BulkAdd,
ExtrasEditor, ExtrasEditor,
draggable,
CategoryTagSelector, CategoryTagSelector,
NutritionEditor, Nutrition,
ImageUploadBtn, ImageUploadBtn,
Instructions,
Ingredients,
Assets,
Notes,
}, },
props: { props: {
value: Object, value: Object,
@ -242,7 +140,6 @@ export default {
mixins: [validators], mixins: [validators],
data() { data() {
return { return {
drag: false,
fileObject: null, fileObject: null,
}; };
}, },
@ -250,30 +147,6 @@ export default {
uploadImage(fileObject) { uploadImage(fileObject) {
this.$emit(UPLOAD_EVENT, fileObject); this.$emit(UPLOAD_EVENT, fileObject);
}, },
toggleDisabled(stepIndex) {
if (this.disabledSteps.includes(stepIndex)) {
const index = this.disabledSteps.indexOf(stepIndex);
if (index !== -1) {
this.disabledSteps.splice(index, 1);
}
} else {
this.disabledSteps.push(stepIndex);
}
},
isDisabled(stepIndex) {
return this.disabledSteps.includes(stepIndex) ? "disabled-card" : null;
},
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
addIngredient(ingredients = null) {
if (ingredients) {
this.value.recipeIngredient.push(...ingredients);
} else {
this.value.recipeIngredient.push("");
}
},
appendSteps(steps) { appendSteps(steps) {
this.value.recipeInstructions.push( this.value.recipeInstructions.push(
...steps.map(x => ({ ...steps.map(x => ({
@ -284,15 +157,9 @@ export default {
addStep() { addStep() {
this.value.recipeInstructions.push({ text: "" }); this.value.recipeInstructions.push({ text: "" });
}, },
addNote() {
this.value.notes.push({ text: "" });
},
saveExtras(extras) { saveExtras(extras) {
this.value.extras = extras; this.value.extras = extras;
}, },
removeByIndex(list, index) {
list.splice(index, 1);
},
validateRecipe() { validateRecipe() {
return this.$refs.form.validate(); return this.$refs.form.validate();
}, },

View file

@ -1,62 +0,0 @@
<template>
<div>
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
<v-list-item
dense
v-for="(ingredient, index) in ingredients"
:key="generateKey('ingredient', index)"
@click="toggleChecked(index)"
>
<v-checkbox
hide-details
:value="checked[index]"
class="pt-0 my-auto py-auto"
color="secondary"
>
</v-checkbox>
<v-list-item-content>
<vue-markdown
class="ma-0 pa-0 text-subtitle-1 dense-markdown"
:source="ingredient"
>
</vue-markdown>
</v-list-item-content>
</v-list-item>
</div>
</template>
<script>
import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils";
export default {
components: {
VueMarkdown,
},
props: {
ingredients: Array,
},
data() {
return {
checked: [],
};
},
mounted() {
this.checked = this.ingredients.map(() => false);
},
methods: {
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
toggleChecked(index) {
this.$set(this.checked, index, !this.checked[index]);
},
},
};
</script>
<style >
.dense-markdown p {
margin: auto !important;
}
</style>

View file

@ -1,36 +0,0 @@
<template>
<div>
<h2 v-if="notes[0]" class="my-4">{{ $t("recipe.notes") }}</h2>
<v-card
class="mt-1"
v-for="(note, index) in notes"
:key="generateKey('note', index)"
>
<v-card-title> {{ note.title }}</v-card-title>
<v-card-text>
<vue-markdown :source="note.text"> </vue-markdown>
</v-card-text>
</v-card>
</div>
</template>
<script>
import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils";
export default {
props: {
notes: Array,
},
components: {
VueMarkdown,
},
methods: {
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
},
};
</script>
<style>
</style>

View file

@ -1,67 +0,0 @@
<template>
<div>
<h2 class="mb-4">{{ $t("recipe.instructions") }}</h2>
<v-hover
v-for="(step, index) in steps"
:key="generateKey('step', index)"
v-slot="{ hover }"
>
<v-card
class="ma-1"
:class="[{ 'on-hover': hover }, isDisabled(index)]"
:elevation="hover ? 12 : 2"
@click="toggleDisabled(index)"
>
<v-card-title>{{
$t("recipe.step-index", { step: index + 1 })
}}</v-card-title>
<v-card-text>
<vue-markdown :source="step.text"> </vue-markdown>
</v-card-text>
</v-card>
</v-hover>
</div>
</template>
<script>
import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils";
export default {
props: {
steps: Array,
},
components: {
VueMarkdown,
},
data() {
return {
disabledSteps: [],
};
},
methods: {
toggleDisabled(stepIndex) {
if (this.disabledSteps.includes(stepIndex)) {
let index = this.disabledSteps.indexOf(stepIndex);
if (index !== -1) {
this.disabledSteps.splice(index, 1);
}
} else {
this.disabledSteps.push(stepIndex);
}
},
isDisabled(stepIndex) {
if (this.disabledSteps.includes(stepIndex)) {
return "disabled-card";
} else {
return;
}
},
generateKey(item, index) {
return utils.generateUniqueKey(item, index);
},
},
};
</script>
<style>
</style>

View file

@ -31,16 +31,29 @@
</v-row> </v-row>
<v-row> <v-row>
<v-col cols="12" sm="12" md="4" lg="4"> <v-col cols="12" sm="12" md="4" lg="4">
<Ingredients :ingredients="ingredients" /> <Ingredients :value="ingredients" :edit="false" />
<div v-if="medium"> <div v-if="medium">
<RecipeChips :title="$t('recipe.categories')" :items="categories" /> <v-card class="mt-2" v-if="categories.length > 0">
<RecipeChips <v-card-title class="py-2">
:title="$t('recipe.tags')" {{ $t("recipe.categories") }}
:items="tags" </v-card-title>
:isCategory="false" <v-divider class="mx-2"></v-divider>
/> <v-card-text>
<Notes :notes="notes" /> <RecipeChips :items="categories" />
<NutritionEditor :value="nutrition" :edit="false" /> </v-card-text>
</v-card>
<v-card class="mt-2" v-if="tags.length > 0">
<v-card-title class="py-2">
{{ $t("recipe.tags") }}
</v-card-title>
<v-divider class="mx-2"></v-divider>
<v-card-text>
<RecipeChips :items="tags" :isCategory="false" />
</v-card-text>
</v-card>
<Nutrition :value="nutrition" :edit="false" />
<Assets :value="assets" :edit="false" :slug="slug" />
</div> </div>
</v-col> </v-col>
<v-divider <v-divider
@ -50,14 +63,15 @@
></v-divider> ></v-divider>
<v-col cols="12" sm="12" md="8" lg="8"> <v-col cols="12" sm="12" md="8" lg="8">
<Steps :steps="instructions" /> <Instructions :value="instructions" :edit="false" />
<Notes :value="notes" :edit="false" />
</v-col> </v-col>
</v-row> </v-row>
<div v-if="!medium"> <div v-if="!medium">
<RecipeChips :title="$t('recipe.categories')" :items="categories" /> <RecipeChips :title="$t('recipe.categories')" :items="categories" />
<RecipeChips :title="$t('recipe.tags')" :items="tags" /> <RecipeChips :title="$t('recipe.tags')" :items="tags" />
<Notes :notes="notes" /> <Nutrition :value="nutrition" :edit="false" />
<NutritionEditor :value="nutrition" :edit="false" /> <Assets :value="assets" :edit="false" :slug="slug" />
</div> </div>
<v-row class="mt-2 mb-1"> <v-row class="mt-2 mb-1">
<v-col></v-col> <v-col></v-col>
@ -82,24 +96,27 @@
</template> </template>
<script> <script>
import NutritionEditor from "@/components/Recipe/RecipeEditor/NutritionEditor"; import Nutrition from "@/components/Recipe/Parts/Nutrition";
import VueMarkdown from "@adapttive/vue-markdown"; import VueMarkdown from "@adapttive/vue-markdown";
import utils from "@/utils"; import utils from "@/utils";
import RecipeChips from "./RecipeChips"; import RecipeChips from "./RecipeChips";
import Steps from "./Steps"; import Notes from "@/components/Recipe/Parts/Notes";
import Notes from "./Notes"; import Ingredients from "@/components/Recipe/Parts/Ingredients";
import Ingredients from "./Ingredients"; import Instructions from "@/components/Recipe/Parts/Instructions.vue";
import Assets from "../Parts/Assets.vue";
export default { export default {
components: { components: {
VueMarkdown, VueMarkdown,
RecipeChips, RecipeChips,
Steps,
Notes, Notes,
Ingredients, Ingredients,
NutritionEditor, Nutrition,
Instructions,
Assets,
}, },
props: { props: {
name: String, name: String,
slug: String,
description: String, description: String,
ingredients: Array, ingredients: Array,
instructions: Array, instructions: Array,
@ -110,6 +127,7 @@ export default {
yields: String, yields: String,
orgURL: String, orgURL: String,
nutrition: Object, nutrition: Object,
assets: Array,
}, },
data() { data() {
return { return {

View file

@ -1,5 +1,6 @@
<template> <template>
<div> <div>
<slot name="open" v-bind="{ open }"> </slot>
<v-dialog <v-dialog
v-model="dialog" v-model="dialog"
:width="modalWidth + 'px'" :width="modalWidth + 'px'"
@ -25,7 +26,7 @@
Cancel Cancel
</v-btn> </v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="success" @click="$emit('submit')"> <v-btn color="success" @click="submitEvent">
Submit Submit
</v-btn> </v-btn>
</slot> </slot>
@ -65,6 +66,10 @@ export default {
}; };
}, },
methods: { methods: {
submitEvent() {
this.$emit("submit");
this.close();
},
open() { open() {
this.dialog = true; this.dialog = true;
}, },

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Seneste" "recent": "Seneste"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Beskrivelse", "description": "Beskrivelse",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingrediens", "ingredient": "Ingrediens",
@ -132,13 +134,13 @@
"original-url": "Oprindelig opskrift", "original-url": "Oprindelig opskrift",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Opskriftens navn", "recipe-name": "Opskriftens navn",
"servings": "Portioner", "servings": "Portioner",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Trin: {step}", "step-index": "Trin: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Mærker", "tags": "Mærker",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Neueste" "recent": "Neueste"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Schlüssel hinzufügen", "add-key": "Schlüssel hinzufügen",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Kalorien", "calories": "Kalorien",
@ -113,8 +114,9 @@
"delete-confirmation": "Bist du dir sicher, dass du dieses Rezept löschen möchtest?", "delete-confirmation": "Bist du dir sicher, dass du dieses Rezept löschen möchtest?",
"delete-recipe": "Rezept löschen", "delete-recipe": "Rezept löschen",
"description": "Beschreibung", "description": "Beschreibung",
"fat-content": "Fettgehalt", "fat-content": "Fat",
"fiber-content": "Ballaststoffe", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "g", "grams": "g",
"image": "Bild", "image": "Bild",
"ingredient": "Zutat", "ingredient": "Zutat",
@ -132,13 +134,13 @@
"original-url": "Ursprüngliche URL", "original-url": "Ursprüngliche URL",
"perform-time": "Kochzeit", "perform-time": "Kochzeit",
"prep-time": "Vorbereitung", "prep-time": "Vorbereitung",
"protein-content": "Eiweißgehalt", "protein-content": "Protein",
"recipe-image": "Rezeptbild", "recipe-image": "Rezeptbild",
"recipe-name": "Rezeptname", "recipe-name": "Rezeptname",
"servings": "Portionen", "servings": "Portionen",
"sodium-content": "Natriumgehalt", "sodium-content": "Sodium",
"step-index": "Schritt {step}:", "step-index": "Schritt {step}:",
"sugar-content": "Zuckergehalt", "sugar-content": "Sugar",
"tags": "Schlagworte", "tags": "Schlagworte",
"title": "Titel", "title": "Titel",
"total-time": "Gesamtzeit", "total-time": "Gesamtzeit",
@ -152,7 +154,7 @@
"exclude": "Ausschließen", "exclude": "Ausschließen",
"include": "Einbeziehen", "include": "Einbeziehen",
"or": "Oder", "or": "Oder",
"and": "and", "and": "und",
"search": "Suchen", "search": "Suchen",
"tag-filter": "Schlagwortfilter" "tag-filter": "Schlagwortfilter"
}, },
@ -221,7 +223,7 @@
}, },
"toolbox": { "toolbox": {
"toolbox": "Toolbox", "toolbox": "Toolbox",
"new-name": "New Name", "new-name": "Neuer Name",
"recipes-effected": "Recipes Effected", "recipes-effected": "Recipes Effected",
"title-case-all": "Title Case All", "title-case-all": "Title Case All",
"no-unused-items": "No Unused Items", "no-unused-items": "No Unused Items",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -161,6 +161,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -169,8 +170,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"ingredient": "Ingredient", "ingredient": "Ingredient",
"ingredients": "Ingredients", "ingredients": "Ingredients",
@ -187,7 +189,7 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-created": "Recipe created", "recipe-created": "Recipe created",
"recipe-creation-failed": "Recipe creation failed", "recipe-creation-failed": "Recipe creation failed",
"recipe-deleted": "Recipe deleted", "recipe-deleted": "Recipe deleted",
@ -197,9 +199,9 @@
"recipe-update-failed": "Recipe update failed", "recipe-update-failed": "Recipe update failed",
"recipe-updated": "Recipe updated", "recipe-updated": "Recipe updated",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Récent" "recent": "Récent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Ajouter une clé", "add-key": "Ajouter une clé",
"api-extras": "Extras API", "api-extras": "Extras API",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Êtes-vous sûr(e) de vouloir supprimer cette recette ?", "delete-confirmation": "Êtes-vous sûr(e) de vouloir supprimer cette recette ?",
"delete-recipe": "Supprimer la recette", "delete-recipe": "Supprimer la recette",
"description": "Description", "description": "Description",
"fat-content": "Lipides", "fat-content": "Fat",
"fiber-content": "Fibres", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grammes", "grams": "grammes",
"image": "Image", "image": "Image",
"ingredient": "Ingrédient", "ingredient": "Ingrédient",
@ -132,13 +134,13 @@
"original-url": "Recette originale", "original-url": "Recette originale",
"perform-time": "Temps de cuisson", "perform-time": "Temps de cuisson",
"prep-time": "Temps de préparation", "prep-time": "Temps de préparation",
"protein-content": "Protéines", "protein-content": "Protein",
"recipe-image": "Image de la recette", "recipe-image": "Image de la recette",
"recipe-name": "Nom de la recette", "recipe-name": "Nom de la recette",
"servings": "Portions", "servings": "Portions",
"sodium-content": "Sels", "sodium-content": "Sodium",
"step-index": "Étape : {step}", "step-index": "Étape : {step}",
"sugar-content": "Glucides", "sugar-content": "Sugar",
"tags": "Mots-clés", "tags": "Mots-clés",
"title": "Titre", "title": "Titre",
"total-time": "Temps total", "total-time": "Temps total",
@ -152,7 +154,7 @@
"exclude": "Exclure", "exclude": "Exclure",
"include": "Inclure", "include": "Inclure",
"or": "Ou", "or": "Ou",
"and": "and", "and": "et",
"search": "Rechercher", "search": "Rechercher",
"tag-filter": "Filtre par mots-clés" "tag-filter": "Filtre par mots-clés"
}, },
@ -220,14 +222,14 @@
"webhook-url": "Lien du webhook" "webhook-url": "Lien du webhook"
}, },
"toolbox": { "toolbox": {
"toolbox": "Toolbox", "toolbox": "Boîte à outils",
"new-name": "New Name", "new-name": "Nouveau nom",
"recipes-effected": "Recipes Effected", "recipes-effected": "Recipes Effected",
"title-case-all": "Title Case All", "title-case-all": "Majuscules partout",
"no-unused-items": "No Unused Items", "no-unused-items": "Aucun élément inutilisé",
"remove-unused": "Remove Unused", "remove-unused": "Supprimer orphelins",
"assign-all": "Assign All", "assign-all": "Assigner tout",
"bulk-assign": "Bulk Assign" "bulk-assign": "Assigner en masse"
} }
}, },
"user": { "user": {

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent(e)" "recent": "Recent(e)"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Sleutel toevoegen", "add-key": "Sleutel toevoegen",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calorieën", "calories": "Calorieën",
@ -113,8 +114,9 @@
"delete-confirmation": "Weet u zeker dat u dit recept wilt verwijderen?", "delete-confirmation": "Weet u zeker dat u dit recept wilt verwijderen?",
"delete-recipe": "Recept verwijderen", "delete-recipe": "Recept verwijderen",
"description": "Omschrijving", "description": "Omschrijving",
"fat-content": "Vetten", "fat-content": "Fat",
"fiber-content": "Vezels", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "gram", "grams": "gram",
"image": "Afbeelding", "image": "Afbeelding",
"ingredient": "Ingrediënt", "ingredient": "Ingrediënt",
@ -132,13 +134,13 @@
"original-url": "Oorspronkelijke URL", "original-url": "Oorspronkelijke URL",
"perform-time": "Kook tijd", "perform-time": "Kook tijd",
"prep-time": "Voorbereiding tijd", "prep-time": "Voorbereiding tijd",
"protein-content": "Eiwitten", "protein-content": "Protein",
"recipe-image": "Recept afbeelding", "recipe-image": "Recept afbeelding",
"recipe-name": "Receptnaam", "recipe-name": "Receptnaam",
"servings": "Porties", "servings": "Porties",
"sodium-content": "Sodium gehalte", "sodium-content": "Sodium",
"step-index": "Stap: {step}", "step-index": "Stap: {step}",
"sugar-content": "Suiker gehalte", "sugar-content": "Sugar",
"tags": "Labels", "tags": "Labels",
"title": "Titel", "title": "Titel",
"total-time": "Totale Tijd", "total-time": "Totale Tijd",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -4,65 +4,65 @@
"take-me-home": "Powrót na stronę główną" "take-me-home": "Powrót na stronę główną"
}, },
"about": { "about": {
"about-mealie": "About Mealie", "about-mealie": "O Mealie",
"api-docs": "API Docs", "api-docs": "Dokumentacja API",
"api-port": "API Port", "api-port": "Port API",
"application-mode": "Application Mode", "application-mode": "Tryb aplikacji",
"database-type": "Database Type", "database-type": "Rodzaj bazy danych",
"default-group": "Default Group", "default-group": "Domyślna grupa",
"demo": "Demo", "demo": "Demo",
"demo-status": "Demo Status", "demo-status": "Status demo",
"development": "Development", "development": "Wersja testowa",
"not-demo": "Not Demo", "not-demo": "Nie demo",
"production": "Production", "production": "Produkcyjna",
"sqlite-file": "SQLite File", "sqlite-file": "Plik SQLite'a",
"version": "Version" "version": "Wersja"
}, },
"general": { "general": {
"apply": "Apply", "apply": "Zastosuj",
"cancel": "Anuluj", "cancel": "Anuluj",
"close": "Zamknij", "close": "Zamknij",
"confirm": "Potwierdź", "confirm": "Potwierdź",
"create": "Utwórz", "create": "Utwórz",
"current-parenthesis": "(Current)", "current-parenthesis": "(Bieżący)",
"delete": "Usuń", "delete": "Usuń",
"disabled": "Disabled", "disabled": "Wyłączone",
"download": "Pobierz", "download": "Pobierz",
"edit": "Edytuj", "edit": "Edytuj",
"enabled": "Włączone", "enabled": "Włączone",
"field-required": "Field Required", "field-required": "Pole jest wymagane",
"filter": "Filter", "filter": "Filtruj",
"friday": "Friday", "friday": "Piątek",
"get": "Get", "get": "Zastosuj",
"groups": "Groups", "groups": "Grupy",
"import": "Importuj", "import": "Importuj",
"monday": "Monday", "monday": "Poniedziałek",
"name": "Nazwa", "name": "Nazwa",
"no": "No", "no": "Nie",
"ok": "OK", "ok": "OK",
"options": "Opcje", "options": "Opcje",
"random": "Losowa", "random": "Losowa",
"recent": "Recent", "recent": "Najnowsze",
"recipes": "Przepisy", "recipes": "Przepisy",
"reset": "Reset", "reset": "Resetuj",
"saturday": "Saturday", "saturday": "Sobota",
"save": "Zapisz", "save": "Zapisz",
"settings": "Ustawienia", "settings": "Ustawienia",
"sort": "Sort", "sort": "Sortuj",
"sort-alphabetically": "A-Z", "sort-alphabetically": "A-Z",
"submit": "Zatwierdź", "submit": "Zatwierdź",
"sunday": "Sunday", "sunday": "Niedziela",
"templates": "Szablony", "templates": "Szablony",
"themes": "Motywy", "themes": "Motywy",
"thursday": "Thursday", "thursday": "Czwartek",
"token": "Token", "token": "Token",
"tuesday": "Tuesday", "tuesday": "Wtorek",
"update": "Uaktualnij", "update": "Uaktualnij",
"upload": "Wrzuć", "upload": "Prześlij",
"url": "URL", "url": "URL",
"users": "Users", "users": "Użytkownicy",
"wednesday": "Wednesday", "wednesday": "Środa",
"yes": "Yes" "yes": "Tak"
}, },
"meal-plan": { "meal-plan": {
"create-a-new-meal-plan": "Utwórz nowy plan posiłku", "create-a-new-meal-plan": "Utwórz nowy plan posiłku",
@ -70,13 +70,13 @@
"dinner-today": "Obiad dziś", "dinner-today": "Obiad dziś",
"edit-meal-plan": "Edytuj plan posiłku", "edit-meal-plan": "Edytuj plan posiłku",
"end-date": "Data zakończenia", "end-date": "Data zakończenia",
"group": "Group (Beta)", "group": "Grupa (Beta)",
"meal-planner": "Meal Planner", "meal-planner": "Plan posiłków",
"meal-plans": "Plany posiłku", "meal-plans": "Plany posiłku",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans", "only-recipes-with-these-categories-will-be-used-in-meal-plans": "Tylko przepisy z tych kategorii będą używane w planach posiłków",
"planner": "Planer", "planner": "Planer",
"quick-week": "Quick Week", "quick-week": "Szybki plan na tydzień",
"shopping-list": "Shopping List", "shopping-list": "Lista zakupów",
"start-date": "Data rozpoczęcia" "start-date": "Data rozpoczęcia"
}, },
"migration": { "migration": {
@ -93,73 +93,75 @@
}, },
"new-recipe": { "new-recipe": {
"bulk-add": "Dodanie zbiorcze", "bulk-add": "Dodanie zbiorcze",
"error-message": "Wygląda na to, że wystąpił błąd. Sprawdź log i debug/last_recipe.json aby zasięgnąć po więcej informacji.", "error-message": "Wygląda na to, że wystąpił błąd. Sprawdź log i debug/last_recipe.json aby sprawdzić co poszło nie tak.",
"from-url": "Z odnośnika", "from-url": "Importuj przepis",
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Przeklej zawartość przepisu. Każda indywidualna linia traktowana będzie jako pozycja na liście", "paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Wklej zawartość przepisu. Każda indywidualna linia traktowana będzie jako pozycja na liście",
"recipe-url": "Odnośnik przepisu", "recipe-url": "Adres URL przepisu",
"url-form-hint": "Copy and paste a link from your favorite recipe website" "url-form-hint": "Skopiuj i wklej link ze swojej ulubionej strony z przepisami"
}, },
"page": { "page": {
"all-recipes": "All Recipes", "all-recipes": "Wszystkie przepisy",
"home-page": "Home Page", "home-page": "Strona Główna",
"recent": "Recent" "recent": "Najnowsze"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Dodaj klucz", "add-key": "Dodaj klucz",
"api-extras": "Dodatki API", "api-extras": "Dodatki API",
"calories": "Calories", "calories": "Kalorie",
"calories-suffix": "calories", "calories-suffix": "kalorie",
"categories": "Kategorie", "categories": "Kategorie",
"delete-confirmation": "Czy jesteś pewien, że chcesz usunąć ten przepis?", "delete-confirmation": "Czy jesteś pewien, że chcesz usunąć ten przepis?",
"delete-recipe": "Usuń przepis", "delete-recipe": "Usuń przepis",
"description": "Opis", "description": "Opis",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"grams": "grams", "carbohydrate-content": "Carbohydrate",
"image": "Image", "grams": "gram",
"image": "Zdjęcie",
"ingredient": "Składnik", "ingredient": "Składnik",
"ingredients": "Składniki", "ingredients": "Składniki",
"instructions": "Instrukcje", "instructions": "Instrukcje",
"key-name-required": "Nazwa klucza jest wymagana", "key-name-required": "Nazwa klucza jest wymagana",
"milligrams": "milligrams", "milligrams": "miligram",
"new-key-name": "Nazwa nowego klucza", "new-key-name": "Nazwa nowego klucza",
"no-white-space-allowed": "Znaki niedrukowalne są niedozwolone", "no-white-space-allowed": "Znaki niedrukowalne są niedozwolone",
"note": "Notatka", "note": "Notatka",
"notes": "Notatki", "notes": "Notatki",
"nutrition": "Nutrition", "nutrition": "Wartości odżywcze",
"object-key": "Klucz obiektu", "object-key": "Klucz obiektu",
"object-value": "Wartość obiektu", "object-value": "Wartość obiektu",
"original-url": "Oryginalny odnośnik", "original-url": "Oryginalny adres URL",
"perform-time": "Czas gotowania", "perform-time": "Czas gotowania",
"prep-time": "Czas przyrządzania", "prep-time": "Czas przyrządzania",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Zdjęcie do przepisu",
"recipe-name": "Nazwa przepisu", "recipe-name": "Nazwa przepisu",
"servings": "Porcje", "servings": "Porcje",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Krok: {step}", "step-index": "Krok: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Etykiety", "tags": "Tagi",
"title": "Tytuł", "title": "Tytuł",
"total-time": "Czas całkowity", "total-time": "Czas całkowity",
"view-recipe": "Wyświetl przepis" "view-recipe": "Wyświetl przepis"
}, },
"search": { "search": {
"search-mealie": "Search Mealie (press /)", "search-mealie": "Przeszukaj Mealie (naciśnij /)",
"search-placeholder": "Search...", "search-placeholder": "Szukaj...",
"max-results": "Max Results", "max-results": "Maksymalna liczba wyników",
"category-filter": "Category Filter", "category-filter": "Filtr kategorii",
"exclude": "Exclude", "exclude": "Wyklucz",
"include": "Include", "include": "Dołącz",
"or": "Or", "or": "Lub",
"and": "and", "and": "oraz",
"search": "Search", "search": "Szukaj",
"tag-filter": "Tag Filter" "tag-filter": "Filtr tagów"
}, },
"settings": { "settings": {
"add-a-new-theme": "Dodaj nowy motyw", "add-a-new-theme": "Dodaj nowy motyw",
"admin-settings": "Admin Settings", "admin-settings": "Ustawienia administratora",
"available-backups": "Dostępne kopie zapsowe", "available-backups": "Dostępne kopie zapasowe",
"backup": { "backup": {
"backup-tag": "Etykieta kopii zapasowej", "backup-tag": "Etykieta kopii zapasowej",
"create-heading": "Utwórz kopię zapasową", "create-heading": "Utwórz kopię zapasową",
@ -167,43 +169,43 @@
"partial-backup": "Częściowa kopia zapasowa" "partial-backup": "Częściowa kopia zapasowa"
}, },
"backup-and-exports": "Kopie zapasowe", "backup-and-exports": "Kopie zapasowe",
"backup-info": "Kopie zapasowe zapisywane są w standardowym formacie JSON wraz ze zdjęciami w systemie plików. W katalogu kopii zapasowej znajdziesz plik z rozszerzeniem .zip zawierający wszystkie przepisy i zdjęcia z bazy danych. Jeśli oznaczone zostały pliki markdown, one także znajdą się w pliku .zip. Aby zaimportować kopię, musi ona znajdować się w folderze kopii zapasowych. Kopie automatyczne tworzone są codziennie o godzinie 03:00.", "backup-info": "Kopie zapasowe zapisywane są w standardowym formacie JSON wraz ze zdjęciami w systemie plików. W katalogu kopii zapasowej znajdziesz plik z rozszerzeniem .zip zawierający wszystkie przepisy i zdjęcia z bazy danych. Jeśli zaznaczone zostały pliki markdown, one także znajdą się w pliku .zip. Aby zaimportować kopię, musi ona znajdować się w folderze kopii zapasowych. Kopie automatyczne tworzone są codziennie o godzinie 03:00.",
"change-password": "Change Password", "change-password": "Zmień hasło",
"current": "Wersja:", "current": "Wersja:",
"custom-pages": "Custom Pages", "custom-pages": "Niestandardowe strony",
"edit-page": "Edit Page", "edit-page": "Edytuj stronę",
"first-day-of-week": "First day of the week", "first-day-of-week": "Pierwszy dzień tygodnia",
"homepage": { "homepage": {
"all-categories": "All Categories", "all-categories": "Wszystkie kategorie",
"card-per-section": "Card Per Section", "card-per-section": "Karty na sekcję",
"home-page": "Home Page", "home-page": "Strona Główna",
"home-page-sections": "Home Page Sections", "home-page-sections": "Sekcje strony głównej",
"show-recent": "Show Recent" "show-recent": "Pokaż najnowsze"
}, },
"language": "Język", "language": "Język",
"latest": "Najnowsza", "latest": "Najnowsza",
"local-api": "Lokalne API", "local-api": "Lokalne API",
"locale-settings": "Locale settings", "locale-settings": "Ustawienia językowe",
"manage-users": "Manage Users", "manage-users": "Zarządzaj użytkownikami",
"migrations": "Migrations", "migrations": "Migracje",
"new-page": "New Page", "new-page": "Nowa Strona",
"page-name": "Page Name", "page-name": "Nazwa strony",
"profile": "Profile", "profile": "Profil",
"remove-existing-entries-matching-imported-entries": "Remove existing entries matching imported entries", "remove-existing-entries-matching-imported-entries": "Usuń istniejące wpisy pasujące do importowanych wpisów",
"set-new-time": "Ustaw nowy czas", "set-new-time": "Ustaw nowy czas",
"site-settings": "Site Settings", "site-settings": "Ustawienia strony",
"theme": { "theme": {
"accent": "Akcent", "accent": "Akcent",
"are-you-sure-you-want-to-delete-this-theme": "Czy jesteś pewien, że chcesz usunąć ten motyw?", "are-you-sure-you-want-to-delete-this-theme": "Czy jesteś pewien, że chcesz usunąć ten motyw?",
"choose-how-mealie-looks-to-you-set-your-theme-preference-to-follow-your-system-settings-or-choose-to-use-the-light-or-dark-theme": "Wybierz jak Mealie ma dla Ciebie wyglądać. Dostępne opcje to podążanie za odcieniem systemowym, bądź motyw jasny lub ciemny.", "choose-how-mealie-looks-to-you-set-your-theme-preference-to-follow-your-system-settings-or-choose-to-use-the-light-or-dark-theme": "Wybierz jak Mealie ma dla Ciebie wyglądać. Dostępne opcje to podążanie za odcieniem systemowym, bądź motyw jasny lub ciemny.",
"dark": "Ciemny", "dark": "Ciemny",
"dark-mode": "Ciemny motyw", "dark-mode": "Ciemny motyw",
"default-to-system": "Domyślny dla systemu", "default-to-system": "Motyw systemowy",
"delete-theme": "Usuń motyw", "delete-theme": "Usuń motyw",
"error": "Błąd", "error": "Błąd",
"info": "Informacja", "info": "Informacja",
"light": "Jasny", "light": "Jasny",
"primary": "Pierwszorzędny", "primary": "Podstawowy",
"secondary": "Drugorzędny", "secondary": "Drugorzędny",
"select-a-theme-from-the-dropdown-or-create-a-new-theme-note-that-the-default-theme-will-be-served-to-all-users-who-have-not-set-a-theme-preference": "Wybierz motyw z rozwijanej listy bądź stwórz nowy. Domyślny motyw zostanie użyty dla wszystkich użytkowników którzy nie wybrali własnej preferencji.", "select-a-theme-from-the-dropdown-or-create-a-new-theme-note-that-the-default-theme-will-be-served-to-all-users-who-have-not-set-a-theme-preference": "Wybierz motyw z rozwijanej listy bądź stwórz nowy. Domyślny motyw zostanie użyty dla wszystkich użytkowników którzy nie wybrali własnej preferencji.",
"success": "Powodzenie", "success": "Powodzenie",
@ -217,63 +219,63 @@
"meal-planner-webhooks": "Webhooki planera posiłków", "meal-planner-webhooks": "Webhooki planera posiłków",
"test-webhooks": "Testuj webhooki", "test-webhooks": "Testuj webhooki",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "Odnośniki poniżej otrzymają webhook zawierający dane o przepisie dla danego dnia. Aktualnie webhooki zostanę wykonane o", "the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "Odnośniki poniżej otrzymają webhook zawierający dane o przepisie dla danego dnia. Aktualnie webhooki zostanę wykonane o",
"webhook-url": "Odnośnik webhooka" "webhook-url": "URL webhooka"
}, },
"toolbox": { "toolbox": {
"toolbox": "Toolbox", "toolbox": "Przybornik",
"new-name": "New Name", "new-name": "Nowa nazwa",
"recipes-effected": "Recipes Effected", "recipes-effected": "Objęte przepisy",
"title-case-all": "Title Case All", "title-case-all": "Wszędzie wielkie litery",
"no-unused-items": "No Unused Items", "no-unused-items": "Brak nieużywanych elementów",
"remove-unused": "Remove Unused", "remove-unused": "Usuń nieużywane",
"assign-all": "Assign All", "assign-all": "Przypisz wszystkie",
"bulk-assign": "Bulk Assign" "bulk-assign": "Masowe przypisanie"
} }
}, },
"user": { "user": {
"admin": "Admin", "admin": "Administrator",
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?", "are-you-sure-you-want-to-delete-the-group": "Czy na pewno chcesz usunąć <b>{groupName}<b/>?",
"are-you-sure-you-want-to-delete-the-link": "Are you sure you want to delete the link <b>{link}<b/>?", "are-you-sure-you-want-to-delete-the-link": "Czy na pewno chcesz usunąć link <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "Are you sure you want to delete the user <b>{activeName} ID: {activeId}<b/>?", "are-you-sure-you-want-to-delete-the-user": "Czy na pewno chcesz usunąć użytkownika <b>{activeName} ID: {activeId}<b/>?",
"confirm-group-deletion": "Confirm Group Deletion", "confirm-group-deletion": "Potwierdź usunięcie grupy",
"confirm-link-deletion": "Confirm Link Deletion", "confirm-link-deletion": "Potwierdź usunięcie linku",
"confirm-password": "Confirm Password", "confirm-password": "Potwierdź hasło",
"confirm-user-deletion": "Confirm User Deletion", "confirm-user-deletion": "Potwierdź usunięcie użytkownika",
"could-not-validate-credentials": "Could Not Validate Credentials", "could-not-validate-credentials": "Nie można zweryfikować danych logowania",
"create-group": "Create Group", "create-group": "Utwórz Grupę",
"create-link": "Create Link", "create-link": "Utwórz link",
"create-user": "Create User", "create-user": "Utwórz użytkownika",
"current-password": "Current Password", "current-password": "Obecne hasło",
"e-mail-must-be-valid": "E-mail must be valid", "e-mail-must-be-valid": "E-mail musi być poprawny",
"edit-user": "Edit User", "edit-user": "Edytuj użytkownika",
"email": "Email", "email": "Email",
"full-name": "Full Name", "full-name": "Imię i nazwisko",
"group": "Group", "group": "Grupa",
"group-id-with-value": "Group ID: {groupID}", "group-id-with-value": "ID grupy: {groupID}",
"group-name": "Group Name", "group-name": "Nazwa grupy",
"groups": "Groups", "groups": "Grupy",
"groups-can-only-be-set-by-administrators": "Groups can only be set by administrators", "groups-can-only-be-set-by-administrators": "Grupy mogą być ustawiane tylko przez administratorów",
"link-id": "Link ID", "link-id": "ID linku",
"link-name": "Link Name", "link-name": "Nazwa linku",
"login": "Login", "login": "Login",
"logout": "Logout", "logout": "Wyloguj się",
"new-password": "New Password", "new-password": "Nowe Hasło",
"new-user": "New User", "new-user": "Nowy użytkownik",
"password": "Hasło", "password": "Hasło",
"password-must-match": "Password must match", "password-must-match": "Hasła muszą być takie same",
"reset-password": "Reset Password", "reset-password": "Zresetuj hasło",
"sign-in": "Zaloguj się", "sign-in": "Zaloguj się",
"sign-up-links": "Sign Up Links", "sign-up-links": "Linki do rejestracji",
"total-mealplans": "Total MealPlans", "total-mealplans": "Ilość planów posiłków",
"total-users": "Total Users", "total-users": "Ilość użytkowników",
"upload-photo": "Upload Photo", "upload-photo": "Prześlij zdjęcie",
"use-8-characters-or-more-for-your-password": "Use 8 characters or more for your password", "use-8-characters-or-more-for-your-password": "Hasło musi składać się z 8 lub więcej znaków",
"user-group": "User Group", "user-group": "Grupa użytkownika",
"user-id": "User ID", "user-id": "ID użytkownika",
"user-id-with-value": "User ID: {id}", "user-id-with-value": "ID użytkownika: {id}",
"user-password": "User Password", "user-password": "Hasło użytkownika",
"users": "Users", "users": "Użytkownicy",
"webhook-time": "Webhook Time", "webhook-time": "Czas webhooka",
"webhooks-enabled": "Webhooks Enabled" "webhooks-enabled": "Webhooki włączone"
} }
} }

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Adicionar Chave", "add-key": "Adicionar Chave",
"api-extras": "Extras API", "api-extras": "Extras API",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Tem a certeza que deseja eliminar esta receita?", "delete-confirmation": "Tem a certeza que deseja eliminar esta receita?",
"delete-recipe": "Eliminar Receita", "delete-recipe": "Eliminar Receita",
"description": "Descrição", "description": "Descrição",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingrediente", "ingredient": "Ingrediente",
@ -132,13 +134,13 @@
"original-url": "URL Original", "original-url": "URL Original",
"perform-time": "Tempo de Cozedura", "perform-time": "Tempo de Cozedura",
"prep-time": "Tempo de Preparação", "prep-time": "Tempo de Preparação",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Nome da Receita", "recipe-name": "Nome da Receita",
"servings": "Porções", "servings": "Porções",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Passo: {step}", "step-index": "Passo: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Etiquetas", "tags": "Etiquetas",
"title": "Título", "title": "Título",
"total-time": "Tempo Total", "total-time": "Tempo Total",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Beskrivning", "description": "Beskrivning",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingrediens", "ingredient": "Ingrediens",
@ -132,13 +134,13 @@
"original-url": "Originalrecept", "original-url": "Originalrecept",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Receptets namn", "recipe-name": "Receptets namn",
"servings": "Portioner", "servings": "Portioner",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Steg: {step}", "step-index": "Steg: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Taggar", "tags": "Taggar",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "Are you sure you want to delete this recipe?", "delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"description": "Description", "description": "Description",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "Ingredient", "ingredient": "Ingredient",
@ -132,13 +134,13 @@
"original-url": "Original URL", "original-url": "Original URL",
"perform-time": "Cook Time", "perform-time": "Cook Time",
"prep-time": "Prep Time", "prep-time": "Prep Time",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "Recipe Name", "recipe-name": "Recipe Name",
"servings": "Servings", "servings": "Servings",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "Step: {step}", "step-index": "Step: {step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "Tags", "tags": "Tags",
"title": "Title", "title": "Title",
"total-time": "Total Time", "total-time": "Total Time",

View file

@ -105,6 +105,7 @@
"recent": "最近" "recent": "最近"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "您确定要删除此食谱吗?", "delete-confirmation": "您确定要删除此食谱吗?",
"delete-recipe": "删除食谱", "delete-recipe": "删除食谱",
"description": "描述", "description": "描述",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "材料", "ingredient": "材料",
@ -132,13 +134,13 @@
"original-url": "原食谱链接", "original-url": "原食谱链接",
"perform-time": "烹饪时间", "perform-time": "烹饪时间",
"prep-time": "准备时间", "prep-time": "准备时间",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "食谱名称", "recipe-name": "食谱名称",
"servings": "份量", "servings": "份量",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "步骤:{step}", "step-index": "步骤:{step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "标签", "tags": "标签",
"title": "标题", "title": "标题",
"total-time": "总时间", "total-time": "总时间",

View file

@ -105,6 +105,7 @@
"recent": "Recent" "recent": "Recent"
}, },
"recipe": { "recipe": {
"assets": "Assets",
"add-key": "Add Key", "add-key": "Add Key",
"api-extras": "API Extras", "api-extras": "API Extras",
"calories": "Calories", "calories": "Calories",
@ -113,8 +114,9 @@
"delete-confirmation": "您確定要刪除此食譜嗎?", "delete-confirmation": "您確定要刪除此食譜嗎?",
"delete-recipe": "刪除食譜", "delete-recipe": "刪除食譜",
"description": "描述", "description": "描述",
"fat-content": "Fat Content", "fat-content": "Fat",
"fiber-content": "Fiber Content", "fiber-content": "Fiber",
"carbohydrate-content": "Carbohydrate",
"grams": "grams", "grams": "grams",
"image": "Image", "image": "Image",
"ingredient": "材料", "ingredient": "材料",
@ -132,13 +134,13 @@
"original-url": "原食譜鏈接", "original-url": "原食譜鏈接",
"perform-time": "烹飪時間 / 執行時間", "perform-time": "烹飪時間 / 執行時間",
"prep-time": "準備時間", "prep-time": "準備時間",
"protein-content": "Protein Content", "protein-content": "Protein",
"recipe-image": "Recipe Image", "recipe-image": "Recipe Image",
"recipe-name": "食譜名稱", "recipe-name": "食譜名稱",
"servings": "份量", "servings": "份量",
"sodium-content": "Sodium Content", "sodium-content": "Sodium",
"step-index": "步驟:{step}", "step-index": "步驟:{step}",
"sugar-content": "Sugar Content", "sugar-content": "Sugar",
"tags": "標籤", "tags": "標籤",
"title": "標題", "title": "標題",
"total-time": "總時間", "total-time": "總時間",

View file

@ -1,85 +0,0 @@
<template>
<div>
<ImportDialog
:name="selectedName"
:date="selectedDate"
ref="import_dialog"
@import="importBackup"
@delete="deleteBackup"
/>
<v-row>
<v-col
:sm="6"
:md="6"
:lg="4"
:xl="4"
v-for="backup in backups"
:key="backup.name"
>
<v-card @click="openDialog(backup)">
<v-card-text>
<v-row align="center">
<v-col cols="12" sm="2">
<v-icon color="primary"> mdi-backup-restore </v-icon>
</v-col>
<v-col cols="12" sm="10">
<div>
<strong>{{ backup.name }}</strong>
</div>
<div>{{ $d(new Date(backup.date), "medium") }}</div>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script>
import ImportDialog from "./ImportDialog";
import { api } from "@/api";
export default {
props: {
backups: Array,
},
components: {
ImportDialog,
},
data() {
return {
selectedName: "",
selectedDate: "",
loading: false,
};
},
methods: {
openDialog(backup) {
this.selectedDate = backup.date;
this.selectedName = backup.name;
this.$refs.import_dialog.open();
},
async importBackup(data) {
this.$emit("loading");
let response = await api.backups.import(data.name, data);
let failed = response.data.failed;
let succesful = response.data.successful;
this.$emit("finished", succesful, failed);
},
deleteBackup(data) {
this.$emit("loading");
api.backups.delete(data.name);
this.selectedBackup = null;
this.backupLoading = false;
this.$emit("finished");
},
},
};
</script>
<style>
</style>

View file

@ -71,17 +71,6 @@ export default {
this.availableBackups = response.imports; this.availableBackups = response.imports;
this.availableTemplates = response.templates; this.availableTemplates = response.templates;
}, },
deleteBackup() {
if (this.$refs.form.validate()) {
this.backupLoading = true;
api.backups.delete(this.selectedBackup);
this.getAvailableBackups();
this.selectedBackup = null;
this.backupLoading = false;
}
},
processFinished(data) { processFinished(data) {
this.getAvailableBackups(); this.getAvailableBackups();
this.backupLoading = false; this.backupLoading = false;

View file

@ -68,7 +68,6 @@ export default {
}, },
async openDialog() { async openDialog() {
this.$refs.deleteDialog.open(); this.$refs.deleteDialog.open();
console.log(this.isTags);
if (this.isTags) { if (this.isTags) {
this.deleteList = await api.tags.getEmpty(); this.deleteList = await api.tags.getEmpty();
} else { } else {

View file

@ -51,6 +51,8 @@
:yields="recipeDetails.recipeYield" :yields="recipeDetails.recipeYield"
:orgURL="recipeDetails.orgURL" :orgURL="recipeDetails.orgURL"
:nutrition="recipeDetails.nutrition" :nutrition="recipeDetails.nutrition"
:assets="recipeDetails.assets"
:slug="recipeDetails.slug"
/> />
<VJsoneditor <VJsoneditor
@error="logError()" @error="logError()"

View file

@ -36,7 +36,6 @@ const actions = {
async requestRecentRecipes() { async requestRecentRecipes() {
const payload = await api.recipes.allSummary(0, 30); const payload = await api.recipes.allSummary(0, 30);
payload.sort((a, b) => (a.dateAdded > b.dateAdded ? -1 : 1)); payload.sort((a, b) => (a.dateAdded > b.dateAdded ? -1 : 1));
console.log(payload);
const hash = Object.fromEntries(payload.map(e => [e.id, e])); const hash = Object.fromEntries(payload.map(e => [e.id, e]));
this.commit("setRecentRecipes", hash); this.commit("setRecentRecipes", hash);
}, },
@ -44,7 +43,6 @@ const actions = {
const all = getters.getAllRecipes; const all = getters.getAllRecipes;
const payload = await api.recipes.allSummary(all.length, 9999); const payload = await api.recipes.allSummary(all.length, 9999);
const hash = Object.fromEntries([...all, ...payload].map(e => [e.id, e])); const hash = Object.fromEntries([...all, ...payload].map(e => [e.id, e]));
console.log(hash);
this.commit("setAllRecipes", hash); this.commit("setAllRecipes", hash);
}, },

View file

@ -2,13 +2,14 @@ import uvicorn
from fastapi import FastAPI from fastapi import FastAPI
from mealie.core import root_logger from mealie.core import root_logger
# import utils.startup as startup
from mealie.core.config import APP_VERSION, settings from mealie.core.config import APP_VERSION, settings
from mealie.routes import backup_routes, debug_routes, migration_routes, theme_routes, utility_routes from mealie.routes import (backup_routes, debug_routes, migration_routes,
theme_routes, utility_routes)
from mealie.routes.groups import groups from mealie.routes.groups import groups
from mealie.routes.mealplans import mealplans from mealie.routes.mealplans import mealplans
from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_crud_routes, tag_routes from mealie.routes.recipe import (all_recipe_routes, category_routes,
recipe_assets, recipe_crud_routes,
tag_routes)
from mealie.routes.site_settings import all_settings from mealie.routes.site_settings import all_settings
from mealie.routes.users import users from mealie.routes.users import users
@ -37,6 +38,7 @@ def api_routers():
app.include_router(category_routes.router) app.include_router(category_routes.router)
app.include_router(tag_routes.router) app.include_router(tag_routes.router)
app.include_router(recipe_crud_routes.router) app.include_router(recipe_crud_routes.router)
app.include_router(recipe_assets.router)
# Meal Routes # Meal Routes
app.include_router(mealplans.router) app.include_router(mealplans.router)
# Settings Routes # Settings Routes
@ -50,11 +52,11 @@ def api_routers():
api_routers() api_routers()
start_scheduler()
@app.on_event("startup") @app.on_event("startup")
def system_startup(): def system_startup():
start_scheduler()
logger.info("-----SYSTEM STARTUP----- \n") logger.info("-----SYSTEM STARTUP----- \n")
logger.info("------APP SETTINGS------") logger.info("------APP SETTINGS------")
logger.info(settings.json(indent=4, exclude={"SECRET", "DEFAULT_PASSWORD", "SFTP_PASSWORD", "SFTP_USERNAME"})) logger.info(settings.json(indent=4, exclude={"SECRET", "DEFAULT_PASSWORD", "SFTP_PASSWORD", "SFTP_USERNAME"}))

View file

@ -9,7 +9,7 @@ from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
class Meal(SqlAlchemyBase): class Meal(SqlAlchemyBase):
__tablename__ = "meal" __tablename__ = "meal"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("mealplan.uid")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("mealplan.uid"))
slug = sa.Column(sa.String) slug = sa.Column(sa.String)
name = sa.Column(sa.String) name = sa.Column(sa.String)
date = sa.Column(sa.Date) date = sa.Column(sa.Date)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class ApiExtras(SqlAlchemyBase): class ApiExtras(SqlAlchemyBase):
__tablename__ = "api_extras" __tablename__ = "api_extras"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
key_name = sa.Column(sa.String, unique=True) key_name = sa.Column(sa.String, unique=True)
value = sa.Column(sa.String) value = sa.Column(sa.String)

View file

@ -0,0 +1,22 @@
import sqlalchemy as sa
from mealie.db.models.model_base import SqlAlchemyBase
class RecipeAsset(SqlAlchemyBase):
__tablename__ = "recipe_assets"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
name = sa.Column(sa.String)
icon = sa.Column(sa.String)
file_name = sa.Column(sa.String)
def __init__(
self,
name=None,
icon=None,
file_name=None,
) -> None:
print("Asset Saved", name)
self.name = name
self.file_name = file_name
self.icon = icon

View file

@ -41,7 +41,7 @@ class Category(SqlAlchemyBase):
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, index=True, nullable=False) name = sa.Column(sa.String, index=True, nullable=False)
slug = sa.Column(sa.String, index=True, unique=True, nullable=False) slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipeCategory") recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipe_category")
@validates("name") @validates("name")
def validate_name(self, key, name): def validate_name(self, key, name):

View file

@ -6,7 +6,7 @@ class RecipeIngredient(SqlAlchemyBase):
__tablename__ = "recipes_ingredients" __tablename__ = "recipes_ingredients"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
position = sa.Column(sa.Integer) position = sa.Column(sa.Integer)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
ingredient = sa.Column(sa.String) ingredient = sa.Column(sa.String)
def update(self, ingredient): def update(self, ingredient):

View file

@ -5,7 +5,8 @@ from mealie.db.models.model_base import SqlAlchemyBase
class RecipeInstruction(SqlAlchemyBase): class RecipeInstruction(SqlAlchemyBase):
__tablename__ = "recipe_instructions" __tablename__ = "recipe_instructions"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
position = sa.Column(sa.Integer) position = sa.Column(sa.Integer)
type = sa.Column(sa.String, default="") type = sa.Column(sa.String, default="")
text = sa.Column(sa.String) text = sa.Column(sa.String)
title = sa.Column(sa.String)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Note(SqlAlchemyBase): class Note(SqlAlchemyBase):
__tablename__ = "notes" __tablename__ = "notes"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
title = sa.Column(sa.String) title = sa.Column(sa.String)
text = sa.Column(sa.String) text = sa.Column(sa.String)

View file

@ -5,26 +5,29 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Nutrition(SqlAlchemyBase): class Nutrition(SqlAlchemyBase):
__tablename__ = "recipe_nutrition" __tablename__ = "recipe_nutrition"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
calories = sa.Column(sa.String) calories = sa.Column(sa.String)
fatContent = sa.Column(sa.String) fat_content = sa.Column(sa.String)
fiberContent = sa.Column(sa.String) fiber_content = sa.Column(sa.String)
proteinContent = sa.Column(sa.String) protein_content = sa.Column(sa.String)
sodiumContent = sa.Column(sa.String) carbohydrate_content = sa.Column(sa.String)
sugarContent = sa.Column(sa.String) sodium_content = sa.Column(sa.String)
sugar_content = sa.Column(sa.String)
def __init__( def __init__(
self, self,
calories=None, calories=None,
fatContent=None, fat_content=None,
fiberContent=None, fiber_content=None,
proteinContent=None, protein_content=None,
sodiumContent=None, sodium_content=None,
sugarContent=None, sugar_content=None,
carbohydrate_content=None,
) -> None: ) -> None:
self.calories = calories self.calories = calories
self.fatContent = fatContent self.fat_content = fat_content
self.fiberContent = fiberContent self.fiber_content = fiber_content
self.proteinContent = proteinContent self.protein_content = protein_content
self.sodiumContent = sodiumContent self.sodium_content = sodium_content
self.sugarContent = sugarContent self.sugar_content = sugar_content
self.carbohydrate_content = carbohydrate_content

View file

@ -1,16 +1,17 @@
import datetime import datetime
from datetime import date from datetime import date
from typing import List
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy.orm as orm import sqlalchemy.orm as orm
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
from mealie.db.models.recipe.api_extras import ApiExtras from mealie.db.models.recipe.api_extras import ApiExtras
from mealie.db.models.recipe.assets import RecipeAsset
from mealie.db.models.recipe.category import Category, recipes2categories from mealie.db.models.recipe.category import Category, recipes2categories
from mealie.db.models.recipe.ingredient import RecipeIngredient from mealie.db.models.recipe.ingredient import RecipeIngredient
from mealie.db.models.recipe.instruction import RecipeInstruction from mealie.db.models.recipe.instruction import RecipeInstruction
from mealie.db.models.recipe.note import Note from mealie.db.models.recipe.note import Note
from mealie.db.models.recipe.nutrition import Nutrition from mealie.db.models.recipe.nutrition import Nutrition
from mealie.db.models.recipe.settings import RecipeSettings
from mealie.db.models.recipe.tag import Tag, recipes2tags from mealie.db.models.recipe.tag import Tag, recipes2tags
from mealie.db.models.recipe.tool import Tool from mealie.db.models.recipe.tool import Tool
from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.ext.orderinglist import ordering_list
@ -26,23 +27,24 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
name = sa.Column(sa.String, nullable=False) name = sa.Column(sa.String, nullable=False)
description = sa.Column(sa.String) description = sa.Column(sa.String)
image = sa.Column(sa.String) image = sa.Column(sa.String)
totalTime = sa.Column(sa.String) total_time = sa.Column(sa.String)
prepTime = sa.Column(sa.String) prep_time = sa.Column(sa.String)
performTime = sa.Column(sa.String) perform_time = sa.Column(sa.String)
cookTime = sa.Column(sa.String) cookTime = sa.Column(sa.String)
recipeYield = sa.Column(sa.String) recipe_yield = sa.Column(sa.String)
recipeCuisine = sa.Column(sa.String) recipeCuisine = sa.Column(sa.String)
tools: List[Tool] = orm.relationship("Tool", cascade="all, delete-orphan") tools: list[Tool] = orm.relationship("Tool", cascade="all, delete-orphan")
assets: list[RecipeAsset] = orm.relationship("RecipeAsset", cascade="all, delete-orphan")
nutrition: Nutrition = orm.relationship("Nutrition", uselist=False, cascade="all, delete-orphan") nutrition: Nutrition = orm.relationship("Nutrition", uselist=False, cascade="all, delete-orphan")
recipeCategory: List = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes") recipe_category: list = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
recipeIngredient: List[RecipeIngredient] = orm.relationship( recipe_ingredient: list[RecipeIngredient] = orm.relationship(
"RecipeIngredient", "RecipeIngredient",
cascade="all, delete-orphan", cascade="all, delete-orphan",
order_by="RecipeIngredient.position", order_by="RecipeIngredient.position",
collection_class=ordering_list("position"), collection_class=ordering_list("position"),
) )
recipeInstructions: List[RecipeInstruction] = orm.relationship( recipe_instructions: list[RecipeInstruction] = orm.relationship(
"RecipeInstruction", "RecipeInstruction",
cascade="all, delete-orphan", cascade="all, delete-orphan",
order_by="RecipeInstruction.position", order_by="RecipeInstruction.position",
@ -51,12 +53,13 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
# Mealie Specific # Mealie Specific
slug = sa.Column(sa.String, index=True, unique=True) slug = sa.Column(sa.String, index=True, unique=True)
tags: List[Tag] = orm.relationship("Tag", secondary=recipes2tags, back_populates="recipes") settings = orm.relationship("RecipeSettings", uselist=False, cascade="all, delete-orphan")
dateAdded = sa.Column(sa.Date, default=date.today) tags: list[Tag] = orm.relationship("Tag", secondary=recipes2tags, back_populates="recipes")
notes: List[Note] = orm.relationship("Note", cascade="all, delete-orphan") date_added = sa.Column(sa.Date, default=date.today)
notes: list[Note] = orm.relationship("Note", cascade="all, delete-orphan")
rating = sa.Column(sa.Integer) rating = sa.Column(sa.Integer)
orgURL = sa.Column(sa.String) org_url = sa.Column(sa.String)
extras: List[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete-orphan") extras: list[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete-orphan")
@validates("name") @validates("name")
def validate_name(self, key, name): def validate_name(self, key, name):
@ -69,23 +72,25 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
name: str = None, name: str = None,
description: str = None, description: str = None,
image: str = None, image: str = None,
recipeYield: str = None, recipe_yield: str = None,
recipeIngredient: List[str] = None, recipe_ingredient: list[str] = None,
recipeInstructions: List[dict] = None, recipe_instructions: list[dict] = None,
recipeCuisine: str = None, recipeCuisine: str = None,
totalTime: str = None, total_time: str = None,
prepTime: str = None, prep_time: str = None,
nutrition: dict = None, nutrition: dict = None,
tools: list[str] = [], tools: list[str] = None,
performTime: str = None, perform_time: str = None,
slug: str = None, slug: str = None,
recipeCategory: List[str] = None, recipe_category: list[str] = None,
tags: List[str] = None, tags: list[str] = None,
dateAdded: datetime.date = None, date_added: datetime.date = None,
notes: List[dict] = None, notes: list[dict] = None,
rating: int = None, rating: int = None,
orgURL: str = None, org_url: str = None,
extras: dict = None, extras: dict = None,
assets: list = None,
settings: dict = None,
*args, *args,
**kwargs **kwargs
) -> None: ) -> None:
@ -95,77 +100,33 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
self.recipeCuisine = recipeCuisine self.recipeCuisine = recipeCuisine
self.nutrition = Nutrition(**nutrition) if self.nutrition else Nutrition() self.nutrition = Nutrition(**nutrition) if self.nutrition else Nutrition()
self.tools = [Tool(tool=x) for x in tools] if tools else [] self.tools = [Tool(tool=x) for x in tools] if tools else []
self.recipeYield = recipeYield self.recipe_yield = recipe_yield
self.recipeIngredient = [RecipeIngredient(ingredient=ingr) for ingr in recipeIngredient] self.recipe_ingredient = [RecipeIngredient(ingredient=ingr) for ingr in recipe_ingredient]
self.recipeInstructions = [ self.assets = [RecipeAsset(**a) for a in assets]
RecipeInstruction(text=instruc.get("text"), type=instruc.get("@type", None)) self.recipe_instructions = [
for instruc in recipeInstructions RecipeInstruction(text=instruc.get("text"), title=instruc.get("title"), type=instruc.get("@type", None))
for instruc in recipe_instructions
] ]
self.totalTime = totalTime self.total_time = total_time
self.prepTime = prepTime self.prep_time = prep_time
self.performTime = performTime self.perform_time = perform_time
self.recipeCategory = [Category.create_if_not_exist(session=session, name=cat) for cat in recipeCategory] self.recipe_category = [Category.create_if_not_exist(session=session, name=cat) for cat in recipe_category]
# Mealie Specific # Mealie Specific
self.settings = RecipeSettings(**settings) if settings else RecipeSettings()
print(self.settings)
self.tags = [Tag.create_if_not_exist(session=session, name=tag) for tag in tags] self.tags = [Tag.create_if_not_exist(session=session, name=tag) for tag in tags]
self.slug = slug self.slug = slug
self.dateAdded = dateAdded self.date_added = date_added
self.notes = [Note(**note) for note in notes] self.notes = [Note(**note) for note in notes]
self.rating = rating self.rating = rating
self.orgURL = orgURL self.org_url = org_url
self.extras = [ApiExtras(key=key, value=value) for key, value in extras.items()] self.extras = [ApiExtras(key=key, value=value) for key, value in extras.items()]
def update( def update(self, *args, **kwargs):
self,
session,
name: str = None,
description: str = None,
image: str = None,
recipeYield: str = None,
recipeIngredient: List[str] = None,
recipeInstructions: List[dict] = None,
recipeCuisine: str = None,
totalTime: str = None,
tools: list[str] = [],
prepTime: str = None,
performTime: str = None,
nutrition: dict = None,
slug: str = None,
recipeCategory: List[str] = None,
tags: List[str] = None,
dateAdded: datetime.date = None,
notes: List[dict] = None,
rating: int = None,
orgURL: str = None,
extras: dict = None,
*args,
**kwargs
):
"""Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions""" """Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions"""
self.__init__(*args, **kwargs)
self.__init__(
session=session,
name=name,
description=description,
image=image,
recipeYield=recipeYield,
recipeIngredient=recipeIngredient,
recipeInstructions=recipeInstructions,
totalTime=totalTime,
recipeCuisine=recipeCuisine,
prepTime=prepTime,
performTime=performTime,
nutrition=nutrition,
tools=tools,
slug=slug,
recipeCategory=recipeCategory,
tags=tags,
dateAdded=dateAdded,
notes=notes,
rating=rating,
orgURL=orgURL,
extras=extras,
)

View file

@ -0,0 +1,18 @@
import sqlalchemy as sa
from mealie.db.models.model_base import SqlAlchemyBase
class RecipeSettings(SqlAlchemyBase):
__tablename__ = "recipe_settings"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
public = sa.Column(sa.Boolean)
show_nutrition = sa.Column(sa.Boolean)
show_assets = sa.Column(sa.Boolean)
landscape_view = sa.Column(sa.Boolean)
def __init__(self, public=True, show_nutrition=True, show_assets=True, landscape_view=True) -> None:
self.public = public
self.show_nutrition = show_nutrition
self.show_assets = show_assets
self.landscape_view = landscape_view

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Tool(SqlAlchemyBase): class Tool(SqlAlchemyBase):
__tablename__ = "tools" __tablename__ = "tools"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id")) parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
tool = sa.Column(sa.String) tool = sa.Column(sa.String)
def __init__(self, tool) -> None: def __init__(self, tool) -> None:

View file

@ -21,4 +21,4 @@ def get_shopping_list(
mealplan: MealPlanInDB mealplan: MealPlanInDB
slugs = [x.slug for x in mealplan.meals] slugs = [x.slug for x in mealplan.meals]
recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs] recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs]
return [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x] return [{"name": x.name, "recipe_ingredient": x.recipe_ingredient} for x in recipes if x]

View file

@ -50,11 +50,11 @@ def get_all_recipes(
- description - description
- image - image
- recipeYield - recipeYield
- totalTime - total_time
- prepTime - prep_time
- performTime - perform_time
- rating - rating
- orgURL - org_url
**Note:** You may experience problems with with query parameters. As an alternative **Note:** You may experience problems with with query parameters. As an alternative
you may also use the post method and provide a body. you may also use the post method and provide a body.
@ -78,11 +78,11 @@ def get_all_recipes_post(body: AllRecipeRequest, session: Session = Depends(gene
- description - description
- image - image
- recipeYield - recipeYield
- totalTime - total_time
- prepTime - prep_time
- performTime - perform_time
- rating - rating
- orgURL - org_url
Refer to the body example for data formats. Refer to the body example for data formats.

View file

@ -0,0 +1,50 @@
import shutil
from fastapi import APIRouter, Depends, File, Form
from fastapi.datastructures import UploadFile
from mealie.core.config import app_dirs
from mealie.db.database import db
from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user
from mealie.schema.recipe import Recipe, RecipeAsset
from mealie.schema.snackbar import SnackResponse
from slugify import slugify
from sqlalchemy.orm.session import Session
from starlette.responses import FileResponse
router = APIRouter(prefix="/api/recipes", tags=["Recipe Assets"])
@router.get("/{recipe_slug}/asset")
async def get_recipe_asset(recipe_slug, file_name: str):
""" Returns a recipe asset """
file = app_dirs.RECIPE_DATA_DIR.joinpath(recipe_slug, file_name)
return FileResponse(file)
@router.post("/{recipe_slug}/asset", response_model=RecipeAsset)
def upload_recipe_asset(
recipe_slug: str,
name: str = Form(...),
icon: str = Form(...),
extension: str = Form(...),
file: UploadFile = File(...),
session: Session = Depends(generate_session),
current_user=Depends(get_current_user),
):
""" Upload a file to store as a recipe asset """
file_name = slugify(name) + "." + extension
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
dest = app_dirs.RECIPE_DATA_DIR.joinpath(recipe_slug, file_name)
dest.parent.mkdir(exist_ok=True, parents=True)
with dest.open("wb") as buffer:
shutil.copyfileobj(file.file, buffer)
if dest.is_file():
recipe: Recipe = db.recipes.get(session, recipe_slug)
recipe.assets.append(asset_in)
db.recipes.update(session, recipe_slug, recipe.dict())
return asset_in
else:
return SnackResponse.error("Failure uploading file")

View file

@ -56,6 +56,7 @@ def update_recipe(
""" Updates a recipe by existing slug and data. """ """ Updates a recipe by existing slug and data. """
recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict()) recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict())
print(recipe.assets)
if recipe_slug != recipe.slug: if recipe_slug != recipe.slug:
rename_image(original_slug=recipe_slug, new_slug=recipe.slug) rename_image(original_slug=recipe_slug, new_slug=recipe.slug)
@ -64,7 +65,7 @@ def update_recipe(
@router.patch("/{recipe_slug}") @router.patch("/{recipe_slug}")
def update_recipe( def patch_recipe(
recipe_slug: str, recipe_slug: str,
data: dict, data: dict,
session: Session = Depends(generate_session), session: Session = Depends(generate_session),

View file

@ -1,12 +1,23 @@
import datetime import datetime
from typing import Any, List, Optional from typing import Any, Optional
from fastapi_camelcase import CamelModel
from mealie.db.models.recipe.recipe import RecipeModel from mealie.db.models.recipe.recipe import RecipeModel
from pydantic import BaseModel, validator from pydantic import BaseModel, Field, validator
from pydantic.utils import GetterDict from pydantic.utils import GetterDict
from slugify import slugify from slugify import slugify
class RecipeSettings(CamelModel):
public: bool = True
show_nutrition: bool = True
show_assets: bool = True
landscape_view: bool = True
class Config:
orm_mode = True
class RecipeNote(BaseModel): class RecipeNote(BaseModel):
title: str title: str
text: str text: str
@ -15,34 +26,45 @@ class RecipeNote(BaseModel):
orm_mode = True orm_mode = True
class RecipeStep(BaseModel): class RecipeStep(CamelModel):
title: Optional[str] = ""
text: str text: str
class Config: class Config:
orm_mode = True orm_mode = True
class Nutrition(BaseModel): class RecipeAsset(CamelModel):
calories: Optional[str] name: str
fatContent: Optional[str] icon: str
fiberContent: Optional[str] file_name: Optional[str]
proteinContent: Optional[str]
sodiumContent: Optional[str]
sugarContent: Optional[str]
class Config: class Config:
orm_mode = True orm_mode = True
class RecipeSummary(BaseModel): class Nutrition(CamelModel):
calories: Optional[str]
fat_content: Optional[str]
protein_content: Optional[str]
carbohydrate_content: Optional[str]
fiber_content: Optional[str]
sodium_content: Optional[str]
sugar_content: Optional[str]
class Config:
orm_mode = True
class RecipeSummary(CamelModel):
id: Optional[int] id: Optional[int]
name: str name: str
slug: Optional[str] = "" slug: Optional[str] = ""
image: Optional[Any] image: Optional[Any]
description: Optional[str] description: Optional[str]
recipeCategory: Optional[List[str]] = [] recipe_category: Optional[list[str]] = []
tags: Optional[List[str]] = [] tags: Optional[list[str]] = []
rating: Optional[int] rating: Optional[int]
class Config: class Config:
@ -52,26 +74,28 @@ class RecipeSummary(BaseModel):
def getter_dict(_cls, name_orm: RecipeModel): def getter_dict(_cls, name_orm: RecipeModel):
return { return {
**GetterDict(name_orm), **GetterDict(name_orm),
"recipeCategory": [x.name for x in name_orm.recipeCategory], "recipe_category": [x.name for x in name_orm.recipe_category],
"tags": [x.name for x in name_orm.tags], "tags": [x.name for x in name_orm.tags],
} }
class Recipe(RecipeSummary): class Recipe(RecipeSummary):
recipeYield: Optional[str] recipe_yield: Optional[str]
recipeIngredient: Optional[list[str]] recipe_ingredient: Optional[list[str]]
recipeInstructions: Optional[list[RecipeStep]] recipe_instructions: Optional[list[RecipeStep]]
nutrition: Optional[Nutrition] nutrition: Optional[Nutrition]
tools: Optional[list[str]] = [] tools: Optional[list[str]] = []
totalTime: Optional[str] = None total_time: Optional[str] = None
prepTime: Optional[str] = None prep_time: Optional[str] = None
performTime: Optional[str] = None perform_time: Optional[str] = None
# Mealie Specific # Mealie Specific
dateAdded: Optional[datetime.date] settings: Optional[RecipeSettings]
notes: Optional[List[RecipeNote]] = [] assets: Optional[list[RecipeAsset]] = []
orgURL: Optional[str] date_added: Optional[datetime.date]
notes: Optional[list[RecipeNote]] = []
org_url: Optional[str] = Field(None, alias="orgURL")
extras: Optional[dict] = {} extras: Optional[dict] = {}
class Config: class Config:
@ -81,8 +105,8 @@ class Recipe(RecipeSummary):
def getter_dict(_cls, name_orm: RecipeModel): def getter_dict(_cls, name_orm: RecipeModel):
return { return {
**GetterDict(name_orm), **GetterDict(name_orm),
"recipeIngredient": [x.ingredient for x in name_orm.recipeIngredient], "recipe_ingredient": [x.ingredient for x in name_orm.recipe_ingredient],
"recipeCategory": [x.name for x in name_orm.recipeCategory], "recipe_category": [x.name for x in name_orm.recipe_category],
"tags": [x.name for x in name_orm.tags], "tags": [x.name for x in name_orm.tags],
"tools": [x.tool for x in name_orm.tools], "tools": [x.tool for x in name_orm.tools],
"extras": {x.key_name: x.value for x in name_orm.extras}, "extras": {x.key_name: x.value for x in name_orm.extras},
@ -93,22 +117,22 @@ class Recipe(RecipeSummary):
"name": "Chicken and Rice With Leeks and Salsa Verde", "name": "Chicken and Rice With Leeks and Salsa Verde",
"description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.", "description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.",
"image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg", "image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg",
"recipeYield": "4 Servings", "recipe_yield": "4 Servings",
"recipeIngredient": [ "recipe_ingredient": [
"1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)", "1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)",
"Kosher salt, freshly ground pepper", "Kosher salt, freshly ground pepper",
"3 Tbsp. unsalted butter, divided", "3 Tbsp. unsalted butter, divided",
], ],
"recipeInstructions": [ "recipe_instructions": [
{ {
"text": "Season chicken with salt and pepper.", "text": "Season chicken with salt and pepper.",
}, },
], ],
"slug": "chicken-and-rice-with-leeks-and-salsa-verde", "slug": "chicken-and-rice-with-leeks-and-salsa-verde",
"tags": ["favorite", "yummy!"], "tags": ["favorite", "yummy!"],
"recipeCategory": ["Dinner", "Pasta"], "recipe_category": ["Dinner", "Pasta"],
"notes": [{"title": "Watch Out!", "text": "Prep the day before!"}], "notes": [{"title": "Watch Out!", "text": "Prep the day before!"}],
"orgURL": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde", "org_url": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde",
"rating": 3, "rating": 3,
"extras": {"message": "Don't forget to defrost the chicken!"}, "extras": {"message": "Don't forget to defrost the chicken!"},
} }
@ -126,7 +150,7 @@ class Recipe(RecipeSummary):
class AllRecipeRequest(BaseModel): class AllRecipeRequest(BaseModel):
properties: List[str] properties: list[str]
limit: Optional[int] limit: Optional[int]
class Config: class Config:

View file

@ -83,7 +83,7 @@ class ImportDatabase:
del recipe_dict["categories"] del recipe_dict["categories"]
try: try:
del recipe_dict["_id"] del recipe_dict["_id"]
del recipe_dict["dateAdded"] del recipe_dict["date_added"]
except: except:
pass pass
# Migration from list to Object Type Data # Migration from list to Object Type Data

View file

@ -144,7 +144,7 @@ class MigrationBase(BaseModel):
"""Calls the rewrite_alias function and the Cleaner.clean function on a """Calls the rewrite_alias function and the Cleaner.clean function on a
dictionary and returns the result unpacked into a Recipe object""" dictionary and returns the result unpacked into a Recipe object"""
recipe_dict = self.rewrite_alias(recipe_dict) recipe_dict = self.rewrite_alias(recipe_dict)
recipe_dict = Cleaner.clean(recipe_dict, url=recipe_dict.get("orgURL", None)) recipe_dict = Cleaner.clean(recipe_dict, url=recipe_dict.get("org_url", None))
return Recipe(**recipe_dict) return Recipe(**recipe_dict)

View file

@ -37,7 +37,7 @@ class NextcloudDir:
class NextcloudMigration(MigrationBase): class NextcloudMigration(MigrationBase):
key_aliases: Optional[list[MigrationAlias]] = [ key_aliases: Optional[list[MigrationAlias]] = [
MigrationAlias(key="tags", alias="keywords", func=helpers.split_by_comma), MigrationAlias(key="tags", alias="keywords", func=helpers.split_by_comma),
MigrationAlias(key="orgURL", alias="url", func=None), MigrationAlias(key="org_url", alias="url", func=None),
] ]

View file

@ -1,9 +1,16 @@
from mealie.core.config import app_dirs, settings
#! I don't like it either!
SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db")
SQLITE_FILE.unlink(missing_ok=True)
settings.SQLITE_FILE = SQLITE_FILE
import json import json
import requests import requests
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from mealie.app import app from mealie.app import app
from mealie.core.config import app_dirs, settings
from mealie.db.db_setup import generate_session, sql_global_init from mealie.db.db_setup import generate_session, sql_global_init
from mealie.db.init_db import init_db from mealie.db.init_db import init_db
from pytest import fixture from pytest import fixture
@ -12,10 +19,6 @@ from tests.app_routes import AppRoutes
from tests.test_config import TEST_DATA from tests.test_config import TEST_DATA
from tests.utils.recipe_data import build_recipe_store, get_raw_no_image, get_raw_recipe from tests.utils.recipe_data import build_recipe_store, get_raw_no_image, get_raw_recipe
SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db")
SQLITE_FILE.unlink(missing_ok=True)
TestSessionLocal = sql_global_init(SQLITE_FILE, check_thread=False) TestSessionLocal = sql_global_init(SQLITE_FILE, check_thread=False)
init_db(TestSessionLocal()) init_db(TestSessionLocal())