diff --git a/.gitignore b/.gitignore index d01991ff2040..3b2646bfc75f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ mealie/temp/api.html .temp/ .secret - dev/data/backups/* dev/data/debug/* dev/data/img/* @@ -157,39 +156,6 @@ mealie/data/debug/last_recipe.json *.sqlite dev/data/db/test.db scratch.py -frontend/dist/favicon.ico -frontend/dist/index.html -frontend/dist/css/app.29fe0155.css -frontend/dist/css/chunk-vendors.db944396.css -frontend/dist/fonts/materialdesignicons-webfont.7a44ea19.woff2 -frontend/dist/fonts/materialdesignicons-webfont.64d4cf64.eot -frontend/dist/fonts/materialdesignicons-webfont.147e3378.woff -frontend/dist/fonts/materialdesignicons-webfont.174c02fc.ttf -frontend/dist/fonts/roboto-latin-100.5cb7edfc.woff -frontend/dist/fonts/roboto-latin-100.7370c367.woff2 -frontend/dist/fonts/roboto-latin-100italic.f8b1df51.woff2 -frontend/dist/fonts/roboto-latin-100italic.f9e8e590.woff -frontend/dist/fonts/roboto-latin-300.b00849e0.woff -frontend/dist/fonts/roboto-latin-300.ef7c6637.woff2 -frontend/dist/fonts/roboto-latin-300italic.4df32891.woff -frontend/dist/fonts/roboto-latin-300italic.14286f3b.woff2 -frontend/dist/fonts/roboto-latin-400.60fa3c06.woff -frontend/dist/fonts/roboto-latin-400.479970ff.woff2 -frontend/dist/fonts/roboto-latin-400italic.51521a2a.woff2 -frontend/dist/fonts/roboto-latin-400italic.fe65b833.woff -frontend/dist/fonts/roboto-latin-500.020c97dc.woff2 -frontend/dist/fonts/roboto-latin-500.87284894.woff -frontend/dist/fonts/roboto-latin-500italic.288ad9c6.woff -frontend/dist/fonts/roboto-latin-500italic.db4a2a23.woff2 -frontend/dist/fonts/roboto-latin-700.2735a3a6.woff2 -frontend/dist/fonts/roboto-latin-700.adcde98f.woff -frontend/dist/fonts/roboto-latin-700italic.81f57861.woff -frontend/dist/fonts/roboto-latin-700italic.da0e7178.woff2 -frontend/dist/fonts/roboto-latin-900.9b3766ef.woff2 -frontend/dist/fonts/roboto-latin-900.bb1e4dc6.woff -frontend/dist/fonts/roboto-latin-900italic.28f91510.woff -frontend/dist/fonts/roboto-latin-900italic.ebf6d164.woff2 -frontend/dist/js/app.36f2760c.js -frontend/dist/js/app.36f2760c.js.map -frontend/dist/js/chunk-vendors.c93761e4.js -frontend/dist/js/chunk-vendors.c93761e4.js.map +dev/data/backups/dev_sample_data*.zip +dev/data/backups/dev_sample_data*.zip +!dev/data/backups/test*.zip diff --git a/dev/data/backups/dev_sample_data_2021-Feb-13.zip b/dev/data/backups/test_backup_2021-Apr-27.zip similarity index 72% rename from dev/data/backups/dev_sample_data_2021-Feb-13.zip rename to dev/data/backups/test_backup_2021-Apr-27.zip index 7a79d98bc3b0..bac642b1bdbc 100644 Binary files a/dev/data/backups/dev_sample_data_2021-Feb-13.zip and b/dev/data/backups/test_backup_2021-Apr-27.zip differ diff --git a/docs/docs/changelog/v0.5.0.md b/docs/docs/changelog/v0.5.0.md index 930b272ec685..252a8568ab3c 100644 --- a/docs/docs/changelog/v0.5.0.md +++ b/docs/docs/changelog/v0.5.0.md @@ -19,6 +19,11 @@ ## Features and Improvements ### General +- New Toolbox Page! + - Bulk assign categories and tags by keyword search + - Title case all Categories or Tags with 1 click + - Create/Rename/Delete Operations for Tags/Categories + - Remove Unused Categories or Tags with 1 click - More localization - Start date for Week is now selectable - Languages are now managed through Crowdin diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b3474e9eb970..56b8c537a735 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -46,6 +46,7 @@ export default { this.darkModeAddEventListener(); this.$store.dispatch("requestAppInfo"); this.$store.dispatch("requestCustomPages"); + this.$store.dispatch("requestSiteSettings"); }, methods: { diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js index 853d5ac9fa72..47868d0f7eb7 100644 --- a/frontend/src/api/api-utils.js +++ b/frontend/src/api/api-utils.js @@ -39,6 +39,16 @@ const apiReq = { processResponse(response); return response; }, + patch: async function(url, data) { + let response = await axios.patch(url, data).catch(function(error) { + if (error.response) { + processResponse(error.response); + return response; + } else return; + }); + processResponse(response); + return response; + }, get: async function(url, data) { let response = await axios.get(url, data).catch(function(error) { diff --git a/frontend/src/api/category.js b/frontend/src/api/category.js index f60739c8dc61..8c2219e58f4f 100644 --- a/frontend/src/api/category.js +++ b/frontend/src/api/category.js @@ -6,8 +6,10 @@ const prefix = baseURL + "categories"; const categoryURLs = { getAll: `${prefix}`, + getEmpty: `${prefix}/empty`, getCategory: category => `${prefix}/${category}`, deleteCategory: category => `${prefix}/${category}`, + updateCategory: category => `${prefix}/${category}`, }; export const categoryAPI = { @@ -15,6 +17,10 @@ export const categoryAPI = { let response = await apiReq.get(categoryURLs.getAll); return response.data; }, + async getEmpty() { + let response = await apiReq.get(categoryURLs.getEmpty); + return response.data; + }, async create(name) { let response = await apiReq.post(categoryURLs.getAll, { name: name }); store.dispatch("requestCategories"); @@ -24,9 +30,20 @@ export const categoryAPI = { let response = await apiReq.get(categoryURLs.getCategory(category)); return response.data; }, - async delete(category) { + async update(name, newName, overrideRequest = false) { + let response = await apiReq.put(categoryURLs.updateCategory(name), { + name: newName, + }); + if (!overrideRequest) { + store.dispatch("requestCategories"); + } + return response.data; + }, + async delete(category, overrideRequest = false) { let response = await apiReq.delete(categoryURLs.deleteCategory(category)); - store.dispatch("requestCategories"); + if (!overrideRequest) { + store.dispatch("requestCategories"); + } return response.data; }, }; @@ -35,8 +52,10 @@ const tagPrefix = baseURL + "tags"; const tagURLs = { getAll: `${tagPrefix}`, + getEmpty: `${tagPrefix}/empty`, getTag: tag => `${tagPrefix}/${tag}`, deleteTag: tag => `${tagPrefix}/${tag}`, + updateTag: tag => `${tagPrefix}/${tag}`, }; export const tagAPI = { @@ -44,6 +63,10 @@ export const tagAPI = { let response = await apiReq.get(tagURLs.getAll); return response.data; }, + async getEmpty() { + let response = await apiReq.get(tagURLs.getEmpty); + return response.data; + }, async create(name) { let response = await apiReq.post(tagURLs.getAll, { name: name }); store.dispatch("requestTags"); @@ -53,9 +76,20 @@ export const tagAPI = { let response = await apiReq.get(tagURLs.getTag(tag)); return response.data; }, - async delete(tag) { + async update(name, newName, overrideRequest = false) { + let response = await apiReq.put(tagURLs.updateTag(name), { name: newName }); + + if (!overrideRequest) { + store.dispatch("requestTags"); + } + + return response.data; + }, + async delete(tag, overrideRequest = false) { let response = await apiReq.delete(tagURLs.deleteTag(tag)); - store.dispatch("requestTags"); + if (!overrideRequest) { + store.dispatch("requestTags"); + } return response.data; }, }; diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js index c86e5b4cf42c..7ef5489ea599 100644 --- a/frontend/src/api/recipe.js +++ b/frontend/src/api/recipe.js @@ -67,7 +67,13 @@ export const recipeAPI = { async update(data) { let response = await apiReq.put(recipeURLs.update(data.slug), data); - store.dispatch("requestRecentRecipes"); + store.dispatch("patchRecipe", response.data); + return response.data.slug; // ! Temporary until I rewrite to refresh page without additional request + }, + + async patch(data) { + let response = await apiReq.patch(recipeURLs.update(data.slug), data); + store.dispatch("patchRecipe", response.data); return response.data; }, diff --git a/frontend/src/components/MealPlan/MealPlanNew.vue b/frontend/src/components/MealPlan/MealPlanNew.vue index 29487c65e60c..5bdd403f94b5 100644 --- a/frontend/src/components/MealPlan/MealPlanNew.vue +++ b/frontend/src/components/MealPlan/MealPlanNew.vue @@ -3,7 +3,8 @@ {{ $t("meal-plan.create-a-new-meal-plan") }} - mdi-calendar-minus {{$t('meal-plan.quick-week')}} + mdi-calendar-minus + {{ $t("meal-plan.quick-week") }} @@ -153,7 +154,7 @@ export default { return recipes.length > 0 ? recipes : this.items; }, allRecipes() { - return this.$store.getters.getRecentRecipes; + return this.$store.getters.getAllRecipes; }, }, diff --git a/frontend/src/components/UI/CardSection.vue b/frontend/src/components/UI/CardSection.vue index d29a9178e2cd..dd6efb0f3719 100644 --- a/frontend/src/components/UI/CardSection.vue +++ b/frontend/src/components/UI/CardSection.vue @@ -60,10 +60,10 @@ @@ -79,14 +79,16 @@
- + + +
@@ -109,6 +111,12 @@ export default { hardLimit: { default: 99999, }, + mobileCards: { + default: false, + }, + singleColumn: { + defualt: false, + }, recipes: Array, }, data() { @@ -117,8 +125,14 @@ export default { loading: false, }; }, + watch: { + recipes() { + this.bumpList(); + }, + }, computed: { viewScale() { + if (this.mobileCards) return true; switch (this.$vuetify.breakpoint.name) { case "xs": return true; @@ -128,10 +142,16 @@ export default { return false; } }, + effectiveHardLimit() { + return Math.min(this.hardLimit, this.recipes.length); + }, }, methods: { bumpList() { - const newCardLimit = Math.min(this.cardLimit + 20, this.hardLimit); + const newCardLimit = Math.min( + this.cardLimit + 20, + this.effectiveHardLimit + ); if (this.loading === false && newCardLimit > this.cardLimit) { this.setLoader(); @@ -141,7 +161,7 @@ export default { }, async setLoader() { this.loading = true; - await new Promise(r => setTimeout(r, 3000)); + await new Promise(r => setTimeout(r, 1000)); this.loading = false; }, }, diff --git a/frontend/src/components/UI/Dialogs/BaseDialog.vue b/frontend/src/components/UI/Dialogs/BaseDialog.vue index a1f64a2585aa..23123fce41eb 100644 --- a/frontend/src/components/UI/Dialogs/BaseDialog.vue +++ b/frontend/src/components/UI/Dialogs/BaseDialog.vue @@ -1,21 +1,38 @@ @@ -35,6 +52,12 @@ export default { modalWidth: { default: "500", }, + loading: { + default: false, + }, + top: { + default: false, + }, }, data() { return { @@ -45,9 +68,15 @@ export default { open() { this.dialog = true; }, + close() { + this.dialog = false; + }, }, }; \ No newline at end of file diff --git a/frontend/src/components/UI/Dialogs/NewCategoryTagDialog.vue b/frontend/src/components/UI/Dialogs/NewCategoryTagDialog.vue index 8f91292e852d..69c0c1588b65 100644 --- a/frontend/src/components/UI/Dialogs/NewCategoryTagDialog.vue +++ b/frontend/src/components/UI/Dialogs/NewCategoryTagDialog.vue @@ -1,8 +1,10 @@