mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat: Allow to host under subpath #145
This commit is contained in:
+30
-7
@@ -37,8 +37,8 @@ use http::{HeaderValue, Method};
|
||||
use poem::endpoint::EmbeddedFilesEndpoint;
|
||||
use poem::listener::{Listener, TcpListener};
|
||||
use poem::middleware::{CatchPanic, Compression, SetHeader};
|
||||
use poem::{endpoint::EmbeddedFileEndpoint, middleware::Cors, EndpointExt, Route, Server};
|
||||
use poem::{get, post};
|
||||
use poem::{get, handler, post, IntoResponse};
|
||||
use poem::{middleware::Cors, EndpointExt, Route, Server};
|
||||
use public::oauth2::oauth2_callback;
|
||||
use std::collections::HashSet;
|
||||
use std::time::Duration;
|
||||
@@ -115,7 +115,7 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
)
|
||||
};
|
||||
|
||||
let route = Route::new()
|
||||
let app_logic = Route::new()
|
||||
.nest("/api-docs/swagger", swagger)
|
||||
.nest("/api-docs/redoc", redoc)
|
||||
.nest("/api-docs/explorer", openapi_explorer)
|
||||
@@ -130,10 +130,10 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
"/assets",
|
||||
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
||||
)
|
||||
.at(
|
||||
"/*",
|
||||
EmbeddedFileEndpoint::<FrontEndAssets>::new("index.html"),
|
||||
)
|
||||
.at("/*", serve_index_with_base);
|
||||
|
||||
let route = Route::new()
|
||||
.nest(&SETTINGS.bichon_base_url, app_logic)
|
||||
.with(cors)
|
||||
.with_if(SETTINGS.bichon_http_compression_enabled, Compression::new())
|
||||
.with(CatchPanic::new());
|
||||
@@ -158,3 +158,26 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
.await
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))
|
||||
}
|
||||
|
||||
#[handler]
|
||||
async fn serve_index_with_base() -> impl IntoResponse {
|
||||
let mut html =
|
||||
String::from_utf8_lossy(&FrontEndAssets::get("index.html").unwrap().data).to_string();
|
||||
|
||||
let raw_base = &SETTINGS.bichon_base_url;
|
||||
let base_href = if raw_base.ends_with('/') {
|
||||
raw_base.clone()
|
||||
} else {
|
||||
format!("{}/", raw_base)
|
||||
};
|
||||
|
||||
let inject_content = format!(
|
||||
r#"<base href="{}"><script>window.__BICHON_BASE__ = '{}';</script>"#,
|
||||
base_href, raw_base
|
||||
);
|
||||
|
||||
html = html.replace("<head>", &format!("<head>{}", inject_content));
|
||||
poem::Response::builder()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(html)
|
||||
}
|
||||
|
||||
@@ -74,6 +74,16 @@ pub struct Settings {
|
||||
)]
|
||||
pub bichon_public_url: String,
|
||||
|
||||
/// bichon base URL path (default: "/")
|
||||
#[clap(
|
||||
long,
|
||||
default_value = "/",
|
||||
env,
|
||||
help = "Set the base UI path for bichon (e.g., '/bichon' or '/bichon/'). Must start with /",
|
||||
value_parser = validate_base_url
|
||||
)]
|
||||
pub bichon_base_url: String,
|
||||
|
||||
/// CORS allowed origins (default: "*")
|
||||
#[clap(
|
||||
long,
|
||||
@@ -381,6 +391,18 @@ impl Settings {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_base_url(s: &str) -> Result<String, String> {
|
||||
if s == "/" {
|
||||
return Ok(s.to_string());
|
||||
}
|
||||
if !s.starts_with('/') {
|
||||
return Err(String::from(
|
||||
"Base URL must start with '/' (e.g., '/bichon')",
|
||||
));
|
||||
}
|
||||
Ok(s.to_string())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
|
||||
pub enum CompressionAlgorithm {
|
||||
#[clap(name = "none")]
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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'>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
base: '',
|
||||
plugins: [react(), TanStackRouterVite()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in New Issue
Block a user