mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-04-07 14:04:35 +08:00
[feature] Reset config settings
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import {useState, useRef} from 'react';
|
import {useState, useRef, useEffect} from 'react';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
import {saveConfig, selectConfig} from '../../store/slices/configSlice';
|
import {saveConfig, resetConfig, selectConfig} from '../../store/slices/configSlice';
|
||||||
import {getNestedValue} from '../../utils/getNestedValue';
|
import {getNestedValue} from '../../utils/getNestedValue';
|
||||||
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
||||||
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
||||||
@ -8,7 +8,7 @@ import PageHeader from '../../components/PageHeader/PageHeader';
|
|||||||
import PageDescription from '../../components/PageDescription/PageDescription';
|
import PageDescription from '../../components/PageDescription/PageDescription';
|
||||||
import Tabs from '../../components/Tabs/Tabs';
|
import Tabs from '../../components/Tabs/Tabs';
|
||||||
import Input from '../../components/Input/Input';
|
import Input from '../../components/Input/Input';
|
||||||
import FixedSaveButton from '../../components/FixedSaveButton/FixedSaveButton';
|
import FixedSaveButtonGroup from '../../components/FixedSaveButtonGroup/FixedSaveButtonGroup';
|
||||||
import styles from './Expiration.module.scss';
|
import styles from './Expiration.module.scss';
|
||||||
|
|
||||||
const expirationTabs = [
|
const expirationTabs = [
|
||||||
@ -46,11 +46,12 @@ function Expiration() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Reset state and errors to global config
|
// Reset state and errors to global config
|
||||||
const resetToGlobalConfig = () => {
|
const resetToGlobalConfig = source => {
|
||||||
if (config) {
|
const src = source || config;
|
||||||
|
if (src) {
|
||||||
const settings = {};
|
const settings = {};
|
||||||
Object.keys(CONFIG_PATHS).forEach(key => {
|
Object.keys(CONFIG_PATHS).forEach(key => {
|
||||||
const value = getNestedValue(config, CONFIG_PATHS[key], '');
|
const value = getNestedValue(src, CONFIG_PATHS[key], '');
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
});
|
});
|
||||||
setLocalSettings(settings);
|
setLocalSettings(settings);
|
||||||
@ -74,6 +75,12 @@ function Expiration() {
|
|||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync from Redux when config changes (e.g., after reset), unless user has local edits
|
||||||
|
useEffect(() => {
|
||||||
|
if (config && !hasChanges) {
|
||||||
|
resetToGlobalConfig();
|
||||||
|
}
|
||||||
|
}, [config]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
// Handle field changes
|
// Handle field changes
|
||||||
const handleFieldChange = (field, value) => {
|
const handleFieldChange = (field, value) => {
|
||||||
setLocalSettings(prev => ({
|
setLocalSettings(prev => ({
|
||||||
@ -129,6 +136,24 @@ function Expiration() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle reset for active tab
|
||||||
|
const handleReset = async () => {
|
||||||
|
const confirmed = window.confirm('Reset settings on this tab to defaults?');
|
||||||
|
if (!confirmed) return;
|
||||||
|
try {
|
||||||
|
const paths =
|
||||||
|
activeTab === 'garbage-collection'
|
||||||
|
? [CONFIG_PATHS.filesCron, CONFIG_PATHS.documentsCron, CONFIG_PATHS.files, CONFIG_PATHS.filesremovedatonce]
|
||||||
|
: [CONFIG_PATHS.sessionidle, CONFIG_PATHS.sessionabsolute];
|
||||||
|
const merged = await dispatch(resetConfig(paths)).unwrap();
|
||||||
|
resetToGlobalConfig(merged);
|
||||||
|
setHasChanges(false);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to reset expiration settings:', e);
|
||||||
|
alert('Failed to reset settings. Please try again.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Render tab content
|
// Render tab content
|
||||||
const renderTabContent = () => {
|
const renderTabContent = () => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
@ -224,9 +249,20 @@ function Expiration() {
|
|||||||
{renderTabContent()}
|
{renderTabContent()}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<FixedSaveButton onClick={handleSave} disabled={!hasChanges || hasValidationErrors()}>
|
<FixedSaveButtonGroup
|
||||||
Save Changes
|
buttons={[
|
||||||
</FixedSaveButton>
|
{
|
||||||
|
text: 'Save Changes',
|
||||||
|
onClick: handleSave,
|
||||||
|
disabled: !hasChanges || hasValidationErrors()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reset to Defaults',
|
||||||
|
onClick: handleReset,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import {useState, useEffect} from 'react';
|
import {useState, useEffect} from 'react';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
import {saveConfig, selectConfig} from '../../store/slices/configSlice';
|
import {saveConfig, resetConfig, selectConfig} from '../../store/slices/configSlice';
|
||||||
import {getNestedValue} from '../../utils/getNestedValue';
|
import {getNestedValue} from '../../utils/getNestedValue';
|
||||||
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
||||||
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
||||||
import PageHeader from '../../components/PageHeader/PageHeader';
|
import PageHeader from '../../components/PageHeader/PageHeader';
|
||||||
import PageDescription from '../../components/PageDescription/PageDescription';
|
import PageDescription from '../../components/PageDescription/PageDescription';
|
||||||
import Input from '../../components/Input/Input';
|
import Input from '../../components/Input/Input';
|
||||||
import FixedSaveButton from '../../components/FixedSaveButton/FixedSaveButton';
|
import FixedSaveButtonGroup from '../../components/FixedSaveButtonGroup/FixedSaveButtonGroup';
|
||||||
import styles from './FileLimits.module.scss';
|
import styles from './FileLimits.module.scss';
|
||||||
|
|
||||||
function FileLimits() {
|
function FileLimits() {
|
||||||
@ -163,6 +163,20 @@ function FileLimits() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle reset to defaults
|
||||||
|
const handleReset = async () => {
|
||||||
|
const confirmed = window.confirm('Reset file limits to defaults? This cannot be undone.');
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await dispatch(resetConfig(['FileConverter.converter.maxDownloadBytes', 'FileConverter.converter.inputLimits'])).unwrap();
|
||||||
|
setHasChanges(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error resetting file limits:', error);
|
||||||
|
alert('Failed to reset file limits. Please try again.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.fileLimits} ${styles.pageWithFixedSave}`}>
|
<div className={`${styles.fileLimits} ${styles.pageWithFixedSave}`}>
|
||||||
<PageHeader>File Size Limits</PageHeader>
|
<PageHeader>File Size Limits</PageHeader>
|
||||||
@ -230,9 +244,20 @@ function FileLimits() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FixedSaveButton onClick={handleSave} disabled={!hasChanges || hasValidationErrors()}>
|
<FixedSaveButtonGroup
|
||||||
Save Changes
|
buttons={[
|
||||||
</FixedSaveButton>
|
{
|
||||||
|
text: 'Save Changes',
|
||||||
|
onClick: handleSave,
|
||||||
|
disabled: !hasChanges || hasValidationErrors()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reset to Defaults',
|
||||||
|
onClick: handleReset,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import {useState, useRef} from 'react';
|
import {useState, useRef, useEffect} from 'react';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
import {saveConfig, selectConfig} from '../../store/slices/configSlice';
|
import {saveConfig, resetConfig, selectConfig} from '../../store/slices/configSlice';
|
||||||
import {getNestedValue} from '../../utils/getNestedValue';
|
import {getNestedValue} from '../../utils/getNestedValue';
|
||||||
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
||||||
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
||||||
import Checkbox from '../../components/Checkbox/Checkbox';
|
import Checkbox from '../../components/Checkbox/Checkbox';
|
||||||
import FixedSaveButton from '../../components/FixedSaveButton/FixedSaveButton';
|
import FixedSaveButtonGroup from '../../components/FixedSaveButtonGroup/FixedSaveButtonGroup';
|
||||||
import PageHeader from '../../components/PageHeader/PageHeader';
|
import PageHeader from '../../components/PageHeader/PageHeader';
|
||||||
import PageDescription from '../../components/PageDescription/PageDescription';
|
import PageDescription from '../../components/PageDescription/PageDescription';
|
||||||
import styles from './RequestFiltering.module.scss';
|
import styles from './RequestFiltering.module.scss';
|
||||||
@ -28,12 +28,13 @@ function RequestFiltering() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hasInitialized = useRef(false);
|
const hasInitialized = useRef(false);
|
||||||
const resetToGlobalConfig = () => {
|
const resetToGlobalConfig = source => {
|
||||||
if (config) {
|
const src = source || config;
|
||||||
|
if (src) {
|
||||||
const newSettings = {};
|
const newSettings = {};
|
||||||
Object.keys(CONFIG_PATHS).forEach(key => {
|
Object.keys(CONFIG_PATHS).forEach(key => {
|
||||||
const path = CONFIG_PATHS[key];
|
const path = CONFIG_PATHS[key];
|
||||||
newSettings[key] = getNestedValue(config, path, false);
|
newSettings[key] = getNestedValue(src, path, false);
|
||||||
});
|
});
|
||||||
setLocalSettings(newSettings);
|
setLocalSettings(newSettings);
|
||||||
}
|
}
|
||||||
@ -44,6 +45,12 @@ function RequestFiltering() {
|
|||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync from Redux when config changes (e.g., after reset), unless user has local edits
|
||||||
|
useEffect(() => {
|
||||||
|
if (config && !hasChanges) {
|
||||||
|
resetToGlobalConfig();
|
||||||
|
}
|
||||||
|
}, [config]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
// Handle field changes
|
// Handle field changes
|
||||||
const handleFieldChange = (field, value) => {
|
const handleFieldChange = (field, value) => {
|
||||||
setLocalSettings(prev => ({
|
setLocalSettings(prev => ({
|
||||||
@ -82,6 +89,19 @@ function RequestFiltering() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleReset = async () => {
|
||||||
|
const confirmed = window.confirm('Reset request filtering settings to defaults?');
|
||||||
|
if (!confirmed) return;
|
||||||
|
try {
|
||||||
|
const merged = await dispatch(resetConfig(Object.values(CONFIG_PATHS))).unwrap();
|
||||||
|
resetToGlobalConfig(merged);
|
||||||
|
setHasChanges(false);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to reset request filtering:', e);
|
||||||
|
alert('Failed to reset settings. Please try again.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.requestFiltering} ${styles.pageWithFixedSave}`}>
|
<div className={`${styles.requestFiltering} ${styles.pageWithFixedSave}`}>
|
||||||
<PageHeader>Request Filtering</PageHeader>
|
<PageHeader>Request Filtering</PageHeader>
|
||||||
@ -114,9 +134,20 @@ function RequestFiltering() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FixedSaveButton onClick={handleSave} disabled={!hasChanges || hasValidationErrors()}>
|
<FixedSaveButtonGroup
|
||||||
Save Changes
|
buttons={[
|
||||||
</FixedSaveButton>
|
{
|
||||||
|
text: 'Save Changes',
|
||||||
|
onClick: handleSave,
|
||||||
|
disabled: !hasChanges || hasValidationErrors()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reset to Defaults',
|
||||||
|
onClick: handleReset,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {useState, useRef} from 'react';
|
import {useState, useRef, useEffect} from 'react';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
import {saveConfig, selectConfig} from '../../store/slices/configSlice';
|
import {saveConfig, resetConfig, selectConfig} from '../../store/slices/configSlice';
|
||||||
import {getNestedValue} from '../../utils/getNestedValue';
|
import {getNestedValue} from '../../utils/getNestedValue';
|
||||||
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
||||||
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
||||||
@ -8,7 +8,7 @@ import PageHeader from '../../components/PageHeader/PageHeader';
|
|||||||
import PageDescription from '../../components/PageDescription/PageDescription';
|
import PageDescription from '../../components/PageDescription/PageDescription';
|
||||||
import Tabs from '../../components/Tabs/Tabs';
|
import Tabs from '../../components/Tabs/Tabs';
|
||||||
import AccessRules from '../../components/AccessRules/AccessRules';
|
import AccessRules from '../../components/AccessRules/AccessRules';
|
||||||
import FixedSaveButton from '../../components/FixedSaveButton/FixedSaveButton';
|
import FixedSaveButtonGroup from '../../components/FixedSaveButtonGroup/FixedSaveButtonGroup';
|
||||||
import styles from './SecuritySettings.module.scss';
|
import styles from './SecuritySettings.module.scss';
|
||||||
|
|
||||||
const securityTabs = [{key: 'ip-filtering', label: 'IP Filtering'}];
|
const securityTabs = [{key: 'ip-filtering', label: 'IP Filtering'}];
|
||||||
@ -23,9 +23,10 @@ function SecuritySettings() {
|
|||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
|
|
||||||
// Reset state and errors to global config
|
// Reset state and errors to global config
|
||||||
const resetToGlobalConfig = () => {
|
const resetToGlobalConfig = source => {
|
||||||
if (config) {
|
const src = source || config;
|
||||||
const ipFilterRules = getNestedValue(config, 'services.CoAuthoring.ipfilter.rules', []);
|
if (src) {
|
||||||
|
const ipFilterRules = getNestedValue(src, 'services.CoAuthoring.ipfilter.rules', []);
|
||||||
const uiRules = ipFilterRules.map(rule => ({
|
const uiRules = ipFilterRules.map(rule => ({
|
||||||
type: rule.allowed ? 'Allow' : 'Deny',
|
type: rule.allowed ? 'Allow' : 'Deny',
|
||||||
value: rule.address
|
value: rule.address
|
||||||
@ -50,6 +51,12 @@ function SecuritySettings() {
|
|||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync from Redux when config changes (e.g., after reset), unless user has local edits
|
||||||
|
useEffect(() => {
|
||||||
|
if (config && !hasChanges) {
|
||||||
|
resetToGlobalConfig();
|
||||||
|
}
|
||||||
|
}, [config]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
// Handle rules changes
|
// Handle rules changes
|
||||||
const handleRulesChange = newRules => {
|
const handleRulesChange = newRules => {
|
||||||
setLocalRules(newRules);
|
setLocalRules(newRules);
|
||||||
@ -85,6 +92,23 @@ function SecuritySettings() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleReset = async () => {
|
||||||
|
const confirmed = window.confirm('Reset security settings on this tab to defaults?');
|
||||||
|
if (!confirmed) return;
|
||||||
|
try {
|
||||||
|
// Only reset active tab settings
|
||||||
|
const paths = activeTab === 'ip-filtering' ? ['services.CoAuthoring.ipfilter.rules'] : [];
|
||||||
|
if (paths.length > 0) {
|
||||||
|
const merged = await dispatch(resetConfig(paths)).unwrap();
|
||||||
|
resetToGlobalConfig(merged);
|
||||||
|
}
|
||||||
|
setHasChanges(false);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to reset security settings:', e);
|
||||||
|
alert('Failed to reset settings. Please try again.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderTabContent = () => {
|
const renderTabContent = () => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
case 'ip-filtering':
|
case 'ip-filtering':
|
||||||
@ -110,9 +134,20 @@ function SecuritySettings() {
|
|||||||
{renderTabContent()}
|
{renderTabContent()}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<FixedSaveButton onClick={handleSave} disabled={!hasChanges || hasValidationErrors()}>
|
<FixedSaveButtonGroup
|
||||||
Save Changes
|
buttons={[
|
||||||
</FixedSaveButton>
|
{
|
||||||
|
text: 'Save Changes',
|
||||||
|
onClick: handleSave,
|
||||||
|
disabled: !hasChanges || hasValidationErrors()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reset to Defaults',
|
||||||
|
onClick: handleReset,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {useState, useRef} from 'react';
|
import {useState, useRef, useEffect} from 'react';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
import {saveConfig, selectConfig, rotateWopiKeysAction} from '../../store/slices/configSlice';
|
import {saveConfig, resetConfig, selectConfig, rotateWopiKeysAction} from '../../store/slices/configSlice';
|
||||||
import {getNestedValue} from '../../utils/getNestedValue';
|
import {getNestedValue} from '../../utils/getNestedValue';
|
||||||
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
import {mergeNestedObjects} from '../../utils/mergeNestedObjects';
|
||||||
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
import {useFieldValidation} from '../../hooks/useFieldValidation';
|
||||||
@ -10,7 +10,7 @@ import PageDescription from '../../components/PageDescription/PageDescription';
|
|||||||
import ToggleSwitch from '../../components/ToggleSwitch/ToggleSwitch';
|
import ToggleSwitch from '../../components/ToggleSwitch/ToggleSwitch';
|
||||||
import Input from '../../components/Input/Input';
|
import Input from '../../components/Input/Input';
|
||||||
import Checkbox from '../../components/Checkbox/Checkbox';
|
import Checkbox from '../../components/Checkbox/Checkbox';
|
||||||
import FixedSaveButton from '../../components/FixedSaveButton/FixedSaveButton';
|
import FixedSaveButtonGroup from '../../components/FixedSaveButtonGroup/FixedSaveButtonGroup';
|
||||||
import Note from '../../components/Note/Note';
|
import Note from '../../components/Note/Note';
|
||||||
import styles from './WOPISettings.module.scss';
|
import styles from './WOPISettings.module.scss';
|
||||||
|
|
||||||
@ -31,14 +31,17 @@ function WOPISettings() {
|
|||||||
const wopiPublicKey = getNestedValue(config, 'wopi.publicKey', '');
|
const wopiPublicKey = getNestedValue(config, 'wopi.publicKey', '');
|
||||||
const configRefreshLockInterval = getNestedValue(config, 'wopi.refreshLockInterval', '10m');
|
const configRefreshLockInterval = getNestedValue(config, 'wopi.refreshLockInterval', '10m');
|
||||||
|
|
||||||
const resetToGlobalConfig = () => {
|
const resetToGlobalConfig = source => {
|
||||||
if (config) {
|
const src = source || config;
|
||||||
setLocalWopiEnabled(configWopiEnabled);
|
if (src) {
|
||||||
|
const srcEnabled = getNestedValue(src, 'wopi.enable');
|
||||||
|
const srcInterval = getNestedValue(src, 'wopi.refreshLockInterval');
|
||||||
|
setLocalWopiEnabled(srcEnabled);
|
||||||
setLocalRotateKeys(false);
|
setLocalRotateKeys(false);
|
||||||
setLocalRefreshLockInterval(configRefreshLockInterval);
|
setLocalRefreshLockInterval(srcInterval);
|
||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
validateField('wopi.enable', configWopiEnabled);
|
validateField('wopi.enable', srcEnabled);
|
||||||
validateField('wopi.refreshLockInterval', configRefreshLockInterval);
|
validateField('wopi.refreshLockInterval', srcInterval);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,6 +51,12 @@ function WOPISettings() {
|
|||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync from Redux when config changes (e.g., after reset), unless user has local edits
|
||||||
|
useEffect(() => {
|
||||||
|
if (config && !hasChanges) {
|
||||||
|
resetToGlobalConfig();
|
||||||
|
}
|
||||||
|
}, [config]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
const handleWopiEnabledChange = enabled => {
|
const handleWopiEnabledChange = enabled => {
|
||||||
setLocalWopiEnabled(enabled);
|
setLocalWopiEnabled(enabled);
|
||||||
// If WOPI is disabled, uncheck rotate keys
|
// If WOPI is disabled, uncheck rotate keys
|
||||||
@ -118,6 +127,20 @@ function WOPISettings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleReset = async () => {
|
||||||
|
const confirmed = window.confirm('Reset WOPI settings to defaults?');
|
||||||
|
if (!confirmed) return;
|
||||||
|
try {
|
||||||
|
const merged = await dispatch(resetConfig(['wopi.enable', 'wopi.refreshLockInterval'])).unwrap();
|
||||||
|
resetToGlobalConfig(merged);
|
||||||
|
setHasChanges(false);
|
||||||
|
setLocalRotateKeys(false);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to reset WOPI settings:', e);
|
||||||
|
alert('Failed to reset settings. Please try again.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.wopiSettings} ${styles.pageWithFixedSave}`}>
|
<div className={`${styles.wopiSettings} ${styles.pageWithFixedSave}`}>
|
||||||
<PageHeader>WOPI Settings</PageHeader>
|
<PageHeader>WOPI Settings</PageHeader>
|
||||||
@ -175,9 +198,20 @@ function WOPISettings() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<FixedSaveButton onClick={handleSave} disabled={!hasChanges || hasValidationErrors()}>
|
<FixedSaveButtonGroup
|
||||||
Save Changes
|
buttons={[
|
||||||
</FixedSaveButton>
|
{
|
||||||
|
text: 'Save Changes',
|
||||||
|
onClick: handleSave,
|
||||||
|
disabled: !hasChanges || hasValidationErrors()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reset to Defaults',
|
||||||
|
onClick: handleReset,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user