UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

250 lines (249 loc) 14.2 kB
import * as React from 'react'; import kebabCase from 'lodash/kebabCase'; import * as ToolPanelRedux from '../../../Redux/ActionsReducers/ToolPanelRedux'; import { connect } from 'react-redux'; import { Flex } from 'rebass'; import ArrayExtensions from '../../../Utilities/Extensions/ArrayExtensions'; import { Icon } from '../../../components/icons'; import { CheckBox } from '../../../components/CheckBox'; import DropdownButton from '../../../components/DropdownButton'; import { ALL_TOOL_PANELS, } from '../../../AdaptableState/Common/Types'; import SimpleButton from '../../../components/SimpleButton'; import { ButtonConfigure } from '../Buttons/ButtonConfigure'; import { renderWithAdaptableContext } from '../../renderWithAdaptableContext'; import { ToolPanelWrapper } from './ToolPanelWrapper'; import { ToolPanelConfigView } from './ToolPanelPopup'; import { createUuid } from '../../../components/utils/uuid'; import { ToolPanelModuleId } from '../../../Utilities/Constants/ModuleConstants'; import HelpBlock from '../../../components/HelpBlock'; const preventDefault = (e) => e.preventDefault(); const AdaptableToolPanelComponent = (props) => { const toolPanelsGlyph = React.createElement(Icon, { name: 'align-justify' }); const moduleService = props.api.internalApi.getModuleService(); const adaptableOptions = props.api.optionsApi.getAdaptableOptions(); const toolPanelOptions = adaptableOptions.toolPanelOptions; const settingsPanelOptions = adaptableOptions.settingsPanelOptions; if (props.api.entitlementApi.isModuleHiddenEntitlement('ToolPanel')) { // do NOT show any toolPanel content if the required entitlements are missing return (React.createElement(HelpBlock, { mt: 2, mb: 2, p: 2, style: { fontSize: 'var(--ab-font-size-3)' } }, "Not enough rights")); } const availableModuleItems = props.MainMenuItems.filter((menuItem) => menuItem.isVisible); const availableModules = availableModuleItems.map((menuItem) => menuItem.category); // 'Dashboard' is a special case because it's not available in the dashboard menu items, s we have to add it manually if (!props.api.entitlementApi.isModuleHiddenEntitlement('Dashboard')) { availableModules.push('Dashboard'); } if (props.api.pluginsApi.getipushpullPluginApi() && !props.api.entitlementApi.isModuleHiddenEntitlement('IPushPull')) { availableModules.push('IPushPull'); } if (props.api.pluginsApi.getOpenFinPluginApi() && !props.api.entitlementApi.isModuleHiddenEntitlement('OpenFin')) { availableModules.push('OpenFin'); } const availableModuleToolPanels = ALL_TOOL_PANELS.filter((moduleToolPanel) => ArrayExtensions.ContainsItem(availableModules, moduleToolPanel)); const onStateChange = (toolPanel, visibilityMode) => { if (visibilityMode === 'expanded') { props.onExpandToolPanel(toolPanel); } else { props.onCollapseToolPanel(toolPanel); } }; const isToolPanelModuleConfigurable = props.api.internalApi .getModuleService() .getModuleById(ToolPanelModuleId) .isModuleEditable(); const visibleToolPanels = []; const visibleToolPanelControls = (props.ToolPanels ?? []).map((toolPanelDefinition) => { const visibilityMode = toolPanelDefinition.VisibilityMode ?? 'collapsed'; // 1. check if it is a custom toolPanel const customToolPanel = props.api.toolPanelApi.getCustomToolPanelByName(toolPanelDefinition.Name); if (customToolPanel) { visibleToolPanels.push(customToolPanel.name); return (React.createElement(ToolPanelWrapper, { key: customToolPanel.name, customToolPanel: customToolPanel, visibilityMode: visibilityMode, onVisibilityModeChange: (state) => onStateChange(customToolPanel.name, state) })); } // 2. check if it's an available module toolPanel if (availableModuleToolPanels.some((module) => module === toolPanelDefinition.Name)) { // assertion is safe as if just checked it in the if clause const moduleToolPanel = toolPanelDefinition.Name; visibleToolPanels.push(moduleToolPanel); return (React.createElement(ToolPanelWrapper, { key: moduleToolPanel, adaptableToolPanel: moduleToolPanel, visibilityMode: visibilityMode, onVisibilityModeChange: (state) => onStateChange(moduleToolPanel, state) })); } }); const renderToolPanelDropdowns = () => { if (!toolPanelOptions.showToolPanelsDropdown) { return; } let toolpanelItems = [ { clickable: false, label: (React.createElement("div", { key: "toolPanelTitle" }, ' ', "\u00A0\u00A0", React.createElement("b", null, 'Tool Panels'), renderToolPanelConfigureButton(ToolPanelConfigView.ToolPanels))), }, ]; const isItemVisible = (panelItem) => visibleToolPanels.includes(panelItem); const buildDropdownButtonItem = (toolPanel, label, isVisible) => { return { id: toolPanel, onClick: () => { onSetToolPanelVisibility(toolPanel, !isVisible); }, label: (React.createElement(CheckBox, { className: "ab-dd-checkbox", variant: "agGrid", my: 0, as: "div", value: toolPanel, key: toolPanel, checked: isVisible, onMouseDown: preventDefault }, toolPanel)), }; }; // 1. process custom tool panels props.api.toolPanelApi.getCustomToolPanels().forEach((customToolPanel) => { const customToolPanelName = customToolPanel.name; toolpanelItems.push(buildDropdownButtonItem(customToolPanelName, customToolPanelName, isItemVisible(customToolPanelName))); }); // 2. process module tool panels availableModuleToolPanels.forEach((toolPanel) => { let moduleName = moduleService.getModuleInfoByModule(toolPanel).FriendlyName; toolpanelItems.push(buildDropdownButtonItem(toolPanel, moduleName, isItemVisible(toolPanel))); }); // 3. sort the dropdown items alphabetically toolpanelItems.sort((first, second) => { if (first.label < second.label) { return -1; } if (first.label > second.label) { return 1; } return 0; }); return (React.createElement(DropdownButton, { variant: "text", tone: "none", collapseOnItemClick: false, key: 'dropdown-toolpanels', id: 'dropdown-toolpanels', className: "ab-ToolPanel__toolbars", columns: ['label'], items: toolpanelItems, tooltip: "Manage Tool Panels" }, toolPanelsGlyph)); }; const renderToolPanelButtons = () => { const toolPanelButtons = []; let moduleButtons = props.ModuleButtons; const shouldAddSettingsPanel = settingsPanelOptions.alwaysShowInToolPanel && !props.api.entitlementApi.isModuleHiddenEntitlement('SettingsPanel'); if (shouldAddSettingsPanel && !moduleButtons.includes('SettingsPanel')) { moduleButtons = ['SettingsPanel', ...moduleButtons]; } if (moduleButtons?.length) { toolPanelButtons.push(moduleButtons.map((x) => { let menuItem = props.MainMenuItems.find((y) => y.isVisible && y.category == x); if (menuItem) { return (React.createElement(SimpleButton, { "data-name": menuItem.category, key: menuItem.label, icon: menuItem.icon, tone: "none", variant: "text", className: `ab-ToolPanel__Home__${kebabCase(menuItem.label)}`, tooltip: menuItem.label, onClick: () => props.onClick(menuItem.reduxAction), accessLevel: 'Full' })); } })); } return toolPanelButtons; }; const renderCustomToolPanelButtons = () => { return props.api.toolPanelApi.getCustomToolPanelButtons().map((button) => { // TODO: variants of this mapping are present in several places (just search for api.internalApi.getStyleForButton() usages) // with the next opportunity we should abstract it const toolPanelContext = { ...props.api.internalApi.buildBaseContext(), toolPanelState: props.api.toolPanelApi.getToolPanelState(), }; const buttonIcon = props.api.internalApi.getIconForButton(button, toolPanelContext); let buttonStyle = props.api.internalApi.getStyleForButton(button, toolPanelContext); let buttonLabel = props.api.internalApi.getLabelForButton(button, toolPanelContext); let buttonTooltip = props.api.internalApi.getTooltipForButton(button, toolPanelContext); if (button.hidden && button.hidden(button, toolPanelContext)) { return null; } const disabled = button.disabled && button.disabled(button, toolPanelContext); const buttonVariant = buttonStyle && buttonStyle.variant ? buttonStyle.variant : 'text'; const buttonTone = buttonStyle && buttonStyle.tone ? buttonStyle.tone : 'none'; const uniqueKey = buttonLabel ?? createUuid(); return (React.createElement(SimpleButton, { key: uniqueKey, variant: buttonVariant, tone: buttonTone, className: `ab-ToolPanel__Home__${kebabCase(buttonLabel)} ${buttonStyle?.className || ''}`, tooltip: buttonTooltip, icon: buttonIcon, disabled: disabled, onClick: () => button.onClick(button, toolPanelContext), accessLevel: 'Full' }, buttonLabel)); }); }; const onSetToolPanelVisibility = (name, checked) => { if (checked) { props.onShowToolPanel(name); } else { props.onHideToolPanel(name); } }; const renderToolPanelConfigureButton = (initialTab) => { const moduleParams = initialTab ? { source: 'Other', config: { initialTab } } : undefined; return (React.createElement(ButtonConfigure, { iconSize: 16, tone: "none", marginLeft: 2, className: "ab-ToolPanel__configure-button", tooltip: 'Configure ToolPanels', onClick: () => { props.api.internalApi.showSettingsPanel('ToolPanel', moduleParams); } })); }; const toolPanelButtons = renderToolPanelButtons(); return (React.createElement(Flex, { className: "ab-ToolPanel", "data-name": "adaptable-tool-panel", flexDirection: "column", justifyContent: "center", padding: 2, style: { width: '100%', // Cannot have the with of the parent, on windows, when you have scrollbars // the inner-width is smaller // minWidth: 'var(--ab-cmp-toolpanel__width)', } }, React.createElement(Flex, { className: "ab-ToolPanel__header", flexDirection: "row", justifyContent: "left", padding: 1, flexWrap: "wrap", style: { width: '100%' } }, isToolPanelModuleConfigurable && renderToolPanelDropdowns(), toolPanelButtons, isToolPanelModuleConfigurable && renderToolPanelConfigureButton()), Boolean(props.api.toolPanelApi.getCustomToolPanelButtons().length) && (React.createElement(Flex, { className: "ab-ToolPanel__header__buttons", flexDirection: "row", justifyContent: "left", padding: 1, flexWrap: "wrap" }, renderCustomToolPanelButtons())), visibleToolPanelControls)); }; function mapStateToProps(state) { return { ToolPanels: state.ToolPanel.ToolPanels, ModuleButtons: state.ToolPanel.ModuleButtons, MainMenuItems: state.Internal.SettingsPanelModuleEntries, Columns: state.Internal.Columns, }; } function mapDispatchToProps(dispatch) { return { onClick: (action) => dispatch(action), onSetToolPanelVisibility: (toolPanels) => dispatch(ToolPanelRedux.ToolPanelSetToolPanels(toolPanels)), onShowToolPanel: (toolPanel) => dispatch(ToolPanelRedux.ToolPanelShowToolPanel(toolPanel)), onHideToolPanel: (toolPanel) => dispatch(ToolPanelRedux.ToolPanelHideToolPanel(toolPanel)), onExpandToolPanel: (toolPanel) => dispatch(ToolPanelRedux.ToolPanelExpandToolPanel(toolPanel)), onCollapseToolPanel: (toolPanel) => dispatch(ToolPanelRedux.ToolPanelCollapseToolPanel(toolPanel)), }; } export const ConnectedAdaptableToolPanel = connect(mapStateToProps, mapDispatchToProps)(AdaptableToolPanelComponent); const toolPanelContainerStyle = { width: '100%', overflow: 'auto', }; export const getAdaptableToolPanelAgGridComponent = (adaptable) => { function getContainerId() { return 'adaptable-tool-panel_' + adaptable.adaptableOptions.adaptableId; } if (adaptable.variant === 'react') { return () => { const content = renderWithAdaptableContext(React.createElement(ConnectedAdaptableToolPanel, { api: adaptable.api, teamSharingActivated: false }), adaptable); return (React.createElement("div", { id: getContainerId(), className: 'ag-adaptable-panel', style: toolPanelContainerStyle }, content)); }; } return class AdaptableToolPanelAgGridComponent { init(params) { const api = adaptable.api; this.gui = document.createElement('div'); this.gui.id = getContainerId(); // preserve AG Grid naming convention this.gui.className = 'ag-adaptable-panel'; Object.keys(toolPanelContainerStyle).forEach((key) => { //@ts-ignore this.gui.style[key] = toolPanelContainerStyle[key]; }); this.unmountReactRoot = adaptable.renderReactRoot(renderWithAdaptableContext(React.createElement(ConnectedAdaptableToolPanel, { api: api, teamSharingActivated: false }), adaptable), this.gui); } getGui() { if (!this.gui) { this.init(); } return this.gui; } refresh() { // no refresh logic needed } destroy() { this.unmountReactRoot?.(); } }; };