diff --git a/.env.example b/.env.example index b76a1fa..f6d2f69 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,8 @@ UVICORN_PORT = 8000 # SUDO_USERNAME = "admin" # SUDO_PASSWORD = "admin" +# DASHBOARD_PATH = "/dashboard/" + # UVICORN_UDS: "/run/marzban.socket" # UVICORN_SSL_CERTFILE = "/var/lib/marzban/certs/example.com/fullchain.pem" # UVICORN_SSL_KEYFILE = "/var/lib/marzban/certs/example.com/key.pem" diff --git a/app/marzneshin.py b/app/marzneshin.py index 62978bf..0c322fc 100644 --- a/app/marzneshin.py +++ b/app/marzneshin.py @@ -24,6 +24,7 @@ from config import ( UVICORN_SSL_CERTFILE, UVICORN_SSL_KEYFILE, UVICORN_UDS, + DASHBOARD_PATH, ) from . import __version__, telegram @@ -39,7 +40,6 @@ from .tasks import ( ) logger = logging.getLogger(__name__) -dashboard_path = "/dashboard/" app = FastAPI( title="MarzneshinAPI", @@ -110,10 +110,20 @@ def validation_exception_handler(request: Request, exc: RequestValidationError): async def main(): if not DEBUG: app.mount( - "/dashboard/", + DASHBOARD_PATH, StaticFiles(directory="dashboard/dist", html=True), name="dashboard", ) + app.mount( + "/static/", + StaticFiles(directory="dashboard/dist/static"), + name="static", + ) + app.mount( + "/locales/", + StaticFiles(directory="dashboard/dist/locales"), + name="locales", + ) scheduler.start() asyncio.create_task(telegram.start_bot()) cfg = Config( diff --git a/config.py b/config.py index 328b55e..33ebacb 100755 --- a/config.py +++ b/config.py @@ -4,6 +4,7 @@ from dotenv import load_dotenv load_dotenv() +DASHBOARD_PATH = config("DASHBOARD_PATH", default="/dashboard/") SQLALCHEMY_DATABASE_URL = config( "SQLALCHEMY_DATABASE_URL", default="sqlite:///db.sqlite3" diff --git a/dashboard/src/features/i18n/index.ts b/dashboard/src/features/i18n/index.ts index 594a003..e56deb7 100644 --- a/dashboard/src/features/i18n/index.ts +++ b/dashboard/src/features/i18n/index.ts @@ -5,39 +5,39 @@ import HttpApi from 'i18next-http-backend'; import { initReactI18next } from 'react-i18next'; declare module 'i18next' { - interface CustomTypeOptions { - returnNull: false; - } + interface CustomTypeOptions { + returnNull: false; + } } i18n - .use(LanguageDetector) - .use(HttpApi) - .use(initReactI18next) - .init({ - debug: process.env.NODE_ENV === 'development', - fallbackLng: 'en', - interpolation: { - escapeValue: false, - }, - react: { - useSuspense: false, - }, - load: 'languageOnly', - detection: { - order: ['localStorage', 'sessionStorage', 'cookie', 'navigator'], - }, - backend: { - loadPath: '/locales/{{lng}}.json', - }, - supportedLngs: ['en', 'kur', 'kmr', 'ckb', 'fa', 'ru'], - }) - .then(() => { - dayjs.locale(i18n.language); - }); + .use(LanguageDetector) + .use(HttpApi) + .use(initReactI18next) + .init({ + debug: process.env.NODE_ENV === 'development', + fallbackLng: 'en', + interpolation: { + escapeValue: false, + }, + react: { + useSuspense: false, + }, + load: 'languageOnly', + detection: { + order: ['localStorage', 'sessionStorage', 'cookie', 'navigator'], + }, + backend: { + loadPath: `/locales/{{lng}}.json`, + }, + supportedLngs: ['en', 'kur', 'kmr', 'ckb', 'fa', 'ru'], + }) + .then(() => { + dayjs.locale(i18n.language); + }); i18n.on('languageChanged', (lng) => { - dayjs.locale(lng); + dayjs.locale(lng); }); export default i18n; diff --git a/dashboard/vite.config.ts b/dashboard/vite.config.ts index 5be9876..5814d73 100644 --- a/dashboard/vite.config.ts +++ b/dashboard/vite.config.ts @@ -6,18 +6,22 @@ import path from 'path'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - TanStackRouterVite(), - tsconfigPaths(), - react() - ], - root: '.', - resolve: { - alias: [ - { - find: '@marzneshin', - replacement: path.resolve(__dirname, './src/'), - }, + plugins: [ + TanStackRouterVite(), + tsconfigPaths(), + react() ], - }, + root: '.', + build: { + assetsDir: 'static', + outDir: 'dist' + }, + resolve: { + alias: [ + { + find: '@marzneshin', + replacement: path.resolve(__dirname, './src/'), + }, + ], + }, }) diff --git a/makefile b/makefile index 05baf39..b0555d6 100644 --- a/makefile +++ b/makefile @@ -7,20 +7,20 @@ dashboard-deps: pnpm install --prefix ./dashboard dashboard-build: - cd dashboard; VITE_BASE_API=/api/ npm run build --if-present -- --outDir dist --base '/dashboard/' + cd dashboard; VITE_BASE_API=/api/ npm run build --if-present -- --outDir 'dist' --assetsDir 'static' dashboard-dev: VITE_BASE_API=http://0.0.0.0:8000/api/ npm run dev \ --prefix './dashboard/' \ -- --host 0.0.0.0 \ - --base /dashboard/ \ + --base /dashboard \ --clearScreen false dashboard-preview: VITE_BASE_API=http://0.0.0.0:8000/api/ npm run preview \ --prefix './dashboard/' \ -- --host 0.0.0.0 \ - --base /dashboard/ \ + --base /dashboard \ --clearScreen false dashboard-cleanup: