mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-25 08:09:41 +02:00
chore: frontend testing setup (#1739)
* add vitest * initialize lib w/ tests * move to dev dep * run tests in CI * update file names * move api folder to lib * move api and api types to same folder * update generator outpath * rm husky * i guess i _did_ need those types * reorg types * extract validators into testable components * (WIP) start composable testing * fix import type * fix linter complaint * simplify icon type def * fix linter errors (maybe?) * rename client file for sorting
This commit is contained in:
parent
9f6bcc83d5
commit
fcc5d99d40
182 changed files with 902 additions and 487 deletions
34
frontend/lib/api/admin/admin-about.ts
Normal file
34
frontend/lib/api/admin/admin-about.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { AdminAboutInfo, DockerVolumeText, CheckAppConfig } from "~/lib/api/types/admin";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
about: `${prefix}/admin/about`,
|
||||
aboutStatistics: `${prefix}/admin/about/statistics`,
|
||||
check: `${prefix}/admin/about/check`,
|
||||
docker: `${prefix}/admin/about/docker/validate`,
|
||||
validationFile: `${prefix}/media/docker/validate.txt`,
|
||||
};
|
||||
|
||||
export class AdminAboutAPI extends BaseAPI {
|
||||
async about() {
|
||||
return await this.requests.get<AdminAboutInfo>(routes.about);
|
||||
}
|
||||
|
||||
async statistics() {
|
||||
return await this.requests.get(routes.aboutStatistics);
|
||||
}
|
||||
|
||||
async checkApp() {
|
||||
return await this.requests.get<CheckAppConfig>(routes.check);
|
||||
}
|
||||
|
||||
async checkDocker() {
|
||||
return await this.requests.get<DockerVolumeText>(routes.docker);
|
||||
}
|
||||
|
||||
async getDockerValidateFileContents() {
|
||||
return await this.requests.get<string>(routes.validationFile);
|
||||
}
|
||||
}
|
14
frontend/lib/api/admin/admin-analytics.ts
Normal file
14
frontend/lib/api/admin/admin-analytics.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { MealieAnalytics } from "~/lib/api/types/analytics";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/admin/analytics`,
|
||||
};
|
||||
|
||||
export class AdminAnalyticsApi extends BaseAPI {
|
||||
async getAnalytics() {
|
||||
return await this.requests.get<MealieAnalytics>(routes.base);
|
||||
}
|
||||
}
|
33
frontend/lib/api/admin/admin-backups.ts
Normal file
33
frontend/lib/api/admin/admin-backups.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { AllBackups } from "~/lib/api/types/admin";
|
||||
import { ErrorResponse, FileTokenResponse, SuccessResponse } from "~/lib/api/types/response";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/admin/backups`,
|
||||
item: (name: string) => `${prefix}/admin/backups/${name}`,
|
||||
restore: (name: string) => `${prefix}/admin/backups/${name}/restore`,
|
||||
};
|
||||
|
||||
export class AdminBackupsApi extends BaseAPI {
|
||||
async getAll() {
|
||||
return await this.requests.get<AllBackups>(routes.base);
|
||||
}
|
||||
|
||||
async create() {
|
||||
return await this.requests.post<SuccessResponse | ErrorResponse>(routes.base, {});
|
||||
}
|
||||
|
||||
async get(fileName: string) {
|
||||
return await this.requests.get<FileTokenResponse>(routes.item(fileName));
|
||||
}
|
||||
|
||||
async delete(fileName: string) {
|
||||
return await this.requests.delete<SuccessResponse | ErrorResponse>(routes.item(fileName));
|
||||
}
|
||||
|
||||
async restore(fileName: string) {
|
||||
return await this.requests.post<SuccessResponse | ErrorResponse>(routes.restore(fileName), {});
|
||||
}
|
||||
}
|
19
frontend/lib/api/admin/admin-groups.ts
Normal file
19
frontend/lib/api/admin/admin-groups.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { GroupBase, GroupInDB } from "~/lib/api/types/user";
|
||||
import { GroupAdminUpdate } from "~/lib/api/types/group";
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
adminUsers: `${prefix}/admin/groups`,
|
||||
adminUsersId: (id: string) => `${prefix}/admin/groups/${id}`,
|
||||
};
|
||||
|
||||
export class AdminGroupsApi extends BaseCRUDAPI<GroupBase, GroupInDB, GroupAdminUpdate> {
|
||||
baseRoute: string = routes.adminUsers;
|
||||
itemRoute = routes.adminUsersId;
|
||||
|
||||
async updateOne(id: string, payload: GroupAdminUpdate) {
|
||||
// TODO: This should probably be a patch request, which isn't offered by the API currently
|
||||
return await this.requests.put<GroupInDB, GroupAdminUpdate>(this.itemRoute(id), payload);
|
||||
}
|
||||
}
|
45
frontend/lib/api/admin/admin-maintenance.ts
Normal file
45
frontend/lib/api/admin/admin-maintenance.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { SuccessResponse } from "~/lib/api/types/response";
|
||||
import { MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary } from "~/lib/api/types/admin";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/admin/maintenance`,
|
||||
storage: `${prefix}/admin/maintenance/storage`,
|
||||
logs: (lines: number) => `${prefix}/admin/maintenance/logs?lines=${lines}`,
|
||||
cleanTemp: `${prefix}/admin/maintenance/clean/temp`,
|
||||
cleanImages: `${prefix}/admin/maintenance/clean/images`,
|
||||
cleanRecipeFolders: `${prefix}/admin/maintenance/clean/recipe-folders`,
|
||||
cleanLogFile: `${prefix}/admin/maintenance/clean/logs`,
|
||||
};
|
||||
|
||||
export class AdminMaintenanceApi extends BaseAPI {
|
||||
async getInfo() {
|
||||
return this.requests.get<MaintenanceSummary>(routes.base);
|
||||
}
|
||||
|
||||
async getStorageDetails() {
|
||||
return await this.requests.get<MaintenanceStorageDetails>(routes.storage);
|
||||
}
|
||||
|
||||
async cleanTemp() {
|
||||
return await this.requests.post<SuccessResponse>(routes.cleanTemp, {});
|
||||
}
|
||||
|
||||
async cleanImages() {
|
||||
return await this.requests.post<SuccessResponse>(routes.cleanImages, {});
|
||||
}
|
||||
|
||||
async cleanRecipeFolders() {
|
||||
return await this.requests.post<SuccessResponse>(routes.cleanRecipeFolders, {});
|
||||
}
|
||||
|
||||
async cleanLogFile() {
|
||||
return await this.requests.post<SuccessResponse>(routes.cleanLogFile, {});
|
||||
}
|
||||
|
||||
async logs(lines: number) {
|
||||
return await this.requests.get<MaintenanceLogs>(routes.logs(lines));
|
||||
}
|
||||
}
|
18
frontend/lib/api/admin/admin-tasks.ts
Normal file
18
frontend/lib/api/admin/admin-tasks.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { ServerTask } from "~/lib/api/types/server";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/admin/server-tasks`,
|
||||
};
|
||||
|
||||
export class AdminTaskAPI extends BaseAPI {
|
||||
async testTask() {
|
||||
return await this.requests.post<ServerTask>(`${routes.base}`, {});
|
||||
}
|
||||
|
||||
async getAll() {
|
||||
return await this.requests.get<ServerTask[]>(routes.base);
|
||||
}
|
||||
}
|
19
frontend/lib/api/admin/admin-users.ts
Normal file
19
frontend/lib/api/admin/admin-users.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { UnlockResults, UserIn, UserOut } from "~/lib/api/types/user";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
adminUsers: `${prefix}/admin/users`,
|
||||
adminUsersId: (tag: string) => `${prefix}/admin/users/${tag}`,
|
||||
adminResetLockedUsers: (force: boolean) => `${prefix}/admin/users/unlock?force=${force ? "true" : "false"}`,
|
||||
};
|
||||
|
||||
export class AdminUsersApi extends BaseCRUDAPI<UserIn, UserOut, UserOut> {
|
||||
baseRoute: string = routes.adminUsers;
|
||||
itemRoute = routes.adminUsersId;
|
||||
|
||||
async unlockAllUsers(force = false) {
|
||||
return await this.requests.post<UnlockResults>(routes.adminResetLockedUsers(force), {});
|
||||
}
|
||||
}
|
53
frontend/lib/api/base/base-clients.ts
Normal file
53
frontend/lib/api/base/base-clients.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { ApiRequestInstance, PaginationData } from "~/lib/api/types/non-generated";
|
||||
|
||||
export interface CrudAPIInterface {
|
||||
requests: ApiRequestInstance;
|
||||
|
||||
// Route Properties / Methods
|
||||
baseRoute: string;
|
||||
itemRoute(itemId: string | number): string;
|
||||
|
||||
// Methods
|
||||
}
|
||||
|
||||
export abstract class BaseAPI {
|
||||
requests: ApiRequestInstance;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
this.requests = requests;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseCRUDAPI<CreateType, ReadType, UpdateType = CreateType>
|
||||
extends BaseAPI
|
||||
implements CrudAPIInterface
|
||||
{
|
||||
abstract baseRoute: string;
|
||||
abstract itemRoute(itemId: string | number): string;
|
||||
|
||||
async getAll(page = 1, perPage = -1, params = {} as any) {
|
||||
return await this.requests.get<PaginationData<ReadType>>(this.baseRoute, {
|
||||
params: { page, perPage, ...params },
|
||||
});
|
||||
}
|
||||
|
||||
async createOne(payload: CreateType) {
|
||||
return await this.requests.post<ReadType>(this.baseRoute, payload);
|
||||
}
|
||||
|
||||
async getOne(itemId: string | number) {
|
||||
return await this.requests.get<ReadType>(this.itemRoute(itemId));
|
||||
}
|
||||
|
||||
async updateOne(itemId: string | number, payload: UpdateType) {
|
||||
return await this.requests.put<ReadType, UpdateType>(this.itemRoute(itemId), payload);
|
||||
}
|
||||
|
||||
async patchOne(itemId: string, payload: Partial<UpdateType>) {
|
||||
return await this.requests.patch<ReadType, Partial<UpdateType>>(this.itemRoute(itemId), payload);
|
||||
}
|
||||
|
||||
async deleteOne(itemId: string | number) {
|
||||
return await this.requests.delete<ReadType>(this.itemRoute(itemId));
|
||||
}
|
||||
}
|
1
frontend/lib/api/base/index.ts
Normal file
1
frontend/lib/api/base/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { route } from "./route";
|
38
frontend/lib/api/base/route.ts
Normal file
38
frontend/lib/api/base/route.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
const parts = {
|
||||
host: "http://localhost.com",
|
||||
prefix: "/api",
|
||||
};
|
||||
|
||||
export function overrideParts(host: string, prefix: string) {
|
||||
parts.host = host;
|
||||
parts.prefix = prefix;
|
||||
}
|
||||
|
||||
export type QueryValue = string | string[] | number | number[] | boolean | null | undefined;
|
||||
|
||||
/**
|
||||
* route is a the main URL builder for the API. It will use a predefined host and prefix (global)
|
||||
* in the urls.ts file and then append the passed in path parameter uring the `URL` class from the
|
||||
* browser. It will also append any query parameters passed in as the second parameter.
|
||||
*
|
||||
* The default host `http://localhost.com` is removed from the path if it is present. This allows us
|
||||
* to bootstrap the API with different hosts as needed (like for testing) but still allows us to use
|
||||
* relative URLs in production because the API and client bundle are served from the same server/host.
|
||||
*/
|
||||
export function route(rest: string, params: Record<string, QueryValue> | null = null): string {
|
||||
const url = new URL(parts.prefix + rest, parts.host);
|
||||
|
||||
if (params) {
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
url.searchParams.append(key, String(item));
|
||||
}
|
||||
} else {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return url.toString().replace("http://localhost.com", "");
|
||||
}
|
24
frontend/lib/api/base/routes.test.ts
Normal file
24
frontend/lib/api/base/routes.test.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { route } from ".";
|
||||
|
||||
describe("UrlBuilder", () => {
|
||||
it("basic query parameter", () => {
|
||||
const result = route("/test", { a: "b" });
|
||||
expect(result).toBe("/api/test?a=b");
|
||||
});
|
||||
|
||||
it("multiple query parameters", () => {
|
||||
const result = route("/test", { a: "b", c: "d" });
|
||||
expect(result).toBe("/api/test?a=b&c=d");
|
||||
});
|
||||
|
||||
it("no query parameters", () => {
|
||||
const result = route("/test");
|
||||
expect(result).toBe("/api/test");
|
||||
});
|
||||
|
||||
it("list-like query parameters", () => {
|
||||
const result = route("/test", { a: ["b", "c"] });
|
||||
expect(result).toBe("/api/test?a=b&a=c");
|
||||
});
|
||||
});
|
30
frontend/lib/api/client-admin.ts
Normal file
30
frontend/lib/api/client-admin.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { AdminAboutAPI } from "./admin/admin-about";
|
||||
import { AdminTaskAPI } from "./admin/admin-tasks";
|
||||
import { AdminUsersApi } from "./admin/admin-users";
|
||||
import { AdminGroupsApi } from "./admin/admin-groups";
|
||||
import { AdminBackupsApi } from "./admin/admin-backups";
|
||||
import { AdminMaintenanceApi } from "./admin/admin-maintenance";
|
||||
import { AdminAnalyticsApi } from "./admin/admin-analytics";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
export class AdminAPI {
|
||||
public about: AdminAboutAPI;
|
||||
public serverTasks: AdminTaskAPI;
|
||||
public users: AdminUsersApi;
|
||||
public groups: AdminGroupsApi;
|
||||
public backups: AdminBackupsApi;
|
||||
public maintenance: AdminMaintenanceApi;
|
||||
public analytics: AdminAnalyticsApi;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
this.about = new AdminAboutAPI(requests);
|
||||
this.serverTasks = new AdminTaskAPI(requests);
|
||||
this.users = new AdminUsersApi(requests);
|
||||
this.groups = new AdminGroupsApi(requests);
|
||||
this.backups = new AdminBackupsApi(requests);
|
||||
this.maintenance = new AdminMaintenanceApi(requests);
|
||||
this.analytics = new AdminAnalyticsApi(requests);
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
18
frontend/lib/api/client-public.ts
Normal file
18
frontend/lib/api/client-public.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { ValidatorsApi } from "./public/validators";
|
||||
import { ExploreApi } from "./public/explore";
|
||||
import { SharedApi } from "./public/shared";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
export class PublicApi {
|
||||
public validators: ValidatorsApi;
|
||||
public explore: ExploreApi;
|
||||
public shared: SharedApi;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
this.validators = new ValidatorsApi(requests);
|
||||
this.explore = new ExploreApi(requests);
|
||||
this.shared = new SharedApi(requests);
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
99
frontend/lib/api/client-user.ts
Normal file
99
frontend/lib/api/client-user.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
import { RecipeAPI } from "./user/recipes";
|
||||
import { UserApi } from "./user/users";
|
||||
import { GroupAPI } from "./user/groups";
|
||||
import { BackupAPI } from "./user/backups";
|
||||
import { UploadFile } from "./user/upload";
|
||||
import { CategoriesAPI } from "./user/organizer-categories";
|
||||
import { TagsAPI } from "./user/organizer-tags";
|
||||
import { UtilsAPI } from "./user/utils";
|
||||
import { FoodAPI } from "./user/recipe-foods";
|
||||
import { UnitAPI } from "./user/recipe-units";
|
||||
import { CookbookAPI } from "./user/group-cookbooks";
|
||||
import { WebhooksAPI } from "./user/group-webhooks";
|
||||
import { RegisterAPI } from "./user/user-registration";
|
||||
import { MealPlanAPI } from "./user/group-mealplan";
|
||||
import { EmailAPI } from "./user/email";
|
||||
import { BulkActionsAPI } from "./user/recipe-bulk-actions";
|
||||
import { GroupServerTaskAPI } from "./user/group-tasks";
|
||||
import { ToolsApi } from "./user/organizer-tools";
|
||||
import { GroupMigrationApi } from "./user/group-migrations";
|
||||
import { GroupReportsApi } from "./user/group-reports";
|
||||
import { ShoppingApi } from "./user/group-shopping-lists";
|
||||
import { MultiPurposeLabelsApi } from "./user/group-multiple-purpose-labels";
|
||||
import { GroupEventNotifierApi } from "./user/group-event-notifier";
|
||||
import { MealPlanRulesApi } from "./user/group-mealplan-rules";
|
||||
import { GroupDataSeederApi } from "./user/group-seeder";
|
||||
import { OcrAPI } from "./user/ocr";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
export class UserApiClient {
|
||||
public recipes: RecipeAPI;
|
||||
public users: UserApi;
|
||||
public groups: GroupAPI;
|
||||
public backups: BackupAPI;
|
||||
public categories: CategoriesAPI;
|
||||
public tags: TagsAPI;
|
||||
public utils: UtilsAPI;
|
||||
public foods: FoodAPI;
|
||||
public units: UnitAPI;
|
||||
public cookbooks: CookbookAPI;
|
||||
public groupWebhooks: WebhooksAPI;
|
||||
public register: RegisterAPI;
|
||||
public mealplans: MealPlanAPI;
|
||||
public mealplanRules: MealPlanRulesApi;
|
||||
public email: EmailAPI;
|
||||
public bulk: BulkActionsAPI;
|
||||
public groupMigration: GroupMigrationApi;
|
||||
public groupReports: GroupReportsApi;
|
||||
public grouperServerTasks: GroupServerTaskAPI;
|
||||
public tools: ToolsApi;
|
||||
public shopping: ShoppingApi;
|
||||
public multiPurposeLabels: MultiPurposeLabelsApi;
|
||||
public groupEventNotifier: GroupEventNotifierApi;
|
||||
public upload: UploadFile;
|
||||
public seeders: GroupDataSeederApi;
|
||||
public ocr: OcrAPI;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
// Recipes
|
||||
this.recipes = new RecipeAPI(requests);
|
||||
this.categories = new CategoriesAPI(requests);
|
||||
this.tags = new TagsAPI(requests);
|
||||
this.units = new UnitAPI(requests);
|
||||
this.foods = new FoodAPI(requests);
|
||||
this.tools = new ToolsApi(requests);
|
||||
|
||||
// Users
|
||||
this.users = new UserApi(requests);
|
||||
this.groups = new GroupAPI(requests);
|
||||
this.cookbooks = new CookbookAPI(requests);
|
||||
this.groupWebhooks = new WebhooksAPI(requests);
|
||||
this.register = new RegisterAPI(requests);
|
||||
this.mealplans = new MealPlanAPI(requests);
|
||||
this.mealplanRules = new MealPlanRulesApi(requests);
|
||||
this.grouperServerTasks = new GroupServerTaskAPI(requests);
|
||||
|
||||
// Group
|
||||
this.groupMigration = new GroupMigrationApi(requests);
|
||||
this.groupReports = new GroupReportsApi(requests);
|
||||
this.shopping = new ShoppingApi(requests);
|
||||
this.multiPurposeLabels = new MultiPurposeLabelsApi(requests);
|
||||
this.seeders = new GroupDataSeederApi(requests);
|
||||
|
||||
// Admin
|
||||
this.backups = new BackupAPI(requests);
|
||||
|
||||
// Utils
|
||||
this.upload = new UploadFile(requests);
|
||||
this.utils = new UtilsAPI(requests);
|
||||
|
||||
this.email = new EmailAPI(requests);
|
||||
this.bulk = new BulkActionsAPI(requests);
|
||||
this.groupEventNotifier = new GroupEventNotifierApi(requests);
|
||||
|
||||
// ocr
|
||||
this.ocr = new OcrAPI(requests);
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
5
frontend/lib/api/config.ts
Normal file
5
frontend/lib/api/config.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
const PREFIX = "/api";
|
||||
|
||||
export const config = {
|
||||
PREFIX,
|
||||
};
|
3
frontend/lib/api/index.ts
Normal file
3
frontend/lib/api/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { AdminAPI } from "./client-admin";
|
||||
export { PublicApi } from "./client-public";
|
||||
export { UserApiClient as UserApi } from "./client-user";
|
14
frontend/lib/api/public/explore.ts
Normal file
14
frontend/lib/api/public/explore.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
recipe: (groupId: string, recipeSlug: string) => `${prefix}/explore/recipes/${groupId}/${recipeSlug}`,
|
||||
};
|
||||
|
||||
export class ExploreApi extends BaseAPI {
|
||||
async recipe(groupId: string, recipeSlug: string) {
|
||||
return await this.requests.get<Recipe>(routes.recipe(groupId, recipeSlug));
|
||||
}
|
||||
}
|
14
frontend/lib/api/public/shared.ts
Normal file
14
frontend/lib/api/public/shared.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
recipeShareToken: (token: string) => `${prefix}/recipes/shared/${token}`,
|
||||
};
|
||||
|
||||
export class SharedApi extends BaseAPI {
|
||||
async getShared(item_id: string) {
|
||||
return await this.requests.get<Recipe>(routes.recipeShareToken(item_id));
|
||||
}
|
||||
}
|
29
frontend/lib/api/public/validators.ts
Normal file
29
frontend/lib/api/public/validators.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { ValidationResponse } from "~/lib/api/types/response";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
group: (name: string) => `${prefix}/validators/group?name=${name}`,
|
||||
user: (name: string) => `${prefix}/validators/user/name?name=${name}`,
|
||||
email: (name: string) => `${prefix}/validators/user/email?email=${name}`,
|
||||
recipe: (groupId: string, name: string) => `${prefix}/validators/group/recipe?group_id=${groupId}?name=${name}`,
|
||||
};
|
||||
|
||||
export class ValidatorsApi extends BaseAPI {
|
||||
async group(name: string) {
|
||||
return await this.requests.get<ValidationResponse>(routes.group(name));
|
||||
}
|
||||
|
||||
async username(name: string) {
|
||||
return await this.requests.get<ValidationResponse>(routes.user(name));
|
||||
}
|
||||
|
||||
async email(email: string) {
|
||||
return await this.requests.get<ValidationResponse>(routes.email(email));
|
||||
}
|
||||
|
||||
async recipe(groupId: string, name: string) {
|
||||
return await this.requests.get<ValidationResponse>(routes.recipe(groupId, name));
|
||||
}
|
||||
}
|
278
frontend/lib/api/types/admin.ts
Normal file
278
frontend/lib/api/types/admin.ts
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface AdminAboutInfo {
|
||||
production: boolean;
|
||||
version: string;
|
||||
demoStatus: boolean;
|
||||
allowSignup: boolean;
|
||||
versionLatest: string;
|
||||
apiPort: number;
|
||||
apiDocs: boolean;
|
||||
dbType: string;
|
||||
dbUrl?: string;
|
||||
defaultGroup: string;
|
||||
buildId: string;
|
||||
recipeScraperVersion: string;
|
||||
}
|
||||
export interface AllBackups {
|
||||
imports: BackupFile[];
|
||||
templates: string[];
|
||||
}
|
||||
export interface BackupFile {
|
||||
name: string;
|
||||
date: string;
|
||||
size: string;
|
||||
}
|
||||
export interface AppInfo {
|
||||
production: boolean;
|
||||
version: string;
|
||||
demoStatus: boolean;
|
||||
allowSignup: boolean;
|
||||
}
|
||||
export interface AppStatistics {
|
||||
totalRecipes: number;
|
||||
totalUsers: number;
|
||||
totalGroups: number;
|
||||
uncategorizedRecipes: number;
|
||||
untaggedRecipes: number;
|
||||
}
|
||||
export interface BackupOptions {
|
||||
recipes?: boolean;
|
||||
settings?: boolean;
|
||||
themes?: boolean;
|
||||
groups?: boolean;
|
||||
users?: boolean;
|
||||
notifications?: boolean;
|
||||
}
|
||||
export interface CheckAppConfig {
|
||||
emailReady: boolean;
|
||||
ldapReady: boolean;
|
||||
baseUrlSet: boolean;
|
||||
isUpToDate: boolean;
|
||||
}
|
||||
export interface ChowdownURL {
|
||||
url: string;
|
||||
}
|
||||
export interface CommentImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface CreateBackup {
|
||||
tag?: string;
|
||||
options: BackupOptions;
|
||||
templates?: string[];
|
||||
}
|
||||
export interface CustomPageBase {
|
||||
name: string;
|
||||
slug?: string;
|
||||
position: number;
|
||||
categories?: RecipeCategoryResponse[];
|
||||
}
|
||||
export interface RecipeCategoryResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface CustomPageImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface CustomPageOut {
|
||||
name: string;
|
||||
slug?: string;
|
||||
position: number;
|
||||
categories?: RecipeCategoryResponse[];
|
||||
id: number;
|
||||
}
|
||||
export interface DockerVolumeText {
|
||||
text: string;
|
||||
}
|
||||
export interface EmailReady {
|
||||
ready: boolean;
|
||||
}
|
||||
export interface EmailSuccess {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
export interface EmailTest {
|
||||
email: string;
|
||||
}
|
||||
export interface GroupImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface ImportBase {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface ImportJob {
|
||||
recipes?: boolean;
|
||||
settings?: boolean;
|
||||
themes?: boolean;
|
||||
groups?: boolean;
|
||||
users?: boolean;
|
||||
notifications?: boolean;
|
||||
name: string;
|
||||
force?: boolean;
|
||||
rebase?: boolean;
|
||||
}
|
||||
export interface MaintenanceLogs {
|
||||
logs: string[];
|
||||
}
|
||||
export interface MaintenanceStorageDetails {
|
||||
tempDirSize: string;
|
||||
backupsDirSize: string;
|
||||
groupsDirSize: string;
|
||||
recipesDirSize: string;
|
||||
userDirSize: string;
|
||||
}
|
||||
export interface MaintenanceSummary {
|
||||
dataDirSize: string;
|
||||
logFileSize: string;
|
||||
cleanableImages: number;
|
||||
cleanableDirs: number;
|
||||
}
|
||||
export interface MigrationFile {
|
||||
name: string;
|
||||
date: string;
|
||||
}
|
||||
export interface MigrationImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
slug?: string;
|
||||
}
|
||||
export interface Migrations {
|
||||
type: string;
|
||||
files?: MigrationFile[];
|
||||
}
|
||||
export interface NotificationImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface RecipeImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
slug?: string;
|
||||
}
|
||||
export interface SettingsImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface UserImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string;
|
||||
}
|
20
frontend/lib/api/types/analytics.ts
Normal file
20
frontend/lib/api/types/analytics.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface MealieAnalytics {
|
||||
installationId: string;
|
||||
version: string;
|
||||
databaseType: string;
|
||||
usingEmail: boolean;
|
||||
usingLdap: boolean;
|
||||
apiTokens: number;
|
||||
users: number;
|
||||
groups: number;
|
||||
recipes: number;
|
||||
shoppingLists: number;
|
||||
cookbooks: number;
|
||||
}
|
189
frontend/lib/api/types/cookbook.ts
Normal file
189
frontend/lib/api/types/cookbook.ts
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface CreateCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
categories?: CategoryBase[];
|
||||
tags?: TagBase[];
|
||||
tools?: RecipeTool[];
|
||||
requireAllCategories?: boolean;
|
||||
requireAllTags?: boolean;
|
||||
requireAllTools?: boolean;
|
||||
}
|
||||
export interface CategoryBase {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface TagBase {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface ReadCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
categories?: CategoryBase[];
|
||||
tags?: TagBase[];
|
||||
tools?: RecipeTool[];
|
||||
requireAllCategories?: boolean;
|
||||
requireAllTags?: boolean;
|
||||
requireAllTools?: boolean;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface RecipeCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
categories?: CategoryBase[];
|
||||
tags?: TagBase[];
|
||||
tools?: RecipeTool[];
|
||||
requireAllCategories?: boolean;
|
||||
requireAllTags?: boolean;
|
||||
requireAllTools?: boolean;
|
||||
groupId: string;
|
||||
id: string;
|
||||
recipes: RecipeSummary[];
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface SaveCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
categories?: CategoryBase[];
|
||||
tags?: TagBase[];
|
||||
tools?: RecipeTool[];
|
||||
requireAllCategories?: boolean;
|
||||
requireAllTags?: boolean;
|
||||
requireAllTools?: boolean;
|
||||
groupId: string;
|
||||
}
|
||||
export interface UpdateCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
categories?: CategoryBase[];
|
||||
tags?: TagBase[];
|
||||
tools?: RecipeTool[];
|
||||
requireAllCategories?: boolean;
|
||||
requireAllTags?: boolean;
|
||||
requireAllTools?: boolean;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
24
frontend/lib/api/types/events.ts
Normal file
24
frontend/lib/api/types/events.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type EventCategory = "general" | "recipe" | "backup" | "scheduled" | "migration" | "group" | "user";
|
||||
|
||||
export interface Event {
|
||||
id?: number;
|
||||
title: string;
|
||||
text: string;
|
||||
timeStamp?: string;
|
||||
category?: EventCategory & string;
|
||||
}
|
||||
export interface EventsOut {
|
||||
total: number;
|
||||
events: Event[];
|
||||
}
|
||||
export interface TestEvent {
|
||||
id?: number;
|
||||
testUrl?: string;
|
||||
}
|
473
frontend/lib/api/types/group.ts
Normal file
473
frontend/lib/api/types/group.ts
Normal file
|
@ -0,0 +1,473 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type WebhookType = "mealplan";
|
||||
export type SupportedMigrations = "nextcloud" | "chowdown" | "paprika" | "mealie_alpha";
|
||||
|
||||
export interface CreateGroupPreferences {
|
||||
privateGroup?: boolean;
|
||||
firstDayOfWeek?: number;
|
||||
recipePublic?: boolean;
|
||||
recipeShowNutrition?: boolean;
|
||||
recipeShowAssets?: boolean;
|
||||
recipeLandscapeView?: boolean;
|
||||
recipeDisableComments?: boolean;
|
||||
recipeDisableAmount?: boolean;
|
||||
groupId: string;
|
||||
}
|
||||
export interface CreateInviteToken {
|
||||
uses: number;
|
||||
}
|
||||
export interface CreateWebhook {
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
url?: string;
|
||||
webhookType?: WebhookType & string;
|
||||
scheduledTime: string;
|
||||
}
|
||||
export interface DataMigrationCreate {
|
||||
sourceType: SupportedMigrations;
|
||||
}
|
||||
export interface EmailInitationResponse {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
export interface EmailInvitation {
|
||||
email: string;
|
||||
token: string;
|
||||
}
|
||||
export interface GroupAdminUpdate {
|
||||
id: string;
|
||||
name: string;
|
||||
preferences?: UpdateGroupPreferences;
|
||||
}
|
||||
export interface UpdateGroupPreferences {
|
||||
privateGroup?: boolean;
|
||||
firstDayOfWeek?: number;
|
||||
recipePublic?: boolean;
|
||||
recipeShowNutrition?: boolean;
|
||||
recipeShowAssets?: boolean;
|
||||
recipeLandscapeView?: boolean;
|
||||
recipeDisableComments?: boolean;
|
||||
recipeDisableAmount?: boolean;
|
||||
}
|
||||
export interface GroupDataExport {
|
||||
id: string;
|
||||
groupId: string;
|
||||
name: string;
|
||||
filename: string;
|
||||
path: string;
|
||||
size: string;
|
||||
expires: string;
|
||||
}
|
||||
export interface GroupEventNotifierCreate {
|
||||
name: string;
|
||||
appriseUrl: string;
|
||||
}
|
||||
/**
|
||||
* These events are in-sync with the EventTypes found in the EventBusService.
|
||||
* If you modify this, make sure to update the EventBusService as well.
|
||||
*/
|
||||
export interface GroupEventNotifierOptions {
|
||||
testMessage?: boolean;
|
||||
webhookTask?: boolean;
|
||||
recipeCreated?: boolean;
|
||||
recipeUpdated?: boolean;
|
||||
recipeDeleted?: boolean;
|
||||
userSignup?: boolean;
|
||||
dataMigrations?: boolean;
|
||||
dataExport?: boolean;
|
||||
dataImport?: boolean;
|
||||
mealplanEntryCreated?: boolean;
|
||||
shoppingListCreated?: boolean;
|
||||
shoppingListUpdated?: boolean;
|
||||
shoppingListDeleted?: boolean;
|
||||
cookbookCreated?: boolean;
|
||||
cookbookUpdated?: boolean;
|
||||
cookbookDeleted?: boolean;
|
||||
tagCreated?: boolean;
|
||||
tagUpdated?: boolean;
|
||||
tagDeleted?: boolean;
|
||||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
}
|
||||
/**
|
||||
* These events are in-sync with the EventTypes found in the EventBusService.
|
||||
* If you modify this, make sure to update the EventBusService as well.
|
||||
*/
|
||||
export interface GroupEventNotifierOptionsOut {
|
||||
testMessage?: boolean;
|
||||
webhookTask?: boolean;
|
||||
recipeCreated?: boolean;
|
||||
recipeUpdated?: boolean;
|
||||
recipeDeleted?: boolean;
|
||||
userSignup?: boolean;
|
||||
dataMigrations?: boolean;
|
||||
dataExport?: boolean;
|
||||
dataImport?: boolean;
|
||||
mealplanEntryCreated?: boolean;
|
||||
shoppingListCreated?: boolean;
|
||||
shoppingListUpdated?: boolean;
|
||||
shoppingListDeleted?: boolean;
|
||||
cookbookCreated?: boolean;
|
||||
cookbookUpdated?: boolean;
|
||||
cookbookDeleted?: boolean;
|
||||
tagCreated?: boolean;
|
||||
tagUpdated?: boolean;
|
||||
tagDeleted?: boolean;
|
||||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
id: string;
|
||||
}
|
||||
/**
|
||||
* These events are in-sync with the EventTypes found in the EventBusService.
|
||||
* If you modify this, make sure to update the EventBusService as well.
|
||||
*/
|
||||
export interface GroupEventNotifierOptionsSave {
|
||||
testMessage?: boolean;
|
||||
webhookTask?: boolean;
|
||||
recipeCreated?: boolean;
|
||||
recipeUpdated?: boolean;
|
||||
recipeDeleted?: boolean;
|
||||
userSignup?: boolean;
|
||||
dataMigrations?: boolean;
|
||||
dataExport?: boolean;
|
||||
dataImport?: boolean;
|
||||
mealplanEntryCreated?: boolean;
|
||||
shoppingListCreated?: boolean;
|
||||
shoppingListUpdated?: boolean;
|
||||
shoppingListDeleted?: boolean;
|
||||
cookbookCreated?: boolean;
|
||||
cookbookUpdated?: boolean;
|
||||
cookbookDeleted?: boolean;
|
||||
tagCreated?: boolean;
|
||||
tagUpdated?: boolean;
|
||||
tagDeleted?: boolean;
|
||||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
notifierId: string;
|
||||
}
|
||||
export interface GroupEventNotifierOut {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
groupId: string;
|
||||
options: GroupEventNotifierOptionsOut;
|
||||
}
|
||||
export interface GroupEventNotifierPrivate {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
groupId: string;
|
||||
options: GroupEventNotifierOptionsOut;
|
||||
appriseUrl: string;
|
||||
}
|
||||
export interface GroupEventNotifierSave {
|
||||
name: string;
|
||||
appriseUrl: string;
|
||||
enabled?: boolean;
|
||||
groupId: string;
|
||||
options?: GroupEventNotifierOptions;
|
||||
}
|
||||
export interface GroupEventNotifierUpdate {
|
||||
name: string;
|
||||
appriseUrl?: string;
|
||||
enabled?: boolean;
|
||||
groupId: string;
|
||||
options?: GroupEventNotifierOptions;
|
||||
id: string;
|
||||
}
|
||||
export interface GroupStatistics {
|
||||
totalRecipes: number;
|
||||
totalUsers: number;
|
||||
totalCategories: number;
|
||||
totalTags: number;
|
||||
totalTools: number;
|
||||
}
|
||||
export interface GroupStorage {
|
||||
usedStorageBytes: number;
|
||||
usedStorageStr: string;
|
||||
totalStorageBytes: number;
|
||||
totalStorageStr: string;
|
||||
}
|
||||
export interface ReadGroupPreferences {
|
||||
privateGroup?: boolean;
|
||||
firstDayOfWeek?: number;
|
||||
recipePublic?: boolean;
|
||||
recipeShowNutrition?: boolean;
|
||||
recipeShowAssets?: boolean;
|
||||
recipeLandscapeView?: boolean;
|
||||
recipeDisableComments?: boolean;
|
||||
recipeDisableAmount?: boolean;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface ReadInviteToken {
|
||||
token: string;
|
||||
usesLeft: number;
|
||||
groupId: string;
|
||||
}
|
||||
export interface ReadWebhook {
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
url?: string;
|
||||
webhookType?: WebhookType & string;
|
||||
scheduledTime: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface SaveInviteToken {
|
||||
usesLeft: number;
|
||||
groupId: string;
|
||||
token: string;
|
||||
}
|
||||
export interface SaveWebhook {
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
url?: string;
|
||||
webhookType?: WebhookType & string;
|
||||
scheduledTime: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface SeederConfig {
|
||||
locale: string;
|
||||
}
|
||||
export interface SetPermissions {
|
||||
userId: string;
|
||||
canManage?: boolean;
|
||||
canInvite?: boolean;
|
||||
canOrganize?: boolean;
|
||||
}
|
||||
export interface ShoppingListCreate {
|
||||
name?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface ShoppingListItemCreate {
|
||||
shoppingListId: string;
|
||||
checked?: boolean;
|
||||
position?: number;
|
||||
isFood?: boolean;
|
||||
note?: string;
|
||||
quantity?: number;
|
||||
unitId?: string;
|
||||
unit?: IngredientUnit;
|
||||
foodId?: string;
|
||||
food?: IngredientFood;
|
||||
labelId?: string;
|
||||
recipeReferences?: ShoppingListItemRecipeRef[];
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface ShoppingListItemRecipeRef {
|
||||
recipeId: string;
|
||||
recipeQuantity?: number;
|
||||
}
|
||||
export interface ShoppingListItemOut {
|
||||
shoppingListId: string;
|
||||
checked?: boolean;
|
||||
position?: number;
|
||||
isFood?: boolean;
|
||||
note?: string;
|
||||
quantity?: number;
|
||||
unitId?: string;
|
||||
unit?: IngredientUnit;
|
||||
foodId?: string;
|
||||
food?: IngredientFood;
|
||||
labelId?: string;
|
||||
recipeReferences?: (ShoppingListItemRecipeRef | ShoppingListItemRecipeRefOut)[];
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
}
|
||||
export interface ShoppingListItemRecipeRefOut {
|
||||
recipeId: string;
|
||||
recipeQuantity?: number;
|
||||
id: string;
|
||||
shoppingListItemId: string;
|
||||
}
|
||||
export interface ShoppingListItemUpdate {
|
||||
shoppingListId: string;
|
||||
checked?: boolean;
|
||||
position?: number;
|
||||
isFood?: boolean;
|
||||
note?: string;
|
||||
quantity?: number;
|
||||
unitId?: string;
|
||||
unit?: IngredientUnit;
|
||||
foodId?: string;
|
||||
food?: IngredientFood;
|
||||
labelId?: string;
|
||||
recipeReferences?: ShoppingListItemRecipeRef[];
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
id: string;
|
||||
}
|
||||
export interface ShoppingListOut {
|
||||
name?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
listItems?: ShoppingListItemOut[];
|
||||
recipeReferences: ShoppingListRecipeRefOut[];
|
||||
}
|
||||
export interface ShoppingListRecipeRefOut {
|
||||
id: string;
|
||||
shoppingListId: string;
|
||||
recipeId: string;
|
||||
recipeQuantity: number;
|
||||
recipe: RecipeSummary;
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface ShoppingListSave {
|
||||
name?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface ShoppingListSummary {
|
||||
name?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface ShoppingListUpdate {
|
||||
name?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
listItems?: ShoppingListItemOut[];
|
||||
}
|
34
frontend/lib/api/types/labels.ts
Normal file
34
frontend/lib/api/types/labels.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface MultiPurposeLabelCreate {
|
||||
name: string;
|
||||
color?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelOut {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSave {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface MultiPurposeLabelUpdate {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
224
frontend/lib/api/types/meal-plan.ts
Normal file
224
frontend/lib/api/types/meal-plan.ts
Normal file
|
@ -0,0 +1,224 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type PlanEntryType = "breakfast" | "lunch" | "dinner" | "side";
|
||||
export type PlanRulesDay = "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday" | "unset";
|
||||
export type PlanRulesType = "breakfast" | "lunch" | "dinner" | "side" | "unset";
|
||||
|
||||
export interface Category {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface CreatePlanEntry {
|
||||
date: string;
|
||||
entryType?: PlanEntryType & string;
|
||||
title?: string;
|
||||
text?: string;
|
||||
recipeId?: string;
|
||||
}
|
||||
export interface CreateRandomEntry {
|
||||
date: string;
|
||||
entryType?: PlanEntryType & string;
|
||||
}
|
||||
export interface ListItem {
|
||||
title?: string;
|
||||
text?: string;
|
||||
quantity?: number;
|
||||
checked?: boolean;
|
||||
}
|
||||
export interface MealDayIn {
|
||||
date?: string;
|
||||
meals: MealIn[];
|
||||
}
|
||||
export interface MealIn {
|
||||
slug?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
export interface MealDayOut {
|
||||
date?: string;
|
||||
meals: MealIn[];
|
||||
id: number;
|
||||
}
|
||||
export interface MealPlanIn {
|
||||
group: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
planDays: MealDayIn[];
|
||||
}
|
||||
export interface MealPlanOut {
|
||||
group: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
planDays: MealDayIn[];
|
||||
id: number;
|
||||
shoppingList?: number;
|
||||
}
|
||||
export interface PlanRulesCreate {
|
||||
day?: PlanRulesDay & string;
|
||||
entryType?: PlanRulesType & string;
|
||||
categories?: Category[];
|
||||
tags?: Tag[];
|
||||
}
|
||||
export interface Tag {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface PlanRulesOut {
|
||||
day?: PlanRulesDay & string;
|
||||
entryType?: PlanRulesType & string;
|
||||
categories?: Category[];
|
||||
tags?: Tag[];
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface PlanRulesSave {
|
||||
day?: PlanRulesDay & string;
|
||||
entryType?: PlanRulesType & string;
|
||||
categories?: Category[];
|
||||
tags?: Tag[];
|
||||
groupId: string;
|
||||
}
|
||||
export interface ReadPlanEntry {
|
||||
date: string;
|
||||
entryType?: PlanEntryType & string;
|
||||
title?: string;
|
||||
text?: string;
|
||||
recipeId?: string;
|
||||
id: number;
|
||||
groupId: string;
|
||||
recipe?: RecipeSummary;
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface SavePlanEntry {
|
||||
date: string;
|
||||
entryType?: PlanEntryType & string;
|
||||
title?: string;
|
||||
text?: string;
|
||||
recipeId?: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface ShoppingListIn {
|
||||
name: string;
|
||||
group?: string;
|
||||
items: ListItem[];
|
||||
}
|
||||
export interface ShoppingListOut {
|
||||
name: string;
|
||||
group?: string;
|
||||
items: ListItem[];
|
||||
id: number;
|
||||
}
|
||||
export interface UpdatePlanEntry {
|
||||
date: string;
|
||||
entryType?: PlanEntryType & string;
|
||||
title?: string;
|
||||
text?: string;
|
||||
recipeId?: string;
|
||||
id: number;
|
||||
groupId: string;
|
||||
}
|
33
frontend/lib/api/types/non-generated.ts
Normal file
33
frontend/lib/api/types/non-generated.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { AxiosResponse } from "axios";
|
||||
|
||||
export type NoUndefinedField<T> = { [P in keyof T]-?: NoUndefinedField<NonNullable<T[P]>> };
|
||||
|
||||
export interface RequestResponse<T> {
|
||||
response: AxiosResponse<T> | null;
|
||||
data: T | null;
|
||||
error: any;
|
||||
}
|
||||
|
||||
export interface ApiRequestInstance {
|
||||
get<T>(url: string, data?: unknown): Promise<RequestResponse<T>>;
|
||||
post<T>(url: string, data: unknown): Promise<RequestResponse<T>>;
|
||||
put<T, U = T>(url: string, data: U): Promise<RequestResponse<T>>;
|
||||
patch<T, U = Partial<T>>(url: string, data: U): Promise<RequestResponse<T>>;
|
||||
delete<T>(url: string): Promise<RequestResponse<T>>;
|
||||
}
|
||||
|
||||
export interface PaginationData<T> {
|
||||
page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
total_pages: number;
|
||||
items: T[];
|
||||
}
|
||||
|
||||
export type RecipeOrganizer = "categories" | "tags" | "tools";
|
||||
|
||||
export enum Organizer {
|
||||
Category = "categories",
|
||||
Tag = "tags",
|
||||
Tool = "tools",
|
||||
}
|
25
frontend/lib/api/types/ocr.ts
Normal file
25
frontend/lib/api/types/ocr.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface OcrAssetReq {
|
||||
recipeSlug: string;
|
||||
assetName: string;
|
||||
}
|
||||
export interface OcrTsvResponse {
|
||||
level?: number;
|
||||
pageNum?: number;
|
||||
blockNum?: number;
|
||||
parNum?: number;
|
||||
lineNum?: number;
|
||||
wordNum?: number;
|
||||
left?: number;
|
||||
top?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
conf?: number;
|
||||
text?: string;
|
||||
}
|
425
frontend/lib/api/types/recipe.ts
Normal file
425
frontend/lib/api/types/recipe.ts
Normal file
|
@ -0,0 +1,425 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type ExportTypes = "json";
|
||||
export type RegisteredParser = "nlp" | "brute";
|
||||
export type OrderDirection = "asc" | "desc";
|
||||
|
||||
export interface AssignCategories {
|
||||
recipes: string[];
|
||||
categories: CategoryBase[];
|
||||
}
|
||||
export interface CategoryBase {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface AssignSettings {
|
||||
recipes: string[];
|
||||
settings: RecipeSettings;
|
||||
}
|
||||
export interface RecipeSettings {
|
||||
public?: boolean;
|
||||
showNutrition?: boolean;
|
||||
showAssets?: boolean;
|
||||
landscapeView?: boolean;
|
||||
disableComments?: boolean;
|
||||
disableAmount?: boolean;
|
||||
locked?: boolean;
|
||||
}
|
||||
export interface AssignTags {
|
||||
recipes: string[];
|
||||
tags: TagBase[];
|
||||
}
|
||||
export interface TagBase {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface CategoryIn {
|
||||
name: string;
|
||||
}
|
||||
export interface CategoryOut {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface CategorySave {
|
||||
name: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface CreateRecipe {
|
||||
name: string;
|
||||
}
|
||||
export interface CreateRecipeBulk {
|
||||
url: string;
|
||||
categories?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface CreateRecipeByUrlBulk {
|
||||
imports: CreateRecipeBulk[];
|
||||
}
|
||||
export interface DeleteRecipes {
|
||||
recipes: string[];
|
||||
}
|
||||
export interface ExportBase {
|
||||
recipes: string[];
|
||||
}
|
||||
export interface ExportRecipes {
|
||||
recipes: string[];
|
||||
exportType?: ExportTypes & string;
|
||||
}
|
||||
export interface IngredientConfidence {
|
||||
average?: number;
|
||||
comment?: number;
|
||||
name?: number;
|
||||
unit?: number;
|
||||
quantity?: number;
|
||||
food?: number;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
/**
|
||||
* A list of ingredient references.
|
||||
*/
|
||||
export interface IngredientReferences {
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface IngredientRequest {
|
||||
parser?: RegisteredParser & string;
|
||||
ingredient: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface IngredientsRequest {
|
||||
parser?: RegisteredParser & string;
|
||||
ingredients: string[];
|
||||
}
|
||||
export interface MergeFood {
|
||||
fromFood: string;
|
||||
toFood: string;
|
||||
}
|
||||
export interface MergeUnit {
|
||||
fromUnit: string;
|
||||
toUnit: string;
|
||||
}
|
||||
export interface Nutrition {
|
||||
calories?: string;
|
||||
fatContent?: string;
|
||||
proteinContent?: string;
|
||||
carbohydrateContent?: string;
|
||||
fiberContent?: string;
|
||||
sodiumContent?: string;
|
||||
sugarContent?: string;
|
||||
}
|
||||
export interface ParsedIngredient {
|
||||
input?: string;
|
||||
confidence?: IngredientConfidence;
|
||||
ingredient: RecipeIngredient;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface Recipe {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
recipeInstructions?: RecipeStep[];
|
||||
nutrition?: Nutrition;
|
||||
settings?: RecipeSettings;
|
||||
assets?: RecipeAsset[];
|
||||
notes?: RecipeNote[];
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
isOcrRecipe?: boolean;
|
||||
comments?: RecipeCommentOut[];
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeStep {
|
||||
id?: string;
|
||||
title?: string;
|
||||
text: string;
|
||||
ingredientReferences?: IngredientReferences[];
|
||||
}
|
||||
export interface RecipeAsset {
|
||||
name: string;
|
||||
icon: string;
|
||||
fileName?: string;
|
||||
}
|
||||
export interface RecipeNote {
|
||||
title: string;
|
||||
text: string;
|
||||
}
|
||||
export interface RecipeCommentOut {
|
||||
recipeId: string;
|
||||
text: string;
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updateAt: string;
|
||||
userId: string;
|
||||
user: UserBase;
|
||||
}
|
||||
export interface UserBase {
|
||||
id: string;
|
||||
username?: string;
|
||||
admin: boolean;
|
||||
}
|
||||
export interface RecipeCategoryResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCommentCreate {
|
||||
recipeId: string;
|
||||
text: string;
|
||||
}
|
||||
export interface RecipeCommentSave {
|
||||
recipeId: string;
|
||||
text: string;
|
||||
userId: string;
|
||||
}
|
||||
export interface RecipeCommentUpdate {
|
||||
id: string;
|
||||
text: string;
|
||||
}
|
||||
export interface RecipePaginationQuery {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: string;
|
||||
orderDirection?: OrderDirection & string;
|
||||
queryFilter?: string;
|
||||
loadFood?: boolean;
|
||||
}
|
||||
export interface RecipeShareToken {
|
||||
recipeId: string;
|
||||
expiresAt?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
createdAt: string;
|
||||
recipe: Recipe;
|
||||
}
|
||||
export interface RecipeShareTokenCreate {
|
||||
recipeId: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
export interface RecipeShareTokenSave {
|
||||
recipeId: string;
|
||||
expiresAt?: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface RecipeShareTokenSummary {
|
||||
recipeId: string;
|
||||
expiresAt?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface RecipeSlug {
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTagResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
export interface RecipeToolCreate {
|
||||
name: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeToolOut {
|
||||
name: string;
|
||||
onHand?: boolean;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeToolResponse {
|
||||
name: string;
|
||||
onHand?: boolean;
|
||||
id: string;
|
||||
slug: string;
|
||||
recipes?: Recipe[];
|
||||
}
|
||||
export interface RecipeToolSave {
|
||||
name: string;
|
||||
onHand?: boolean;
|
||||
groupId: string;
|
||||
}
|
||||
export interface RecipeZipTokenResponse {
|
||||
token: string;
|
||||
}
|
||||
export interface SaveIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface SaveIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
groupId: string;
|
||||
}
|
||||
export interface ScrapeRecipe {
|
||||
url: string;
|
||||
includeTags?: boolean;
|
||||
}
|
||||
export interface ScrapeRecipeTest {
|
||||
url: string;
|
||||
}
|
||||
export interface SlugResponse {}
|
||||
export interface TagIn {
|
||||
name: string;
|
||||
}
|
||||
export interface TagOut {
|
||||
name: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface TagSave {
|
||||
name: string;
|
||||
groupId: string;
|
||||
}
|
||||
export interface UnitFoodBase {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
}
|
||||
export interface UpdateImageResponse {
|
||||
image: string;
|
||||
}
|
||||
export interface PaginationQuery {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: string;
|
||||
orderDirection?: OrderDirection & string;
|
||||
queryFilter?: string;
|
||||
}
|
49
frontend/lib/api/types/reports.ts
Normal file
49
frontend/lib/api/types/reports.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type ReportCategory = "backup" | "restore" | "migration" | "bulk_import";
|
||||
export type ReportSummaryStatus = "in-progress" | "success" | "failure" | "partial";
|
||||
|
||||
export interface ReportCreate {
|
||||
timestamp?: string;
|
||||
category: ReportCategory;
|
||||
groupId: string;
|
||||
name: string;
|
||||
status?: ReportSummaryStatus & string;
|
||||
}
|
||||
export interface ReportEntryCreate {
|
||||
reportId: string;
|
||||
timestamp?: string;
|
||||
success?: boolean;
|
||||
message: string;
|
||||
exception?: string;
|
||||
}
|
||||
export interface ReportEntryOut {
|
||||
reportId: string;
|
||||
timestamp?: string;
|
||||
success?: boolean;
|
||||
message: string;
|
||||
exception?: string;
|
||||
id: string;
|
||||
}
|
||||
export interface ReportOut {
|
||||
timestamp?: string;
|
||||
category: ReportCategory;
|
||||
groupId: string;
|
||||
name: string;
|
||||
status?: ReportSummaryStatus & string;
|
||||
id: string;
|
||||
entries?: ReportEntryOut[];
|
||||
}
|
||||
export interface ReportSummary {
|
||||
timestamp?: string;
|
||||
category: ReportCategory;
|
||||
groupId: string;
|
||||
name: string;
|
||||
status?: ReportSummaryStatus & string;
|
||||
id: string;
|
||||
}
|
31
frontend/lib/api/types/response.ts
Normal file
31
frontend/lib/api/types/response.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type OrderDirection = "asc" | "desc";
|
||||
|
||||
export interface ErrorResponse {
|
||||
message: string;
|
||||
error?: boolean;
|
||||
exception?: string;
|
||||
}
|
||||
export interface FileTokenResponse {
|
||||
fileToken: string;
|
||||
}
|
||||
export interface PaginationQuery {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: string;
|
||||
orderDirection?: OrderDirection & string;
|
||||
queryFilter?: string;
|
||||
}
|
||||
export interface SuccessResponse {
|
||||
message: string;
|
||||
error?: boolean;
|
||||
}
|
||||
export interface ValidationResponse {
|
||||
valid: boolean;
|
||||
}
|
25
frontend/lib/api/types/server.ts
Normal file
25
frontend/lib/api/types/server.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export type ServerTaskNames = "Background Task" | "Database Backup" | "Bulk Recipe Import";
|
||||
export type ServerTaskStatus = "running" | "finished" | "failed";
|
||||
|
||||
export interface ServerTask {
|
||||
groupId: string;
|
||||
name?: ServerTaskNames & string;
|
||||
createdAt?: string;
|
||||
status?: ServerTaskStatus & string;
|
||||
log?: string;
|
||||
id: number;
|
||||
}
|
||||
export interface ServerTaskCreate {
|
||||
groupId: string;
|
||||
name?: ServerTaskNames & string;
|
||||
createdAt?: string;
|
||||
status?: ServerTaskStatus & string;
|
||||
log?: string;
|
||||
}
|
8
frontend/lib/api/types/static.ts
Normal file
8
frontend/lib/api/types/static.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface _Master_ {}
|
286
frontend/lib/api/types/user.ts
Normal file
286
frontend/lib/api/types/user.ts
Normal file
|
@ -0,0 +1,286 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
export interface ChangePassword {
|
||||
currentPassword: string;
|
||||
newPassword: string;
|
||||
}
|
||||
export interface CreateToken {
|
||||
name: string;
|
||||
integrationId?: string;
|
||||
userId: string;
|
||||
token: string;
|
||||
}
|
||||
export interface CreateUserRegistration {
|
||||
group?: string;
|
||||
groupToken?: string;
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
passwordConfirm: string;
|
||||
advanced?: boolean;
|
||||
private?: boolean;
|
||||
seedData?: boolean;
|
||||
locale?: string;
|
||||
}
|
||||
export interface DeleteTokenResponse {
|
||||
tokenDelete: string;
|
||||
}
|
||||
export interface ForgotPassword {
|
||||
email: string;
|
||||
}
|
||||
export interface GroupBase {
|
||||
name: string;
|
||||
}
|
||||
export interface GroupInDB {
|
||||
name: string;
|
||||
id: string;
|
||||
categories?: CategoryBase[];
|
||||
webhooks?: unknown[];
|
||||
users?: UserOut[];
|
||||
preferences?: ReadGroupPreferences;
|
||||
}
|
||||
export interface CategoryBase {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface UserOut {
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
email: string;
|
||||
admin?: boolean;
|
||||
group: string;
|
||||
advanced?: boolean;
|
||||
favoriteRecipes?: string[];
|
||||
canInvite?: boolean;
|
||||
canManage?: boolean;
|
||||
canOrganize?: boolean;
|
||||
id: string;
|
||||
groupId: string;
|
||||
tokens?: LongLiveTokenOut[];
|
||||
cacheKey: string;
|
||||
}
|
||||
export interface LongLiveTokenOut {
|
||||
token: string;
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
export interface ReadGroupPreferences {
|
||||
privateGroup?: boolean;
|
||||
firstDayOfWeek?: number;
|
||||
recipePublic?: boolean;
|
||||
recipeShowNutrition?: boolean;
|
||||
recipeShowAssets?: boolean;
|
||||
recipeLandscapeView?: boolean;
|
||||
recipeDisableComments?: boolean;
|
||||
recipeDisableAmount?: boolean;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface LongLiveTokenIn {
|
||||
name: string;
|
||||
integrationId?: string;
|
||||
}
|
||||
export interface LongLiveTokenInDB {
|
||||
name: string;
|
||||
integrationId?: string;
|
||||
userId: string;
|
||||
token: string;
|
||||
id: number;
|
||||
user: PrivateUser;
|
||||
}
|
||||
export interface PrivateUser {
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
email: string;
|
||||
admin?: boolean;
|
||||
group: string;
|
||||
advanced?: boolean;
|
||||
favoriteRecipes?: string[];
|
||||
canInvite?: boolean;
|
||||
canManage?: boolean;
|
||||
canOrganize?: boolean;
|
||||
id: string;
|
||||
groupId: string;
|
||||
tokens?: LongLiveTokenOut[];
|
||||
cacheKey: string;
|
||||
password: string;
|
||||
loginAttemps?: number;
|
||||
lockedAt?: string;
|
||||
}
|
||||
export interface PrivatePasswordResetToken {
|
||||
userId: string;
|
||||
token: string;
|
||||
user: PrivateUser;
|
||||
}
|
||||
export interface ResetPassword {
|
||||
token: string;
|
||||
email: string;
|
||||
password: string;
|
||||
passwordConfirm: string;
|
||||
}
|
||||
export interface SavePasswordResetToken {
|
||||
userId: string;
|
||||
token: string;
|
||||
}
|
||||
export interface Token {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
}
|
||||
export interface TokenData {
|
||||
user_id?: string;
|
||||
username?: string;
|
||||
}
|
||||
export interface UnlockResults {
|
||||
unlocked?: number;
|
||||
}
|
||||
export interface UpdateGroup {
|
||||
name: string;
|
||||
id: string;
|
||||
categories?: CategoryBase[];
|
||||
webhooks?: unknown[];
|
||||
}
|
||||
export interface UserBase {
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
email: string;
|
||||
admin?: boolean;
|
||||
group?: string;
|
||||
advanced?: boolean;
|
||||
favoriteRecipes?: string[];
|
||||
canInvite?: boolean;
|
||||
canManage?: boolean;
|
||||
canOrganize?: boolean;
|
||||
}
|
||||
export interface UserFavorites {
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
email: string;
|
||||
admin?: boolean;
|
||||
group?: string;
|
||||
advanced?: boolean;
|
||||
favoriteRecipes?: RecipeSummary[];
|
||||
canInvite?: boolean;
|
||||
canManage?: boolean;
|
||||
canOrganize?: boolean;
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
groupId?: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeYield?: string;
|
||||
totalTime?: string;
|
||||
prepTime?: string;
|
||||
cookTime?: string;
|
||||
performTime?: string;
|
||||
description?: string;
|
||||
recipeCategory?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
tools?: RecipeTool[];
|
||||
rating?: number;
|
||||
orgURL?: string;
|
||||
recipeIngredient?: RecipeIngredient[];
|
||||
dateAdded?: string;
|
||||
dateUpdated?: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
onHand?: boolean;
|
||||
}
|
||||
export interface RecipeIngredient {
|
||||
title?: string;
|
||||
note?: string;
|
||||
unit?: IngredientUnit | CreateIngredientUnit;
|
||||
food?: IngredientFood | CreateIngredientFood;
|
||||
disableAmount?: boolean;
|
||||
quantity?: number;
|
||||
originalText?: string;
|
||||
referenceId?: string;
|
||||
}
|
||||
export interface IngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
id: string;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
fraction?: boolean;
|
||||
abbreviation?: string;
|
||||
useAbbreviation?: boolean;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
id: string;
|
||||
label?: MultiPurposeLabelSummary;
|
||||
createdAt?: string;
|
||||
updateAt?: string;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
color?: string;
|
||||
groupId: string;
|
||||
id: string;
|
||||
}
|
||||
export interface CreateIngredientFood {
|
||||
name: string;
|
||||
description?: string;
|
||||
extras?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labelId?: string;
|
||||
}
|
||||
export interface UserIn {
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
email: string;
|
||||
admin?: boolean;
|
||||
group?: string;
|
||||
advanced?: boolean;
|
||||
favoriteRecipes?: string[];
|
||||
canInvite?: boolean;
|
||||
canManage?: boolean;
|
||||
canOrganize?: boolean;
|
||||
password: string;
|
||||
}
|
||||
export interface ValidateResetToken {
|
||||
token: string;
|
||||
}
|
40
frontend/lib/api/user/backups.ts
Normal file
40
frontend/lib/api/user/backups.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { AllBackups, BackupOptions, CreateBackup } from "~/lib/api/types/admin";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
backupsAvailable: `${prefix}/backups/available`,
|
||||
backupsExportDatabase: `${prefix}/backups/export/database`,
|
||||
backupsUpload: `${prefix}/backups/upload`,
|
||||
|
||||
backupsFileNameDownload: (fileName: string) => `${prefix}/backups/${fileName}/download`,
|
||||
backupsFileNameImport: (fileName: string) => `${prefix}/backups/${fileName}/import`,
|
||||
backupsFileNameDelete: (fileName: string) => `${prefix}/backups/${fileName}/delete`,
|
||||
};
|
||||
|
||||
export class BackupAPI extends BaseAPI {
|
||||
/** Returns a list of available .zip files for import into Mealie.
|
||||
*/
|
||||
async getAll() {
|
||||
return await this.requests.get<AllBackups>(routes.backupsAvailable);
|
||||
}
|
||||
|
||||
/** Generates a backup of the recipe database in json format.
|
||||
*/
|
||||
async createOne(payload: CreateBackup) {
|
||||
return await this.requests.post(routes.backupsExportDatabase, payload);
|
||||
}
|
||||
|
||||
/** Import a database backup file generated from Mealie.
|
||||
*/
|
||||
async restoreDatabase(fileName: string, payload: BackupOptions) {
|
||||
return await this.requests.post(routes.backupsFileNameImport(fileName), { name: fileName, ...payload });
|
||||
}
|
||||
|
||||
/** Removes a database backup from the file system
|
||||
*/
|
||||
async deleteOne(fileName: string) {
|
||||
return await this.requests.delete(routes.backupsFileNameDelete(fileName));
|
||||
}
|
||||
}
|
25
frontend/lib/api/user/email.ts
Normal file
25
frontend/lib/api/user/email.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { EmailInitationResponse, EmailInvitation } from "~/lib/api/types/group";
|
||||
import { ForgotPassword } from "~/lib/api/types/user";
|
||||
import { EmailTest } from "~/lib/api/types/admin";
|
||||
|
||||
const routes = {
|
||||
base: "/api/admin/email",
|
||||
forgotPassword: "/api/users/forgot-password",
|
||||
|
||||
invitation: "/api/groups/invitations/email",
|
||||
};
|
||||
|
||||
export class EmailAPI extends BaseAPI {
|
||||
test(payload: EmailTest) {
|
||||
return this.requests.post<EmailInitationResponse>(routes.base, payload);
|
||||
}
|
||||
|
||||
sendInvitation(payload: EmailInvitation) {
|
||||
return this.requests.post<EmailInitationResponse>(routes.invitation, payload);
|
||||
}
|
||||
|
||||
sendForgotPassword(payload: ForgotPassword) {
|
||||
return this.requests.post<EmailInitationResponse>(routes.forgotPassword, payload);
|
||||
}
|
||||
}
|
18
frontend/lib/api/user/group-cookbooks.ts
Normal file
18
frontend/lib/api/user/group-cookbooks.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CreateCookBook, RecipeCookBook, UpdateCookBook } from "~/lib/api/types/cookbook";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
cookbooks: `${prefix}/groups/cookbooks`,
|
||||
cookbooksId: (id: number) => `${prefix}/groups/cookbooks/${id}`,
|
||||
};
|
||||
|
||||
export class CookbookAPI extends BaseCRUDAPI<CreateCookBook, RecipeCookBook, UpdateCookBook> {
|
||||
baseRoute: string = routes.cookbooks;
|
||||
itemRoute = routes.cookbooksId;
|
||||
|
||||
async updateAll(payload: UpdateCookBook[]) {
|
||||
return await this.requests.put(this.baseRoute, payload);
|
||||
}
|
||||
}
|
22
frontend/lib/api/user/group-event-notifier.ts
Normal file
22
frontend/lib/api/user/group-event-notifier.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { GroupEventNotifierCreate, GroupEventNotifierOut, GroupEventNotifierUpdate } from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
eventNotifier: `${prefix}/groups/events/notifications`,
|
||||
eventNotifierId: (id: string | number) => `${prefix}/groups/events/notifications/${id}`,
|
||||
};
|
||||
|
||||
export class GroupEventNotifierApi extends BaseCRUDAPI<
|
||||
GroupEventNotifierCreate,
|
||||
GroupEventNotifierOut,
|
||||
GroupEventNotifierUpdate
|
||||
> {
|
||||
baseRoute = routes.eventNotifier;
|
||||
itemRoute = routes.eventNotifierId;
|
||||
|
||||
async test(itemId: string) {
|
||||
return await this.requests.post(`${this.baseRoute}/${itemId}/test`, {});
|
||||
}
|
||||
}
|
14
frontend/lib/api/user/group-mealplan-rules.ts
Normal file
14
frontend/lib/api/user/group-mealplan-rules.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { PlanRulesCreate, PlanRulesOut } from "~/lib/api/types/meal-plan";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
rule: `${prefix}/groups/mealplans/rules`,
|
||||
ruleId: (id: string | number) => `${prefix}/groups/mealplans/rules/${id}`,
|
||||
};
|
||||
|
||||
export class MealPlanRulesApi extends BaseCRUDAPI<PlanRulesCreate, PlanRulesOut> {
|
||||
baseRoute = routes.rule;
|
||||
itemRoute = routes.ruleId;
|
||||
}
|
20
frontend/lib/api/user/group-mealplan.ts
Normal file
20
frontend/lib/api/user/group-mealplan.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CreatePlanEntry, CreateRandomEntry, ReadPlanEntry, UpdatePlanEntry } from "~/lib/api/types/meal-plan";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
mealplan: `${prefix}/groups/mealplans`,
|
||||
random: `${prefix}/groups/mealplans/random`,
|
||||
mealplanId: (id: string | number) => `${prefix}/groups/mealplans/${id}`,
|
||||
};
|
||||
|
||||
export class MealPlanAPI extends BaseCRUDAPI<CreatePlanEntry, ReadPlanEntry, UpdatePlanEntry> {
|
||||
baseRoute = routes.mealplan;
|
||||
itemRoute = routes.mealplanId;
|
||||
|
||||
async setRandom(payload: CreateRandomEntry) {
|
||||
console.log(payload);
|
||||
return await this.requests.post<ReadPlanEntry>(routes.random, payload);
|
||||
}
|
||||
}
|
27
frontend/lib/api/user/group-migrations.ts
Normal file
27
frontend/lib/api/user/group-migrations.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { ReportSummary } from "~/lib/api/types/reports";
|
||||
import { SupportedMigrations } from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
export interface MigrationPayload {
|
||||
addMigrationTag: boolean;
|
||||
migrationType: SupportedMigrations;
|
||||
archive: File;
|
||||
}
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/groups/migrations`,
|
||||
};
|
||||
|
||||
export class GroupMigrationApi extends BaseAPI {
|
||||
async startMigration(payload: MigrationPayload) {
|
||||
const form = new FormData();
|
||||
form.append("add_migration_tag", String(payload.addMigrationTag));
|
||||
form.append("migration_type", payload.migrationType);
|
||||
form.append("archive", payload.archive);
|
||||
|
||||
console.log(form);
|
||||
|
||||
return await this.requests.post<ReportSummary>(routes.base, form);
|
||||
}
|
||||
}
|
18
frontend/lib/api/user/group-multiple-purpose-labels.ts
Normal file
18
frontend/lib/api/user/group-multiple-purpose-labels.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { MultiPurposeLabelCreate, MultiPurposeLabelOut, MultiPurposeLabelUpdate } from "~/lib/api/types/labels";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
labels: `${prefix}/groups/labels`,
|
||||
labelsId: (id: string | number) => `${prefix}/groups/labels/${id}`,
|
||||
};
|
||||
|
||||
export class MultiPurposeLabelsApi extends BaseCRUDAPI<
|
||||
MultiPurposeLabelCreate,
|
||||
MultiPurposeLabelOut,
|
||||
MultiPurposeLabelUpdate
|
||||
> {
|
||||
baseRoute = routes.labels;
|
||||
itemRoute = routes.labelsId;
|
||||
}
|
24
frontend/lib/api/user/group-reports.ts
Normal file
24
frontend/lib/api/user/group-reports.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { ReportCategory, ReportOut, ReportSummary } from "~/lib/api/types/reports";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/groups/reports`,
|
||||
getOne: (id: string) => `${prefix}/groups/reports/${id}`,
|
||||
};
|
||||
|
||||
export class GroupReportsApi extends BaseAPI {
|
||||
async getAll(category: ReportCategory | null) {
|
||||
const query = category ? `?report_type=${category}` : "";
|
||||
return await this.requests.get<ReportSummary[]>(routes.base + query);
|
||||
}
|
||||
|
||||
async getOne(id: string) {
|
||||
return await this.requests.get<ReportOut>(routes.getOne(id));
|
||||
}
|
||||
|
||||
async deleteOne(id: string) {
|
||||
return await this.requests.delete(routes.getOne(id));
|
||||
}
|
||||
}
|
26
frontend/lib/api/user/group-seeder.ts
Normal file
26
frontend/lib/api/user/group-seeder.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { SuccessResponse } from "~/lib/api/types/response";
|
||||
import { SeederConfig } from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/groups/seeders`,
|
||||
foods: `${prefix}/groups/seeders/foods`,
|
||||
units: `${prefix}/groups/seeders/units`,
|
||||
labels: `${prefix}/groups/seeders/labels`,
|
||||
};
|
||||
|
||||
export class GroupDataSeederApi extends BaseAPI {
|
||||
foods(payload: SeederConfig) {
|
||||
return this.requests.post<SuccessResponse>(routes.foods, payload);
|
||||
}
|
||||
|
||||
units(payload: SeederConfig) {
|
||||
return this.requests.post<SuccessResponse>(routes.units, payload);
|
||||
}
|
||||
|
||||
labels(payload: SeederConfig) {
|
||||
return this.requests.post<SuccessResponse>(routes.labels, payload);
|
||||
}
|
||||
}
|
67
frontend/lib/api/user/group-shopping-lists.ts
Normal file
67
frontend/lib/api/user/group-shopping-lists.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
import {
|
||||
ShoppingListCreate,
|
||||
ShoppingListItemCreate,
|
||||
ShoppingListItemOut,
|
||||
ShoppingListItemUpdate,
|
||||
ShoppingListOut,
|
||||
ShoppingListUpdate,
|
||||
} from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
shoppingLists: `${prefix}/groups/shopping/lists`,
|
||||
shoppingListsId: (id: string) => `${prefix}/groups/shopping/lists/${id}`,
|
||||
shoppingListIdAddRecipe: (id: string, recipeId: string) => `${prefix}/groups/shopping/lists/${id}/recipe/${recipeId}`,
|
||||
|
||||
shoppingListItems: `${prefix}/groups/shopping/items`,
|
||||
shoppingListItemsId: (id: string) => `${prefix}/groups/shopping/items/${id}`,
|
||||
};
|
||||
|
||||
export class ShoppingListsApi extends BaseCRUDAPI<ShoppingListCreate, ShoppingListOut, ShoppingListUpdate> {
|
||||
baseRoute = routes.shoppingLists;
|
||||
itemRoute = routes.shoppingListsId;
|
||||
|
||||
async addRecipe(itemId: string, recipeId: string) {
|
||||
return await this.requests.post(routes.shoppingListIdAddRecipe(itemId, recipeId), {});
|
||||
}
|
||||
|
||||
async removeRecipe(itemId: string, recipeId: string) {
|
||||
return await this.requests.delete(routes.shoppingListIdAddRecipe(itemId, recipeId));
|
||||
}
|
||||
}
|
||||
|
||||
export class ShoppingListItemsApi extends BaseCRUDAPI<
|
||||
ShoppingListItemCreate,
|
||||
ShoppingListItemOut,
|
||||
ShoppingListItemUpdate
|
||||
> {
|
||||
baseRoute = routes.shoppingListItems;
|
||||
itemRoute = routes.shoppingListItemsId;
|
||||
|
||||
async updateMany(items: ShoppingListItemOut[]) {
|
||||
return await this.requests.put(routes.shoppingListItems, items);
|
||||
}
|
||||
|
||||
async deleteMany(items: ShoppingListItemOut[]) {
|
||||
let query = "?";
|
||||
|
||||
items.forEach((item) => {
|
||||
query += `ids=${item.id}&`;
|
||||
});
|
||||
|
||||
return await this.requests.delete(routes.shoppingListItems + query);
|
||||
}
|
||||
}
|
||||
|
||||
export class ShoppingApi {
|
||||
public lists: ShoppingListsApi;
|
||||
public items: ShoppingListItemsApi;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
this.lists = new ShoppingListsApi(requests);
|
||||
this.items = new ShoppingListItemsApi(requests);
|
||||
}
|
||||
}
|
13
frontend/lib/api/user/group-tasks.ts
Normal file
13
frontend/lib/api/user/group-tasks.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { ServerTask } from "~/lib/api/types/server";
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
base: `${prefix}/groups/server-tasks`,
|
||||
};
|
||||
|
||||
export class GroupServerTaskAPI extends BaseAPI {
|
||||
async getAll() {
|
||||
return await this.requests.get<ServerTask[]>(routes.base);
|
||||
}
|
||||
}
|
14
frontend/lib/api/user/group-webhooks.ts
Normal file
14
frontend/lib/api/user/group-webhooks.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CreateWebhook, ReadWebhook } from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
webhooks: `${prefix}/groups/webhooks`,
|
||||
webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`,
|
||||
};
|
||||
|
||||
export class WebhooksAPI extends BaseCRUDAPI<CreateWebhook, ReadWebhook> {
|
||||
baseRoute = routes.webhooks;
|
||||
itemRoute = routes.webhooksId;
|
||||
}
|
78
frontend/lib/api/user/groups.ts
Normal file
78
frontend/lib/api/user/groups.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CategoryBase, GroupBase, GroupInDB, UserOut } from "~/lib/api/types/user";
|
||||
import {
|
||||
CreateInviteToken,
|
||||
GroupAdminUpdate,
|
||||
GroupStatistics,
|
||||
GroupStorage,
|
||||
ReadGroupPreferences,
|
||||
ReadInviteToken,
|
||||
SetPermissions,
|
||||
UpdateGroupPreferences,
|
||||
} from "~/lib/api/types/group";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
groups: `${prefix}/admin/groups`,
|
||||
groupsSelf: `${prefix}/groups/self`,
|
||||
categories: `${prefix}/groups/categories`,
|
||||
members: `${prefix}/groups/members`,
|
||||
permissions: `${prefix}/groups/permissions`,
|
||||
|
||||
preferences: `${prefix}/groups/preferences`,
|
||||
statistics: `${prefix}/groups/statistics`,
|
||||
storage: `${prefix}/groups/storage`,
|
||||
|
||||
invitation: `${prefix}/groups/invitations`,
|
||||
|
||||
groupsId: (id: string | number) => `${prefix}/admin/groups/${id}`,
|
||||
};
|
||||
|
||||
export class GroupAPI extends BaseCRUDAPI<GroupBase, GroupInDB, GroupAdminUpdate> {
|
||||
baseRoute = routes.groups;
|
||||
itemRoute = routes.groupsId;
|
||||
/** Returns the Group Data for the Current User
|
||||
*/
|
||||
async getCurrentUserGroup() {
|
||||
return await this.requests.get<GroupInDB>(routes.groupsSelf);
|
||||
}
|
||||
|
||||
async getCategories() {
|
||||
return await this.requests.get<CategoryBase[]>(routes.categories);
|
||||
}
|
||||
|
||||
async setCategories(payload: CategoryBase[]) {
|
||||
return await this.requests.put<CategoryBase[]>(routes.categories, payload);
|
||||
}
|
||||
|
||||
async getPreferences() {
|
||||
return await this.requests.get<ReadGroupPreferences>(routes.preferences);
|
||||
}
|
||||
|
||||
async setPreferences(payload: UpdateGroupPreferences) {
|
||||
// TODO: This should probably be a patch request, which isn't offered by the API currently
|
||||
return await this.requests.put<ReadGroupPreferences, UpdateGroupPreferences>(routes.preferences, payload);
|
||||
}
|
||||
|
||||
async createInvitation(payload: CreateInviteToken) {
|
||||
return await this.requests.post<ReadInviteToken>(routes.invitation, payload);
|
||||
}
|
||||
|
||||
async fetchMembers() {
|
||||
return await this.requests.get<UserOut[]>(routes.members);
|
||||
}
|
||||
|
||||
async setMemberPermissions(payload: SetPermissions) {
|
||||
// TODO: This should probably be a patch request, which isn't offered by the API currently
|
||||
return await this.requests.put<UserOut, SetPermissions>(routes.permissions, payload);
|
||||
}
|
||||
|
||||
async statistics() {
|
||||
return await this.requests.get<GroupStatistics>(routes.statistics);
|
||||
}
|
||||
|
||||
async storage() {
|
||||
return await this.requests.get<GroupStorage>(routes.storage);
|
||||
}
|
||||
}
|
16
frontend/lib/api/user/ocr.ts
Normal file
16
frontend/lib/api/user/ocr.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
export class OcrAPI extends BaseAPI {
|
||||
// Currently unused in favor for the endpoint using asset names
|
||||
async fileToTsv(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return await this.requests.post(`${prefix}/ocr/file-to-tsv`, formData);
|
||||
}
|
||||
|
||||
async assetToTsv(recipeSlug: string, assetName: string) {
|
||||
return await this.requests.post(`${prefix}/ocr/asset-to-tsv`, { recipeSlug, assetName });
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/organizer-categories.ts
Normal file
20
frontend/lib/api/user/organizer-categories.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { config } from "../config";
|
||||
import { CategoryIn, RecipeCategoryResponse } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = config.PREFIX + "/organizers";
|
||||
|
||||
const routes = {
|
||||
categories: `${prefix}/categories`,
|
||||
categoriesId: (category: string) => `${prefix}/categories/${category}`,
|
||||
categoriesSlug: (category: string) => `${prefix}/categories/slug/${category}`,
|
||||
};
|
||||
|
||||
export class CategoriesAPI extends BaseCRUDAPI<CategoryIn, RecipeCategoryResponse> {
|
||||
baseRoute: string = routes.categories;
|
||||
itemRoute = routes.categoriesId;
|
||||
|
||||
async bySlug(slug: string) {
|
||||
return await this.requests.get<RecipeCategoryResponse>(routes.categoriesSlug(slug));
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/organizer-tags.ts
Normal file
20
frontend/lib/api/user/organizer-tags.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { config } from "../config";
|
||||
import { RecipeTagResponse, TagIn } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = config.PREFIX + "/organizers";
|
||||
|
||||
const routes = {
|
||||
tags: `${prefix}/tags`,
|
||||
tagsId: (tag: string) => `${prefix}/tags/${tag}`,
|
||||
tagsSlug: (tag: string) => `${prefix}/tags/slug/${tag}`,
|
||||
};
|
||||
|
||||
export class TagsAPI extends BaseCRUDAPI<TagIn, RecipeTagResponse> {
|
||||
baseRoute: string = routes.tags;
|
||||
itemRoute = routes.tagsId;
|
||||
|
||||
async bySlug(slug: string) {
|
||||
return await this.requests.get<RecipeTagResponse>(routes.tagsSlug(slug));
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/organizer-tools.ts
Normal file
20
frontend/lib/api/user/organizer-tools.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { config } from "../config";
|
||||
import { RecipeTool, RecipeToolCreate, RecipeToolResponse } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = config.PREFIX + "/organizers";
|
||||
|
||||
const routes = {
|
||||
tools: `${prefix}/tools`,
|
||||
toolsId: (id: string) => `${prefix}/tools/${id}`,
|
||||
toolsSlug: (id: string) => `${prefix}/tools/slug/${id}`,
|
||||
};
|
||||
|
||||
export class ToolsApi extends BaseCRUDAPI<RecipeToolCreate, RecipeTool> {
|
||||
baseRoute: string = routes.tools;
|
||||
itemRoute = routes.toolsId;
|
||||
|
||||
async bySlug(slug: string) {
|
||||
return await this.requests.get<RecipeToolResponse>(routes.toolsSlug(slug));
|
||||
}
|
||||
}
|
48
frontend/lib/api/user/recipe-bulk-actions.ts
Normal file
48
frontend/lib/api/user/recipe-bulk-actions.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { AssignCategories, AssignSettings, AssignTags, DeleteRecipes, ExportRecipes } from "~/lib/api/types/recipe";
|
||||
import { GroupDataExport } from "~/lib/api/types/group";
|
||||
|
||||
// Many bulk actions return nothing
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface BulkActionResponse {}
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
bulkExport: prefix + "/recipes/bulk-actions/export",
|
||||
purgeExports: prefix + "/recipes/bulk-actions/export/purge",
|
||||
bulkCategorize: prefix + "/recipes/bulk-actions/categorize",
|
||||
bulkTag: prefix + "/recipes/bulk-actions/tag",
|
||||
bulkDelete: prefix + "/recipes/bulk-actions/delete",
|
||||
bulkSettings: prefix + "/recipes/bulk-actions/settings",
|
||||
};
|
||||
|
||||
export class BulkActionsAPI extends BaseAPI {
|
||||
async bulkExport(payload: ExportRecipes) {
|
||||
return await this.requests.post<BulkActionResponse>(routes.bulkExport, payload);
|
||||
}
|
||||
|
||||
async bulkCategorize(payload: AssignCategories) {
|
||||
return await this.requests.post<BulkActionResponse>(routes.bulkCategorize, payload);
|
||||
}
|
||||
|
||||
async bulkSetSettings(payload: AssignSettings) {
|
||||
return await this.requests.post<BulkActionResponse>(routes.bulkSettings, payload);
|
||||
}
|
||||
|
||||
async bulkTag(payload: AssignTags) {
|
||||
return await this.requests.post<BulkActionResponse>(routes.bulkTag, payload);
|
||||
}
|
||||
|
||||
async bulkDelete(payload: DeleteRecipes) {
|
||||
return await this.requests.post<BulkActionResponse>(routes.bulkDelete, payload);
|
||||
}
|
||||
|
||||
async fetchExports() {
|
||||
return await this.requests.get<GroupDataExport[]>(routes.bulkExport);
|
||||
}
|
||||
|
||||
async purgeExports() {
|
||||
return await this.requests.delete<BulkActionResponse>(routes.purgeExports);
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/recipe-foods.ts
Normal file
20
frontend/lib/api/user/recipe-foods.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CreateIngredientFood, IngredientFood } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
food: `${prefix}/foods`,
|
||||
foodsFood: (tag: string) => `${prefix}/foods/${tag}`,
|
||||
merge: `${prefix}/foods/merge`,
|
||||
};
|
||||
|
||||
export class FoodAPI extends BaseCRUDAPI<CreateIngredientFood, IngredientFood> {
|
||||
baseRoute: string = routes.food;
|
||||
itemRoute = routes.foodsFood;
|
||||
|
||||
merge(fromId: string, toId: string) {
|
||||
// @ts-ignore TODO: fix this
|
||||
return this.requests.put<IngredientFood>(routes.merge, { fromFood: fromId, toFood: toId });
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/recipe-units.ts
Normal file
20
frontend/lib/api/user/recipe-units.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import { CreateIngredientUnit, IngredientUnit } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
unit: `${prefix}/units`,
|
||||
unitsUnit: (tag: string) => `${prefix}/units/${tag}`,
|
||||
merge: `${prefix}/units/merge`,
|
||||
};
|
||||
|
||||
export class UnitAPI extends BaseCRUDAPI<CreateIngredientUnit, IngredientUnit> {
|
||||
baseRoute: string = routes.unit;
|
||||
itemRoute = routes.unitsUnit;
|
||||
|
||||
merge(fromId: string, toId: string) {
|
||||
// @ts-ignore TODO: fix this
|
||||
return this.requests.put<IngredientUnit>(routes.merge, { fromUnit: fromId, toUnit: toId });
|
||||
}
|
||||
}
|
1
frontend/lib/api/user/recipes/index.ts
Normal file
1
frontend/lib/api/user/recipes/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { RecipeAPI } from "./recipe";
|
19
frontend/lib/api/user/recipes/recipe-comments.ts
Normal file
19
frontend/lib/api/user/recipes/recipe-comments.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { BaseCRUDAPI } from "../../base/base-clients";
|
||||
import { RecipeCommentCreate, RecipeCommentOut, RecipeCommentUpdate } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
comment: `${prefix}/comments`,
|
||||
byRecipe: (id: string) => `${prefix}/recipes/${id}/comments`,
|
||||
commentsId: (id: string) => `${prefix}/comments/${id}`,
|
||||
};
|
||||
|
||||
export class CommentsApi extends BaseCRUDAPI<RecipeCommentCreate, RecipeCommentOut, RecipeCommentUpdate> {
|
||||
baseRoute: string = routes.comment;
|
||||
itemRoute = routes.commentsId;
|
||||
|
||||
async byRecipe(slug: string) {
|
||||
return await this.requests.get<RecipeCommentOut[]>(routes.byRecipe(slug));
|
||||
}
|
||||
}
|
14
frontend/lib/api/user/recipes/recipe-share.ts
Normal file
14
frontend/lib/api/user/recipes/recipe-share.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseCRUDAPI } from "../../base/base-clients";
|
||||
import { RecipeShareToken, RecipeShareTokenCreate } from "~/lib/api/types/recipe";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
shareToken: `${prefix}/shared/recipes`,
|
||||
shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`,
|
||||
};
|
||||
|
||||
export class RecipeShareApi extends BaseCRUDAPI<RecipeShareTokenCreate, RecipeShareToken> {
|
||||
baseRoute: string = routes.shareToken;
|
||||
itemRoute = routes.shareTokenId;
|
||||
}
|
129
frontend/lib/api/user/recipes/recipe.ts
Normal file
129
frontend/lib/api/user/recipes/recipe.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
import { BaseCRUDAPI } from "../../base/base-clients";
|
||||
import { CommentsApi } from "./recipe-comments";
|
||||
import { RecipeShareApi } from "./recipe-share";
|
||||
|
||||
import {
|
||||
Recipe,
|
||||
CreateRecipe,
|
||||
RecipeAsset,
|
||||
CreateRecipeByUrlBulk,
|
||||
ParsedIngredient,
|
||||
UpdateImageResponse,
|
||||
RecipeZipTokenResponse,
|
||||
} from "~/lib/api/types/recipe";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
export type Parser = "nlp" | "brute";
|
||||
|
||||
export interface CreateAsset {
|
||||
name: string;
|
||||
icon: string;
|
||||
extension: string;
|
||||
file: File;
|
||||
}
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
recipesCreate: `${prefix}/recipes/create`,
|
||||
recipesBase: `${prefix}/recipes`,
|
||||
recipesTestScrapeUrl: `${prefix}/recipes/test-scrape-url`,
|
||||
recipesCreateUrl: `${prefix}/recipes/create-url`,
|
||||
recipesCreateUrlBulk: `${prefix}/recipes/create-url/bulk`,
|
||||
recipesCreateFromZip: `${prefix}/recipes/create-from-zip`,
|
||||
recipesCategory: `${prefix}/recipes/category`,
|
||||
recipesParseIngredient: `${prefix}/parser/ingredient`,
|
||||
recipesParseIngredients: `${prefix}/parser/ingredients`,
|
||||
recipesCreateFromOcr: `${prefix}/recipes/create-ocr`,
|
||||
|
||||
recipesRecipeSlug: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}`,
|
||||
recipesRecipeSlugExport: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports`,
|
||||
recipesRecipeSlugExportZip: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports/zip`,
|
||||
recipesRecipeSlugImage: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/image`,
|
||||
recipesRecipeSlugAssets: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/assets`,
|
||||
|
||||
recipesSlugComments: (slug: string) => `${prefix}/recipes/${slug}/comments`,
|
||||
recipesSlugCommentsId: (slug: string, id: number) => `${prefix}/recipes/${slug}/comments/${id}`,
|
||||
};
|
||||
|
||||
export class RecipeAPI extends BaseCRUDAPI<CreateRecipe, Recipe, Recipe> {
|
||||
baseRoute: string = routes.recipesBase;
|
||||
itemRoute = routes.recipesRecipeSlug;
|
||||
|
||||
comments: CommentsApi;
|
||||
share: RecipeShareApi;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
super(requests);
|
||||
|
||||
this.comments = new CommentsApi(requests);
|
||||
this.share = new RecipeShareApi(requests);
|
||||
}
|
||||
|
||||
async getAllByCategory(categories: string[]) {
|
||||
return await this.requests.get<Recipe[]>(routes.recipesCategory, {
|
||||
categories,
|
||||
});
|
||||
}
|
||||
|
||||
async createAsset(recipeSlug: string, payload: CreateAsset) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", payload.file);
|
||||
formData.append("name", payload.name);
|
||||
formData.append("extension", payload.extension);
|
||||
formData.append("icon", payload.icon);
|
||||
|
||||
return await this.requests.post<RecipeAsset>(routes.recipesRecipeSlugAssets(recipeSlug), formData);
|
||||
}
|
||||
|
||||
updateImage(slug: string, fileObject: File) {
|
||||
const formData = new FormData();
|
||||
formData.append("image", fileObject);
|
||||
formData.append("extension", fileObject.name.split(".").pop() ?? "");
|
||||
|
||||
return this.requests.put<UpdateImageResponse, FormData>(routes.recipesRecipeSlugImage(slug), formData);
|
||||
}
|
||||
|
||||
updateImagebyURL(slug: string, url: string) {
|
||||
return this.requests.post<UpdateImageResponse>(routes.recipesRecipeSlugImage(slug), { url });
|
||||
}
|
||||
|
||||
async testCreateOneUrl(url: string) {
|
||||
return await this.requests.post<Recipe | null>(routes.recipesTestScrapeUrl, { url });
|
||||
}
|
||||
|
||||
async createOneByUrl(url: string, includeTags: boolean) {
|
||||
return await this.requests.post<string>(routes.recipesCreateUrl, { url, includeTags });
|
||||
}
|
||||
|
||||
async createManyByUrl(payload: CreateRecipeByUrlBulk) {
|
||||
return await this.requests.post<string>(routes.recipesCreateUrlBulk, payload);
|
||||
}
|
||||
|
||||
async parseIngredients(parser: Parser, ingredients: Array<string>) {
|
||||
parser = parser || "nlp";
|
||||
return await this.requests.post<ParsedIngredient[]>(routes.recipesParseIngredients, { parser, ingredients });
|
||||
}
|
||||
|
||||
async parseIngredient(parser: Parser, ingredient: string) {
|
||||
parser = parser || "nlp";
|
||||
return await this.requests.post<ParsedIngredient>(routes.recipesParseIngredient, { parser, ingredient });
|
||||
}
|
||||
|
||||
async getZipToken(recipeSlug: string) {
|
||||
return await this.requests.post<RecipeZipTokenResponse>(routes.recipesRecipeSlugExport(recipeSlug), {});
|
||||
}
|
||||
|
||||
getZipRedirectUrl(recipeSlug: string, token: string) {
|
||||
return `${routes.recipesRecipeSlugExportZip(recipeSlug)}?token=${token}`;
|
||||
}
|
||||
|
||||
async createFromOcr(file: File, makeFileRecipeImage: boolean) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("extension", file.name.split(".").pop() ?? "");
|
||||
formData.append("makefilerecipeimage", String(makeFileRecipeImage));
|
||||
|
||||
return await this.requests.post(routes.recipesCreateFromOcr, formData);
|
||||
}
|
||||
}
|
7
frontend/lib/api/user/upload.ts
Normal file
7
frontend/lib/api/user/upload.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
|
||||
export class UploadFile extends BaseAPI {
|
||||
file(url: string, fileObject: any) {
|
||||
return this.requests.post<string>(url, fileObject);
|
||||
}
|
||||
}
|
16
frontend/lib/api/user/user-registration.ts
Normal file
16
frontend/lib/api/user/user-registration.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { CreateUserRegistration } from "~/lib/api/types/user";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
register: `${prefix}/users/register`,
|
||||
};
|
||||
|
||||
export class RegisterAPI extends BaseAPI {
|
||||
/** Returns a list of available .zip files for import into Mealie.
|
||||
*/
|
||||
async register(payload: CreateUserRegistration) {
|
||||
return await this.requests.post<any>(routes.register, payload);
|
||||
}
|
||||
}
|
68
frontend/lib/api/user/users.ts
Normal file
68
frontend/lib/api/user/users.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import {
|
||||
ChangePassword,
|
||||
DeleteTokenResponse,
|
||||
LongLiveTokenIn,
|
||||
LongLiveTokenOut,
|
||||
ResetPassword,
|
||||
UserBase,
|
||||
UserFavorites,
|
||||
UserIn,
|
||||
UserOut,
|
||||
} from "~/lib/api/types/user";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
usersSelf: `${prefix}/users/self`,
|
||||
passwordReset: `${prefix}/users/reset-password`,
|
||||
passwordChange: `${prefix}/users/password`,
|
||||
users: `${prefix}/users`,
|
||||
|
||||
usersIdImage: (id: string) => `${prefix}/users/${id}/image`,
|
||||
usersIdResetPassword: (id: string) => `${prefix}/users/${id}/reset-password`,
|
||||
usersId: (id: string) => `${prefix}/users/${id}`,
|
||||
usersIdFavorites: (id: string) => `${prefix}/users/${id}/favorites`,
|
||||
usersIdFavoritesSlug: (id: string, slug: string) => `${prefix}/users/${id}/favorites/${slug}`,
|
||||
|
||||
usersApiTokens: `${prefix}/users/api-tokens`,
|
||||
usersApiTokensTokenId: (token_id: string | number) => `${prefix}/users/api-tokens/${token_id}`,
|
||||
};
|
||||
|
||||
export class UserApi extends BaseCRUDAPI<UserIn, UserOut, UserBase> {
|
||||
baseRoute: string = routes.users;
|
||||
itemRoute = (itemid: string) => routes.usersId(itemid);
|
||||
|
||||
async addFavorite(id: string, slug: string) {
|
||||
return await this.requests.post(routes.usersIdFavoritesSlug(id, slug), {});
|
||||
}
|
||||
|
||||
async removeFavorite(id: string, slug: string) {
|
||||
return await this.requests.delete(routes.usersIdFavoritesSlug(id, slug));
|
||||
}
|
||||
|
||||
async getFavorites(id: string) {
|
||||
return await this.requests.get<UserFavorites>(routes.usersIdFavorites(id));
|
||||
}
|
||||
|
||||
async changePassword(changePassword: ChangePassword) {
|
||||
return await this.requests.put(routes.passwordChange, changePassword);
|
||||
}
|
||||
|
||||
async createAPIToken(tokenName: LongLiveTokenIn) {
|
||||
return await this.requests.post<LongLiveTokenOut>(routes.usersApiTokens, tokenName);
|
||||
}
|
||||
|
||||
async deleteAPIToken(tokenId: number) {
|
||||
return await this.requests.delete<DeleteTokenResponse>(routes.usersApiTokensTokenId(tokenId));
|
||||
}
|
||||
|
||||
userProfileImage(id: string) {
|
||||
if (!id || id === undefined) return;
|
||||
return `/api/users/${id}/image`;
|
||||
}
|
||||
|
||||
async resetPassword(payload: ResetPassword) {
|
||||
return await this.requests.post(routes.passwordReset, payload);
|
||||
}
|
||||
}
|
20
frontend/lib/api/user/utils.ts
Normal file
20
frontend/lib/api/user/utils.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { FileTokenResponse } from "~/lib/api/types/response";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
export class UtilsAPI extends BaseAPI {
|
||||
async download(url: string) {
|
||||
const { response } = await this.requests.get<FileTokenResponse>(url);
|
||||
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token: string = response.data.fileToken;
|
||||
|
||||
const tokenURL = prefix + "/utils/download?token=" + token;
|
||||
window.open(tokenURL, "_blank");
|
||||
return response;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue