mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[feature] Refactor env, routing
This commit is contained in:
@ -1 +1,2 @@
|
|||||||
REACT_APP_BACKEND_URL=http://localhost:9000
|
REACT_APP_BACKEND_URL=http://localhost:9000
|
||||||
|
REACT_APP_BASE_PATH=/admin
|
||||||
|
|||||||
@ -1 +1,12 @@
|
|||||||
REACT_APP_BACKEND_URL=http://localhost:9000
|
# Admin Panel Environment Variables
|
||||||
|
# Copy this file to .env for local development
|
||||||
|
|
||||||
|
# Backend URL for API calls
|
||||||
|
REACT_APP_BACKEND_URL=http://localhost:9000
|
||||||
|
|
||||||
|
# Base path for the admin panel (empty for root deployment)
|
||||||
|
# Examples:
|
||||||
|
# REACT_APP_BASE_PATH= # Root deployment: http://localhost:3000/
|
||||||
|
# REACT_APP_BASE_PATH=/admin # Under /admin: http://localhost:3000/admin/
|
||||||
|
# REACT_APP_BASE_PATH=/docserver-admin # Under /docserver-admin: http://localhost:3000/docserver-admin/
|
||||||
|
REACT_APP_BASE_PATH=/admin
|
||||||
|
|||||||
6
AdminPanel/client/package-lock.json
generated
6
AdminPanel/client/package-lock.json
generated
@ -2768,6 +2768,12 @@
|
|||||||
"is-obj": "^2.0.0"
|
"is-obj": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "17.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz",
|
||||||
|
"integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"dunder-proto": {
|
"dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "set \"REACT_APP_BACKEND_URL=http://localhost:9000\" && webpack serve --mode=development",
|
"start": "webpack serve --mode=development",
|
||||||
"build": "webpack --mode=production"
|
"build": "webpack --mode=production"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"babel-loader": "8.2.0",
|
"babel-loader": "8.2.0",
|
||||||
"copy-webpack-plugin": "11.0.0",
|
"copy-webpack-plugin": "11.0.0",
|
||||||
"css-loader": "^6.2.0",
|
"css-loader": "^6.2.0",
|
||||||
|
"dotenv": "^17.2.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "5.5.0",
|
"html-webpack-plugin": "5.5.0",
|
||||||
"sass": "^1.77.0",
|
"sass": "^1.77.0",
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="images/favicon.ico" />
|
<link rel="icon" href="./images/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="Document Server Admin Panel" />
|
<meta name="description" content="Document Server Admin Panel" />
|
||||||
|
|||||||
@ -1,32 +1,37 @@
|
|||||||
import {Provider} from 'react-redux';
|
import {Provider} from 'react-redux';
|
||||||
import {Routes, Route, Navigate} from 'react-router-dom';
|
import {Routes, Route, Navigate, BrowserRouter} from 'react-router-dom';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import {store} from './store';
|
import {store} from './store';
|
||||||
import AuthWrapper from './components/AuthWrapper/AuthWrapper';
|
import AuthWrapper from './components/AuthWrapper/AuthWrapper';
|
||||||
import ConfigLoader from './components/ConfigLoader/ConfigLoader';
|
import ConfigLoader from './components/ConfigLoader/ConfigLoader';
|
||||||
import Menu from './components/Menu/Menu';
|
import Menu from './components/Menu/Menu';
|
||||||
import {menuItems} from './config/menuItems';
|
import {menuItems} from './config/menuItems';
|
||||||
|
import {getBasePath} from './utils/basePath';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const basePath = getBasePath();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<div className='app'>
|
<BrowserRouter basename={basePath}>
|
||||||
<AuthWrapper>
|
<div className='app'>
|
||||||
<div className='appLayout'>
|
<AuthWrapper>
|
||||||
<Menu />
|
<div className='appLayout'>
|
||||||
<div className='mainContent'>
|
<Menu />
|
||||||
<ConfigLoader>
|
<div className='mainContent'>
|
||||||
<Routes>
|
<ConfigLoader>
|
||||||
<Route path='/' element={<Navigate to='/statistics' replace />} />
|
<Routes>
|
||||||
{menuItems.map(item => (
|
<Route path='/' element={<Navigate to='/statistics' replace />} />
|
||||||
<Route key={item.key} path={item.path} element={<item.component />} />
|
{menuItems.map(item => (
|
||||||
))}
|
<Route key={item.key} path={item.path} element={<item.component />} />
|
||||||
</Routes>
|
))}
|
||||||
</ConfigLoader>
|
</Routes>
|
||||||
|
</ConfigLoader>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</AuthWrapper>
|
||||||
</AuthWrapper>
|
</div>
|
||||||
</div>
|
</BrowserRouter>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
const BACKEND_URL = process.env.REACT_APP_BACKEND_URL ?? '';
|
const BACKEND_URL = process.env.REACT_APP_BACKEND_URL ?? '';
|
||||||
|
const API_BASE_PATH = '/api/v1/admin';
|
||||||
|
|
||||||
export const fetchStatistics = async () => {
|
export const fetchStatistics = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/stat`);
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/stat`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to fetch statistics');
|
throw new Error('Failed to fetch statistics');
|
||||||
}
|
}
|
||||||
@ -9,7 +10,7 @@ export const fetchStatistics = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fetchConfiguration = async () => {
|
export const fetchConfiguration = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/config`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/config`, {
|
||||||
credentials: 'include'
|
credentials: 'include'
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -19,7 +20,7 @@ export const fetchConfiguration = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fetchConfigurationSchema = async () => {
|
export const fetchConfigurationSchema = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/config/schema`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/config/schema`, {
|
||||||
credentials: 'include'
|
credentials: 'include'
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -29,7 +30,7 @@ export const fetchConfigurationSchema = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const updateConfiguration = async configData => {
|
export const updateConfiguration = async configData => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/config`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/config`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -54,7 +55,7 @@ export const updateConfiguration = async configData => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fetchCurrentUser = async () => {
|
export const fetchCurrentUser = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/me`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/me`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include' // Include cookies in the request
|
credentials: 'include' // Include cookies in the request
|
||||||
});
|
});
|
||||||
@ -70,7 +71,7 @@ export const fetchCurrentUser = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const login = async ({tenantName, secret}) => {
|
export const login = async ({tenantName, secret}) => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/login`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/login`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -90,7 +91,7 @@ export const login = async ({tenantName, secret}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const logout = async () => {
|
export const logout = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/logout`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/logout`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -106,7 +107,7 @@ export const logout = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const rotateWopiKeys = async () => {
|
export const rotateWopiKeys = async () => {
|
||||||
const response = await fetch(`${BACKEND_URL}/api/v1/admin/wopi/rotate-keys`, {
|
const response = await fetch(`${BACKEND_URL}${API_BASE_PATH}/wopi/rotate-keys`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {StrictMode} from 'react';
|
import {StrictMode} from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import {BrowserRouter} from 'react-router-dom';
|
|
||||||
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
@ -18,9 +17,7 @@ const root = ReactDOM.createRoot(document.getElementById('root'));
|
|||||||
root.render(
|
root.render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<BrowserRouter>
|
<App />
|
||||||
<App />
|
|
||||||
</BrowserRouter>
|
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
15
AdminPanel/client/src/utils/basePath.js
Normal file
15
AdminPanel/client/src/utils/basePath.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Utility functions for handling BASE_PATH environment variable
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Get the base path from environment variable, with fallback to empty string
|
||||||
|
export const getBasePath = () => {
|
||||||
|
return process.env.REACT_APP_BASE_PATH || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a full path by combining base path with the given path
|
||||||
|
export const createPath = (path) => {
|
||||||
|
const basePath = getBasePath();
|
||||||
|
const cleanPath = path.startsWith('/') ? path : `/${path}`;
|
||||||
|
return `${basePath}${cleanPath}`;
|
||||||
|
};
|
||||||
@ -2,6 +2,19 @@ const path = require('path');
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
const dotenv = require('dotenv');
|
||||||
|
|
||||||
|
// Load environment variables from .env files
|
||||||
|
// Priority: .env.local > .env.development/.env.production > .env
|
||||||
|
const envFiles = [
|
||||||
|
'.env.local',
|
||||||
|
process.env.NODE_ENV === 'production' ? '.env.production' : '.env.development',
|
||||||
|
'.env'
|
||||||
|
];
|
||||||
|
|
||||||
|
envFiles.forEach(file => {
|
||||||
|
dotenv.config({ path: file });
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/index.js',
|
entry: './src/index.js',
|
||||||
@ -39,7 +52,8 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.REACT_APP_BACKEND_URL': JSON.stringify(process.env.REACT_APP_BACKEND_URL)
|
'process.env.REACT_APP_BACKEND_URL': JSON.stringify(process.env.REACT_APP_BACKEND_URL),
|
||||||
|
'process.env.REACT_APP_BASE_PATH': JSON.stringify(process.env.REACT_APP_BASE_PATH || '')
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user