1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-02 20:15:24 +02:00

Refactor/group page (#666)

* refactor(backend): ♻️ Refactor base class to be abstract and create a router factory method

* feat(frontend):  add group edit

* refactor(backend):  add group edit support

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-09-01 21:39:40 -08:00 committed by GitHub
parent 9b1bf56a5d
commit 990244e37e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 749 additions and 196 deletions

View file

@ -0,0 +1,25 @@
import { BaseCRUDAPI } from "./_base";
const prefix = "/api";
const routes = {
webhooks: `${prefix}/groups/webhooks`,
webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`,
};
export interface CreateGroupWebhook {
enabled: boolean;
name: string;
url: string;
time: string;
}
export interface GroupWebhook extends CreateGroupWebhook {
id: string;
groupId: string;
}
export class WebhooksAPI extends BaseCRUDAPI<GroupWebhook, CreateGroupWebhook> {
baseRoute = routes.webhooks;
itemRoute = routes.webhooksId;
}

View file

@ -1,4 +1,3 @@
import { requests } from "../requests";
import { BaseCRUDAPI } from "./_base";
import { GroupInDB } from "~/types/api-types/user";
@ -7,10 +6,17 @@ const prefix = "/api";
const routes = {
groups: `${prefix}/groups`,
groupsSelf: `${prefix}/groups/self`,
categories: `${prefix}/groups/categories`,
groupsId: (id: string | number) => `${prefix}/groups/${id}`,
};
interface Category {
id: number;
name: string;
slug: string;
}
export interface CreateGroup {
name: string;
}
@ -21,6 +27,14 @@ export class GroupAPI extends BaseCRUDAPI<GroupInDB, CreateGroup> {
/** Returns the Group Data for the Current User
*/
async getCurrentUserGroup() {
return await requests.get(routes.groupsSelf);
return await this.requests.get(routes.groupsSelf);
}
async getCategories() {
return await this.requests.get<Category[]>(routes.categories);
}
async setCategories(payload: Category[]) {
return await this.requests.put<Category[]>(routes.categories, payload);
}
}

View file

@ -12,6 +12,7 @@ import { NotificationsAPI } from "./class-interfaces/event-notifications";
import { FoodAPI } from "./class-interfaces/recipe-foods";
import { UnitAPI } from "./class-interfaces/recipe-units";
import { CookbookAPI } from "./class-interfaces/cookbooks";
import { WebhooksAPI } from "./class-interfaces/group-webhooks";
import { ApiRequestInstance } from "~/types/api";
class Api {
@ -29,6 +30,7 @@ class Api {
public foods: FoodAPI;
public units: UnitAPI;
public cookbooks: CookbookAPI;
public groupWebhooks: WebhooksAPI;
// Utils
public upload: UploadFile;
@ -49,6 +51,7 @@ class Api {
this.users = new UserApi(requests);
this.groups = new GroupAPI(requests);
this.cookbooks = new CookbookAPI(requests);
this.groupWebhooks = new WebhooksAPI(requests);
// Admin
this.debug = new DebugAPI(requests);

View file

@ -0,0 +1,75 @@
import { useAsync, ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils";
import { useApiSingleton } from "~/composables/use-api";
import { GroupWebhook } from "~/api/class-interfaces/group-webhooks";
export const useGroupWebhooks = function () {
const api = useApiSingleton();
const loading = ref(false);
const validForm = ref(true);
const actions = {
getAll() {
loading.value = true;
const units = useAsync(async () => {
const { data } = await api.groupWebhooks.getAll();
return data;
}, useAsyncKey());
loading.value = false;
return units;
},
async refreshAll() {
loading.value = true;
const { data } = await api.groupWebhooks.getAll();
if (data) {
webhooks.value = data;
}
loading.value = false;
},
async createOne() {
loading.value = true;
const payload = {
enabled: false,
name: "New Webhook",
url: "",
time: "00:00",
};
const { data } = await api.groupWebhooks.createOne(payload);
if (data) {
this.refreshAll();
}
loading.value = false;
},
async updateOne(updateData: GroupWebhook) {
if (!updateData.id) {
return;
}
loading.value = true;
const { data } = await api.groupWebhooks.updateOne(updateData.id, updateData);
if (data) {
this.refreshAll();
}
loading.value = false;
},
async deleteOne(id: string | number) {
loading.value = true;
const { data } = await api.groupWebhooks.deleteOne(id);
if (data) {
this.refreshAll();
}
},
};
const webhooks = actions.getAll();
return { webhooks, actions, validForm };
};

View file

@ -1,8 +1,33 @@
import { useAsync, ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils";
import { useApiSingleton } from "~/composables/use-api";
import { CreateGroup } from "~/api/class-interfaces/groups";
export const useGroup = function () {
const api = useApiSingleton();
const actions = {
getAll() {
const units = useAsync(async () => {
const { data } = await api.groups.getCategories();
return data;
}, useAsyncKey());
return units;
},
async updateAll() {
if (!categories.value) {
return;
}
const { data } = await api.groups.setCategories(categories.value);
categories.value = data;
},
};
const categories = actions.getAll();
return { actions, categories };
};
export const useGroups = function () {
const api = useApiSingleton();

View file

@ -61,6 +61,11 @@ export default defineComponent({
to: "/user/group/cookbooks",
title: this.$t("sidebar.cookbooks"),
},
{
icon: this.$globals.icons.webhook,
to: "/user/group/webhooks",
title: "Webhooks",
},
],
adminLinks: [
{

View file

@ -31,7 +31,7 @@ import { computed, defineComponent, useContext } from "@nuxtjs/composition-api";
import AppHeader from "@/components/Layout/AppHeader.vue";
import AppSidebar from "@/components/Layout/AppSidebar.vue";
import AppFloatingButton from "@/components/Layout/AppFloatingButton.vue";
import { useCookbooks } from "~/composables/use-cookbooks";
import { useCookbooks } from "~/composables/use-group-cookbooks";
export default defineComponent({
components: { AppHeader, AppSidebar, AppFloatingButton },

View file

@ -25,7 +25,7 @@
<script lang="ts">
import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue";
import { defineComponent, useRoute, ref } from "@nuxtjs/composition-api";
import { useCookbook } from "~/composables/use-cookbooks";
import { useCookbook } from "~/composables/use-group-cookbooks";
export default defineComponent({
components: { RecipeCardSection },
setup() {

View file

@ -43,27 +43,24 @@
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
import { useCookbooks } from "@/composables/use-cookbooks";
import { useCookbooks } from "@/composables/use-group-cookbooks";
import draggable from "vuedraggable";
export default defineComponent({
components: { draggable },
layout: "admin",
setup() {
const { cookbooks, actions, workingCookbookData, deleteTargetId, validForm } = useCookbooks();
const { cookbooks, actions } = useCookbooks();
return {
cookbooks,
actions,
workingCookbookData,
deleteTargetId,
validForm,
};
},
});
</script>
<style scoped>
<style>
.my-border {
border-left: 5px solid var(--v-primary-base);
}

View file

@ -1,21 +1,33 @@
<template>
<v-container fluid>
<BaseCardSectionTitle title="Group Settings">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias error provident, eveniet, laboriosam assumenda
earum amet quaerat vel consequatur molestias sed enim. Adipisci a consequuntur dolor culpa expedita voluptatem
praesentium optio iste atque, ea reiciendis iure non aut suscipit modi ducimus ratione, quam numquam quaerat
distinctio illum nemo. Dicta, doloremque!
</BaseCardSectionTitle>
<section>
<BaseCardSectionTitle title="Group Settings">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias error provident, eveniet, laboriosam assumenda
earum amet quaerat vel consequatur molestias sed enim. Adipisci a consequuntur dolor culpa expedita voluptatem
praesentium optio iste atque, ea reiciendis iure non aut suscipit modi ducimus ratione, quam numquam quaerat
distinctio illum nemo. Dicta, doloremque!
</BaseCardSectionTitle>
<div v-if="categories" class="d-flex">
<DomainRecipeCategoryTagSelector v-model="categories" class="mt-5 mr-5" />
<BaseButton save class="mt-auto mb-3" @click="actions.updateAll()" />
</div>
</section>
</v-container>
</template>
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
import { useGroup } from "~/composables/use-groups";
export default defineComponent({
layout: "admin",
setup() {
return {};
const { categories, actions } = useGroup();
return {
categories,
actions,
};
},
});
</script>

View file

@ -0,0 +1,68 @@
<template>
<v-container fluid>
<BaseCardSectionTitle title="MealPlan Webhooks">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias error provident, eveniet, laboriosam assumenda
earum amet quaerat vel consequatur molestias sed enim. Adipisci a consequuntur dolor culpa expedita voluptatem
praesentium optio iste atque, ea reiciendis iure non aut suscipit modi ducimus ratione, quam numquam quaerat
distinctio illum nemo. Dicta, doloremque!
</BaseCardSectionTitle>
<BaseButton create @click="actions.createOne()" />
<v-expansion-panels class="mt-2">
<v-expansion-panel v-for="(webhook, index) in webhooks" :key="index" class="my-2 my-border rounded">
<v-expansion-panel-header disable-icon-rotate class="headline">
<div class="d-flex align-center">
<v-icon large left :color="webhook.enabled ? 'info' : null">
{{ $globals.icons.webhook }}
</v-icon>
{{ webhook.name }} - {{ webhook.time }}
</div>
<template #actions>
<v-btn color="info" fab small class="ml-2">
<v-icon color="white">
{{ $globals.icons.edit }}
</v-icon>
</v-btn>
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-card-text>
<v-switch v-model="webhook.enabled" label="Enabled"></v-switch>
<v-text-field v-model="webhook.name" label="Webhook Name"></v-text-field>
<v-text-field v-model="webhook.url" label="Webhook Url"></v-text-field>
<v-time-picker v-model="webhook.time" class="elevation-2" ampm-in-title format="ampm"></v-time-picker>
</v-card-text>
<v-card-actions>
<BaseButton secondary color="info">
<template #icon>
{{ $globals.icons.testTube }}
</template>
Test
</BaseButton>
<v-spacer></v-spacer>
<BaseButton delete @click="actions.deleteOne(webhook.id)" />
<BaseButton save @click="actions.updateOne(webhook)" />
</v-card-actions>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-container>
</template>
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
import { useGroupWebhooks } from "~/composables/use-group-webhooks";
export default defineComponent({
layout: "admin",
setup() {
const { actions, webhooks } = useGroupWebhooks();
return {
actions,
webhooks,
};
},
});
</script>
<style scoped>
</style>