chore: Nuxt 4 upgrade (#7426)

This commit is contained in:
Kuchenpirat
2026-04-08 17:25:41 +02:00
committed by GitHub
parent 70a251a331
commit d3e41582ae
561 changed files with 1840 additions and 2750 deletions

View File

@@ -1,3 +0,0 @@
export { useUserForm } from "./user-form";
export { useUserRegistrationForm } from "./user-registration-form";
export { useUserSelfRatings } from "./user-ratings";

View File

@@ -1,249 +0,0 @@
import { useLocalStorage, useSessionStorage } from "@vueuse/core";
import { ActivityKey } from "~/lib/api/types/activity";
import type { RegisteredParser, TimelineEventType } from "~/lib/api/types/recipe";
import type { QueryFilterJSON } from "~/lib/api/types/non-generated";
export interface UserPrintPreferences {
imagePosition: string;
showDescription: boolean;
showNotes: boolean;
showNutrition: boolean;
expandChildRecipes: boolean;
}
export interface UserSearchQuery {
recipe: string;
}
export enum ImagePosition {
hidden = "hidden",
left = "left",
right = "right",
}
export interface UserMealPlanPreferences {
numberOfDaysPast: number;
numberOfDays: number;
}
export interface UserRecipePreferences {
orderBy: string;
orderDirection: string;
filterNull: boolean;
sortIcon: string;
useMobileCards: boolean;
}
export interface UserShoppingListPreferences {
viewAllLists: boolean;
}
export interface UserTimelinePreferences {
orderDirection: string;
types: TimelineEventType[];
}
export interface UserParsingPreferences {
parser: RegisteredParser;
}
export interface UserCookbooksPreferences {
hideOtherHouseholds: boolean;
}
export interface UserRecipeFinderPreferences {
foodIds: string[];
toolIds: string[];
queryFilter: string;
queryFilterJSON: QueryFilterJSON;
maxMissingFoods: number;
maxMissingTools: number;
includeFoodsOnHand: boolean;
includeToolsOnHand: boolean;
}
export interface UserRecipeCreatePreferences {
importKeywordsAsTags: boolean;
importCategories: boolean;
stayInEditMode: boolean;
parseRecipe: boolean;
}
export interface UserActivityPreferences {
defaultActivity: ActivityKey;
}
export function useUserMealPlanPreferences(): Ref<UserMealPlanPreferences> {
const fromStorage = useLocalStorage(
"meal-planner-preferences",
{
numberOfDaysPast: 0,
numberOfDays: 7,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserMealPlanPreferences>;
return fromStorage;
}
export function useUserPrintPreferences(): Ref<UserPrintPreferences> {
const fromStorage = useLocalStorage(
"recipe-print-preferences",
{
imagePosition: "left",
showDescription: true,
showNotes: true,
expandChildRecipes: false,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserPrintPreferences>;
return fromStorage;
}
export function useUserSortPreferences(): Ref<UserRecipePreferences> {
const { $globals } = useNuxtApp();
const fromStorage = useLocalStorage(
"recipe-section-preferences",
{
orderBy: "created_at",
orderDirection: "desc",
filterNull: false,
sortIcon: $globals.icons.sortAlphabeticalAscending,
useMobileCards: false,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserRecipePreferences>;
return fromStorage;
}
export function useUserActivityPreferences(): Ref<UserActivityPreferences> {
const fromStorage = useLocalStorage(
"activity-preferences",
{
defaultActivity: ActivityKey.RECIPES,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as Ref<UserActivityPreferences>;
return fromStorage;
}
export function useUserSearchQuerySession(): Ref<UserSearchQuery> {
const fromStorage = useSessionStorage(
"search-query",
{
recipe: "",
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserSearchQuery>;
return fromStorage;
}
export function useShoppingListPreferences(): Ref<UserShoppingListPreferences> {
const fromStorage = useLocalStorage(
"shopping-list-preferences",
{
viewAllLists: false,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserShoppingListPreferences>;
return fromStorage;
}
export function useTimelinePreferences(): Ref<UserTimelinePreferences> {
const fromStorage = useLocalStorage(
"timeline-preferences",
{
orderDirection: "asc",
types: ["info", "system", "comment"] as TimelineEventType[],
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserTimelinePreferences>;
return fromStorage;
}
export function useParsingPreferences(): Ref<UserParsingPreferences> {
const fromStorage = useLocalStorage(
"parsing-preferences",
{
parser: "nlp",
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserParsingPreferences>;
return fromStorage;
}
export function useCookbookPreferences(): Ref<UserCookbooksPreferences> {
const fromStorage = useLocalStorage(
"cookbook-preferences",
{
hideOtherHouseholds: false,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserCookbooksPreferences>;
return fromStorage;
}
export function useRecipeFinderPreferences(): Ref<UserRecipeFinderPreferences> {
const fromStorage = useLocalStorage(
"recipe-finder-preferences",
{
foodIds: [],
toolIds: [],
queryFilter: "",
queryFilterJSON: { parts: [] } as QueryFilterJSON,
maxMissingFoods: 20,
maxMissingTools: 20,
includeFoodsOnHand: true,
includeToolsOnHand: true,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserRecipeFinderPreferences>;
return fromStorage;
}
export function useRecipeCreatePreferences(): Ref<UserRecipeCreatePreferences> {
const fromStorage = useLocalStorage(
"recipe-create-preferences",
{
importKeywordsAsTags: false,
importCategories: false,
stayInEditMode: false,
parseRecipe: true,
},
{ mergeDefaults: true },
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserRecipeCreatePreferences>;
return fromStorage;
}

View File

@@ -1,93 +0,0 @@
import { fieldTypes } from "../forms";
import { validators } from "../use-validators";
import type { AutoFormItems } from "~/types/auto-forms";
export const useUserForm = () => {
const i18n = useI18n();
const userForm: AutoFormItems = [
{
section: i18n.t("user.user-details"),
label: i18n.t("user.user-name"),
varName: "username",
type: fieldTypes.TEXT,
rules: [validators.required],
},
{
label: i18n.t("user.full-name"),
varName: "fullName",
type: fieldTypes.TEXT,
rules: [validators.required],
},
{
label: i18n.t("user.email"),
varName: "email",
type: fieldTypes.TEXT,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.password"),
varName: "password",
disableUpdate: true,
type: fieldTypes.PASSWORD,
rules: [validators.required, validators.minLength(8)],
},
{
cols: 6,
label: i18n.t("user.authentication-method"),
varName: "authMethod",
type: fieldTypes.SELECT,
hint: i18n.t("user.authentication-method-hint"),
disableCreate: true,
options: [{ text: "Mealie" }, { text: "LDAP" }, { text: "OIDC" }],
},
{
section: i18n.t("user.permissions"),
cols: 6,
label: i18n.t("user.administrator"),
varName: "admin",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.user-can-invite-other-to-group"),
varName: "canInvite",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.user-can-manage-group"),
varName: "canManage",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.user-can-organize-group-data"),
varName: "canOrganize",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.user-can-manage-household"),
varName: "canManageHousehold",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
{
cols: 6,
label: i18n.t("user.enable-advanced-features"),
varName: "advanced",
type: fieldTypes.BOOLEAN,
rules: [validators.required],
},
];
return {
userForm,
};
};

View File

@@ -1,47 +0,0 @@
import { useUserApi } from "~/composables/api";
import type { UserRatingSummary } from "~/lib/api/types/user";
const userRatings = ref<UserRatingSummary[]>([]);
const loading = ref(false);
const ready = ref(false);
export const useUserSelfRatings = function () {
const auth = useMealieAuth();
async function refreshUserRatings() {
if (!auth.user.value || loading.value) {
return;
}
loading.value = true;
const api = useUserApi();
const { data } = await api.users.getSelfRatings();
userRatings.value = data?.ratings || [];
loading.value = false;
ready.value = true;
}
async function setRating(slug: string, rating: number | null, isFavorite: boolean | null) {
loading.value = true;
const api = useUserApi();
const userId = auth.user.value?.id || "";
await api.users.setRating(userId, slug, rating, isFavorite);
loading.value = false;
await refreshUserRatings();
}
if (!ready.value) {
refreshUserRatings();
}
return {
userRatings,
refreshUserRatings,
setRating,
ready,
};
};

View File

@@ -1,93 +0,0 @@
import { useAsyncValidator } from "~/composables/use-validators";
import type { VForm } from "~/types/auto-forms";
import { usePublicApi } from "~/composables/api/api-client";
const domAccountForm = ref<VForm | null>(null);
const username = ref("");
const fullName = ref("");
const email = ref("");
const password1 = ref("");
const password2 = ref("");
const advancedOptions = ref(false);
export const useUserRegistrationForm = () => {
const i18n = useI18n();
async function safeValidate(form: Ref<VForm | null>) {
if (!form.value) {
return false;
}
const result = await form.value.validate();
return result.valid;
}
// ================================================================
// Provide Group Details
const publicApi = usePublicApi();
// ================================================================
// Provide Account Details
const usernameErrorMessages = ref<string[]>([]);
const { validate: validateUsername, valid: validUsername } = useAsyncValidator(
username,
(v: string) => publicApi.validators.username(v),
i18n.t("validation.username-is-taken"),
usernameErrorMessages,
);
const emailErrorMessages = ref<string[]>([]);
const { validate: validateEmail, valid: validEmail } = useAsyncValidator(
email,
(v: string) => publicApi.validators.email(v),
i18n.t("validation.email-is-taken"),
emailErrorMessages,
);
const accountDetails = {
username,
fullName,
email,
advancedOptions,
validate: async () => {
if (!validUsername.value || !validEmail.value) {
await Promise.all([validateUsername(), validateEmail()]);
}
if (!validUsername.value || !validEmail.value) {
return false;
}
return await safeValidate(domAccountForm as Ref<VForm>);
},
reset: () => {
accountDetails.username.value = "";
accountDetails.fullName.value = "";
accountDetails.email.value = "";
accountDetails.advancedOptions.value = false;
},
};
// ================================================================
// Provide Credentials
const passwordMatch = () => password1.value === password2.value || i18n.t("user.password-must-match");
const credentials = {
password1,
password2,
passwordMatch,
reset: () => {
credentials.password1.value = "";
credentials.password2.value = "";
},
};
return {
accountDetails,
credentials,
emailErrorMessages,
usernameErrorMessages,
// Fields
advancedOptions,
// Validators
validateUsername,
validateEmail,
// Dom Refs
domAccountForm,
};
};