diff --git a/.vscode/settings.json b/.vscode/settings.json index 21ff09b98..b0dfef42d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,28 +1,19 @@ { "python.formatting.provider": "black", "python.pythonPath": ".venv/bin/python3.9", - "python.linting.pylintEnabled": true, + "python.linting.pylintEnabled": false, "python.linting.enabled": true, "python.testing.unittestEnabled": false, "python.testing.nosetestsEnabled": false, "python.testing.pytestEnabled": true, "python.testing.autoTestDiscoverOnSaveEnabled": false, "python.testing.pytestArgs": ["tests"], - "cSpell.enableFiletypes": [ - "!javascript", - "!python", - "!yaml" - ], + "cSpell.enableFiletypes": ["!javascript", "!python", "!yaml"], "i18n-ally.localesPaths": "frontend/src/locales/messages", "i18n-ally.sourceLanguage": "en-US", "i18n-ally.enabledFrameworks": ["vue"], "i18n-ally.keystyle": "nested", - "cSpell.words": [ - "compression", - "hkotel", - "performant", - "postgres", - "webp" - ], - "search.mode": "reuseEditor" + "cSpell.words": ["compression", "hkotel", "performant", "postgres", "webp"], + "search.mode": "reuseEditor", + "python.linting.flake8Enabled": true } diff --git a/Caddyfile b/Caddyfile index ba5d2e454..73fb21ab3 100644 --- a/Caddyfile +++ b/Caddyfile @@ -6,12 +6,12 @@ :80 { @proxied path /api/* /docs /openapi.json - root * /app/dist - encode gzip + encode gzip zstd uri strip_suffix / - handle_path /api/recipes/image/* { - root * /app/data/img/ + # Handles Recipe Images / Assets + handle_path /api/media/recipes/* { + root * /app/data/recipes/ file_server } @@ -20,8 +20,8 @@ } handle { - try_files {path}.html {path} / + root * /app/dist + try_files {path}.html {path} /index.html file_server } - } \ No newline at end of file diff --git a/Caddyfile.dev b/Caddyfile.dev new file mode 100644 index 000000000..f8d99bb39 --- /dev/null +++ b/Caddyfile.dev @@ -0,0 +1,9 @@ +{ + admin off +} + +localhost { + handle /mealie/* { + reverse_proxy http://127.0.0.1:9090 + } +} \ No newline at end of file diff --git a/README.md b/README.md index 72a9a3176..b8b0833a0 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,16 @@ Mealie is a self hosted recipe manager and meal planner with a RestAPI backend a ## Key Features - 🔍 Fuzzy search -- 🏷️ Tag recipes with categories or tags to flexible sorting +- 🏷️ Tag recipes with categories or tags for flexible sorting - 🕸 Import recipes from around the web by URL +- 💪 Powerful bulk Category/Tag assignment - 📱 Beautiful Mobile Views - 📆 Create Meal Plans - 🛒 Generate shopping lists - 🐳 Easy setup with Docker -- 🎨 Customize your interface with color themes layouts -- 💾 Export all your data in any format with Jinja2 Templates, with easy data restoration from the user interface. +- 🎨 Customize your interface with color themes +- 💾 Export all your data in any format with Jinja2 Templates +- 🔒 Keep your data safe with automated backup and easy restore options - 🌍 localized in many languages - ➕ Plus tons more! - Flexible API diff --git a/dev/scripts/app_routes_gen.py b/dev/scripts/app_routes_gen.py index c15267d90..aa52c1da9 100644 --- a/dev/scripts/app_routes_gen.py +++ b/dev/scripts/app_routes_gen.py @@ -1,12 +1,10 @@ import json import re from pathlib import Path -from typing import Optional import slugify from jinja2 import Template from mealie.app import app -from pydantic import BaseModel CWD = Path(__file__).parent OUT_FILE = CWD.joinpath("output", "app_routes.py") diff --git a/dev/scripts/output/app_routes.py b/dev/scripts/output/app_routes.py index 6c43040c9..40e4b2c16 100644 --- a/dev/scripts/output/app_routes.py +++ b/dev/scripts/output/app_routes.py @@ -2,25 +2,32 @@ class AppRoutes: def __init__(self) -> None: self.prefix = "/api" - self.users_sign_ups = "/api/users/sign-ups" self.auth_token = "/api/auth/token" self.auth_token_long = "/api/auth/token/long" self.auth_refresh = "/api/auth/refresh" + self.users_sign_ups = "/api/users/sign-ups" self.users = "/api/users" self.users_self = "/api/users/self" + self.users_api_tokens = "/api/users-tokens" self.groups = "/api/groups" self.groups_self = "/api/groups/self" - self.recipes = "/api/recipes" + self.recipes_summary = "/api/recipes/summary" + self.recipes_summary_untagged = "/api/recipes/summary/untagged" + self.recipes_summary_uncategorized = "/api/recipes/summary/uncategorized" self.recipes_category = "/api/recipes/category" self.recipes_tag = "/api/recipes/tag" - self.categories = "/api/categories" - self.recipes_tags = "/api/recipes/tags/" self.recipes_create = "/api/recipes/create" self.recipes_create_url = "/api/recipes/create-url" + self.categories = "/api/categories" + self.categories_empty = "/api/categories/empty" + self.tags = "/api/tags" + self.tags_empty = "/api/tags/empty" + self.about_events = "/api/about/events" self.meal_plans_all = "/api/meal-plans/all" self.meal_plans_create = "/api/meal-plans/create" self.meal_plans_this_week = "/api/meal-plans/this-week" self.meal_plans_today = "/api/meal-plans/today" + self.meal_plans_today_image = "/api/meal-plans/today/image" self.site_settings_custom_pages = "/api/site-settings/custom-pages" self.site_settings = "/api/site-settings" self.site_settings_webhooks_test = "/api/site-settings/webhooks/test" @@ -30,8 +37,12 @@ class AppRoutes: self.backups_export_database = "/api/backups/export/database" self.backups_upload = "/api/backups/upload" self.migrations = "/api/migrations" + self.debug = "/api/debug" + self.debug_statistics = "/api/debug/statistics" self.debug_version = "/api/debug/version" self.debug_last_recipe_json = "/api/debug/last-recipe-json" + self.debug_log = "/api/debug/log" + self.utils_download = "/api/utils/download" def users_sign_ups_token(self, token): return f"{self.prefix}/users/sign-ups/{token}" @@ -48,21 +59,36 @@ class AppRoutes: def users_id_password(self, id): return f"{self.prefix}/users/{id}/password" + def users_api_tokens_token_id(self, token_id): + return f"{self.prefix}/users-tokens/{token_id}" + def groups_id(self, id): return f"{self.prefix}/groups/{id}" - def categories_category(self, category): - return f"{self.prefix}/categories/{category}" - - def recipes_tags_tag(self, tag): - return f"{self.prefix}/recipes/tags/{tag}" - def recipes_recipe_slug(self, recipe_slug): return f"{self.prefix}/recipes/{recipe_slug}" def recipes_recipe_slug_image(self, recipe_slug): return f"{self.prefix}/recipes/{recipe_slug}/image" + def recipes_recipe_slug_assets(self, recipe_slug): + return f"{self.prefix}/recipes/{recipe_slug}/assets" + + def categories_category(self, category): + return f"{self.prefix}/categories/{category}" + + def tags_tag(self, tag): + return f"{self.prefix}/tags/{tag}" + + def media_recipes_recipe_slug_images_file_name(self, recipe_slug, file_name): + return f"{self.prefix}/media/recipes/{recipe_slug}/images/{file_name}" + + def media_recipes_recipe_slug_assets_file_name(self, recipe_slug, file_name): + return f"{self.prefix}/media/recipes/{recipe_slug}/assets/{file_name}" + + def about_events_id(self, id): + return f"{self.prefix}/about/events/{id}" + def meal_plans_plan_id(self, plan_id): return f"{self.prefix}/meal-plans/{plan_id}" @@ -72,8 +98,8 @@ class AppRoutes: def site_settings_custom_pages_id(self, id): return f"{self.prefix}/site-settings/custom-pages/{id}" - def themes_theme_name(self, theme_name): - return f"{self.prefix}/themes/{theme_name}" + def themes_id(self, id): + return f"{self.prefix}/themes/{id}" def backups_file_name_download(self, file_name): return f"{self.prefix}/backups/{file_name}/download" @@ -84,14 +110,14 @@ class AppRoutes: def backups_file_name_delete(self, file_name): return f"{self.prefix}/backups/{file_name}/delete" - def migrations_type_file_name_import(self, type, file_name): - return f"{self.prefix}/migrations/{type}/{file_name}/import" + def migrations_import_type_file_name_import(self, import_type, file_name): + return f"{self.prefix}/migrations/{import_type}/{file_name}/import" - def migrations_type_file_name_delete(self, type, file_name): - return f"{self.prefix}/migrations/{type}/{file_name}/delete" + def migrations_import_type_file_name_delete(self, import_type, file_name): + return f"{self.prefix}/migrations/{import_type}/{file_name}/delete" - def migrations_type_upload(self, type): - return f"{self.prefix}/migrations/{type}/upload" + def migrations_import_type_upload(self, import_type): + return f"{self.prefix}/migrations/{import_type}/upload" def debug_log_num(self, num): return f"{self.prefix}/debug/log/{num}" diff --git a/docker-compose.yml b/docker-compose.yml index 07593c567..09452c92c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: dockerfile: Dockerfile container_name: mealie restart: always + depends_on: + - "postgres" ports: - 9090:80 environment: diff --git a/docs/docs/changelog/v0.5.0.md b/docs/docs/changelog/v0.5.0.md index 369df1124..15050e5df 100644 --- a/docs/docs/changelog/v0.5.0.md +++ b/docs/docs/changelog/v0.5.0.md @@ -1,4 +1,4 @@ -# v0.5.0 COOL TITLE GOES HERE +# v0.5.0 Too Many Changes! **App Version: v0.5.0** @@ -9,7 +9,13 @@ !!! error "Breaking Changes" #### Database - Database version has been bumped from v0.4.x -> v0.5.0. You will need to export and import your data. + Database version has been bumped from v0.4.x -> v0.5.0. You will need to export and import your data. Moving forward, we will be using database migrations (BETA) to do this automatically. Note that you still must backup your data. If you don't, it's entirely possible something may go wrong and you could lose your data on upgrade. + + #### Image Directory + the /data/img directory has been depreciated. All images are now stored in the /recipes/{slug}/image directory. Images should be migrated automatically, but you may experience issues related to this change. + + #### API Usage + If you have been using the API directly, many of the routes and status codes have changed. You may experience issues with directly consuming the API. ## Bug Fixes - Fixed #332 - Language settings are saved for one browser @@ -21,18 +27,31 @@ ### Highlights - Beta Support for Postgres! 🎉 See the getting started page for details -- Recipe Steps now support sections, assets, and additional settings. +- Recipe Features + - Step Sections + - Recipe Assets + - Additional View Settings. - 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 + - 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 - Recipe Cards now have a menu button for quick actions! - - Edit - - Delete - - Download (As Json) - - Copy Link -- Rating can be updated without entering the editor - Closes #25 + - Edit + - Delete + - Download (As Json) + - Copy Link +- New Profile Dashboard! + - Edit Your Profile + - Create/Edit Themes + - View other users in your Group + - See what's for dinner + - Manage Long Live API Tokens (New) +- New Admin Dashboard! 🎉 + - Now you can get some insight on your application with application statics and events. + - See uncategorized/untagged recipes and organize them! + - Backup/Restore right from your dashboard + - See server side events. Now you can know who deleted your favorite recipe! ### Performance - Images are now served up by the Caddy increase performance and offloading some loads from the API server @@ -40,6 +59,16 @@ - All images are now converted to .webp for better compression ### General +- New 'Dark' Theme Packages with Mealie +- Updated Recipe Card Sections Toolbar + - New Sort Options (They work this time!) + - Alphabetical + - Rating + - Created Date + - Updated Date + - Shuffle (Random Sort) + - New 'Random' Recipe button on recipe sections. Random recipes are selected from the filtered results below. For example, on the "Cakes" category page, you will only get recipes in the "Cakes" category. +- Rating can be updated without entering the editor - Closes #25 - Updated recipe editor styles and moved notes to below the steps. - Redesigned search bar - 'Dinner this week' shows a warning when no meal is planned yet @@ -47,11 +76,11 @@ - More localization - Start date for Week is now selectable - Languages are now managed through Crowdin -- The main App bar went through a major overhaul - - Sidebar can now be toggled everywhere. - - New and improved mobile friendly bottom bar - - Improved styling for search bar in desktop - - Improved search layout on mobile +- Application Bar was Rewritten + - Sidebar can now be toggled everywhere. + - New and improved mobile friendly bottom bar + - Improved styling for search bar in desktop + - Improved search layout on mobile - Profile image now shown on all sidebars ### Behind the Scenes @@ -61,4 +90,4 @@ - Refactor UI components to fit Vue best practices (WIP) - The API returns more consistent status codes - The API returns error code instead of error text when appropriate - - ⚠️ May cause side-effects if you were directly consuming the API \ No newline at end of file + - ⚠️ May cause side-effects if you were directly consuming the API \ No newline at end of file diff --git a/docs/docs/getting-started/organizing-recipes.md b/docs/docs/getting-started/organizing-recipes.md index 67b42d609..639190f61 100644 --- a/docs/docs/getting-started/organizing-recipes.md +++ b/docs/docs/getting-started/organizing-recipes.md @@ -1,5 +1,19 @@ # Organizing Recipes +Below are some general guidelines that were considered when creating the organization structure for recipes. + + +## From The Community + +> My categories are mostly based on the 'course' they belong to. Appetizers, Starters, Main course, but also sauces or beverages. When I'm looking for an idea for an every day dinner, I just browse "main course". +> +> My tags are for picking the exact type of meal I'm looking for, based on my mood or my guests' diet, like gluten-free, vegetarian, sweet-sour or casserole. They can also act as sub-categories, like "alcohol" for beverages or "hot meal" for a main course. +> +> User: [sephrat](https://github.com/sephrat) + + +## Structure + !!! tip Below is a suggestion of guidelines my wife and I use for organizing our recipes within Mealie. Mealie is fairly flexible, so feel free to utilize how you'd like! 👍 diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index e26f964e1..3455949e0 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/frontend/src/api/about.js b/frontend/src/api/about.js new file mode 100644 index 000000000..f04322939 --- /dev/null +++ b/frontend/src/api/about.js @@ -0,0 +1,59 @@ +import { baseURL } from "./api-utils"; +import { apiReq } from "./api-utils"; + +const prefix = baseURL + "about"; + +const aboutURLs = { + version: `${prefix}/version`, + debug: `${prefix}`, + lastRecipe: `${prefix}/last-recipe-json`, + demo: `${prefix}/is-demo`, + log: num => `${prefix}/log/${num}`, + statistics: `${prefix}/statistics`, + events: `${prefix}/events`, + event: id => `${prefix}/events/${id}`, +}; + +export const aboutAPI = { + async getEvents() { + const resposne = await apiReq.get(aboutURLs.events); + return resposne.data; + }, + async deleteEvent(id) { + const resposne = await apiReq.delete(aboutURLs.event(id)); + return resposne.data; + }, + async deleteAllEvents() { + const resposne = await apiReq.delete(aboutURLs.events); + return resposne.data; + }, + // async getAppInfo() { + // const response = await apiReq.get(aboutURLs.version); + // return response.data; + // }, + + // async getDebugInfo() { + // const response = await apiReq.get(aboutURLs.debug); + // return response.data; + // }, + + // async getLogText(num) { + // const response = await apiReq.get(aboutURLs.log(num)); + // return response.data; + // }, + + // async getLastJson() { + // const response = await apiReq.get(aboutURLs.lastRecipe); + // return response.data; + // }, + + // async getIsDemo() { + // const response = await apiReq.get(aboutURLs.demo); + // return response.data; + // }, + + // async getStatistics() { + // const response = await apiReq.get(aboutURLs.statistics); + // return response.data; + // }, +}; diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js index a143f8452..597423f2e 100644 --- a/frontend/src/api/api-utils.js +++ b/frontend/src/api/api-utils.js @@ -1,7 +1,7 @@ const baseURL = "/api/"; import axios from "axios"; import { store } from "../store"; -import utils from "@/utils"; +import { utils } from "@/utils"; axios.defaults.headers.common["Authorization"] = `Bearer ${store.getters.getToken}`; diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index aa1c612fc..53d22e8ac 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -11,6 +11,7 @@ import { userAPI } from "./users"; import { signupAPI } from "./signUps"; import { groupAPI } from "./groups"; import { siteSettingsAPI } from "./siteSettings"; +import { aboutAPI } from "./about"; /** * The main object namespace for interacting with the backend database @@ -30,4 +31,5 @@ export const api = { users: userAPI, signUps: signupAPI, groups: groupAPI, + about: aboutAPI, }; diff --git a/frontend/src/api/meta.js b/frontend/src/api/meta.js index 59183c0c5..16f7477b7 100644 --- a/frontend/src/api/meta.js +++ b/frontend/src/api/meta.js @@ -8,11 +8,13 @@ const debugURLs = { debug: `${prefix}`, lastRecipe: `${prefix}/last-recipe-json`, demo: `${prefix}/is-demo`, + log: num => `${prefix}/log/${num}`, + statistics: `${prefix}/statistics`, }; export const metaAPI = { async getAppInfo() { - let response = await apiReq.get(debugURLs.version); + const response = await apiReq.get(debugURLs.version); return response.data; }, @@ -21,13 +23,23 @@ export const metaAPI = { return response.data; }, + async getLogText(num) { + const response = await apiReq.get(debugURLs.log(num)); + return response.data; + }, + async getLastJson() { - let response = await apiReq.get(debugURLs.lastRecipe); + const response = await apiReq.get(debugURLs.lastRecipe); return response.data; }, async getIsDemo() { - let response = await apiReq.get(debugURLs.demo); + const response = await apiReq.get(debugURLs.demo); + return response.data; + }, + + async getStatistics() { + const response = await apiReq.get(debugURLs.statistics); return response.data; }, }; diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js index fe755f6f7..f01d88fdc 100644 --- a/frontend/src/api/recipe.js +++ b/frontend/src/api/recipe.js @@ -14,9 +14,9 @@ const recipeURLs = { recipe: slug => prefix + slug, update: slug => prefix + slug, delete: slug => prefix + slug, + createAsset: slug => `${prefix}${slug}/assets`, recipeImage: slug => `${prefix}${slug}/image`, updateImage: slug => `${prefix}${slug}/image`, - createAsset: slug => `${prefix}${slug}/asset`, }; export const recipeAPI = { @@ -84,7 +84,7 @@ export const recipeAPI = { fd.append("extension", fileObject.name.split(".").pop()); fd.append("name", name); fd.append("icon", icon); - let response = apiReq.post(recipeURLs.createAsset(recipeSlug), fd); + const response = apiReq.post(recipeURLs.createAsset(recipeSlug), fd); return response; }, @@ -135,14 +135,18 @@ export const recipeAPI = { }, recipeImage(recipeSlug) { - return `/api/recipes/image/${recipeSlug}/original.webp`; + return `/api/media/recipes/${recipeSlug}/images/original.webp`; }, recipeSmallImage(recipeSlug) { - return `/api/recipes/image/${recipeSlug}/min-original.webp`; + return `/api/media/recipes/${recipeSlug}/images/min-original.webp`; }, recipeTinyImage(recipeSlug) { - return `/api/recipes/image/${recipeSlug}/tiny-original.webp`; + return `/api/media/recipes/${recipeSlug}/images/tiny-original.webp`; + }, + + recipeAssetPath(recipeSlug, assetName) { + return `api/media/recipes/${recipeSlug}/assets/${assetName}`; }, }; diff --git a/frontend/src/api/themes.js b/frontend/src/api/themes.js index cfd433594..0917afb31 100644 --- a/frontend/src/api/themes.js +++ b/frontend/src/api/themes.js @@ -6,10 +6,10 @@ const prefix = baseURL + "themes"; const settingsURLs = { allThemes: `${baseURL}themes`, - specificTheme: themeName => `${prefix}/${themeName}`, + specificTheme: id => `${prefix}/${id}`, createTheme: `${prefix}/create`, - updateTheme: themeName => `${prefix}/${themeName}`, - deleteTheme: themeName => `${prefix}/${themeName}`, + updateTheme: id => `${prefix}/${id}`, + deleteTheme: id => `${prefix}/${id}`, }; export const themeAPI = { @@ -32,22 +32,18 @@ export const themeAPI = { ); }, - update(themeName, colors) { - const body = { - name: themeName, - colors: colors, - }; + update(data) { return apiReq.put( - settingsURLs.updateTheme(themeName), - body, + settingsURLs.updateTheme(data.id), + data, () => i18n.t("settings.theme.error-updating-theme"), () => i18n.t("settings.theme.theme-updated") ); }, - delete(themeName) { + delete(id) { return apiReq.delete( - settingsURLs.deleteTheme(themeName), + settingsURLs.deleteTheme(id), null, () => i18n.t("settings.theme.error-deleting-theme"), () => i18n.t("settings.theme.theme-deleted") diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js index 11609ff29..1ded3c6e9 100644 --- a/frontend/src/api/users.js +++ b/frontend/src/api/users.js @@ -16,17 +16,10 @@ const usersURLs = { userID: id => `${userPrefix}/${id}`, password: id => `${userPrefix}/${id}/password`, resetPassword: id => `${userPrefix}/${id}/reset-password`, + userAPICreate: `${userPrefix}/api-tokens`, + userAPIDelete: id => `${userPrefix}/api-tokens/${id}`, }; -function deleteErrorText(response) { - switch (response.data.detail) { - case "SUPER_USER": - return i18n.t("user.error-cannot-delete-super-user"); - - default: - return i18n.t("user.you-are-not-allowed-to-delete-this-user"); - } -} export const userAPI = { async login(formData) { let response = await apiReq.post(authURLs.token, formData, null, function() { @@ -90,4 +83,21 @@ export const userAPI = { () => i18n.t("user.password-has-been-reset-to-the-default-password") ); }, + async createAPIToken(name) { + const response = await apiReq.post(usersURLs.userAPICreate, { name }); + return response.data; + }, + async deleteAPIToken(id) { + const response = await apiReq.delete(usersURLs.userAPIDelete(id)); + return response.data; + }, +}; + +const deleteErrorText = response => { + switch (response.data.detail) { + case "SUPER_USER": + return i18n.t("user.error-cannot-delete-super-user"); + default: + return i18n.t("user.you-are-not-allowed-to-delete-this-user"); + } }; diff --git a/frontend/src/components/FormHelpers/CategoryTagSelector.vue b/frontend/src/components/FormHelpers/CategoryTagSelector.vue index 4a95208b5..32b5eeba3 100644 --- a/frontend/src/components/FormHelpers/CategoryTagSelector.vue +++ b/frontend/src/components/FormHelpers/CategoryTagSelector.vue @@ -100,7 +100,10 @@ export default { } }, flat() { - return this.selected.length > 0 && this.solo; + if (this.selected) { + return this.selected.length > 0 && this.solo; + } + return false; }, }, methods: { diff --git a/frontend/src/components/FormHelpers/ColorPickerDialog.vue b/frontend/src/components/FormHelpers/ColorPickerDialog.vue index 3c0fc13be..13ba003ec 100644 --- a/frontend/src/components/FormHelpers/ColorPickerDialog.vue +++ b/frontend/src/components/FormHelpers/ColorPickerDialog.vue @@ -3,7 +3,7 @@

{{ buttonText }}

- + diff --git a/frontend/src/pages/Admin/Backup/ImportOptions.vue b/frontend/src/components/FormHelpers/ImportOptions.vue similarity index 92% rename from frontend/src/pages/Admin/Backup/ImportOptions.vue rename to frontend/src/components/FormHelpers/ImportOptions.vue index 35e783c06..74f133edb 100644 --- a/frontend/src/pages/Admin/Backup/ImportOptions.vue +++ b/frontend/src/components/FormHelpers/ImportOptions.vue @@ -1,8 +1,8 @@ + + \ No newline at end of file diff --git a/frontend/src/components/UI/StatCard.vue b/frontend/src/components/UI/StatCard.vue new file mode 100644 index 000000000..a9f11c945 --- /dev/null +++ b/frontend/src/components/UI/StatCard.vue @@ -0,0 +1,103 @@ +w + + + + diff --git a/frontend/src/components/UI/TheSidebar.vue b/frontend/src/components/UI/TheSidebar.vue index 605f87a2d..797434ccf 100644 --- a/frontend/src/components/UI/TheSidebar.vue +++ b/frontend/src/components/UI/TheSidebar.vue @@ -2,7 +2,7 @@
- - diff --git a/frontend/src/pages/Admin/Backup/AvailableBackupCard.vue b/frontend/src/pages/Admin/Backup/AvailableBackupCard.vue deleted file mode 100644 index 591b31b82..000000000 --- a/frontend/src/pages/Admin/Backup/AvailableBackupCard.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Backup/NewBackupCard.vue b/frontend/src/pages/Admin/Backup/NewBackupCard.vue deleted file mode 100644 index e7d903a12..000000000 --- a/frontend/src/pages/Admin/Backup/NewBackupCard.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Backup/index.vue b/frontend/src/pages/Admin/Backup/index.vue deleted file mode 100644 index 6644901b5..000000000 --- a/frontend/src/pages/Admin/Backup/index.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Dashboard/BackupViewer.vue b/frontend/src/pages/Admin/Dashboard/BackupViewer.vue new file mode 100644 index 000000000..cda4e95df --- /dev/null +++ b/frontend/src/pages/Admin/Dashboard/BackupViewer.vue @@ -0,0 +1,147 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/Admin/Dashboard/EventViewer.vue b/frontend/src/pages/Admin/Dashboard/EventViewer.vue new file mode 100644 index 000000000..417fe1a17 --- /dev/null +++ b/frontend/src/pages/Admin/Dashboard/EventViewer.vue @@ -0,0 +1,110 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/Admin/Dashboard/index.vue b/frontend/src/pages/Admin/Dashboard/index.vue new file mode 100644 index 000000000..1cdffc27b --- /dev/null +++ b/frontend/src/pages/Admin/Dashboard/index.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/Admin/ManageUsers/TheSignUpTable.vue b/frontend/src/pages/Admin/ManageUsers/TheSignUpTable.vue index 6deac3ce1..21138a520 100644 --- a/frontend/src/pages/Admin/ManageUsers/TheSignUpTable.vue +++ b/frontend/src/pages/Admin/ManageUsers/TheSignUpTable.vue @@ -160,10 +160,10 @@ export default { methods: { updateClipboard(newClip) { navigator.clipboard.writeText(newClip).then( - function() { + () => { console.log("Copied", newClip); }, - function() { + () => { console.log("Copy Failed", newClip); } ); diff --git a/frontend/src/pages/Admin/ManageUsers/index.vue b/frontend/src/pages/Admin/ManageUsers/index.vue index fbbb1aef5..74aa8bd27 100644 --- a/frontend/src/pages/Admin/ManageUsers/index.vue +++ b/frontend/src/pages/Admin/ManageUsers/index.vue @@ -4,30 +4,30 @@ - + {{ $t("user.users") }} mdi-account - + {{ $t("signup.sign-up-links") }} mdi-account-plus-outline - + {{ $t("group.groups") }} mdi-account-group - + - + - + @@ -42,9 +42,17 @@ import TheSignUpTable from "./TheSignUpTable"; export default { components: { TheUserTable, GroupDashboard, TheSignUpTable }, data() { - return { - tab: 0, - }; + return {}; + }, + computed: { + tab: { + set(tab) { + this.$router.replace({ query: { ...this.$route.query, tab } }); + }, + get() { + return this.$route.query.tab; + }, + }, }, mounted() { this.$store.dispatch("requestAllGroups"); diff --git a/frontend/src/pages/Admin/MealPlanner/index.vue b/frontend/src/pages/Admin/MealPlanner/index.vue deleted file mode 100644 index 51461f5ba..000000000 --- a/frontend/src/pages/Admin/MealPlanner/index.vue +++ /dev/null @@ -1,137 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Profile/APITokenCard.vue b/frontend/src/pages/Admin/Profile/APITokenCard.vue new file mode 100644 index 000000000..3855c03b7 --- /dev/null +++ b/frontend/src/pages/Admin/Profile/APITokenCard.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/frontend/src/pages/Admin/Profile/ProfileGroupCard.vue b/frontend/src/pages/Admin/Profile/ProfileGroupCard.vue new file mode 100644 index 000000000..ce2c2abf7 --- /dev/null +++ b/frontend/src/pages/Admin/Profile/ProfileGroupCard.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/frontend/src/pages/Admin/Profile/ProfileThemeCard.vue b/frontend/src/pages/Admin/Profile/ProfileThemeCard.vue new file mode 100644 index 000000000..e4fa16653 --- /dev/null +++ b/frontend/src/pages/Admin/Profile/ProfileThemeCard.vue @@ -0,0 +1,224 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/Admin/Profile/UserCard.vue b/frontend/src/pages/Admin/Profile/UserCard.vue new file mode 100644 index 000000000..190c0fd65 --- /dev/null +++ b/frontend/src/pages/Admin/Profile/UserCard.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/frontend/src/pages/Admin/Profile/index.vue b/frontend/src/pages/Admin/Profile/index.vue index 106d4b989..e6cfa1a38 100644 --- a/frontend/src/pages/Admin/Profile/index.vue +++ b/frontend/src/pages/Admin/Profile/index.vue @@ -1,206 +1,33 @@ diff --git a/frontend/src/pages/Admin/Theme/NewThemeDialog.vue b/frontend/src/pages/Admin/Theme/NewThemeDialog.vue deleted file mode 100644 index f704bada5..000000000 --- a/frontend/src/pages/Admin/Theme/NewThemeDialog.vue +++ /dev/null @@ -1,89 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Theme/ThemeCard.vue b/frontend/src/pages/Admin/Theme/ThemeCard.vue deleted file mode 100644 index e0d67e285..000000000 --- a/frontend/src/pages/Admin/Theme/ThemeCard.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/Theme/index.vue b/frontend/src/pages/Admin/Theme/index.vue deleted file mode 100644 index 4c30adf7d..000000000 --- a/frontend/src/pages/Admin/Theme/index.vue +++ /dev/null @@ -1,155 +0,0 @@ - - - - - diff --git a/frontend/src/pages/Admin/ToolBox/RecipeOrganizer.vue b/frontend/src/pages/Admin/ToolBox/RecipeOrganizer.vue new file mode 100644 index 000000000..b83cdfcde --- /dev/null +++ b/frontend/src/pages/Admin/ToolBox/RecipeOrganizer.vue @@ -0,0 +1,72 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/Admin/ToolBox/index.vue b/frontend/src/pages/Admin/ToolBox/index.vue index 50333cd6d..d5d029bf2 100644 --- a/frontend/src/pages/Admin/ToolBox/index.vue +++ b/frontend/src/pages/Admin/ToolBox/index.vue @@ -4,20 +4,25 @@ - + {{ $t("recipe.categories") }} mdi-tag-multiple-outline - + {{ $t("tag.tags") }} mdi-tag-multiple-outline + + Organize + mdi-broom + - - + + +
@@ -25,14 +30,24 @@ diff --git a/frontend/src/pages/HomePage.vue b/frontend/src/pages/HomePage.vue index 3b2bc4536..f8d0b5cd1 100644 --- a/frontend/src/pages/HomePage.vue +++ b/frontend/src/pages/HomePage.vue @@ -1,6 +1,7 @@