From 94f57413af03756048878c4ff922b2a964e6b7f0 Mon Sep 17 00:00:00 2001 From: Sandro Mani Date: Mon, 28 Oct 2024 11:52:43 +0100 Subject: [PATCH] Filter allowed menu/toolbar items in TopBar --- components/AppMenu.jsx | 28 ++----------------------- components/Toolbar.jsx | 40 +++++++++--------------------------- plugins/TopBar.jsx | 46 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 58 deletions(-) diff --git a/components/AppMenu.jsx b/components/AppMenu.jsx index 3cd19d432..d9e4d75d9 100644 --- a/components/AppMenu.jsx +++ b/components/AppMenu.jsx @@ -19,10 +19,8 @@ import PropTypes from 'prop-types'; import {setCurrentTask} from '../actions/task'; import {setMenuMargin} from '../actions/windows'; import InputContainer from '../components/InputContainer'; -import ConfigUtils from '../utils/ConfigUtils'; import LocaleUtils from '../utils/LocaleUtils'; import MiscUtils from '../utils/MiscUtils'; -import ThemeUtils from '../utils/ThemeUtils'; import Icon from './Icon'; import './style/AppMenu.css'; @@ -34,7 +32,6 @@ class AppMenu extends React.Component { appMenuShortcut: PropTypes.string, buttonContents: PropTypes.object, currentTaskBlocked: PropTypes.bool, - currentTheme: PropTypes.object, keepMenuOpen: PropTypes.bool, menuCompact: PropTypes.bool, menuItems: PropTypes.array, @@ -93,9 +90,7 @@ class AppMenu extends React.Component { this.addKeyBindings(item.subitems); } else if (item.shortcut) { mousetrap.bind(item.shortcut, () => { - if (this.itemAllowed(item)) { - this.onMenuitemClicked(item); - } + this.onMenuitemClicked(item); return false; }); this.boundShortcuts.push(item.shortcut); @@ -218,9 +213,6 @@ class AppMenu extends React.Component { renderMenuItems = (items, level, filter, path) => { if (items) { return items.map((item, idx) => { - if (!this.itemAllowed(item)) { - return null; - } const active = isEqual(this.state.curEntry, [...path, idx]); if (item.subitems) { const subitems = this.renderMenuItems(item.subitems, level + 1, filter, [...path, idx]); @@ -318,26 +310,10 @@ class AppMenu extends React.Component { mousetrap(el).bind(this.props.appMenuShortcut, this.toggleMenu); } }; - itemAllowed = (item) => { - if (!ThemeUtils.themFlagsAllowed(this.props.currentTheme, item.themeFlagWhitelist, item. themeFlagBlacklist)) { - return false; - } - if (item.themeBlacklist && (item.themeBlacklist.includes(this.props.currentTheme.title) || item.themeBlacklist.includes(this.props.currentTheme.name))) { - return false; - } - if (item.themeWhitelist && !(item.themeWhitelist.includes(this.props.currentTheme.title) || item.themeWhitelist.includes(this.props.currentTheme.name))) { - return false; - } - if (item.requireAuth && !ConfigUtils.getConfigProp("username")) { - return false; - } - return true; - }; } export default connect((state) => ({ - currentTaskBlocked: state.task.blocked, - currentTheme: state.theme.current || {} + currentTaskBlocked: state.task.blocked }), { setCurrentTask: setCurrentTask, setMenuMargin: setMenuMargin diff --git a/components/Toolbar.jsx b/components/Toolbar.jsx index 2f63a0055..0d8da83da 100644 --- a/components/Toolbar.jsx +++ b/components/Toolbar.jsx @@ -13,7 +13,6 @@ import Mousetrap from 'mousetrap'; import PropTypes from 'prop-types'; import {setCurrentTask} from '../actions/task'; -import ConfigUtils from '../utils/ConfigUtils'; import LocaleUtils from '../utils/LocaleUtils'; import Icon from './Icon'; @@ -23,7 +22,6 @@ class Toolbar extends React.Component { static propTypes = { currentTask: PropTypes.string, currentTaskMode: PropTypes.string, - currentTheme: PropTypes.object, openExternalUrl: PropTypes.func, setCurrentTask: PropTypes.func, toolbarItems: PropTypes.array, @@ -34,30 +32,25 @@ class Toolbar extends React.Component { this.boundShortcuts = []; } componentDidUpdate(prevProps) { - if (this.props.currentTheme !== prevProps.currentTheme) { + if (this.props.toolbarItems !== prevProps.toolbarItems) { this.boundShortcuts.forEach(shortcut => Mousetrap.unbind(shortcut)); this.boundShortcuts = []; if (this.props.toolbarItemsShortcutPrefix) { let index = 1; this.props.toolbarItems.forEach(item => { - if (this.itemAllowed(item)) { - const shortcut = this.props.toolbarItemsShortcutPrefix + '+' + index; - Mousetrap.bind(shortcut, () => { - const active = this.props.currentTask === (item.task || item.key) && this.props.currentTaskMode === (item.mode || null); - this.itemClicked(item, active); - return false; - }); - this.boundShortcuts.push(shortcut); - index += 1; - } + const shortcut = this.props.toolbarItemsShortcutPrefix + '+' + index; + Mousetrap.bind(shortcut, () => { + const active = this.props.currentTask === (item.task || item.key) && this.props.currentTaskMode === (item.mode || null); + this.itemClicked(item, active); + return false; + }); + this.boundShortcuts.push(shortcut); + index += 1; }); } } } renderToolbarItem = (item) => { - if (!this.itemAllowed(item)) { - return null; - } const active = this.props.currentTask === (item.task || item.key) && this.props.currentTaskMode === (item.mode || null); const title = LocaleUtils.tr("appmenu.items." + item.key + (item.mode || "")); return ( @@ -71,18 +64,6 @@ class Toolbar extends React.Component { /> ); }; - itemAllowed = (item) => { - if (item.themeBlacklist && (item.themeBlacklist.includes(this.props.currentTheme.title) || item.themeBlacklist.includes(this.props.currentTheme.name))) { - return false; - } - if (item.themeWhitelist && !(item.themeWhitelist.includes(this.props.currentTheme.title) || item.themeWhitelist.includes(this.props.currentTheme.name))) { - return false; - } - if (item.requireAuth && !ConfigUtils.getConfigProp("username")) { - return false; - } - return true; - }; itemClicked = (item, active) => { if (item.url) { this.props.openExternalUrl(item.url, item.target, LocaleUtils.tr("appmenu.items." + item.key), item.icon); @@ -103,8 +84,7 @@ class Toolbar extends React.Component { export default connect((state) => ({ currentTask: state.task.id, - currentTaskMode: state.task.mode, - currentTheme: state.theme.current || {} + currentTaskMode: state.task.mode }), { setCurrentTask: setCurrentTask })(Toolbar); diff --git a/plugins/TopBar.jsx b/plugins/TopBar.jsx index 1a02579bc..8ff21c104 100644 --- a/plugins/TopBar.jsx +++ b/plugins/TopBar.jsx @@ -10,6 +10,7 @@ import React from 'react'; import {connect} from 'react-redux'; import classnames from 'classnames'; +import isEmpty from 'lodash.isempty'; import PropTypes from 'prop-types'; import {toggleFullscreen} from '../actions/display'; @@ -20,6 +21,7 @@ import Icon from '../components/Icon'; import {Swipeable} from '../components/Swipeable'; import ConfigUtils from '../utils/ConfigUtils'; import LocaleUtils from '../utils/LocaleUtils'; +import ThemeUtils from '../utils/ThemeUtils'; import './style/TopBar.css'; @@ -42,6 +44,7 @@ class TopBar extends React.Component { /** Whether to open the app menu on application startup. */ appMenuVisibleOnStartup: PropTypes.bool, components: PropTypes.object, + currentTheme: PropTypes.object, fullscreen: PropTypes.bool, /** The logo file format. */ logoFormat: PropTypes.string, @@ -108,6 +111,18 @@ class TopBar extends React.Component { toolbarItems: [], logoFormat: "svg" }; + state = { + allowedMenuItems: [], + allowedToolbarItems: [] + }; + componentDidUpdate(prevProps) { + if (this.props.currentTheme !== prevProps.currentTheme) { + this.setState({ + allowedToolbarItems: this.allowedItems(this.props.toolbarItems), + allowedMenuItems: this.allowedItems(this.props.menuItems) + }); + } + } render() { let buttonContents; let logo; @@ -165,7 +180,7 @@ class TopBar extends React.Component { {this.props.components.Toolbar ? ( ) : null} @@ -176,7 +191,7 @@ class TopBar extends React.Component { buttonContents={buttonContents} keepMenuOpen={keepMenuOpen} menuCompact={menuCompact} - menuItems={this.props.menuItems} + menuItems={this.state.allowedMenuItems} openExternalUrl={this.openUrl} showFilterField={this.props.appMenuFilterField} showOnStartup={showOnStartup} /> @@ -199,6 +214,32 @@ class TopBar extends React.Component { this.props.setTopbarHeight(el.clientHeight); } }; + allowedItems = (items) => { + return items.map(item => { + if (item.subitems) { + const subitems = this.allowedItems(item.subitems); + if (!isEmpty(subitems)) { + return {...item, subitems}; + } else { + return null; + } + } else { + if (!ThemeUtils.themFlagsAllowed(this.props.currentTheme, item.themeFlagWhitelist, item. themeFlagBlacklist)) { + return null; + } + if (item.themeBlacklist && (item.themeBlacklist.includes(this.props.currentTheme.title) || item.themeBlacklist.includes(this.props.currentTheme.name))) { + return null; + } + if (item.themeWhitelist && !(item.themeWhitelist.includes(this.props.currentTheme.title) || item.themeWhitelist.includes(this.props.currentTheme.name))) { + return null; + } + if (item.requireAuth && !ConfigUtils.getConfigProp("username")) { + return null; + } + return item; + } + }).filter(Boolean); + }; } export default (components) => { @@ -206,6 +247,7 @@ export default (components) => { mobile: state.browser.mobile, fullscreen: state.display.fullscreen, components: components, + currentTheme: state.theme.current, mapMargins: state.windows.mapMargins }), { toggleFullscreen: toggleFullscreen,