@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
JavaScript
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?.();
}
};
};