import { Dropdown, ICommandBarItemProps, IComponentAsProps, IconType, IDropdownOption, IDropdownStyles, } from "@fluentui/react"; import { useQueryCopilot } from "hooks/useQueryCopilot"; import { KeyboardHandlerMap } from "KeyboardShortcuts"; import * as React from "react"; import _ from "underscore"; import ChevronDownIcon from "../../../../images/Chevron_down.svg"; import { PoolIdType } from "../../../Common/Constants"; import { StyleConstants } from "../../../Common/StyleConstants"; import { configContext, Platform } from "../../../ConfigContext"; import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants"; import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import Explorer from "../../Explorer"; import { ConnectionStatus } from "./ConnectionStatusComponent"; import { MemoryTracker } from "./MemoryTrackerComponent"; /** * Convert our NavbarButtonConfig to UI Fabric buttons * @param btns */ export const convertButton = (btns: CommandButtonComponentProps[], backgroundColor: string): ICommandBarItemProps[] => { const buttonHeightPx = configContext.platform == Platform.Fabric ? StyleConstants.FabricCommandBarButtonHeight : StyleConstants.CommandBarButtonHeight; const hoverColor = configContext.platform == Platform.Fabric ? StyleConstants.FabricAccentLight : StyleConstants.AccentLight; const getFilter = (isDisabled: boolean): string => { if (isDisabled) { return StyleConstants.GrayScale; } return configContext.platform == Platform.Fabric ? StyleConstants.FabricToolbarIconColor : undefined; }; return btns .filter((btn) => btn) .map((btn: CommandButtonComponentProps, index: number): ICommandBarItemProps => { if (btn.isDivider) { return createDivider(btn.commandButtonLabel); } const isSplit = !!btn.children && btn.children.length > 0; const label = btn.commandButtonLabel || btn.tooltipText; const result: ICommandBarItemProps = { iconProps: { style: { width: StyleConstants.CommandBarIconWidth, alignSelf: btn.iconName ? "baseline" : undefined, filter: getFilter(btn.disabled), }, imageProps: btn.iconSrc ? { src: btn.iconSrc, alt: btn.iconAlt } : undefined, iconName: btn.iconName, }, onClick: btn.onCommandClick ? (ev?: React.MouseEvent | React.KeyboardEvent) => { btn.onCommandClick(ev); let copilotEnabled = false; if (useQueryCopilot.getState().copilotEnabled && useQueryCopilot.getState().copilotUserDBEnabled) { copilotEnabled = useQueryCopilot.getState().copilotEnabledforExecution; } TelemetryProcessor.trace(Action.ClickCommandBarButton, ActionModifiers.Mark, { label, copilotEnabled }); } : undefined, key: `${btn.commandButtonLabel}${index}`, text: label, title: btn.tooltipText, name: label, disabled: btn.disabled, ariaLabel: btn.ariaLabel, "data-test": `CommandBar/Button:${label}`, buttonStyles: { root: { backgroundColor: "var(--colorNeutralBackground1)", height: buttonHeightPx, paddingRight: 0, paddingLeft: 0, borderRadius: configContext.platform == Platform.Fabric ? StyleConstants.FabricButtonBorderRadius : "0px", minWidth: 24, marginLeft: isSplit ? 0 : 5, marginRight: isSplit ? 0 : 5, color: "var(--colorNeutralForeground1)", selectors: { "&:hover": { backgroundColor: "var(--colorNeutralBackground1Hover)", color: "var(--colorNeutralForeground1)", }, "&:active": { backgroundColor: "var(--colorNeutralBackground1Pressed)", color: "var(--colorNeutralForeground1)", }, }, }, rootDisabled: { backgroundColor: "var(--colorNeutralBackground1)", pointerEvents: "auto", color: "var(--colorNeutralForegroundDisabled)", }, splitButtonMenuButton: { backgroundColor: "var(--colorNeutralBackground1)", selectors: { ":hover": { backgroundColor: "var(--colorNeutralBackground1Hover)", }, }, width: 16, }, label: { fontSize: configContext.platform == Platform.Fabric ? StyleConstants.DefaultFontSize : StyleConstants.mediumFontSize, color: "var(--colorNeutralForeground1)", }, rootHovered: { backgroundColor: "var(--colorNeutralBackground1Hover)", color: "var(--colorNeutralForeground1)", }, rootPressed: { backgroundColor: "var(--colorNeutralBackground1Pressed)", color: "var(--colorNeutralForeground1)", }, splitButtonMenuButtonExpanded: { backgroundColor: "var(--colorNeutralBackground1Pressed)", selectors: { ":hover": { backgroundColor: "var(--colorNeutralBackground1Hover)", }, }, }, splitButtonDivider: { display: "none", }, icon: { paddingLeft: 0, paddingRight: 0, color: "var(--colorNeutralForeground1)", }, splitButtonContainer: { marginLeft: 5, marginRight: 5, height: buttonHeightPx, }, }, className: btn.className, id: btn.id, }; if (isSplit) { // It's a split button result.split = true; result.subMenuProps = { items: convertButton(btn.children, backgroundColor), styles: { list: { // TODO Figure out how to do it the proper way with subComponentStyles. // TODO Remove all this crazy styling once we adopt Ui-Fabric Azure themes selectors: { ".ms-ContextualMenu-itemText": { fontSize: configContext.platform == Platform.Fabric ? StyleConstants.DefaultFontSize : StyleConstants.mediumFontSize, }, ".ms-ContextualMenu-link:hover": { backgroundColor: hoverColor }, ".ms-ContextualMenu-icon": { width: 16, height: 16 }, }, }, }, }; result.menuIconProps = { iconType: IconType.image, style: { width: 12, paddingLeft: 1, paddingTop: 6, filter: getFilter(btn.disabled), }, imageProps: { src: ChevronDownIcon, alt: btn.iconAlt, }, }; } if (btn.isDropdown) { const selectedChild = _.find(btn.children, (child) => child.dropdownItemKey === btn.dropdownSelectedKey); result.name = selectedChild?.commandButtonLabel || btn.dropdownPlaceholder; const dropdownStyles: Partial = { root: { margin: 5 }, dropdown: { width: btn.dropdownWidth }, title: { fontSize: 12, height: 30, lineHeight: 28 }, dropdownItem: { fontSize: 12, lineHeight: 28, minHeight: 30 }, dropdownItemSelected: { fontSize: 12, lineHeight: 28, minHeight: 30 }, }; const onDropdownChange = ( event: React.FormEvent, option?: IDropdownOption, index?: number, ): void => { btn.children[index].onCommandClick(event); TelemetryProcessor.trace(Action.ClickCommandBarButton, ActionModifiers.Mark, { label: option.text }); }; result.commandBarButtonAs = (props: IComponentAsProps) => { return ( ({ key: child.dropdownItemKey, text: child.commandButtonLabel, }))} styles={dropdownStyles} /> ); }; } return result; }); }; export const createDivider = (key: string): ICommandBarItemProps => { return { onRender: () => (
), iconOnly: true, disabled: true, key: key, }; }; export const createMemoryTracker = (key: string): ICommandBarItemProps => { return { key, onRender: () => , }; }; export const createConnectionStatus = (container: Explorer, poolId: PoolIdType, key: string): ICommandBarItemProps => { return { key, onRender: () => , }; }; export function createKeyboardHandlers(allButtons: CommandButtonComponentProps[]): KeyboardHandlerMap { const handlers: KeyboardHandlerMap = {}; function createHandlers(buttons: CommandButtonComponentProps[]) { buttons.forEach((button) => { if (!button.disabled && button.keyboardAction) { handlers[button.keyboardAction] = (e) => { button.onCommandClick(e); // If the handler is bound, it means the button is visible and enabled, so we should prevent the default action return true; }; } if (button.children && button.children.length > 0) { createHandlers(button.children); } }); } createHandlers(allButtons); return handlers; }