Skip to content

Commit

Permalink
feat: Add config toolbar (#18036)
Browse files Browse the repository at this point in the history
* feat: Add config toolbar

* use div

* tie to enable debug

* use only for features

* add outside click close

* add a bit of box shadow

* add basic debug functions

* use isMetaKey

* remove sorting

* move styles to separate file

* Update src/script/components/ConfigToolbar/ConfigToolbar.styles.tsx

Co-authored-by: Virgile <78490891+V-Gira@users.noreply.github.com>

---------

Co-authored-by: Virgile <78490891+V-Gira@users.noreply.github.com>
  • Loading branch information
thisisamir98 and V-Gira authored Sep 13, 2024
1 parent 5804d79 commit 4697848
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/script/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ const Config = {
getConfig: () => {
return config;
},
_dangerouslySetConfigFeaturesForDebug: (newConfigFeatures: Configuration['FEATURE']) => {
(config.FEATURE as unknown) = newConfigFeatures;
},
getDesktopConfig: () => {
if (!Runtime.isDesktopApp) {
return undefined;
Expand Down
33 changes: 33 additions & 0 deletions src/script/components/ConfigToolbar/ConfigToolbar.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Wire
* Copyright (C) 2022 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {CSSObject} from '@emotion/react';

export const wrapperStyles: CSSObject = {
position: 'fixed',
top: 0,
right: 0,
width: '400px',
height: '100vh',
backgroundColor: 'var(--sidebar-bg)',
padding: '20px',
overflow: 'auto',
zIndex: 100000000,
boxShadow: '3px 1px 6px 1px #000',
};
128 changes: 128 additions & 0 deletions src/script/components/ConfigToolbar/ConfigToolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {useState, useEffect, useRef} from 'react';

import {Button, Input, Switch} from '@wireapp/react-ui-kit';

import {Config, Configuration} from 'src/script/Config';
import {useClickOutside} from 'src/script/hooks/useClickOutside';
import {isMetaKey} from 'Util/KeyboardUtil';

import {wrapperStyles} from './ConfigToolbar.styles';

export function ConfigToolbar() {
const [showConfig, setShowConfig] = useState(false);
const [configFeaturesState, setConfigFeaturesState] = useState<Configuration['FEATURE']>(Config.getConfig().FEATURE);
const wrapperRef = useRef(null);

// Toggle config tool on 'cmd/ctrl + shift + 2'
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (isMetaKey(event) && event.shiftKey && event.key === '2') {
setShowConfig(prev => !prev);
}
};

window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, []);

// Update the config state when form input changes
const handleChange = (path: string, value: string | boolean | string[]) => {
const updateConfig = (obj: any, keys: string[]): void => {
if (keys.length === 1) {
obj[keys[0]] = value;
} else {
updateConfig(obj[keys[0]], keys.slice(1));
}
};

const updatedConfig = {...configFeaturesState};
updateConfig(updatedConfig, path.split('.'));
setConfigFeaturesState(updatedConfig);
Config._dangerouslySetConfigFeaturesForDebug(updatedConfig);
};

const renderInput = (value: string | boolean | string[] | number | object | null, path: string) => {
if (typeof value === 'boolean') {
return <Switch checked={value} onToggle={isChecked => handleChange(path, isChecked)} />;
}

if (Array.isArray(value)) {
return (
<Input
type="text"
value={value.join(',')}
onChange={event =>
handleChange(
path,
event.currentTarget.value.split(',').map(value => value.trim()),
)
}
/>
);
}

if (typeof value === 'object' && value !== null) {
return renderConfig(value, path);
}

return (
<Input type="text" value={value as string} onChange={event => handleChange(path, event.currentTarget.value)} />
);
};

const renderConfig = (configObj: object, parentPath: string = '') => {
const entries = Object.entries(configObj);

return entries.map(([key, value]) => {
const path = parentPath ? `${parentPath}.${key}` : key;
return (
<div key={path} style={{marginBottom: '10px'}}>
<label style={{display: 'block', fontWeight: 'bold'}}>{key.split('_').join(' ')}</label>
{renderInput(value, path)}
</div>
);
});
};

useClickOutside(wrapperRef, () => setShowConfig(false));

if (!showConfig) {
return null;
}

return (
<div ref={wrapperRef} css={wrapperStyles}>
<h3>Configuration Tool</h3>
<h4 style={{color: 'red', fontWeight: 'bold'}}>
Caution: Modifying these settings can affect the behavior of the application. Ensure you understand the
implications of each change before proceeding. Changes may cause unexpected behavior.
</h4>
<div>{renderConfig(configFeaturesState)}</div>
<h3>Debug Functions</h3>
<Button onClick={() => window.wire?.app?.debug?.reconnectWebSocket()}>reconnectWebSocket</Button>
<Button onClick={() => window.wire?.app?.debug?.enablePushToTalk()}>enablePushToTalk</Button>
<Button onClick={() => window.wire?.app?.debug?.enablePushToTalk(null)}>disablePushToTalk</Button>
</div>
);
}
3 changes: 3 additions & 0 deletions src/script/page/AppMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ import {WebAppEvents} from '@wireapp/webapp-events';

import {CallingContainer} from 'Components/calling/CallingOverlayContainer';
import {ChooseScreen} from 'Components/calling/ChooseScreen';
import {ConfigToolbar} from 'Components/ConfigToolbar/ConfigToolbar';
import {ErrorFallback} from 'Components/ErrorFallback';
import {GroupCreationModal} from 'Components/Modals/GroupCreation/GroupCreationModal';
import {LegalHoldModal} from 'Components/Modals/LegalHoldModal/LegalHoldModal';
import {PrimaryModal} from 'Components/Modals/PrimaryModal';
import {showUserModal, UserModal} from 'Components/Modals/UserModal';
import {Config} from 'src/script/Config';
import {useKoSubscribableChildren} from 'Util/ComponentUtil';

import {AppLock} from './AppLock';
Expand Down Expand Up @@ -245,6 +247,7 @@ export const AppMain: FC<AppMainProps> = ({
{!locked && <WindowTitleUpdater />}
<RootProvider value={mainView}>
<ErrorBoundary FallbackComponent={ErrorFallback}>
{Config.getConfig().FEATURE.ENABLE_DEBUG && <ConfigToolbar />}
{!locked && (
<div id="app" className="app">
{showLeftSidebar && (
Expand Down

0 comments on commit 4697848

Please sign in to comment.