feat: Allow to host under subpath #145

This commit is contained in:
rustmailer
2026-03-12 01:55:14 +08:00
parent f3c46f97b9
commit 40eca89a75
13 changed files with 121 additions and 67 deletions
+8 -8
View File
@@ -26,7 +26,7 @@ export interface MinimalAccount {
}
export const minimal_account_list = async () => {
const response = await axiosInstance.get<MinimalAccount[]>("/api/v1/minimal-account-list");
const response = await axiosInstance.get<MinimalAccount[]>("api/v1/minimal-account-list");
return response.data;
};
@@ -109,27 +109,27 @@ export interface AccountModel {
}
export const account_state = async (account_id: number) => {
const response = await axiosInstance.get<AccountRunningState>(`/api/v1/account-state/${account_id}`);
const response = await axiosInstance.get<AccountRunningState>(`api/v1/account-state/${account_id}`);
return response.data;
};
export const create_account = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/account", data);
const response = await axiosInstance.post("api/v1/account", data);
return response.data;
};
export const list_accounts = async () => {
const response = await axiosInstance.get<PaginatedResponse<AccountModel>>("/api/v1/accounts?desc=true");
const response = await axiosInstance.get<PaginatedResponse<AccountModel>>("api/v1/accounts?desc=true");
return response.data;
};
export const update_account = async (account_id: number, data: Record<string, any>) => {
const response = await axiosInstance.post(`/api/v1/account/${account_id}`, data);
const response = await axiosInstance.post(`api/v1/account/${account_id}`, data);
return response.data;
};
export const remove_account = async (account_id: number) => {
const response = await axiosInstance.delete(`/api/v1/account/${account_id}`);
const response = await axiosInstance.delete(`api/v1/account/${account_id}`);
return response.data;
};
@@ -152,11 +152,11 @@ export interface OAuth2Config {
}
export const autoconfig = async (email: string) => {
const response = await axiosInstance.get<AutoConfigResult>(`/api/v1/autoconfig/${email}`);
const response = await axiosInstance.get<AutoConfigResult>(`api/v1/autoconfig/${email}`);
return response.data;
};
export const access_assign = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/accounts/access/assignments", data);
const response = await axiosInstance.post("api/v1/accounts/access/assignments", data);
return response.data;
};
+5 -1
View File
@@ -20,9 +20,13 @@
import { getToken } from "@/stores/authStore";
import axios from "axios";
const injectedBase = (window as any).__BICHON_BASE__;
const base_url = (injectedBase === "/" || !injectedBase) ? "" : injectedBase;
// Create an Axios instance
const baseURL = process.env.NODE_ENV === "production"
? "/" // Production: relative to the current domain
? base_url // Production: relative to the current domain
: "http://localhost:15630"; // Development: Poem's backend server
const axiosInstance = axios.create({
+2 -2
View File
@@ -33,12 +33,12 @@ export interface MailboxData {
}
export const list_mailboxes = async (accountId: number, remote: boolean) => {
const response = await axiosInstance.get<MailboxData[]>(`/api/v1/list-mailboxes/${accountId}?remote=${remote}`);
const response = await axiosInstance.get<MailboxData[]>(`api/v1/list-mailboxes/${accountId}?remote=${remote}`);
return response.data;
};
export const delete_mailbox = async (accountId: number, mailboxId: string) => {
const response = await axiosInstance.delete(`/api/v1/delete-mailbox/${accountId}/${mailboxId}`);
const response = await axiosInstance.delete(`api/v1/delete-mailbox/${accountId}/${mailboxId}`);
return response.data;
};
+7 -7
View File
@@ -29,7 +29,7 @@ export const list_messages = async (accountId: number, mailbox_id: number, page:
});
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
`/api/v1/list-messages/${accountId}?${params.toString()}`
`api/v1/list-messages/${accountId}?${params.toString()}`
);
return response.data;
};
@@ -42,13 +42,13 @@ export const get_thread_messages = async (accountId: number, thread_id: number,
});
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
`/api/v1/get-thread-messages/${accountId}?${params.toString()}`
`api/v1/get-thread-messages/${accountId}?${params.toString()}`
);
return response.data;
}
export const download_attachment = async (accountId: number, id: number, attachmentFileName: string) => {
const response = await axiosInstance.get(`/api/v1/download-attachment/${accountId}/${id}?name=${attachmentFileName}`, { responseType: 'blob' });
const response = await axiosInstance.get(`api/v1/download-attachment/${accountId}/${id}?name=${attachmentFileName}`, { responseType: 'blob' });
const blob = new Blob([response.data]);
saveAs(blob, attachmentFileName);
};
@@ -83,17 +83,17 @@ export const getContent = (messageContent: MessageContentResponse): string | nul
};
export const load_message = async (accountId: number, id: number) => {
const response = await axiosInstance.get<MessageContentResponse>(`/api/v1/message-content/${accountId}/${id}`);
const response = await axiosInstance.get<MessageContentResponse>(`api/v1/message-content/${accountId}/${id}`);
return response.data;
};
export const delete_messages = async (payload: Record<string, number[]>) => {
const response = await axiosInstance.post("/api/v1/delete-messages", payload);
const response = await axiosInstance.post("api/v1/delete-messages", payload);
return response.data;
};
export const download_message = async (accountId: number, id: number) => {
const response = await axiosInstance.get(`/api/v1/download-message/${accountId}/${id}`, { responseType: 'blob' });
const response = await axiosInstance.get(`api/v1/download-message/${accountId}/${id}`, { responseType: 'blob' });
const blob = new Blob([response.data]);
saveAs(blob, `${id}.eml`);
};
@@ -101,7 +101,7 @@ export const download_message = async (accountId: number, id: number) => {
export const restore_message = async (accountId: number, messageIds: number[]) => {
const response = await axiosInstance.post(`/api/v1/restore-messages/${accountId}`, {
const response = await axiosInstance.post(`api/v1/restore-messages/${accountId}`, {
message_ids: messageIds,
});
return response.data;
+6 -6
View File
@@ -21,28 +21,28 @@ import { OAuth2Entity } from "@/features/oauth2/data/schema";
import axiosInstance from "../axiosInstance";
export const get_oauth2_list = async () => {
const response = await axiosInstance.get<{ items: OAuth2Entity[] }>("/api/v1/oauth2-list");
const response = await axiosInstance.get<{ items: OAuth2Entity[] }>("api/v1/oauth2-list");
return response.data;
};
export const delete_oauth2 = async (id: number) => {
const response = await axiosInstance.delete(`/api/v1/oauth2/${id}`);
const response = await axiosInstance.delete(`api/v1/oauth2/${id}`);
return response.data;
};
export const create_oauth2 = async (data: Record<string, any>) => {
const response = await axiosInstance.post<OAuth2Entity>("/api/v1/oauth2", data);
const response = await axiosInstance.post<OAuth2Entity>("api/v1/oauth2", data);
return response.data;
};
export const update_oauth2 = async (id: number, data: Record<string, any>) => {
const response = await axiosInstance.post<OAuth2Entity>(`/api/v1/oauth2/${id}`, data);
const response = await axiosInstance.post<OAuth2Entity>(`api/v1/oauth2/${id}`, data);
return response.data;
};
export const get_authorize_url = async (data: Record<string, any>) => {
const response = await axiosInstance.post('/api/v1/oauth2-authorize-url', data);
const response = await axiosInstance.post('api/v1/oauth2-authorize-url', data);
return response.data;
};
@@ -57,6 +57,6 @@ export interface OAuth2Tokens {
}
export const get_oauth2_tokens = async (accountId: number) => {
const response = await axiosInstance.get<OAuth2Tokens>(`/api/v1/oauth2-tokens/${accountId}`);
const response = await axiosInstance.get<OAuth2Tokens>(`api/v1/oauth2-tokens/${accountId}`);
return response.data;
};
+4 -4
View File
@@ -21,7 +21,7 @@ import axiosInstance from "@/api/axiosInstance";
import { EmailEnvelope, PaginatedResponse } from "..";
export const search_messages = async (payload: Record<string, any>) => {
const response = await axiosInstance.post<PaginatedResponse<EmailEnvelope>>("/api/v1/search-messages", payload);
const response = await axiosInstance.post<PaginatedResponse<EmailEnvelope>>("api/v1/search-messages", payload);
return response.data;
};
@@ -31,18 +31,18 @@ export interface TagCount {
}
export const get_tags = async () => {
const response = await axiosInstance.get<TagCount[]>("/api/v1/all-tags");
const response = await axiosInstance.get<TagCount[]>("api/v1/all-tags");
return response.data;
}
export const update_tags = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/update-tags", data);
const response = await axiosInstance.post("api/v1/update-tags", data);
return response.data;
};
export const get_contacts = async () => {
const response = await axiosInstance.get<string[]>("/api/v1/all-contacts");
const response = await axiosInstance.get<string[]>("api/v1/all-contacts");
return response.data;
}
+7 -7
View File
@@ -37,7 +37,7 @@ interface Notifications {
}
export const get_notifications = async () => {
const response = await axiosInstance.get<Notifications>(`/api/v1/notifications`);
const response = await axiosInstance.get<Notifications>(`api/v1/notifications`);
return response.data;
};
@@ -118,22 +118,22 @@ export type ServerConfigurations = {
}
export const get_dashboard_stats = async () => {
const response = await axiosInstance.get<DashboardStats>(`/api/v1/dashboard-stats`);
const response = await axiosInstance.get<DashboardStats>(`api/v1/dashboard-stats`);
return response.data;
};
export const list_proxy = async () => {
const response = await axiosInstance.get<Proxy[]>(`/api/v1/list-proxy`);
const response = await axiosInstance.get<Proxy[]>(`api/v1/list-proxy`);
return response.data;
};
export const delete_proxy = async (id: number) => {
const response = await axiosInstance.delete(`/api/v1/proxy/${id}`);
const response = await axiosInstance.delete(`api/v1/proxy/${id}`);
return response.data;
};
export const update_proxy = async (id: number, url: string) => {
const response = await axiosInstance.post(`/api/v1/proxy/${id}`, url, {
const response = await axiosInstance.post(`api/v1/proxy/${id}`, url, {
headers: {
"Content-Type": "text/plain",
},
@@ -142,7 +142,7 @@ export const update_proxy = async (id: number, url: string) => {
};
export const add_proxy = async (url: string) => {
const response = await axiosInstance.post(`/api/v1/proxy`, url, {
const response = await axiosInstance.post(`api/v1/proxy`, url, {
headers: {
"Content-Type": "text/plain",
},
@@ -152,6 +152,6 @@ export const add_proxy = async (url: string) => {
export const get_system_configurations = async () => {
const response = await axiosInstance.get<ServerConfigurations>(`/api/v1/system-configurations`);
const response = await axiosInstance.get<ServerConfigurations>(`api/v1/system-configurations`);
return response.data;
};
+19 -19
View File
@@ -125,17 +125,17 @@ export interface MinimalUser {
export const login = async (data: Record<string, any>) => {
const response = await axiosInstance.post<LoginResult>(`/api/login`, data);
const response = await axiosInstance.post<LoginResult>(`api/login`, data);
return response.data;
};
export const reset_admin_token = async () => {
const response = await axiosInstance.post("/api/v1/reset-admin-token");
const response = await axiosInstance.post("api/v1/reset-admin-token");
return response.data;
};
export const reset_admin_password = async (password: string) => {
const response = await axiosInstance.post("/api/v1/reset-admin-password", password, {
const response = await axiosInstance.post("api/v1/reset-admin-password", password, {
headers: {
"Content-Type": "text/plain",
},
@@ -144,89 +144,89 @@ export const reset_admin_password = async (password: string) => {
};
export const list_access_tokens = async () => {
const response = await axiosInstance.get<AccessToken[]>("/api/v1/access-token-list");
const response = await axiosInstance.get<AccessToken[]>("api/v1/access-token-list");
return response.data;
};
export const create_access_token = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/access-token", data);
const response = await axiosInstance.post("api/v1/access-token", data);
return response.data;
}
export const update_access_token = async (token: string, data: Record<string, any>) => {
const response = await axiosInstance.post(`/api/v1/access-token/${token}`, data);
const response = await axiosInstance.post(`api/v1/access-token/${token}`, data);
return response.data;
}
export const remove_access_token = async (token: string) => {
const response = await axiosInstance.delete(`/api/v1/access-token/${token}`);
const response = await axiosInstance.delete(`api/v1/access-token/${token}`);
return response.data;
}
export const list_roles = async () => {
const response = await axiosInstance.get<UserRole[]>("/api/v1/list-roles");
const response = await axiosInstance.get<UserRole[]>("api/v1/list-roles");
return response.data;
};
export const remove_role = async (id: number) => {
const response = await axiosInstance.delete(`/api/v1/roles/${id}`);
const response = await axiosInstance.delete(`api/v1/roles/${id}`);
return response.data;
};
export const create_role = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/roles", data);
const response = await axiosInstance.post("api/v1/roles", data);
return response.data;
};
export const update_role = async (id: number, data: Record<string, any>) => {
const response = await axiosInstance.post(`/api/v1/roles/${id}`, data);
const response = await axiosInstance.post(`api/v1/roles/${id}`, data);
return response.data;
};
export const list_users = async () => {
const response = await axiosInstance.get<User[]>("/api/v1/list-users");
const response = await axiosInstance.get<User[]>("api/v1/list-users");
return response.data;
};
export const list_minimal_users = async () => {
const response = await axiosInstance.get<MinimalUser[]>("/api/v1/minimal-user-list");
const response = await axiosInstance.get<MinimalUser[]>("api/v1/minimal-user-list");
return response.data;
};
export const list_account_roles = async () => {
const response = await axiosInstance.get<UserRole[]>("/api/v1/list-account-roles");
const response = await axiosInstance.get<UserRole[]>("api/v1/list-account-roles");
return response.data;
};
export const remove_user = async (id: number) => {
const response = await axiosInstance.delete(`/api/v1/users/${id}`);
const response = await axiosInstance.delete(`api/v1/users/${id}`);
return response.data;
};
export const create_user = async (data: Record<string, any>) => {
const response = await axiosInstance.post("/api/v1/users", data);
const response = await axiosInstance.post("api/v1/users", data);
return response.data;
};
export const update_user = async (id: number, data: Record<string, any>) => {
const response = await axiosInstance.post(`/api/v1/users/${id}`, data);
const response = await axiosInstance.post(`api/v1/users/${id}`, data);
return response.data;
};
export const get_user_tokens = async (id: number) => {
const response = await axiosInstance.get<AccessToken[]>(`/api/v1/user-tokens/${id}`);
const response = await axiosInstance.get<AccessToken[]>(`api/v1/user-tokens/${id}`);
return response.data;
};
export const get_current_user = async () => {
const response = await axiosInstance.get<User>("/api/v1/current-user");
const response = await axiosInstance.get<User>("api/v1/current-user");
return response.data;
};
+7 -6
View File
@@ -27,12 +27,14 @@ import { Separator } from "./ui/separator";
export default function APIDocs() {
const { t } = useTranslation()
const base_url = (window as any).__BICHON_BASE__ || '';
const docsOptions = [
{ name: t('apiDocs.swaggerUI'), path: "/api-docs/swagger" },
{ name: t('apiDocs.reDoc'), path: "/api-docs/redoc" },
{ name: t('apiDocs.openAPIExplorer'), path: "/api-docs/explorer" },
{ name: t('apiDocs.scalar'), path: "/api-docs/scalar" },
{ name: t('apiDocs.downloadSpecYAML'), path: "/api-docs/spec.yaml" }
{ name: t('apiDocs.swaggerUI'), path: `${base_url}/api-docs/swagger` },
{ name: t('apiDocs.reDoc'), path: `${base_url}/api-docs/redoc` },
{ name: t('apiDocs.openAPIExplorer'), path: `${base_url}/api-docs/explorer` },
{ name: t('apiDocs.scalar'), path: `${base_url}/api-docs/scalar` },
{ name: t('apiDocs.downloadSpecYAML'), path: `${base_url}/api-docs/spec.yaml` }
];
const handleCardClick = (path: string) => {
// Open in new tab
@@ -41,7 +43,6 @@ export default function APIDocs() {
return (
<>
<FixedHeader />
<Main>
<div className='mb-2 flex items-center justify-between space-y-2 flex-wrap gap-x-4'>
+3
View File
@@ -121,9 +121,12 @@ const queryClient = new QueryClient({
}),
})
const basepath = (window as any).__BICHON_BASE__ || '/';
console.log('Current Basepath:', basepath);
// Create a new router instance
const router = createRouter({
routeTree,
basepath,
context: { queryClient },
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,