Upload component (#113)

* unified upload button + download backups

* javascript toolings

* fix vuetur config

* fixed type check error

* refactor: clean up bag javascript

* UI updates + name validation

* docs: changelog + sp

* fixed route links

* changelog

Co-authored-by: Hayden <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-01-22 09:23:25 -09:00 committed by GitHub
commit 41e079d423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 204 additions and 139 deletions

View file

@ -72,7 +72,6 @@ Mealie also provides a secure API for interactions from 3rd party applications.
* [Vue.js](https://vuejs.org/) * [Vue.js](https://vuejs.org/)
* [Vuetify](https://vuetifyjs.com/en/) * [Vuetify](https://vuetifyjs.com/en/)
* [FastAPI](https://fastapi.tiangolo.com/) * [FastAPI](https://fastapi.tiangolo.com/)
* [MongoDB](https://www.mongodb.com/)
* [Docker](https://www.docker.com/) * [Docker](https://www.docker.com/)

View file

@ -35,7 +35,7 @@ Frontend
- [ ] Search Bar redesign - [ ] Search Bar redesign
- [x] Initial - [x] Initial
- [ ] Results redesign - [ ] Results redesign
- [ ] Replace Backups card with something like Home Assistant - [x] Replace Backups card with something like Home Assistant
- [x] Replace import card with something like Home Assistant - [x] Replace import card with something like Home Assistant
- [x] Select which imports to do - [x] Select which imports to do

View file

@ -1,9 +1,37 @@
# Release Notes # Release Notes
## V0.2.0 - Now with Test!
### Bug Fixes
- Remove ability to save recipe with no name
- Fixed data validation error on missing parameters
- Fixed failed database initialization at startup
- Fixed misaligned text on various cards
- Fixed bug that blocked opening links in new tabs
### Features and Improvements
- Meal Planner
- Improved Search (Fuzzy Search)
- New Scheduled card support
- Upload/Download backups
- Dockerfile now 1/5 of the size!
- **Minor**
- Continued work on button/style unification
- Adding icons to buttons
### Development
- Fixed Vetur config file. Autocomplete in VSCode works!
- Added Prettier config
- Fixed incorrect layout code
- FastAPI Route tests for major operations
### Breaking Changes
- Officially Dropped MongoDB Support
- Mounting volume moved to different internal location due to development issues. New volume should be mounted as `mealie/data:/app_data/`
## v0.1.0 - Initial Beta ## v0.1.0 - Initial Beta
### Bug Fixes ### Bug Fixes
- Fixed Can't delete recipe after changing name - Closes Issue #67 - Fixed Can't delete recipe after changing name - Closes Issue #67
- Fixed No image when added by URL, and can;t add an image - Closes Issue #66 - Fixed No image when added by URL, and can't add an image - Closes Issue #66
- Fixed Images saved with no way to delete when add recipe via URL fails - Closes Issue #43 - Fixed Images saved with no way to delete when add recipe via URL fails - Closes Issue #43
### Features ### Features
@ -23,7 +51,7 @@
- Major code refactoring to support new database layer - Major code refactoring to support new database layer
- Global variable refactor - Global variable refactor
### Break Changes ### Breaking Changes
- Internal docker port is now 80 instead of 9000. You MUST remap the internal port to connect to the UI. - Internal docker port is now 80 instead of 9000. You MUST remap the internal port to connect to the UI.

View file

@ -65,7 +65,6 @@ Mealie also provides an API for interactions from 3rd party applications. **Why
* [Vue.js](https://vuejs.org/) * [Vue.js](https://vuejs.org/)
* [Vuetify](https://vuetifyjs.com/en/) * [Vuetify](https://vuetifyjs.com/en/)
* [FastAPI](https://fastapi.tiangolo.com/) * [FastAPI](https://fastapi.tiangolo.com/)
* [MongoDB](https://www.mongodb.com/)
* [Docker](https://www.docker.com/) * [Docker](https://www.docker.com/)

View file

@ -34,12 +34,12 @@ Feature placement is not set in stone. This is much more of a guideline than any
- [ ] Category Filter - [ ] Category Filter
- [ ] Tag Filter - [ ] Tag Filter
- [x] Fuzzy Search - [x] Fuzzy Search
- [ ] Backup card redesign - [x] Backup card redesign
- [ ] Additional Backup / Import Features - [ ] Additional Backup / Import Features
- [ ] Import Recipes Force/Rebase options - [ ] Import Recipes Force/Rebase options
- [ ] Upload .zip file - [x] Upload .zip file
- [ ] Improved Color Picker - [ ] Improved Color Picker
- [ ] Meal Plan redesign - [x] Meal Plan redesign
### Backend ### Backend
- [ ] PostgreSQL Support - [ ] PostgreSQL Support
- [ ] Setup SQL Migrations - [ ] Setup SQL Migrations
@ -48,4 +48,4 @@ Feature placement is not set in stone. This is much more of a guideline than any
- MongoDB support dropped - MongoDB support dropped
## Code Chores ## Code Chores
- [x] Remove MongoDB Interface Code - [x] Remove MongoDB Interface Code
- [ ] Dockerfile Trim - [x] Dockerfile Trim

View file

@ -151,11 +151,13 @@ export default {
methods: { methods: {
get_random(list) { get_random(list) {
const object = list[Math.floor(Math.random() * list.length)]; const object = list[Math.floor(Math.random() * list.length)];
return object.slug; return object;
}, },
random() { random() {
this.meals.forEach((element, index) => { this.meals.forEach((element, index) => {
this.meals[index]["slug"] = this.get_random(this.items); let recipe = this.get_random(this.items);
this.meals[index]["slug"] = recipe.slug;
this.meals[index]["name"] = recipe.name;
}); });
}, },
processTime(index) { processTime(index) {

View file

@ -1,5 +1,5 @@
<template> <template>
<div> <v-form ref="form">
<v-card-text> <v-card-text>
<v-row dense> <v-row dense>
<v-col cols="3"></v-col> <v-col cols="3"></v-col>
@ -33,14 +33,26 @@
></v-col> ></v-col>
</v-row> </v-row>
</v-row> </v-row>
<v-text-field class="my-3" :label="$t('recipe.recipe-name')" v-model="value.name"> <v-text-field
class="my-3"
:label="$t('recipe.recipe-name')"
v-model="value.name"
:rules="[rules.required, rules.whiteSpace]"
>
</v-text-field> </v-text-field>
<v-textarea height="100" :label="$t('recipe.description')" v-model="value.description"> <v-textarea
height="100"
:label="$t('recipe.description')"
v-model="value.description"
>
</v-textarea> </v-textarea>
<div class="my-2"></div> <div class="my-2"></div>
<v-row dense disabled> <v-row dense disabled>
<v-col sm="5"> <v-col sm="5">
<v-text-field :label="$t('recipe.servings')" v-model="value.recipeYield"> <v-text-field
:label="$t('recipe.servings')"
v-model="value.recipeYield"
>
</v-text-field> </v-text-field>
</v-col> </v-col>
<v-col></v-col> <v-col></v-col>
@ -54,7 +66,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> <h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
<div <div
v-for="(ingredient, index) in value.recipeIngredient" v-for="(ingredient, index) in value.recipeIngredient"
:key="generateKey('ingredient', index)" :key="generateKey('ingredient', index)"
@ -81,7 +93,7 @@
</v-btn> </v-btn>
<BulkAdd @bulk-data="appendIngredients" /> <BulkAdd @bulk-data="appendIngredients" />
<h2 class="mt-6">{{$t('recipe.categories')}}</h2> <h2 class="mt-6">{{ $t("recipe.categories") }}</h2>
<v-combobox <v-combobox
dense dense
multiple multiple
@ -103,7 +115,7 @@
</template> </template>
</v-combobox> </v-combobox>
<h2 class="mt-4">{{$t('recipe.tags')}}</h2> <h2 class="mt-4">{{ $t("recipe.tags") }}</h2>
<v-combobox dense multiple chips deletable-chips v-model="value.tags"> <v-combobox dense multiple chips deletable-chips v-model="value.tags">
<template v-slot:selection="data"> <template v-slot:selection="data">
<v-chip <v-chip
@ -118,7 +130,7 @@
</template> </template>
</v-combobox> </v-combobox>
<h2 class="my-4">{{$t('recipe.notes')}}</h2> <h2 class="my-4">{{ $t("recipe.notes") }}</h2>
<v-card <v-card
class="mt-1" class="mt-1"
v-for="(note, index) in value.notes" v-for="(note, index) in value.notes"
@ -142,7 +154,10 @@
></v-text-field> ></v-text-field>
</v-row> </v-row>
<v-textarea :label="$t('recipe.note')" v-model="value.notes[index]['text']"> <v-textarea
:label="$t('recipe.note')"
v-model="value.notes[index]['text']"
>
</v-textarea> </v-textarea>
</v-card-text> </v-card-text>
</v-card> </v-card>
@ -155,7 +170,7 @@
<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> <h2 class="mb-4">{{ $t("recipe.instructions") }}</h2>
<div v-for="(step, index) in value.recipeInstructions" :key="index"> <div v-for="(step, index) in value.recipeInstructions" :key="index">
<v-hover v-slot="{ hover }"> <v-hover v-slot="{ hover }">
<v-card <v-card
@ -173,7 +188,9 @@
@click="removeStep(index)" @click="removeStep(index)"
> >
<v-icon color="error">mdi-delete</v-icon> </v-btn <v-icon color="error">mdi-delete</v-icon> </v-btn
>{{ $t('recipe.step-index', {step: index + 1}) }}</v-card-title >{{
$t("recipe.step-index", { step: index + 1 })
}}</v-card-title
> >
<v-card-text> <v-card-text>
<v-textarea <v-textarea
@ -192,7 +209,7 @@
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
</div> </v-form>
</template> </template>
<script> <script>
@ -211,6 +228,11 @@ export default {
data() { data() {
return { return {
fileObject: null, fileObject: null,
rules: {
required: v => !!v || "Key Name Required",
whiteSpace: v =>
!v || v.split(" ").length <= 1 || "No White Space Allowed",
},
}; };
}, },
methods: { methods: {
@ -259,7 +281,7 @@ export default {
appendSteps(steps) { appendSteps(steps) {
let processSteps = []; let processSteps = [];
steps.forEach((element) => { steps.forEach(element => {
processSteps.push({ text: element }); processSteps.push({ text: element });
}); });
@ -289,6 +311,13 @@ export default {
saveExtras(extras) { saveExtras(extras) {
this.value.extras = extras; this.value.extras = extras;
}, },
validateRecipe() {
if (this.$refs.form.validate()) {
return true;
} else {
return false;
}
},
}, },
}; };
</script> </script>

View file

@ -65,14 +65,14 @@
<v-divider></v-divider> <v-divider></v-divider>
<v-card-actions> <v-card-actions>
<v-btn color="success" text :href="`/api/backups/${name}/download/`"> <v-btn color="accent" text :href="`/api/backups/${name}/download/`">
{{ $t("general.download") }} {{ $t("general.download") }}
</v-btn> </v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="error" text @click="raiseEvent('delete')"> <v-btn color="error" text @click="raiseEvent('delete')">
{{ $t("general.delete") }} {{ $t("general.delete") }}
</v-btn> </v-btn>
<v-btn color="success" text @click="raiseEvent('import')"> <v-btn color="success" outlined @click="raiseEvent('import')">
{{ $t("general.import") }} {{ $t("general.import") }}
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>

View file

@ -19,14 +19,14 @@
<v-divider class="my-3"></v-divider> <v-divider class="my-3"></v-divider>
<v-card-title class="mt-n6"> <v-card-title class="mt-n6">
Available Backups Available Backups
<v-spacer></v-spacer>
<span> <span>
<UploadBtn <UploadBtn
class="mt-1" class="mt-1"
url="/api/backups/upload/" url="/api/backups/upload/"
@uploaded="getAvailableBackups" @uploaded="getAvailableBackups"
/> />
</span> </span>
<v-spacer></v-spacer>
</v-card-title> </v-card-title>
<AvailableBackupCard <AvailableBackupCard
@loading="backupLoading = true" @loading="backupLoading = true"

View file

@ -1,7 +1,11 @@
<template> <template>
<v-card-text> <v-card-text>
<p> <p>
{{$t('migration.currently-chowdown-via-public-repo-url-is-the-only-supported-type-of-migration')}} {{
$t(
"migration.currently-chowdown-via-public-repo-url-is-the-only-supported-type-of-migration"
)
}}
</p> </p>
<v-form ref="form"> <v-form ref="form">
<v-row dense align="center"> <v-row dense align="center">
@ -14,12 +18,15 @@
</v-text-field> </v-text-field>
</v-col> </v-col>
<v-col cols="12" md="4" sm="5"> <v-col cols="12" md="4" sm="5">
<v-btn text color="info" @click="importRepo"> {{$t('migration.migrate')}} </v-btn> <v-btn text color="info" @click="importRepo">
<v-icon left> mdi-import </v-icon>
{{ $t("migration.migrate") }}
</v-btn>
</v-col> </v-col>
</v-row> </v-row>
</v-form> </v-form>
<v-alert v-if="failedRecipes[1]" outlined dense type="error"> <v-alert v-if="failedRecipes[1]" outlined dense type="error">
<h4>{{$t('migration.failed-recipes')}}</h4> <h4>{{ $t("migration.failed-recipes") }}</h4>
<v-list dense> <v-list dense>
<v-list-item v-for="fail in this.failedRecipes" :key="fail"> <v-list-item v-for="fail in this.failedRecipes" :key="fail">
{{ fail }} {{ fail }}
@ -27,7 +34,7 @@
</v-list> </v-list>
</v-alert> </v-alert>
<v-alert v-if="failedImages[1]" outlined dense type="error"> <v-alert v-if="failedImages[1]" outlined dense type="error">
<h4>{{$t('migration.failed-images')}}</h4> <h4>{{ $t("migration.failed-images") }}</h4>
<v-list dense> <v-list dense>
<v-list-item v-for="fail in this.failedImages" :key="fail"> <v-list-item v-for="fail in this.failedImages" :key="fail">
{{ fail }} {{ fail }}
@ -49,7 +56,7 @@ export default {
failedRecipes: [], failedRecipes: [],
repo: "", repo: "",
rules: { rules: {
required: (v) => !!v || "Selection Required", required: v => !!v || "Selection Required",
}, },
}; };
}, },

View file

@ -20,9 +20,11 @@
<v-col md="1" sm="12"> <v-col md="1" sm="12">
<v-btn-toggle group> <v-btn-toggle group>
<v-btn text color="info" @click="importRecipes"> <v-btn text color="info" @click="importRecipes">
<v-icon left> mdi-import </v-icon>
{{ $t("migration.migrate") }} {{ $t("migration.migrate") }}
</v-btn> </v-btn>
<v-btn text color="error" @click="deleteImportValidation"> <v-btn text color="error" @click="deleteImportValidation">
<v-icon left> mdi-delete </v-icon>
{{ $t("general.delete") }} {{ $t("general.delete") }}
</v-btn> </v-btn>
<UploadBtn <UploadBtn

View file

@ -126,6 +126,7 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="success" @click="saveThemes" class="mr-2"> <v-btn color="success" @click="saveThemes" class="mr-2">
<v-icon left> mdi-content-save </v-icon>
{{ $t("general.save") }} {{ $t("general.save") }}
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>

View file

@ -15,18 +15,14 @@
<v-row dense align="center"> <v-row dense align="center">
<v-col cols="12" md="2" sm="5"> <v-col cols="12" md="2" sm="5">
<v-switch <v-switch v-model="enabled" :label="$t('general.enabled')"></v-switch>
v-model="enabled"
inset
:label="$t('general.enabled')"
class="my-n3"
></v-switch>
</v-col> </v-col>
<v-col cols="12" md="3" sm="5"> <v-col cols="12" md="3" sm="5">
<TimePickerDialog @save-time="saveTime" /> <TimePickerDialog @save-time="saveTime" />
</v-col> </v-col>
<v-col cols="12" md="4" sm="5"> <v-col cols="12" md="4" sm="5">
<v-btn text color="info" @click="testWebhooks"> <v-btn text color="info" @click="testWebhooks">
<v-icon left> mdi-webhook </v-icon>
{{ $t("settings.webhooks.test-webhooks") }} {{ $t("settings.webhooks.test-webhooks") }}
</v-btn> </v-btn>
</v-col> </v-col>
@ -47,19 +43,14 @@
</v-row> </v-row>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-row> <v-btn icon color="success" @click="addWebhook">
<v-col> <v-icon>mdi-plus</v-icon>
<v-btn icon color="success" @click="addWebhook"> </v-btn>
<v-icon>mdi-plus</v-icon> <v-spacer></v-spacer>
</v-btn> <v-btn color="success" @click="saveWebhooks" class="mr-2 mb-1">
</v-col> <v-icon left> mdi-content-save </v-icon>
<v-col> </v-col> {{ $t("general.save") }}
<v-col align="end"> </v-btn>
<v-btn color="success" @click="saveWebhooks" class="mr-2 mb-1">
{{ $t("settings.webhooks.save-webhooks") }}
</v-btn>
</v-col>
</v-row>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>

View file

@ -3,7 +3,8 @@
<v-card <v-card
:class="{ 'on-hover': hover }" :class="{ 'on-hover': hover }"
:elevation="hover ? 12 : 2" :elevation="hover ? 12 : 2"
@click="moreInfo(slug)" :to="route ? `/recipe/${slug}` : ''"
@click="$emit('click')"
> >
<v-img height="200" :src="getImage(image)"></v-img> <v-img height="200" :src="getImage(image)"></v-img>
<v-card-title class="my-n3 mb-n6">{{ name | truncate(30) }}</v-card-title> <v-card-title class="my-n3 mb-n6">{{ name | truncate(30) }}</v-card-title>
@ -52,11 +53,6 @@ export default {
}, },
}, },
methods: { methods: {
moreInfo(recipeSlug) {
if (this.route) {
this.$router.push(`/recipe/${recipeSlug}`);
} else this.$emit("click");
},
getImage(image) { getImage(image) {
return utils.getImageURL(image); return utils.getImageURL(image);
}, },

View file

@ -1,13 +1,8 @@
<template> <template>
<v-form ref="file"> <v-form ref="file">
<input ref="uploader" class="d-none" type="file" @change="onFileChanged" /> <input ref="uploader" class="d-none" type="file" @change="onFileChanged" />
<v-btn <v-btn :loading="isSelecting" @click="onButtonClick" color="accent" text>
:loading="isSelecting" <v-icon left> mdi-cloud-upload </v-icon>
@click="onButtonClick"
color="success"
text
>
<v-icon left > mdi-cloud-upload </v-icon>
Upload Upload
</v-btn> </v-btn>
</v-form> </v-form>

View file

@ -12,65 +12,64 @@
{{ $t("meal-plan.meal-plans") }} {{ $t("meal-plan.meal-plans") }}
</v-card-title> </v-card-title>
<v-divider></v-divider> <v-divider></v-divider>
<v-row no-gutters>
<v-col
:sm="6"
:md="6"
:lg="4"
:xl="3"
v-for="(mealplan, i) in plannedMeals"
:key="i"
>
<v-card class="ml-2 mt-2 mr-0">
<v-card-title>
{{ formatDate(mealplan.startDate) }} -
{{ formatDate(mealplan.endDate) }}
</v-card-title>
<v-list nav>
<v-list-item-group color="primary">
<v-list-item
v-for="(meal, index) in mealplan.meals"
:key="generateKey(meal.slug, index)"
@click="$router.push(`/recipe/${meal.slug}`)"
>
<v-list-item-avatar
color="primary"
class="headline font-weight-light white--text"
>
<v-img :src="getImage(meal.image)"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="meal.name"></v-list-item-title>
<v-list-item-subtitle v-text="meal.dateText">
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
<v-card-actions class="mt-n5">
<v-spacer></v-spacer>
<v-btn
color="accent lighten-2"
class="mx-0"
text
@click="editPlan(mealplan.uid)"
>
{{ $t("general.edit") }}
</v-btn>
<v-btn
color="error lighten-2"
class="mx-2"
text
@click="deletePlan(mealplan.uid)"
>
{{ $t("general.delete") }}
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-card> </v-card>
<v-row dense>
<v-col
:sm="6"
:md="6"
:lg="4"
:xl="3"
v-for="(mealplan, i) in plannedMeals"
:key="i"
>
<v-card class="mt-1">
<v-card-title>
{{ formatDate(mealplan.startDate) }} -
{{ formatDate(mealplan.endDate) }}
</v-card-title>
<v-list nav>
<v-list-item-group color="primary">
<v-list-item
v-for="(meal, index) in mealplan.meals"
:key="generateKey(meal.slug, index)"
@click="$router.push(`/recipe/${meal.slug}`)"
>
<v-list-item-avatar
color="primary"
class="headline font-weight-light white--text"
>
<v-img :src="getImage(meal.image)"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="meal.name"></v-list-item-title>
<v-list-item-subtitle v-text="meal.dateText">
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
<v-card-actions class="mt-n5">
<v-spacer></v-spacer>
<v-btn
color="accent lighten-2"
class="mx-0"
text
@click="editPlan(mealplan.uid)"
>
{{ $t("general.edit") }}
</v-btn>
<v-btn
color="error lighten-2"
class="mx-2"
text
@click="deletePlan(mealplan.uid)"
>
{{ $t("general.delete") }}
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</div> </div>
</template> </template>

View file

@ -23,14 +23,16 @@
<v-card-text> {{ meal.description }} </v-card-text> <v-card-text> {{ meal.description }} </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer>
<v-btn <v-btn
align="center" align="center"
color="secondary" color="secondary"
text text
@click="$router.push(`/recipe/${meal.slug}`)" @click="$router.push(`/recipe/${meal.slug}`)"
> >
{{$t('recipe.view-recipe')}} {{ $t("recipe.view-recipe") }}
</v-btn> </v-btn>
<v-spacer></v-spacer>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-col> </v-col>

View file

@ -29,7 +29,12 @@
/> />
</div> </div>
<RecipeEditor v-else v-model="recipeDetails" @upload="getImage" /> <RecipeEditor
ref="recipeEditor"
v-else
v-model="recipeDetails"
@upload="getImage"
/>
</v-card> </v-card>
</template> </template>
@ -85,20 +90,22 @@ export default {
}, },
async createRecipe() { async createRecipe() {
this.isLoading = true; if (this.$refs.recipeEditor.validateRecipe()) {
this.isLoading = true;
if (this.fileObject) { if (this.fileObject) {
this.recipeDetails.image = this.fileObject.name; this.recipeDetails.image = this.fileObject.name;
}
let slug = await api.recipes.create(this.recipeDetails);
if (this.fileObject) {
await api.recipes.updateImage(slug, this.fileObject);
}
this.isLoading = false;
this.$router.push(`/recipe/${slug}`);
} }
let slug = await api.recipes.create(this.recipeDetails);
if (this.fileObject) {
await api.recipes.updateImage(slug, this.fileObject);
}
this.isLoading = false;
this.$router.push(`/recipe/${slug}`);
}, },
}, },
}; };

View file

@ -45,7 +45,12 @@
height="1500px" height="1500px"
:options="jsonEditorOptions" :options="jsonEditorOptions"
/> />
<RecipeEditor v-else v-model="recipeDetails" @upload="getImageFile" /> <RecipeEditor
v-else
v-model="recipeDetails"
ref="recipeEditor"
@upload="getImageFile"
/>
</v-card> </v-card>
</template> </template>
@ -101,7 +106,7 @@ export default {
}, },
watch: { watch: {
$route: function () { $route: function() {
this.getRecipeDetails(); this.getRecipeDetails();
}, },
}, },
@ -138,6 +143,9 @@ export default {
api.recipes.delete(this.recipeDetails.slug); api.recipes.delete(this.recipeDetails.slug);
}, },
async saveRecipe() { async saveRecipe() {
if (this.$refs.recipeEditor.validateRecipe()) {
console.log("Thank you")
}
let slug = await api.recipes.update(this.recipeDetails); let slug = await api.recipes.update(this.recipeDetails);
if (this.fileObject) { if (this.fileObject) {