diff --git a/web/packages/shared/components/AwsLaunchButton.tsx b/web/packages/shared/components/AwsLaunchButton.tsx index a7c2476495fcf..fcd3c3ec09a3f 100644 --- a/web/packages/shared/components/AwsLaunchButton.tsx +++ b/web/packages/shared/components/AwsLaunchButton.tsx @@ -18,7 +18,8 @@ import React from 'react'; import styled from 'styled-components'; -import { ButtonBorder, Text } from 'design'; +import { space } from 'design/system'; +import { ButtonBorder, Flex, Text, Box } from 'design'; import Menu, { MenuItem } from 'design/Menu'; import { ChevronDown } from 'design/Icon'; @@ -30,14 +31,19 @@ export class AwsLaunchButton extends React.Component { state = { open: false, anchorEl: null, + filtered: '', }; onOpen = () => { - this.setState({ open: true }); + this.setState({ open: true, filtered: '' }); }; onClose = () => { - this.setState({ open: false }); + this.setState({ open: false, filtered: '' }); + }; + + onChange = (event: React.ChangeEvent) => { + this.setState({ filtered: event.target.value }); }; render() { @@ -57,8 +63,9 @@ export class AwsLaunchButton extends React.Component { ({ - overflow: 'auto', + overflow: 'hidden', minWidth: '180px', + maxHeight: '400px', })} transformOrigin={{ vertical: 'top', @@ -74,10 +81,19 @@ export class AwsLaunchButton extends React.Component { onClose={this.onClose} > { + const lowerFilter = this.state.filtered.toLowerCase(); + const lowerDisplay = role.display.toLowerCase(); + const lowerName = role.name.toLowerCase(); + return ( + lowerDisplay.includes(lowerFilter) || + lowerName.includes(lowerFilter) + ); + })} getLaunchUrl={getLaunchUrl} onLaunchUrl={onLaunchUrl} closeMenu={this.onClose} + onChange={this.onChange} /> @@ -89,10 +105,14 @@ function RoleItemList({ awsRoles, getLaunchUrl, closeMenu, + onChange, onLaunchUrl, -}: Props & { closeMenu: () => void }) { +}: Props & { + closeMenu: () => void; + onChange: (event: React.ChangeEvent) => void; +}) { const awsRoleItems = awsRoles.map((item, key) => { - const { display, arn } = item; + const { display, arn, name } = item; const launchUrl = getLaunchUrl(arn); return ( - {display} + {`${display !== name ? `${display} (${name})` : display}`} ); }); return ( - <> + props.theme.colors.text.main}; background: ${props => props.theme.colors.spotBackground[2]}; @@ -126,14 +145,30 @@ function RoleItemList({ > Select IAM Role - {awsRoleItems.length ? ( - awsRoleItems - ) : ( - - No roles found - - )} - + + + {awsRoleItems.length ? ( + awsRoleItems + ) : ( + + No roles found + + )} + + ); } @@ -159,3 +194,26 @@ const StyledMenuItem = styled(MenuItem)( } ` ); + +const StyledInput = styled.input( + ({ theme }) => ` + background: transparent; + border: 1px solid ${theme.colors.text.muted}; + border-radius: 4px; + box-sizing: border-box; + color: ${theme.colors.text.main}; + height: 32px; + outline: none; + + &:focus, &:hover { + border 1px solid ${theme.colors.text.slightlyMuted}; + outline: none; + } + + ::placeholder { + color: ${theme.colors.text.muted}; + opacity: 1; + } +`, + space +); diff --git a/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx b/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx index 0a69a6363247d..c6d6edb493944 100644 --- a/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx +++ b/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx @@ -32,6 +32,7 @@ import { desktops } from 'teleport/Desktops/fixtures'; import { nodes } from 'teleport/Nodes/fixtures'; import makeApp from 'teleport/services/apps/makeApps'; +import { ResourceActionButton } from 'teleport/UnifiedResources/ResourceActionButton'; import { makeUnifiedResourceViewItemApp, @@ -104,7 +105,9 @@ export const Cards: Story = { {[ ...apps.map(resource => - makeUnifiedResourceViewItemApp(resource, { ActionButton }) + makeUnifiedResourceViewItemApp(resource, { + ActionButton: , + }) ), ...databases.map(resource => makeUnifiedResourceViewItemDatabase(resource, { @@ -115,7 +118,9 @@ export const Cards: Story = { makeUnifiedResourceViewItemKube(resource, { ActionButton }) ), ...nodes.map(resource => - makeUnifiedResourceViewItemNode(resource, { ActionButton }) + makeUnifiedResourceViewItemNode(resource, { + ActionButton, + }) ), ...additionalResources.map(resource => makeUnifiedResourceViewItemApp(resource, { ActionButton }) diff --git a/web/packages/shared/services/apps.ts b/web/packages/shared/services/apps.ts index 76492a5e375ad..6146ae07998cf 100644 --- a/web/packages/shared/services/apps.ts +++ b/web/packages/shared/services/apps.ts @@ -17,6 +17,7 @@ */ export type AwsRole = { + name: string; arn: string; display: string; }; diff --git a/web/packages/teleport/src/Apps/fixtures/index.ts b/web/packages/teleport/src/Apps/fixtures/index.ts index 2d2fae5045b03..c197f20183d23 100644 --- a/web/packages/teleport/src/Apps/fixtures/index.ts +++ b/web/packages/teleport/src/Apps/fixtures/index.ts @@ -151,13 +151,27 @@ export const apps = [ awsConsole: true, awsRoles: [ { + name: 'role name', arn: 'arn:aws:iam::joe123:role/EC2FullAccess', display: 'EC2FullAccess', }, { + name: 'other role name', + arn: 'arn:aws:iam::joe123:role/EC2FullAccess', + display: 'ReallyLonReallyLonggggggEC2FullAccess', + }, + { + name: 'thisthing', arn: 'arn:aws:iam::joe123:role/EC2ReadOnly', display: 'EC2ReadOnly', }, + ...new Array(20).fill(undefined).map((_, index) => { + return { + name: `long-${index}`, + arc: `arn:aws:iam::${index}`, + display: `LONG${index}`, + }; + }), ], clusterId: 'one', fqdn: 'awsconsole-1.com',