mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-02 20:15:24 +02:00
feat: Filter Recipes By Household (and a ton of bug fixes) (#4207)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
2a6922a85c
commit
7c274de778
65 changed files with 896 additions and 590 deletions
|
@ -45,7 +45,7 @@
|
|||
import { defineComponent, useRoute, onMounted, ref, useContext } from "@nuxtjs/composition-api";
|
||||
import HouseholdPreferencesEditor from "~/components/Domain/Household/HouseholdPreferencesEditor.vue";
|
||||
import { useGroups } from "~/composables/use-groups";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAdminApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { HouseholdInDB } from "~/lib/api/types/household";
|
||||
|
@ -68,14 +68,14 @@ export default defineComponent({
|
|||
|
||||
const refHouseholdEditForm = ref<VForm | null>(null);
|
||||
|
||||
const userApi = useUserApi();
|
||||
const adminApi = useAdminApi();
|
||||
|
||||
const household = ref<HouseholdInDB | null>(null);
|
||||
|
||||
const userError = ref(false);
|
||||
|
||||
onMounted(async () => {
|
||||
const { data, error } = await userApi.households.getOne(householdId);
|
||||
const { data, error } = await adminApi.households.getOne(householdId);
|
||||
|
||||
if (error?.response?.status === 404) {
|
||||
alert.error(i18n.tc("user.user-not-found"));
|
||||
|
@ -92,7 +92,7 @@ export default defineComponent({
|
|||
return;
|
||||
}
|
||||
|
||||
const { response, data } = await userApi.households.updateOne(household.value.id, household.value);
|
||||
const { response, data } = await adminApi.households.updateOne(household.value.id, household.value);
|
||||
if (response?.status === 200 && data) {
|
||||
household.value = data;
|
||||
alert.success(i18n.tc("settings.settings-updated"));
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
import { defineComponent, reactive, toRefs, useContext, useRouter } from "@nuxtjs/composition-api";
|
||||
import { fieldTypes } from "~/composables/forms";
|
||||
import { useGroups } from "~/composables/use-groups";
|
||||
import { useHouseholds } from "~/composables/use-households";
|
||||
import { useAdminHouseholds } from "~/composables/use-households";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { HouseholdInDB } from "~/lib/api/types/household";
|
||||
|
||||
|
@ -97,7 +97,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
const { i18n } = useContext();
|
||||
const { groups } = useGroups();
|
||||
const { households, refreshAllHouseholds, deleteHousehold, createHousehold } = useHouseholds();
|
||||
const { households, refreshAllHouseholds, deleteHousehold, createHousehold } = useAdminHouseholds();
|
||||
|
||||
const state = reactive({
|
||||
createDialog: false,
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
import { computed, defineComponent, useRoute, onMounted, ref, useContext } from "@nuxtjs/composition-api";
|
||||
import { useAdminApi, useUserApi } from "~/composables/api";
|
||||
import { useGroups } from "~/composables/use-groups";
|
||||
import { useHouseholds } from "~/composables/use-households";
|
||||
import { useAdminHouseholds } from "~/composables/use-households";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { useUserForm } from "~/composables/use-users";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
@ -92,7 +92,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
const { userForm } = useUserForm();
|
||||
const { groups } = useGroups();
|
||||
const { useHouseholdsInGroup } = useHouseholds();
|
||||
const { useHouseholdsInGroup } = useAdminHouseholds();
|
||||
const { i18n } = useContext();
|
||||
const route = useRoute();
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
import { computed, defineComponent, useRouter, reactive, ref, toRefs, watch } from "@nuxtjs/composition-api";
|
||||
import { useAdminApi } from "~/composables/api";
|
||||
import { useGroups } from "~/composables/use-groups";
|
||||
import { useHouseholds } from "~/composables/use-households";
|
||||
import { useAdminHouseholds } from "~/composables/use-households";
|
||||
import { useUserForm } from "~/composables/use-users";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { VForm } from "~/types/vuetify";
|
||||
|
@ -60,7 +60,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
const { userForm } = useUserForm();
|
||||
const { groups } = useGroups();
|
||||
const { useHouseholdsInGroup } = useHouseholds();
|
||||
const { useHouseholdsInGroup } = useAdminHouseholds();
|
||||
const router = useRouter();
|
||||
|
||||
// ==============================================
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, useContext, useRouter } from "@nuxtjs/composition-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAdminApi, useUserApi } from "~/composables/api";
|
||||
import { useLocales } from "~/composables/use-locales";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { useUserRegistrationForm } from "~/composables/use-users/user-registration-form";
|
||||
|
@ -108,7 +108,8 @@ export default defineComponent({
|
|||
// ================================================================
|
||||
// Setup
|
||||
const { $auth, $globals, i18n } = useContext();
|
||||
const api = useUserApi();
|
||||
const userApi = useUserApi();
|
||||
const adminApi = useAdminApi();
|
||||
|
||||
const groupSlug = computed(() => $auth.user?.groupSlug);
|
||||
const { locale } = useLocales();
|
||||
|
@ -264,7 +265,7 @@ export default defineComponent({
|
|||
|
||||
async function updateUser() {
|
||||
// @ts-ignore-next-line user will never be null here
|
||||
const { response } = await api.users.updateOne($auth.user?.id, {
|
||||
const { response } = await userApi.users.updateOne($auth.user?.id, {
|
||||
...$auth.user,
|
||||
email: accountDetails.email.value,
|
||||
username: accountDetails.username.value,
|
||||
|
@ -285,7 +286,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
async function updatePassword() {
|
||||
const { response } = await api.users.changePassword({
|
||||
const { response } = await userApi.users.changePassword({
|
||||
currentPassword: "MyPassword",
|
||||
newPassword: credentials.password1.value,
|
||||
});
|
||||
|
@ -303,7 +304,7 @@ export default defineComponent({
|
|||
|
||||
async function updateGroup() {
|
||||
// @ts-ignore-next-line user will never be null here
|
||||
const { data } = await api.groups.getOne($auth.user?.groupId);
|
||||
const { data } = await userApi.groups.getOne($auth.user?.groupId);
|
||||
if (!data || !data.preferences) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
return;
|
||||
|
@ -320,7 +321,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// @ts-ignore-next-line user will never be null here
|
||||
const { response } = await api.groups.updateOne($auth.user?.groupId, payload);
|
||||
const { response } = await userApi.groups.updateOne($auth.user?.groupId, payload);
|
||||
if (!response || response.status !== 200) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
}
|
||||
|
@ -328,7 +329,7 @@ export default defineComponent({
|
|||
|
||||
async function updateHousehold() {
|
||||
// @ts-ignore-next-line user will never be null here
|
||||
const { data } = await api.households.getOne($auth.user?.householdId);
|
||||
const { data } = await adminApi.households.getOne($auth.user?.householdId);
|
||||
if (!data || !data.preferences) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
return;
|
||||
|
@ -346,28 +347,28 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// @ts-ignore-next-line user will never be null here
|
||||
const { response } = await api.households.updateOne($auth.user?.householdId, payload);
|
||||
const { response } = await adminApi.households.updateOne($auth.user?.householdId, payload);
|
||||
if (!response || response.status !== 200) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
}
|
||||
}
|
||||
|
||||
async function seedFoods() {
|
||||
const { response } = await api.seeders.foods({ locale: locale.value })
|
||||
const { response } = await userApi.seeders.foods({ locale: locale.value })
|
||||
if (!response || response.status !== 200) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
}
|
||||
}
|
||||
|
||||
async function seedUnits() {
|
||||
const { response } = await api.seeders.units({ locale: locale.value })
|
||||
const { response } = await userApi.seeders.units({ locale: locale.value })
|
||||
if (!response || response.status !== 200) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
}
|
||||
}
|
||||
|
||||
async function seedLabels() {
|
||||
const { response } = await api.seeders.labels({ locale: locale.value })
|
||||
const { response } = await userApi.seeders.labels({ locale: locale.value })
|
||||
if (!response || response.status !== 200) {
|
||||
alert.error(i18n.tc("events.something-went-wrong"));
|
||||
}
|
||||
|
|
|
@ -272,12 +272,10 @@ export default defineComponent({
|
|||
const errors = ref<Error[]>([]);
|
||||
|
||||
function checkForUnit(unit?: IngredientUnit | CreateIngredientUnit) {
|
||||
// @ts-expect-error; we're just checking if there's an id on this unit and returning a boolean
|
||||
return !!unit?.id;
|
||||
}
|
||||
|
||||
function checkForFood(food?: IngredientFood | CreateIngredientFood) {
|
||||
// @ts-expect-error; we're just checking if there's an id on this food and returning a boolean
|
||||
return !!food?.id;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<RecipeOrganizerPage
|
||||
v-if="items"
|
||||
:items="items"
|
||||
v-if="store"
|
||||
:items="store"
|
||||
:icon="$globals.icons.categories"
|
||||
item-type="categories"
|
||||
@delete="actions.deleteOne"
|
||||
|
@ -24,10 +24,10 @@ export default defineComponent({
|
|||
},
|
||||
middleware: ["auth", "group-only"],
|
||||
setup() {
|
||||
const { items, actions } = useCategoryStore();
|
||||
const { store, actions } = useCategoryStore();
|
||||
|
||||
return {
|
||||
items,
|
||||
store,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<RecipeOrganizerPage
|
||||
v-if="items"
|
||||
:items="items"
|
||||
v-if="store"
|
||||
:items="store"
|
||||
:icon="$globals.icons.tags"
|
||||
item-type="tags"
|
||||
@delete="actions.deleteOne"
|
||||
|
@ -24,10 +24,10 @@ export default defineComponent({
|
|||
},
|
||||
middleware: ["auth", "group-only"],
|
||||
setup() {
|
||||
const { items, actions } = useTagStore();
|
||||
const { store, actions } = useTagStore();
|
||||
|
||||
return {
|
||||
items,
|
||||
store,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -29,7 +29,7 @@ export default defineComponent({
|
|||
|
||||
return {
|
||||
dialog,
|
||||
tools: toolStore.items,
|
||||
tools: toolStore.store,
|
||||
actions: toolStore.actions,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
:headers.sync="tableHeaders"
|
||||
:data="categories || []"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="name"
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@delete-selected="bulkDeleteEventHandler"
|
||||
|
@ -198,7 +199,7 @@ export default defineComponent({
|
|||
state,
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
categories: categoryStore.items,
|
||||
categories: categoryStore.store,
|
||||
validators,
|
||||
|
||||
// create
|
||||
|
|
|
@ -241,6 +241,8 @@
|
|||
{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'},
|
||||
{icon: $globals.icons.tags, text: $tc('data-pages.labels.assign-label'), event: 'assign-selected'}
|
||||
]"
|
||||
initial-sort="createdAt"
|
||||
initial-sort-desc
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@create-one="createEventHandler"
|
||||
|
@ -264,6 +266,9 @@
|
|||
{{ item.onHand ? $globals.icons.check : $globals.icons.close }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<template #item.createdAt="{ item }">
|
||||
{{ formatDate(item.createdAt) }}
|
||||
</template>
|
||||
<template #button-bottom>
|
||||
<BaseButton @click="seedDialog = true">
|
||||
<template #icon> {{ $globals.icons.database }} </template>
|
||||
|
@ -326,8 +331,21 @@ export default defineComponent({
|
|||
value: "onHand",
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
text: i18n.tc("general.date-added"),
|
||||
value: "createdAt",
|
||||
show: false,
|
||||
}
|
||||
];
|
||||
|
||||
function formatDate(date: string) {
|
||||
try {
|
||||
return i18n.d(Date.parse(date), "medium");
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const foodStore = useFoodStore();
|
||||
|
||||
// ===============================================================
|
||||
|
@ -453,7 +471,7 @@ export default defineComponent({
|
|||
// ============================================================
|
||||
// Labels
|
||||
|
||||
const { labels: allLabels } = useLabelStore();
|
||||
const { store: allLabels } = useLabelStore();
|
||||
|
||||
// ============================================================
|
||||
// Seed
|
||||
|
@ -501,16 +519,15 @@ export default defineComponent({
|
|||
bulkAssignTarget.value = [];
|
||||
bulkAssignLabelId.value = undefined;
|
||||
foodStore.actions.refresh();
|
||||
// reload page, because foodStore.actions.refresh() does not update the table, reactivity for this seems to be broken (again)
|
||||
document.location.reload();
|
||||
}
|
||||
|
||||
return {
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
foods: foodStore.foods,
|
||||
foods: foodStore.store,
|
||||
allLabels,
|
||||
validators,
|
||||
formatDate,
|
||||
// Create
|
||||
createDialog,
|
||||
domNewFoodForm,
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
:headers.sync="tableHeaders"
|
||||
:data="labels || []"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="name"
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@delete-selected="bulkDeleteEventHandler"
|
||||
|
@ -271,7 +272,7 @@ export default defineComponent({
|
|||
state,
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
labels: labelStore.labels,
|
||||
labels: labelStore.store,
|
||||
validators,
|
||||
|
||||
// create
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
:headers.sync="tableHeaders"
|
||||
:data="actions || []"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="title"
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@delete-selected="bulkDeleteEventHandler"
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
:headers.sync="tableHeaders"
|
||||
:data="tags || []"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="name"
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@delete-selected="bulkDeleteEventHandler"
|
||||
|
@ -199,7 +200,7 @@ export default defineComponent({
|
|||
state,
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
tags: tagStore.items,
|
||||
tags: tagStore.store,
|
||||
validators,
|
||||
|
||||
// create
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
:headers.sync="tableHeaders"
|
||||
:data="tools || []"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="name"
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@delete-selected="bulkDeleteEventHandler"
|
||||
|
@ -209,7 +210,7 @@ export default defineComponent({
|
|||
state,
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
tools: toolStore.items,
|
||||
tools: toolStore.store,
|
||||
validators,
|
||||
|
||||
// create
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
</template>
|
||||
</i18n>
|
||||
|
||||
<v-autocomplete v-model="fromUnit" return-object :items="units" item-text="id" :label="$t('data-pages.units.source-unit')">
|
||||
<v-autocomplete v-model="fromUnit" return-object :items="store" item-text="id" :label="$t('data-pages.units.source-unit')">
|
||||
<template #selection="{ item }"> {{ item.name }}</template>
|
||||
<template #item="{ item }"> {{ item.name }} </template>
|
||||
</v-autocomplete>
|
||||
<v-autocomplete v-model="toUnit" return-object :items="units" item-text="id" :label="$t('data-pages.units.target-unit')">
|
||||
<v-autocomplete v-model="toUnit" return-object :items="store" item-text="id" :label="$t('data-pages.units.target-unit')">
|
||||
<template #selection="{ item }"> {{ item.name }}</template>
|
||||
<template #item="{ item }"> {{ item.name }} </template>
|
||||
</v-autocomplete>
|
||||
|
@ -185,7 +185,7 @@
|
|||
</template>
|
||||
</v-autocomplete>
|
||||
|
||||
<v-alert v-if="units && units.length > 0" type="error" class="mb-0 text-body-2">
|
||||
<v-alert v-if="store && store.length > 0" type="error" class="mb-0 text-body-2">
|
||||
{{ $t("data-pages.foods.seed-dialog-warning") }}
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
|
@ -196,8 +196,10 @@
|
|||
<CrudTable
|
||||
:table-config="tableConfig"
|
||||
:headers.sync="tableHeaders"
|
||||
:data="units || []"
|
||||
:data="store"
|
||||
:bulk-actions="[{icon: $globals.icons.delete, text: $tc('general.delete'), event: 'delete-selected'}]"
|
||||
initial-sort="createdAt"
|
||||
initial-sort-desc
|
||||
@delete-one="deleteEventHandler"
|
||||
@edit-one="editEventHandler"
|
||||
@create-one="createEventHandler"
|
||||
|
@ -221,6 +223,9 @@
|
|||
{{ item.fraction ? $globals.icons.check : $globals.icons.close }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<template #item.createdAt="{ item }">
|
||||
{{ formatDate(item.createdAt) }}
|
||||
</template>
|
||||
<template #button-bottom>
|
||||
<BaseButton @click="seedDialog = true">
|
||||
<template #icon> {{ $globals.icons.database }} </template>
|
||||
|
@ -292,9 +297,22 @@ export default defineComponent({
|
|||
value: "fraction",
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
text: i18n.tc("general.date-added"),
|
||||
value: "createdAt",
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
const { units, actions: unitActions } = useUnitStore();
|
||||
function formatDate(date: string) {
|
||||
try {
|
||||
return i18n.d(Date.parse(date), "medium");
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const { store, actions: unitActions } = useUnitStore();
|
||||
|
||||
// ============================================================
|
||||
// Create Units
|
||||
|
@ -447,8 +465,9 @@ export default defineComponent({
|
|||
return {
|
||||
tableConfig,
|
||||
tableHeaders,
|
||||
units,
|
||||
store,
|
||||
validators,
|
||||
formatDate,
|
||||
// Create
|
||||
createDialog,
|
||||
domNewUnitForm,
|
||||
|
|
|
@ -602,9 +602,9 @@ export default defineComponent({
|
|||
|
||||
const localLabels = ref<ShoppingListMultiPurposeLabelOut[]>()
|
||||
|
||||
const { labels: allLabels } = useLabelStore();
|
||||
const { units: allUnits } = useUnitStore();
|
||||
const { foods: allFoods } = useFoodStore();
|
||||
const { store: allLabels } = useLabelStore();
|
||||
const { store: allUnits } = useUnitStore();
|
||||
const { store: allFoods } = useFoodStore();
|
||||
|
||||
function getLabelColor(item: ShoppingListItemOut | null) {
|
||||
return item?.label?.color;
|
||||
|
|
|
@ -5,34 +5,40 @@
|
|||
:icon="$globals.icons.heart"
|
||||
:title="$tc('user.user-favorites')"
|
||||
:recipes="recipes"
|
||||
:query="query"
|
||||
@sortRecipes="assignSorted"
|
||||
@replaceRecipes="replaceRecipes"
|
||||
@appendRecipes="appendRecipes"
|
||||
@delete="removeRecipe"
|
||||
/>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useLazyRecipes } from "~/composables/recipes";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeCardSection },
|
||||
middleware: "auth",
|
||||
setup() {
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
const { isOwnGroup } = useLoggedInState();
|
||||
|
||||
const userId = route.value.params.id;
|
||||
const recipes = useAsync(async () => {
|
||||
const { data } = await api.recipes.getAll(1, -1, { queryFilter: `favoritedBy.id = "${userId}"` });
|
||||
return data?.items || null;
|
||||
}, useAsyncKey());
|
||||
const query = { queryFilter: `favoritedBy.id = "${userId}"` }
|
||||
const { recipes, appendRecipes, assignSorted, removeRecipe, replaceRecipes } = useLazyRecipes();
|
||||
|
||||
return {
|
||||
query,
|
||||
recipes,
|
||||
isOwnGroup,
|
||||
appendRecipes,
|
||||
assignSorted,
|
||||
removeRecipe,
|
||||
replaceRecipes,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue