majors settings rework

This commit is contained in:
hay-kot 2021-02-23 13:19:56 -09:00
commit 194713ebe7
18 changed files with 506 additions and 182 deletions

View file

@ -28,6 +28,7 @@
</v-btn>
<SiteMenu />
<LanguageMenu />
</v-app-bar>
<v-main>
<v-container>
@ -40,10 +41,12 @@
</template>
<script>
import SiteMenu from "./components/UI/SiteMenu";
import SearchBar from "./components/UI/Search/SearchBar";
import AddRecipeFab from "./components/UI/AddRecipeFab";
import SiteMenu from "@/components/UI/SiteMenu";
import SearchBar from "@/components/UI/Search/SearchBar";
import AddRecipeFab from "@/components/UI/AddRecipeFab";
import LanguageMenu from "@/components/UI/LanguageMenu";
import Vuetify from "./plugins/vuetify";
export default {
name: "App",
@ -51,6 +54,7 @@ export default {
SiteMenu,
AddRecipeFab,
SearchBar,
LanguageMenu,
},
watch: {

View file

@ -70,7 +70,7 @@ export default {
router.push(`/`);
},
async allByKeys(recipeKeys, num = 100) {
async allByKeys(recipeKeys, num = 999) {
const response = await apiReq.get(recipeURLs.allRecipes, {
params: {
keys: recipeKeys,

View file

@ -75,38 +75,16 @@ export default {
mobile: false,
links: [],
superLinks: [
{
icon: "mdi-cog",
to: "/admin/settings",
title: "Site Settings",
},
{
icon: "mdi-account-group",
to: "/admin/manage-users",
title: "Manage Users",
},
{
icon: "mdi-cog",
to: "/admin/settings",
title: "Admin Settings",
},
],
baseLinks: [
{
icon: "mdi-account",
to: "/admin/profile",
title: "Profile",
},
{
icon: "mdi-card-bulleted-settings-outline",
to: "/admin/general",
title: "General",
},
{
icon: "mdi-format-color-fill",
to: "/admin/themes",
title: "Themes",
},
{
icon: "mdi-food",
to: "/admin/meal-planner",
title: "Meal Planner",
},
{
icon: "mdi-backup-restore",
to: "/admin/backups",
@ -118,6 +96,23 @@ export default {
title: "Migrations",
},
],
baseLinks: [
{
icon: "mdi-account",
to: "/admin/profile",
title: "Profile",
},
{
icon: "mdi-format-color-fill",
to: "/admin/themes",
title: "Themes",
},
{
icon: "mdi-food",
to: "/admin/meal-planner",
title: "Meal Planner",
},
],
};
},
mounted() {

View file

@ -25,17 +25,19 @@
<v-card-text>
<v-row>
<v-col cols="12" sm="6">
<v-card outlined min-height="250">
<v-card-text class="pt-2 pb-1">
<h3>Homepage Categories</h3>
</v-card-text>
<v-divider></v-divider>
<v-list
min-height="200"
dense
max-height="200"
style="overflow:auto"
>
<v-card outlined min-height="350px">
<v-app-bar dark dense color="primary">
<v-icon left>
mdi-home
</v-icon>
<v-toolbar-title class="headline">
Home Page Categories
</v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
<v-list height="300" dense style="overflow:auto">
<v-list-item-group>
<draggable
v-model="homeCategories"
@ -65,24 +67,19 @@
</v-card>
</v-col>
<v-col cols="12" sm="6">
<v-card outlined min-height="250px">
<v-card-text class="pt-2 pb-1">
<h3>
<v-card outlined height="350px">
<v-app-bar dark dense color="primary">
<v-icon left>
mdi-tag
</v-icon>
<v-toolbar-title class="headline">
All Categories
<span>
<v-btn absolute right x-small color="success" icon>
<v-icon>mdi-plus</v-icon></v-btn
>
</span>
</h3>
</v-card-text>
<v-divider></v-divider>
<v-list
min-height="200"
dense
max-height="200"
style="overflow:auto"
>
</v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
<v-list height="300" dense style="overflow:auto">
<v-list-item-group>
<draggable
v-model="categories"

View file

@ -1,5 +1,5 @@
<template>
<v-card class="my-2" :loading="loading">
<v-card outlined class="my-2" :loading="loading">
<v-card-title>
{{ title }}
<v-spacer></v-spacer>

View file

@ -134,6 +134,7 @@ export default {
this.clear();
}
console.log(key);
this.$store.commit("setToken", key.data.access_token)
this.loading = false;
},
},

View file

@ -0,0 +1,80 @@
<template>
<div class="text-center">
<LoginDialog ref="loginDialog" />
<v-menu
transition="slide-x-transition"
bottom
right
offset-y
close-delay="200"
>
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on" icon>
<v-icon>mdi-translate</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item-group v-model="selectedItem" color="primary">
<v-list-item
v-for="(item, i) in allLanguages"
:key="i"
link
@click="setLanguage(item.value)"
>
<v-list-item-content>
<v-list-item-title>
{{ item.name }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-menu>
</div>
</template>
<script>
import LoginDialog from "../Login/LoginDialog";
export default {
components: {
LoginDialog,
},
data: function() {
return {
selectedItem: 0,
items: [
{
name: "English",
value: "en",
},
],
};
},
mounted() {
let active = this.$store.getters.getActiveLang;
this.allLanguages.forEach((element, index) => {
if (element.value === active) {
this.selectedItem = index;
return;
}
});
},
computed: {
allLanguages() {
return this.$store.getters.getAllLangs;
},
},
methods: {
setLanguage(selectedLanguage) {
this.$store.commit("setLang", selectedLanguage);
},
},
};
</script>
<style>
.menu-text {
text-align: left !important;
}
</style>

View file

@ -52,12 +52,6 @@ export default {
restricted: false,
login: true,
},
{
icon: "mdi-account",
title: "Logout",
restricted: true,
login: true,
},
{
icon: "mdi-calendar-week",
title: this.$i18n.t("meal-plan.dinner-this-week"),
@ -76,6 +70,12 @@ export default {
nav: "/meal-plan/planner",
restricted: true,
},
{
icon: "mdi-account",
title: "Logout",
restricted: true,
nav: "/logout",
},
{
icon: "mdi-cog",
title: this.$i18n.t("general.settings"),

View file

@ -89,6 +89,8 @@
},
"settings": {
"general-settings": "General Settings",
"change-password": "Change Password",
"admin-settings": "Admin Settings",
"local-api": "Local API",
"language": "Language",
"add-a-new-theme": "Add a New Theme",

View file

@ -1,70 +0,0 @@
<template>
<v-card>
<v-card-title class="headline">
{{ $t("settings.general-settings") }}
<v-spacer></v-spacer>
<span>
<v-btn class="pt-1" text href="/docs">
{{ $t("settings.local-api") }}
<v-icon right>mdi-open-in-new</v-icon>
</v-btn>
</span>
</v-card-title>
<v-divider></v-divider>
<v-card-text>
<h2 class="mt-1 mb-4">{{ $t("settings.language") }}</h2>
<v-row>
<v-col sm="3">
<v-select
dense
v-model="selectedLang"
:items="langOptions"
item-text="name"
item-value="value"
:label="$t('settings.language')"
>
</v-select>
</v-col>
</v-row>
</v-card-text>
<v-divider></v-divider>
<HomePageSettings />
<v-divider></v-divider>
</v-card>
</template>
<script>
import HomePageSettings from "@/components/Admin/General/HomePageSettings";
export default {
components: {
HomePageSettings,
},
data() {
return {
langOptions: [],
selectedLang: "en",
};
},
mounted() {
this.getOptions();
},
watch: {
selectedLang() {
this.$store.commit("setLang", this.selectedLang);
},
},
methods: {
getOptions() {
this.langOptions = this.$store.getters.getAllLangs;
this.selectedLang = this.$store.getters.getActiveLang;
},
removeCategory(index) {
this.value.categories.splice(index, 1);
},
},
};
</script>
<style>
</style>

View file

@ -1,9 +1,226 @@
<template>
<h1>Manage Users</h1>
<v-data-table
:headers="headers"
:items="users"
sort-by="calories"
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>Mealie Users</v-toolbar-title>
<v-divider class="mx-4" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="600px">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" dark class="mb-2" v-bind="attrs" v-on="on">
Create User
</v-btn>
</template>
<v-card>
<v-app-bar dark dense color="primary">
<v-icon left>
mdi-account
</v-icon>
<v-toolbar-title class="headline">
{{ formTitle }}
</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-title class="headline">
User ID: {{ editedItem.id }}
</v-toolbar-title>
</v-app-bar>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="12" md="6">
<v-text-field
v-model="editedItem.full_name"
label="Full Name"
></v-text-field>
</v-col>
<v-col cols="12" sm="12" md="6">
<v-text-field
v-model="editedItem.email"
label="Email"
></v-text-field>
</v-col>
<v-col cols="12" sm="12" md="6">
<v-text-field
v-model="editedItem.family"
label="Family Group"
></v-text-field>
<v-col cols="12" sm="12" md="3">
<v-switch
v-model="editedItem.admin"
label="Admin"
></v-switch>
</v-col>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="grey" text @click="close">
Cancel
</v-btn>
<v-btn color="primary" @click="save">
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<Confirmation
ref="deleteUserDialog"
title="Confirm Delete User"
message="Are you sure you want to delete the user?"
icon="mdi-alert"
@confirm="deleteItemConfirm"
/>
</v-toolbar>
</template>
<template v-slot:item.actions="{ item }">
<v-btn class="mr-1" small color="error" @click="deleteItem(item)">
<v-icon small left>
mdi-delete
</v-icon>
Delete
</v-btn>
<v-btn small color="success" @click="editItem(item)">
<v-icon small left class="mr-2">
mdi-pencil
</v-icon>
Edit
</v-btn>
</template>
<template v-slot:item.admin="{ item }">
{{ item.admin ? "Admin" : "User" }}
</template>
<template v-slot:no-data>
<v-btn color="primary" @click="initialize">
Reset
</v-btn>
</template>
</v-data-table>
</template>
<script>
export default {};
import Confirmation from "@/components/UI/Confirmation";
export default {
components: { Confirmation },
data: () => ({
dialog: false,
dialogDelete: false,
headers: [
{
text: "User ID",
align: "start",
sortable: false,
value: "id",
},
{ text: "Full Name", value: "full_name" },
{ text: "Email", value: "email" },
{ text: "Family", value: "family" },
{ text: "Admin", value: "admin" },
{ text: "", value: "actions", sortable: false, align: "center" },
],
users: [],
editedIndex: -1,
editedItem: {
id: 0,
full_name: "",
email: "",
family: "",
admin: false,
},
defaultItem: {
id: 0,
full_name: "",
email: "",
family: "",
admin: false,
},
}),
computed: {
formTitle() {
return this.editedIndex === -1 ? "New User" : "Edit User";
},
},
watch: {
dialog(val) {
val || this.close();
},
dialogDelete(val) {
val || this.closeDelete();
},
},
created() {
this.initialize();
},
methods: {
initialize() {
this.users = [
{
id: 1,
full_name: "Change Me",
email: "changeme@email.com",
family: "public",
admin: false,
},
];
},
editItem(item) {
this.editedIndex = this.users.indexOf(item);
this.editedItem = Object.assign({}, item);
this.dialog = true;
},
deleteItem(item) {
this.editedIndex = this.users.indexOf(item);
this.editedItem = Object.assign({}, item);
this.$refs.deleteUserDialog.open();
},
deleteItemConfirm() {
this.users.splice(this.editedIndex, 1);
this.closeDelete();
},
close() {
this.dialog = false;
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem);
this.editedIndex = -1;
});
},
closeDelete() {
this.dialogDelete = false;
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem);
this.editedIndex = -1;
});
},
save() {
if (this.editedIndex > -1) {
Object.assign(this.users[this.editedIndex], this.editedItem);
} else {
this.users.push(this.editedItem);
}
this.close();
},
},
};
</script>
<style>

View file

@ -13,28 +13,30 @@
{{ $t("migration.recipe-migration") }}
</v-card-title>
<v-divider></v-divider>
</v-card>
<v-row dense>
<v-col
:cols="12"
:sm="6"
:md="6"
:lg="4"
:xl="3"
v-for="migration in migrations"
:key="migration.title"
>
<MigrationCard
:title="migration.title"
:folder="migration.urlVariable"
:description="migration.description"
:available="migration.availableImports"
@refresh="getAvailableMigrations"
@imported="showReport"
/>
</v-col>
</v-row>
<v-card-text>
<v-row dense>
<v-col
:cols="12"
:sm="6"
:md="6"
:lg="4"
:xl="3"
v-for="migration in migrations"
:key="migration.title"
>
<MigrationCard
:title="migration.title"
:folder="migration.urlVariable"
:description="migration.description"
:available="migration.availableImports"
@refresh="getAvailableMigrations"
@imported="showReport"
/>
</v-col>
</v-row>
</v-card-text>
</v-card>
</div>
</template>

View file

@ -1,13 +1,59 @@
<template>
<h1>Profile</h1>
<v-card>
<v-card-title class="headline">
<span>
<v-avatar color="accent" size="40" class="mr-2">
<img src="https://cdn.vuetifyjs.com/images/john.jpg" alt="John" />
</v-avatar>
</span>
Profile
</v-card-title>
<v-divider></v-divider>
<v-card-text>
<v-form>
<v-text-field label="Full Name"> </v-text-field>
<v-text-field label="Email"> </v-text-field>
<v-text-field label="Group" readonly> </v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="accent" class="mr-2">
<v-icon left> mdi-lock </v-icon>
{{ $t("settings.change-password") }}
</v-btn>
<v-spacer></v-spacer>
<v-btn color="success" class="mr-2">
<v-icon left> mdi-content-save </v-icon>
{{ $t("general.save") }}
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
// import AvatarPicker from '@/components/AvatarPicker'
export default {
pageTitle: "My Profile",
data() {
return {
loading: false,
form: {
firstName: "John",
lastName: "Doe",
contactEmail: "john@doe.com",
avatar: "MALE_CAUCASIAN_BLOND_BEARD",
},
showAvatarPicker: false,
};
},
}
</script>
<style>
</style>
methods: {
openAvatarPicker() {
this.showAvatarPicker = true;
},
selectAvatar(avatar) {
this.form.avatar = avatar;
},
},
};
</script>

View file

@ -1,13 +1,54 @@
<template>
<h1>Admin Settings</h1>
<v-card>
<v-card-title class="headline">
{{ $t("settings.admin-settings") }}
<v-spacer></v-spacer>
<span>
<v-btn class="pt-1" text href="/docs">
{{ $t("settings.local-api") }}
<v-icon right>mdi-open-in-new</v-icon>
</v-btn>
</span>
</v-card-title>
<v-divider></v-divider>
<HomePageSettings />
<v-divider></v-divider>
</v-card>
</template>
<script>
export default {
import HomePageSettings from "@/components/Admin/General/HomePageSettings";
}
export default {
components: {
HomePageSettings,
},
data() {
return {
langOptions: [],
selectedLang: "en",
};
},
mounted() {
this.getOptions();
},
watch: {
selectedLang() {
this.$store.commit("setLang", this.selectedLang);
},
},
methods: {
getOptions() {
this.langOptions = this.$store.getters.getAllLangs;
this.selectedLang = this.$store.getters.getActiveLang;
},
removeCategory(index) {
this.value.categories.splice(index, 1);
},
},
};
</script>
<style>
</style>

View file

@ -1,5 +1,4 @@
import Admin from "@/pages/Admin";
import General from "@/pages/Admin/General";
import Backup from "@/pages/Admin/Backup";
import Theme from "@/pages/Admin/Theme";
import MealPlanner from "@/pages/Admin/MealPlanner";
@ -20,10 +19,7 @@ export default {
path: "profile",
component: Profile,
},
{
path: "general",
component: General,
},
{
path: "backups",
component: Backup,

View file

@ -11,9 +11,18 @@ import LoginPage from "../pages/LoginPage";
import MealPlanThisWeekPage from "../pages/MealPlanThisWeekPage";
import api from "@/api";
import Admin from "./admin";
import { store } from "../store/store";
export const routes = [
{ path: "/", name: "home", component: HomePage },
{
path: "/logout",
beforeEnter: (_to, _from, next) => {
store.commit("setToken", "");
store.commit("setIsLoggedIn", false);
next("/");
},
},
{ path: "/mealie", component: HomePage },
{ path: "/login", component: LoginPage },
{ path: "/debug", component: Debug },

View file

@ -18,6 +18,8 @@ const state = {
activeTheme: {},
darkMode: "system",
isDark: false,
isLoggedIn: false,
token: "",
};
const mutations = {
@ -35,6 +37,13 @@ const mutations = {
state.darkMode = payload;
}
},
setIsLoggedIn(state, payload) {
state.isLoggedIn = payload;
},
setToken(state, payload) {
state.isLoggedIn = true;
state.token = payload;
},
};
const actions = {
@ -63,6 +72,8 @@ const getters = {
getActiveTheme: state => state.activeTheme,
getDarkMode: state => state.darkMode,
getIsDark: state => state.isDark,
getIsLoggedIn: state => state.isLoggedIn,
getToken: state => state.token,
};
export default {

View file

@ -20,8 +20,6 @@ const store = new Vuex.Store({
homePage,
},
state: {
// Auth
isLoggedIn: true,
// All Recipe Data Store
recentRecipes: [],
@ -30,10 +28,6 @@ const store = new Vuex.Store({
},
mutations: {
setIsLoggedIn(state, payload) {
state.isLoggedIn = payload;
},
setRecentRecipes(state, payload) {
state.recentRecipes = payload;
},
@ -62,7 +56,6 @@ const store = new Vuex.Store({
getters: {
getRecentRecipes: state => state.recentRecipes,
getMealPlanCategories: state => state.mealPlanCategories,
getIsLoggedIn: state => state.isLoggedIn,
},
});