diff --git a/web/packages/teleterm/src/ui/TopBar/AdditionalActions.story.tsx b/web/packages/teleterm/src/ui/TopBar/AdditionalActions.story.tsx new file mode 100644 index 0000000000000..701de28792529 --- /dev/null +++ b/web/packages/teleterm/src/ui/TopBar/AdditionalActions.story.tsx @@ -0,0 +1,96 @@ +/** + * Copyright 2023 Gravitational, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import * as icons from 'design/Icon'; + +import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvider'; + +import { Menu, MenuItem } from './AdditionalActions'; + +export default { + title: 'Teleterm/AdditionalActions', +}; + +export const MenuItems = () => { + return ( + + + { + alert('Hello!'); + }, + }} + /> + + + + + + + ); +}; + +const noop = () => {}; diff --git a/web/packages/teleterm/src/ui/TopBar/AdditionalActions.tsx b/web/packages/teleterm/src/ui/TopBar/AdditionalActions.tsx index 793d716d9f078..1d1f2d0b07205 100644 --- a/web/packages/teleterm/src/ui/TopBar/AdditionalActions.tsx +++ b/web/packages/teleterm/src/ui/TopBar/AdditionalActions.tsx @@ -32,11 +32,14 @@ import { useNewTabOpener } from 'teleterm/ui/TabHost'; type MenuItem = { title: string; isVisible: boolean; - Icon: React.ComponentType<{ fontSize: number }>; + Icon: React.ElementType; onNavigate: () => void; prependSeparator?: boolean; keyboardShortcutAction?: KeyboardShortcutAction; -}; +} & (MenuItemAlwaysEnabled | MenuItemConditionallyDisabled); + +type MenuItemAlwaysEnabled = { isDisabled?: false }; +type MenuItemConditionallyDisabled = { isDisabled: true; disabledText: string }; function useMenuItems(): MenuItem[] { const ctx = useAppContext(); @@ -51,6 +54,7 @@ function useMenuItems(): MenuItem[] { localClusterUri: workspacesService.getActiveWorkspace()?.localClusterUri, }); + const hasNoActiveWorkspace = !documentsService; const areAccessRequestsSupported = !!activeRootCluster?.features?.advancedAccessWorkflows; @@ -61,6 +65,9 @@ function useMenuItems(): MenuItem[] { { title: 'Open new terminal', isVisible: true, + isDisabled: hasNoActiveWorkspace, + disabledText: + 'You need to be logged in to a cluster to open new terminals.', Icon: icons.Terminal, keyboardShortcutAction: 'newTerminalTab', onNavigate: openTerminalTab, @@ -137,10 +144,11 @@ export function AdditionalActions() { const items = useMenuItems().map(item => { return ( - - {item.prependSeparator && } - setIsPopoverOpened(false)} /> - + setIsPopoverOpened(false)} + /> ); }); @@ -168,7 +176,7 @@ export function AdditionalActions() { ); } -const Menu = styled.menu` +export const Menu = styled.menu` list-style: none; padding: 0; margin: 0; @@ -183,7 +191,7 @@ const Separator = styled.div` height: 1px; `; -function MenuItem({ +export function MenuItem({ item, closeMenu, }: { @@ -197,32 +205,44 @@ function MenuItem({ }; return ( - - - + {item.prependSeparator && } + - {item.title} - - {item.keyboardShortcutAction && ( - props.theme.space[1]}px - ${props => props.theme.space[1]}px; - `} - bg="levels.surface" - > - {getAccelerator(item.keyboardShortcutAction)} - - )} - - + + + {item.title} + + {item.keyboardShortcutAction && ( + + props.theme.colors.spotBackground[0]}; + padding: ${props => props.theme.space[1]}px + ${props => props.theme.space[1]}px; + `} + > + {getAccelerator(item.keyboardShortcutAction)} + + )} + + + ); } @@ -231,4 +251,13 @@ const StyledListItem = styled(ListItem)` gap: ${props => props.theme.space[3]}px; padding: 0 ${props => props.theme.space[3]}px; border-radius: 0; + + &:disabled { + cursor: default; + color: ${props => props.theme.colors.text.disabled}; + + &:hover { + background-color: inherit; + } + } `;