mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
Merge pull request 'fix/admin-panel-bugs-4' (#75) from fix/admin-panel-bugs-4 into release/v9.1.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/server/pulls/75
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
import {useEffect, useState} from 'react';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
import {useLocation, useNavigate} from 'react-router-dom';
|
||||
import {fetchUser, selectUser, selectUserLoading, selectIsAuthenticated} from '../../store/slices/userSlice';
|
||||
import {checkSetupRequired} from '../../api';
|
||||
import Spinner from '../../assets/Spinner.svg';
|
||||
@ -10,8 +9,6 @@ import ServerUnavailable from '../ServerUnavailable/ServerUnavailable';
|
||||
|
||||
export default function AuthWrapper({children}) {
|
||||
const dispatch = useDispatch();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const user = useSelector(selectUser);
|
||||
const loading = useSelector(selectUserLoading);
|
||||
const isAuthenticated = useSelector(selectIsAuthenticated);
|
||||
@ -20,24 +17,6 @@ export default function AuthWrapper({children}) {
|
||||
const [checkingSetup, setCheckingSetup] = useState(true);
|
||||
const [serverUnavailable, setServerUnavailable] = useState(false);
|
||||
|
||||
// Save intended URL for redirect after setup/login
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated && location.pathname !== '/admin/setup' && location.pathname !== '/admin/login') {
|
||||
sessionStorage.setItem('redirectAfterAuth', location.pathname + location.search);
|
||||
}
|
||||
}, [location, isAuthenticated]);
|
||||
|
||||
// Redirect after successful authentication
|
||||
useEffect(() => {
|
||||
if (isAuthenticated && user) {
|
||||
const redirectUrl = sessionStorage.getItem('redirectAfterAuth');
|
||||
if (redirectUrl) {
|
||||
sessionStorage.removeItem('redirectAfterAuth');
|
||||
navigate(redirectUrl, {replace: true});
|
||||
}
|
||||
}
|
||||
}, [isAuthenticated, user, navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
const checkSetup = async () => {
|
||||
try {
|
||||
|
||||
@ -194,6 +194,8 @@
|
||||
}
|
||||
|
||||
AI.onLoadInternalProviders();
|
||||
if (Asc.plugin.sendEvent)
|
||||
Asc.plugin.sendEvent("ai_onLoadInternalProviders");
|
||||
};
|
||||
|
||||
AI.InternalCustomProvidersSources = {};
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
import {useState, useEffect, useCallback} from 'react';
|
||||
import {useSelector, useDispatch} from 'react-redux';
|
||||
import {selectConfig, saveConfig} from '../../../store/slices/configSlice';
|
||||
import {registerShowWindowCallback, registerCloseWindowCallback, registerSaveCallback, initAISettings} from '../js/plugins-sdk';
|
||||
import {
|
||||
registerShowWindowCallback,
|
||||
registerCloseWindowCallback,
|
||||
registerSaveCallback,
|
||||
registerLoadInternalProvidersCallback,
|
||||
initAISettings
|
||||
} from '../js/plugins-sdk';
|
||||
|
||||
/**
|
||||
* Custom hook for managing complete AI plugin functionality
|
||||
@ -11,6 +17,7 @@ import {registerShowWindowCallback, registerCloseWindowCallback, registerSaveCal
|
||||
*/
|
||||
const useAiPlugin = statisticsData => {
|
||||
const [pluginWindows, setPluginWindows] = useState([]);
|
||||
const [internalProvidersLoaded, setInternalProvidersLoaded] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const config = useSelector(selectConfig);
|
||||
|
||||
@ -121,16 +128,22 @@ const useAiPlugin = statisticsData => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoadInternalProviders = () => {
|
||||
setInternalProvidersLoaded(true);
|
||||
};
|
||||
|
||||
// Register all callbacks with SDK
|
||||
registerShowWindowCallback(handleShowWindow);
|
||||
registerCloseWindowCallback(handleCloseWindow);
|
||||
registerSaveCallback(handleSave);
|
||||
registerLoadInternalProvidersCallback(handleLoadInternalProviders);
|
||||
|
||||
// Cleanup: unregister all callbacks
|
||||
return () => {
|
||||
registerShowWindowCallback(null);
|
||||
registerCloseWindowCallback(null);
|
||||
registerSaveCallback(null);
|
||||
registerLoadInternalProvidersCallback(null);
|
||||
};
|
||||
}, [config, dispatch]);
|
||||
|
||||
@ -139,7 +152,8 @@ const useAiPlugin = statisticsData => {
|
||||
return {
|
||||
pluginWindows,
|
||||
currentWindow,
|
||||
handleIframeLoad
|
||||
handleIframeLoad,
|
||||
internalProvidersLoaded
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ export default function AiIntegration() {
|
||||
});
|
||||
|
||||
// Use custom hook for complete AI plugin functionality
|
||||
const {currentWindow, handleIframeLoad} = useAiPlugin(data);
|
||||
const {currentWindow, handleIframeLoad, internalProvidersLoaded} = useAiPlugin(data);
|
||||
|
||||
// Constants
|
||||
const AI_IFRAME_SRC = `ai/index.html`;
|
||||
@ -58,7 +58,8 @@ export default function AiIntegration() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', height: '100%', position: 'relative'}}>
|
||||
<iframe id={AI_IFRAME_ID} title='AI Settings' src={AI_IFRAME_SRC} style={iframeStyle} onLoad={() => handleIframeLoad(AI_IFRAME_ID)} />
|
||||
{currentWindow && (
|
||||
{!internalProvidersLoaded && <div>Please, wait...</div>}
|
||||
{internalProvidersLoaded && currentWindow && (
|
||||
<div key={currentWindow.iframeId} style={{width: '100%', height: '100%'}}>
|
||||
<PageHeader>{currentWindow.description || ''} </PageHeader>
|
||||
<iframe id={currentWindow.iframeId} title={currentWindow.description || ''} src={currentWindow.url} style={pluginWindowStyle} />
|
||||
|
||||
@ -9,6 +9,7 @@ const mainButtonId = 'settings.html';
|
||||
let showPluginWindowCallback = null;
|
||||
let closePluginWindowCallback = null;
|
||||
let saveCallback = null;
|
||||
let loadInternalProvidersCallback = null;
|
||||
|
||||
let settingsButton = null;
|
||||
|
||||
@ -390,6 +391,11 @@ function handleMethod(data) {
|
||||
} else if (data.methodName === 'CloseWindow') {
|
||||
CloseWindow(data.data);
|
||||
handleMethodReturn(undefined);
|
||||
} else if (data.methodName === 'SendEvent') {
|
||||
if (data.data && data.data[0] === 'ai_onLoadInternalProviders' && loadInternalProvidersCallback) {
|
||||
loadInternalProvidersCallback();
|
||||
}
|
||||
handleMethodReturn(undefined);
|
||||
} else {
|
||||
handleMethodReturn(undefined);
|
||||
}
|
||||
@ -543,4 +549,12 @@ function registerSaveCallback(callback) {
|
||||
saveCallback = callback;
|
||||
}
|
||||
|
||||
export {initAISettings, registerShowWindowCallback, registerCloseWindowCallback, registerSaveCallback};
|
||||
/**
|
||||
* Registers callback for loading internal providers
|
||||
* @param {function} callback - Function to call when internal providers should be loaded () => void
|
||||
*/
|
||||
function registerLoadInternalProvidersCallback(callback) {
|
||||
loadInternalProvidersCallback = callback;
|
||||
}
|
||||
|
||||
export {initAISettings, registerShowWindowCallback, registerCloseWindowCallback, registerSaveCallback, registerLoadInternalProvidersCallback};
|
||||
|
||||
@ -67,9 +67,9 @@ router.patch('/', validateJWT, rawFileParser, async (req, res) => {
|
||||
await runtimeConfigManager.saveConfig(ctx, validationResult.value);
|
||||
}
|
||||
|
||||
await ctx.initTenantCache();
|
||||
const filteredConfig = getScopedConfig(ctx);
|
||||
res.status(200).json(filteredConfig);
|
||||
const newConfig = await runtimeConfigManager.getConfig(ctx);
|
||||
|
||||
res.status(200).json(newConfig);
|
||||
} catch (error) {
|
||||
ctx.logger.error('Configuration save error: %s', error.stack);
|
||||
res.status(500).json({error: 'Internal server error', details: error.message});
|
||||
|
||||
@ -38,7 +38,7 @@ const utils = require('../../../../../Common/sources/utils');
|
||||
const runtimeConfigManager = require('../../../../../Common/sources/runtimeConfigManager');
|
||||
const tenantManager = require('../../../../../Common/sources/tenantManager');
|
||||
const {validateJWT} = require('../../middleware/auth');
|
||||
const {getScopedConfig} = require('../config/config.service');
|
||||
const {getConfig} = require('../../../../../Common/sources/runtimeConfigManager');
|
||||
const cookieParser = require('cookie-parser');
|
||||
|
||||
const router = express.Router();
|
||||
@ -156,8 +156,8 @@ router.post('/rotate-keys', validateJWT, express.json(), async (req, res) => {
|
||||
try {
|
||||
ctx.logger.info('WOPI key rotation start');
|
||||
|
||||
const currentConfig = ctx.getFullCfg();
|
||||
const wopiConfig = utils.getImpl(currentConfig, 'wopi') || {};
|
||||
const currentConfig = await getConfig(ctx);
|
||||
const wopiConfig = currentConfig.wopi || {};
|
||||
|
||||
const newWopiConfig = generateWopiKeys();
|
||||
|
||||
@ -184,9 +184,7 @@ router.post('/rotate-keys', validateJWT, express.json(), async (req, res) => {
|
||||
await runtimeConfigManager.saveConfig(ctx, newConfig);
|
||||
}
|
||||
|
||||
await ctx.initTenantCache();
|
||||
const filteredConfig = getScopedConfig(ctx);
|
||||
res.status(200).json(filteredConfig);
|
||||
res.status(200).json(newConfig);
|
||||
} catch (error) {
|
||||
ctx.logger.error('WOPI key rotation error: %s', error.stack);
|
||||
res.status(500).json({
|
||||
|
||||
@ -201,7 +201,7 @@ function concatParams(...parameters) {
|
||||
function getTableColumns(ctx, tableName) {
|
||||
const values = [];
|
||||
const sqlParam = addSqlParameter(tableName, values);
|
||||
const sqlCommand = `SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME = ${sqlParam} AND TABLE_SCHEMA = 'dbo';`;
|
||||
const sqlCommand = `SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME = ${sqlParam} AND TABLE_SCHEMA = SCHEMA_NAME();`;
|
||||
return executeQuery(ctx, sqlCommand, values);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user