mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
group admin init
This commit is contained in:
parent
19c09a1f74
commit
f5a193f3b6
11 changed files with 422 additions and 339 deletions
123
frontend/src/components/Admin/ManageUsers/GroupCard.vue
Normal file
123
frontend/src/components/Admin/ManageUsers/GroupCard.vue
Normal file
|
@ -0,0 +1,123 @@
|
|||
<template>
|
||||
<div>
|
||||
<Confirmation
|
||||
ref="deleteGroupConfirm"
|
||||
title="Confirm Group Deletion"
|
||||
:message="`Are you sure you want to delete <b>${group.name}<b/>`"
|
||||
icon="mdi-alert"
|
||||
@confirm="deleteGroup"
|
||||
:width="450"
|
||||
@close="closeGroupDelete"
|
||||
/>
|
||||
<v-card class="ma-auto" tile min-height="325px">
|
||||
<v-list dense>
|
||||
<v-card-title class="py-1">{{ group.name }}</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
<v-subheader>Group ID: {{ group.id }}</v-subheader>
|
||||
<v-list-item-group color="primary">
|
||||
<v-list-item v-for="property in groupProps" :key="property.text">
|
||||
<v-list-item-icon>
|
||||
<v-icon> {{ property.icon || "mdi-account" }} </v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="pl-4 flex row justify-space-between">
|
||||
<div>{{ property.text }}</div>
|
||||
<div>{{ property.value }}</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
small
|
||||
color="error"
|
||||
@click="confirmDelete"
|
||||
:disabled="ableToDelete"
|
||||
>
|
||||
Delete
|
||||
</v-btn>
|
||||
<!-- Coming Soon! -->
|
||||
<v-btn small color="success" disabled>
|
||||
Edit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const RENDER_EVENT = "update";
|
||||
import Confirmation from "@/components/UI/Confirmation";
|
||||
import api from "@/api";
|
||||
export default {
|
||||
components: { Confirmation },
|
||||
props: {
|
||||
group: {
|
||||
default: {
|
||||
name: "DEFAULT_NAME",
|
||||
id: 1,
|
||||
users: [],
|
||||
mealplans: [],
|
||||
categories: [],
|
||||
webhookUrls: [],
|
||||
webhookTime: "00:00",
|
||||
webhookEnable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
groupProps: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
ableToDelete() {
|
||||
return this.group.users.length >= 1 ? true : false;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.buildData();
|
||||
},
|
||||
methods: {
|
||||
confirmDelete() {
|
||||
this.$refs.deleteGroupConfirm.open();
|
||||
},
|
||||
async deleteGroup() {
|
||||
await api.groups.delete(this.group.id);
|
||||
this.$emit(RENDER_EVENT);
|
||||
},
|
||||
closeGroupDelete() {
|
||||
console.log("Close Delete");
|
||||
},
|
||||
buildData() {
|
||||
this.groupProps = [
|
||||
{
|
||||
text: "Total Users",
|
||||
icon: "mdi-account",
|
||||
value: this.group.users.length,
|
||||
},
|
||||
{
|
||||
text: "Total MealPlans",
|
||||
icon: "mdi-food",
|
||||
value: this.group.mealplans.length,
|
||||
},
|
||||
{
|
||||
text: "Webhooks Enabled",
|
||||
icon: "mdi-webhook",
|
||||
value: this.group.webhookEnable ? "True" : "False",
|
||||
},
|
||||
{
|
||||
text: "Webhook Time",
|
||||
icon: "mdi-clock-outline",
|
||||
value: this.group.webhookTime,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
120
frontend/src/components/Admin/ManageUsers/GroupDashboard.vue
Normal file
120
frontend/src/components/Admin/ManageUsers/GroupDashboard.vue
Normal file
|
@ -0,0 +1,120 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-card outlined class="mt-n1">
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<div width="100px">
|
||||
<v-text-field
|
||||
v-model="filter"
|
||||
clearable
|
||||
class="mr-2 pt-0"
|
||||
append-icon="mdi-filter"
|
||||
label="Filter"
|
||||
single-line
|
||||
hide-details
|
||||
></v-text-field>
|
||||
</div>
|
||||
<v-dialog v-model="groupDialog" max-width="400">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="mx-2"
|
||||
small
|
||||
color="success"
|
||||
dark
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
Create Group
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card>
|
||||
<v-app-bar dark dense color="primary">
|
||||
<v-icon left>
|
||||
mdi-account-group
|
||||
</v-icon>
|
||||
|
||||
<v-toolbar-title class="headline">
|
||||
Create Group
|
||||
</v-toolbar-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
</v-app-bar>
|
||||
|
||||
<v-card-text>
|
||||
<v-form ref="newGroup">
|
||||
<v-text-field
|
||||
v-model="newGroupName"
|
||||
label="Group Name"
|
||||
:rules="[existsRule]"
|
||||
></v-text-field>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" text @click="groupDialog = false">
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn color="primary" @click="createGroup">
|
||||
Create
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-card-actions>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col
|
||||
:sm="6"
|
||||
:md="6"
|
||||
:lg="3"
|
||||
:xl="3"
|
||||
v-for="group in groups"
|
||||
:key="group.id"
|
||||
>
|
||||
<GroupCard
|
||||
:group="group"
|
||||
@update="$store.dispatch('requestAllGroups')"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validators } from "@/mixins/validators";
|
||||
import api from "@/api";
|
||||
import GroupCard from "@/components/Admin/ManageUsers/GroupCard";
|
||||
export default {
|
||||
components: { GroupCard },
|
||||
mixins: [validators],
|
||||
data() {
|
||||
return {
|
||||
filter: "",
|
||||
groupDialog: false,
|
||||
newGroupName: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
groups() {
|
||||
return this.$store.getters.getGroups;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createGroup() {
|
||||
this.groupLoading = true;
|
||||
let response = await api.groups.create(this.newGroupName);
|
||||
if (response.created) {
|
||||
this.groupLoading = false;
|
||||
this.groupDialog = false;
|
||||
this.$store.dispatch("requestAllGroups");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -1,256 +0,0 @@
|
|||
<template>
|
||||
<v-card outlined class="mt-n1">
|
||||
<Confirmation
|
||||
ref="deleteUserDialog"
|
||||
title="Confirm User Deletion"
|
||||
:message="
|
||||
`Are you sure you want to delete the user <b>${activeName} ID: ${activeId}<b/>`
|
||||
"
|
||||
icon="mdi-alert"
|
||||
@confirm="deleteUser"
|
||||
:width="450"
|
||||
@close="closeDelete"
|
||||
/>
|
||||
<v-toolbar flat>
|
||||
<v-icon large color="accent" class="mr-1">
|
||||
mdi-account-group
|
||||
</v-icon>
|
||||
<v-toolbar-title class="headine">
|
||||
User Groups
|
||||
</v-toolbar-title>
|
||||
|
||||
<div>
|
||||
<v-select class="mt-7 ml-5" dense flat solo> </v-select>
|
||||
</div>
|
||||
|
||||
<v-spacer> </v-spacer>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn small color="success" dark v-bind="attrs" v-on="on">
|
||||
Create Group
|
||||
</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-form ref="newUser">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="editedItem.fullName"
|
||||
label="Full Name"
|
||||
:rules="[existsRule]"
|
||||
validate-on-blur
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="editedItem.email"
|
||||
label="Email"
|
||||
:rules="[existsRule, emailRule]"
|
||||
validate-on-blur
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="editedItem.group"
|
||||
label="Group Group"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" v-if="showPassword">
|
||||
<v-text-field
|
||||
v-model="editedItem.password"
|
||||
label="User Password"
|
||||
:rules="[existsRule, minRule]"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-switch v-model="editedItem.admin" label="Admin"></v-switch>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
</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>
|
||||
</v-toolbar>
|
||||
<v-divider></v-divider>
|
||||
<v-card-text>
|
||||
<v-data-table :headers="headers" :items="users" sort-by="calories">
|
||||
<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>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Confirmation from "@/components/UI/Confirmation";
|
||||
import api from "@/api";
|
||||
import { validators } from "@/mixins/validators";
|
||||
export default {
|
||||
components: { Confirmation },
|
||||
mixins: [validators],
|
||||
data: () => ({
|
||||
dialog: false,
|
||||
activeId: null,
|
||||
activeName: null,
|
||||
headers: [
|
||||
{
|
||||
text: "User IDs",
|
||||
align: "start",
|
||||
sortable: false,
|
||||
value: "id",
|
||||
},
|
||||
{ text: "Full Name", value: "fullName" },
|
||||
{ text: "Email", value: "email" },
|
||||
{ text: "Group", value: "group" },
|
||||
{ text: "Admin", value: "admin" },
|
||||
{ text: "", value: "actions", sortable: false, align: "center" },
|
||||
],
|
||||
users: [],
|
||||
editedIndex: -1,
|
||||
editedItem: {
|
||||
id: 0,
|
||||
fullName: "",
|
||||
password: "",
|
||||
email: "",
|
||||
group: "",
|
||||
admin: false,
|
||||
},
|
||||
defaultItem: {
|
||||
id: 0,
|
||||
fullName: "",
|
||||
password: "",
|
||||
email: "",
|
||||
group: "",
|
||||
admin: false,
|
||||
},
|
||||
}),
|
||||
|
||||
computed: {
|
||||
formTitle() {
|
||||
return this.editedIndex === -1 ? "New User" : "Edit User";
|
||||
},
|
||||
showPassword() {
|
||||
return this.editedIndex === -1 ? true : false;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialog(val) {
|
||||
val || this.close();
|
||||
},
|
||||
dialogDelete(val) {
|
||||
val || this.closeDelete();
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.initialize();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async initialize() {
|
||||
this.users = await api.users.allUsers();
|
||||
},
|
||||
|
||||
async deleteUser() {
|
||||
await api.users.delete(this.activeId);
|
||||
this.initialize();
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
this.editedIndex = this.users.indexOf(item);
|
||||
this.editedItem = Object.assign({}, item);
|
||||
this.dialog = true;
|
||||
},
|
||||
|
||||
deleteItem(item) {
|
||||
this.activeId = item.id;
|
||||
this.activeName = item.fullName;
|
||||
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;
|
||||
});
|
||||
},
|
||||
|
||||
async save() {
|
||||
if (this.editedIndex > -1) {
|
||||
api.users.update(this.editedItem);
|
||||
this.close();
|
||||
} else if (this.$refs.newUser.validate()) {
|
||||
api.users.create(this.editedItem);
|
||||
this.close();
|
||||
}
|
||||
await this.initialize();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -68,7 +68,7 @@
|
|||
</v-dialog>
|
||||
</v-toolbar>
|
||||
<v-divider></v-divider>
|
||||
|
||||
|
||||
<v-card-text>
|
||||
<v-data-table :headers="headers" :items="links" sort-by="calories">
|
||||
<template v-slot:item.token="{ item }">
|
||||
|
|
|
@ -12,35 +12,18 @@
|
|||
@close="closeDelete"
|
||||
/>
|
||||
<v-toolbar flat>
|
||||
<v-icon large color="accent" class="mr-1">
|
||||
mdi-account
|
||||
</v-icon>
|
||||
<v-toolbar-title class="headine">
|
||||
Users
|
||||
</v-toolbar-title>
|
||||
|
||||
<v-spacer> </v-spacer>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
append-icon="mdi-filter"
|
||||
label="Filter"
|
||||
single-line
|
||||
hide-details
|
||||
></v-text-field>
|
||||
<v-dialog>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="mx-2"
|
||||
small
|
||||
color="success"
|
||||
dark
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
Create Group
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-dialog>
|
||||
<div width="100px">
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
class="mr-2"
|
||||
append-icon="mdi-filter"
|
||||
label="Filter"
|
||||
single-line
|
||||
hide-details
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn small color="success" dark v-bind="attrs" v-on="on">
|
||||
|
@ -83,11 +66,12 @@
|
|||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
<v-select
|
||||
dense
|
||||
v-model="editedItem.group"
|
||||
label="Group Group"
|
||||
></v-text-field>
|
||||
:items="existingGroups"
|
||||
label="User Group"
|
||||
></v-select>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" v-if="showPassword">
|
||||
<v-text-field
|
||||
|
@ -203,6 +187,9 @@ export default {
|
|||
showPassword() {
|
||||
return this.editedIndex === -1 ? true : false;
|
||||
},
|
||||
existingGroups() {
|
||||
return this.$store.getters.getGroupNames;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
|
53
frontend/src/components/UI/BasicModal.vue
Normal file
53
frontend/src/components/UI/BasicModal.vue
Normal file
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-dialog v-model="dialog" :width="modalWidth + 'px'">
|
||||
<v-app-bar dark :color="color" class="mt-n1 mb-2">
|
||||
<v-icon large left v-if="!loading">
|
||||
{{ titleIcon }}
|
||||
</v-icon>
|
||||
<v-progress-circular
|
||||
v-else
|
||||
indeterminate
|
||||
color="white"
|
||||
large
|
||||
class="mr-2"
|
||||
>
|
||||
</v-progress-circular>
|
||||
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
</v-app-bar>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
color: {
|
||||
default: "primary",
|
||||
},
|
||||
title: {
|
||||
default: "Modal Title",
|
||||
},
|
||||
titleIcon: {
|
||||
default: "mdi-account",
|
||||
},
|
||||
modalWidth: {
|
||||
default: "500",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.dialog = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
|
@ -8,10 +8,10 @@
|
|||
@keydown.esc="cancel"
|
||||
>
|
||||
<v-card>
|
||||
<v-toolbar v-if="Boolean(title)" :color="color" dense flat dark>
|
||||
<v-app-bar v-if="Boolean(title)" :color="color" dense flat dark>
|
||||
<v-icon v-if="Boolean(icon)" left> {{ icon }}</v-icon>
|
||||
<v-toolbar-title v-text="title" />
|
||||
</v-toolbar>
|
||||
</v-app-bar>
|
||||
|
||||
<v-card-text
|
||||
v-show="!!message"
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<TheSignUpTable />
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<TheGroupTable />
|
||||
<GroupDashboard />
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-card>
|
||||
|
@ -43,15 +43,18 @@
|
|||
|
||||
<script>
|
||||
import TheUserTable from "@/components/Admin/ManageUsers/TheUserTable";
|
||||
import TheGroupTable from "@/components/Admin/ManageUsers/TheGroupTable";
|
||||
import GroupDashboard from "@/components/Admin/ManageUsers/GroupDashboard";
|
||||
import TheSignUpTable from "@/components/Admin/ManageUsers/TheSignUpTable";
|
||||
export default {
|
||||
components: { TheUserTable, TheGroupTable, TheSignUpTable },
|
||||
components: { TheUserTable, GroupDashboard, TheSignUpTable },
|
||||
data() {
|
||||
return {
|
||||
tab: 0,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch("requestAllGroups");
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -13,13 +13,17 @@
|
|||
outlined
|
||||
:flat="isFlat"
|
||||
elavation="0"
|
||||
v-model="planCategories"
|
||||
v-model="groupSettings.categories"
|
||||
:items="categories"
|
||||
item-text="name"
|
||||
item-value="name"
|
||||
return-object
|
||||
multiple
|
||||
chips
|
||||
:hint="$t('meal-plan.only-recipes-with-these-categories-will-be-used-in-meal-plans')"
|
||||
:hint="
|
||||
$t(
|
||||
'meal-plan.only-recipes-with-these-categories-will-be-used-in-meal-plans'
|
||||
)
|
||||
"
|
||||
class="mt-2"
|
||||
persistent-hint
|
||||
>
|
||||
|
@ -50,12 +54,15 @@
|
|||
"settings.webhooks.the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at"
|
||||
)
|
||||
}}
|
||||
<strong>{{ time }}</strong>
|
||||
<strong>{{ groupSettings.webhookTime }}</strong>
|
||||
</p>
|
||||
|
||||
<v-row dense align="center">
|
||||
<v-col cols="12" md="2" sm="5">
|
||||
<v-switch v-model="enabled" :label="$t('general.enabled')"></v-switch>
|
||||
<v-switch
|
||||
v-model="groupSettings.webhookEnable"
|
||||
:label="$t('general.enabled')"
|
||||
></v-switch>
|
||||
</v-col>
|
||||
<v-col cols="12" md="3" sm="5">
|
||||
<TimePickerDialog @save-time="saveTime" />
|
||||
|
@ -68,7 +75,12 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-for="(url, index) in webhooks" :key="index" align="center" dense>
|
||||
<v-row
|
||||
v-for="(url, index) in groupSettings.webhookUrls"
|
||||
:key="index"
|
||||
align="center"
|
||||
dense
|
||||
>
|
||||
<v-col cols="1">
|
||||
<v-btn icon color="error" @click="removeWebhook(index)">
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
|
@ -76,7 +88,7 @@
|
|||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="webhooks[index]"
|
||||
v-model="groupSettings.webhookUrls[index]"
|
||||
:label="$t('settings.webhooks.webhook-url')"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
|
@ -87,7 +99,7 @@
|
|||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="success" @click="saveWebhooks" class="mr-2 mb-1">
|
||||
<v-btn color="success" @click="saveGroupSettings" class="mr-2 mb-1">
|
||||
<v-icon left> mdi-content-save </v-icon>
|
||||
{{ $t("general.save") }}
|
||||
</v-btn>
|
||||
|
@ -104,14 +116,19 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
name: "main",
|
||||
webhooks: [],
|
||||
enabled: false,
|
||||
time: "",
|
||||
planCategories: [],
|
||||
groupSettings: {
|
||||
name: "home",
|
||||
id: 1,
|
||||
mealplans: [],
|
||||
categories: [],
|
||||
webhookUrls: [],
|
||||
webhookTime: "00:00",
|
||||
webhookEnable: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
async mounted() {
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
this.getSiteSettings();
|
||||
},
|
||||
computed: {
|
||||
|
@ -119,44 +136,39 @@ export default {
|
|||
return this.$store.getters.getCategories;
|
||||
},
|
||||
isFlat() {
|
||||
return this.planCategories ? true : false;
|
||||
return this.groupSettings.categories >= 1 ? true : false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
saveTime(value) {
|
||||
this.time = value;
|
||||
this.groupSettings.webhookTime = value;
|
||||
},
|
||||
async getSiteSettings() {
|
||||
let settings = await api.settings.requestAll();
|
||||
this.webhooks = settings.webhooks.webhookURLs;
|
||||
this.name = settings.name;
|
||||
this.time = settings.webhooks.webhookTime;
|
||||
this.enabled = settings.webhooks.enabled;
|
||||
this.planCategories = settings.planCategories;
|
||||
getSiteSettings() {
|
||||
let settings = this.$store.getters.getCurrentGroup;
|
||||
|
||||
this.groupSettings.name = settings.name;
|
||||
this.groupSettings.id = settings.id;
|
||||
this.groupSettings.categories = settings.categories;
|
||||
this.groupSettings.webhookUrls = settings.webhookUrls;
|
||||
this.groupSettings.webhookTime = settings.webhookTime;
|
||||
this.groupSettings.webhookEnable = settings.webhookEnable;
|
||||
},
|
||||
addWebhook() {
|
||||
this.webhooks.push(" ");
|
||||
this.groupSettings.webhookUrls.push(" ");
|
||||
},
|
||||
removeWebhook(index) {
|
||||
this.webhooks.splice(index, 1);
|
||||
this.groupSettings.webhookUrls.splice(index, 1);
|
||||
},
|
||||
saveWebhooks() {
|
||||
const body = {
|
||||
name: this.name,
|
||||
planCategories: this.planCategories,
|
||||
webhooks: {
|
||||
webhookURLs: this.webhooks,
|
||||
webhookTime: this.time,
|
||||
enabled: this.enabled,
|
||||
},
|
||||
};
|
||||
api.settings.update(body);
|
||||
async saveGroupSettings() {
|
||||
await api.groups.update(this.groupSettings);
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
this.getSiteSettings();
|
||||
},
|
||||
testWebhooks() {
|
||||
api.settings.testWebhooks();
|
||||
},
|
||||
removeCategory(index) {
|
||||
this.planCategories.splice(index, 1);
|
||||
this.groupSettings.categories.splice(index, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<AdminSidebar />
|
||||
<v-slide-x-transition hide-on-leave>
|
||||
<router-view></router-view>
|
||||
</v-slide-x-transition>
|
||||
<!-- <v-footer fixed>
|
||||
<v-col class="text-center" cols="12">
|
||||
<div>
|
||||
<v-container height="100%">
|
||||
<AdminSidebar />
|
||||
<v-slide-x-transition hide-on-leave>
|
||||
<router-view></router-view>
|
||||
</v-slide-x-transition>
|
||||
</v-container>
|
||||
<!-- <v-footer absolute>
|
||||
<div class="flex text-center" cols="12">
|
||||
{{ $t("settings.current") }}
|
||||
{{ version }} |
|
||||
{{ $t("settings.latest") }}
|
||||
|
@ -21,9 +23,9 @@
|
|||
>
|
||||
{{ $t("settings.contribute") }}
|
||||
</a>
|
||||
</v-col>
|
||||
</div>
|
||||
</v-footer> -->
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
39
frontend/src/store/modules/groups.js
Normal file
39
frontend/src/store/modules/groups.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import api from "@/api";
|
||||
|
||||
const state = {
|
||||
groups: [],
|
||||
currentGroup: {},
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
setGroups(state, payload) {
|
||||
state.groups = payload;
|
||||
},
|
||||
setCurrentGroup(state, payload) {
|
||||
state.currentGroup = payload;
|
||||
},
|
||||
};
|
||||
|
||||
const actions = {
|
||||
async requestAllGroups({ commit }) {
|
||||
const groups = await api.groups.allGroups();
|
||||
commit("setGroups", groups);
|
||||
},
|
||||
async requestCurrentGroup({ commit }) {
|
||||
const group = await api.groups.current();
|
||||
commit("setCurrentGroup", group);
|
||||
},
|
||||
};
|
||||
|
||||
const getters = {
|
||||
getGroups: state => state.groups,
|
||||
getGroupNames: state => Array.from(state.groups, x => x.name),
|
||||
getCurrentGroup: state => state.currentGroup
|
||||
};
|
||||
|
||||
export default {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue