diff --git a/web/packages/teleport/src/Discover/SelectResource/SelectResource.tsx b/web/packages/teleport/src/Discover/SelectResource/SelectResource.tsx index 42d1d22882a29..a9682b527b7fd 100644 --- a/web/packages/teleport/src/Discover/SelectResource/SelectResource.tsx +++ b/web/packages/teleport/src/Discover/SelectResource/SelectResource.tsx @@ -19,9 +19,10 @@ import { useLocation, useHistory } from 'react-router'; import * as Icons from 'design/Icon'; import styled from 'styled-components'; -import { Box, Flex, Text, Popover, Link } from 'design'; +import { Box, Flex, Text, Link } from 'design'; import useTeleport from 'teleport/useTeleport'; +import { ToolTipNoPermBadge } from 'teleport/components/ToolTipNoPermBadge'; import { Acl } from 'teleport/services/user'; import { ResourceKind, @@ -151,7 +152,7 @@ export function SelectResource(props: SelectResourceProps) { Guided )} {!r.hasAccess && ( - } @@ -228,59 +229,6 @@ const ClearSearch = ({ onClick }: { onClick(): void }) => { ); }; -const ToolTip: React.FC = ({ children }) => { - const [anchorEl, setAnchorEl] = useState(); - const open = Boolean(anchorEl); - - function handlePopoverOpen(event) { - setAnchorEl(event.currentTarget); - } - - function handlePopoverClose() { - setAnchorEl(null); - } - - return ( - <> -
- Lacking Permissions -
- `pointer-events: none;`} - onClose={handlePopoverClose} - open={open} - anchorEl={anchorEl} - anchorOrigin={{ - vertical: 'bottom', - horizontal: 'left', - }} - transformOrigin={{ - vertical: 'top', - horizontal: 'left', - }} - > - - {children} - - - - ); -}; - function checkHasAccess(acl: Acl, resourceKind: ResourceKind) { const basePerm = acl.tokens.create; if (!basePerm) { @@ -397,12 +345,6 @@ const BadgeGuided = styled.div` font-size: 10px; `; -const StyledOnHover = styled(Text)` - background-color: white; - color: black; - max-width: 350px; -`; - const InputWrapper = styled.div` border-radius: 200px; height: 40px; diff --git a/web/packages/teleport/src/Discover/SelectResource/__snapshots__/SelectResource.story.test.tsx.snap b/web/packages/teleport/src/Discover/SelectResource/__snapshots__/SelectResource.story.test.tsx.snap index 344d1f59323c5..297d046e71a42 100644 --- a/web/packages/teleport/src/Discover/SelectResource/__snapshots__/SelectResource.story.test.tsx.snap +++ b/web/packages/teleport/src/Discover/SelectResource/__snapshots__/SelectResource.story.test.tsx.snap @@ -2373,6 +2373,18 @@ exports[`render with no access 1`] = ` justify-content: center; } +.c9 { + box-sizing: border-box; + background-color: red; + border-top-right-radius: 4px; + border-bottom-left-radius: 4px; + position: absolute; + padding: 0px 6px; + top: 0px; + right: 0px; + font-size: 10px; +} + .c6 { display: grid; grid-template-columns: repeat(auto-fill,320px); @@ -2434,17 +2446,6 @@ exports[`render with no access 1`] = ` opacity: 0.6; } -.c9 { - position: absolute; - background: red; - padding: 0px 6px; - border-top-right-radius: 8px; - border-bottom-left-radius: 8px; - top: 0px; - right: 0px; - font-size: 10px; -} -
@@ -2487,6 +2488,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2523,6 +2525,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2558,6 +2561,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2599,6 +2603,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2640,6 +2645,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2681,6 +2687,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2722,6 +2729,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2763,6 +2771,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2803,6 +2812,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2844,6 +2854,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2885,6 +2896,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2926,6 +2938,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -2969,6 +2982,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3013,6 +3027,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3057,6 +3072,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3101,6 +3117,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3145,6 +3162,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3189,6 +3207,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3233,6 +3252,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3277,6 +3297,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3321,6 +3342,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3365,6 +3387,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3409,6 +3432,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3453,6 +3477,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3497,6 +3522,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3535,6 +3561,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3579,6 +3606,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3623,6 +3651,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3667,6 +3696,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3711,6 +3741,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3755,6 +3786,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3799,6 +3831,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3837,6 +3870,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3881,6 +3915,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -3925,6 +3960,7 @@ exports[`render with no access 1`] = ` >
Lacking Permissions
@@ -4098,6 +4134,18 @@ exports[`render with partial access 1`] = ` justify-content: center; } +.c20 { + box-sizing: border-box; + background-color: red; + border-top-right-radius: 4px; + border-bottom-left-radius: 4px; + position: absolute; + padding: 0px 6px; + top: 0px; + right: 0px; + font-size: 10px; +} + .c6 { display: grid; grid-template-columns: repeat(auto-fill,320px); @@ -4192,17 +4240,6 @@ exports[`render with partial access 1`] = ` opacity: 0.6; } -.c20 { - position: absolute; - background: red; - padding: 0px 6px; - border-top-right-radius: 8px; - border-bottom-left-radius: 8px; - top: 0px; - right: 0px; - font-size: 10px; -} -
@@ -4557,6 +4594,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4598,6 +4636,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4639,6 +4678,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4680,6 +4720,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4723,6 +4764,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4767,6 +4809,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4811,6 +4854,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4855,6 +4899,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4899,6 +4944,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4943,6 +4989,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -4987,6 +5034,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5031,6 +5079,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5075,6 +5124,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5119,6 +5169,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5163,6 +5214,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5207,6 +5259,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5251,6 +5304,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5289,6 +5343,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5333,6 +5388,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5377,6 +5433,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5421,6 +5478,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5465,6 +5523,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5509,6 +5568,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5553,6 +5613,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5591,6 +5652,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5635,6 +5697,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
@@ -5679,6 +5742,7 @@ exports[`render with partial access 1`] = ` >
Lacking Permissions
diff --git a/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.story.tsx b/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.story.tsx new file mode 100644 index 0000000000000..3400e616deee7 --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.story.tsx @@ -0,0 +1,30 @@ +/** + * 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 { MemoryRouter } from 'react-router'; + +import { IntegrationEnroll } from './IntegrationEnroll'; + +export default { + title: 'Teleport/Integrations', +}; + +export const Enroll = () => ( + + + +); diff --git a/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.tsx b/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.tsx new file mode 100644 index 0000000000000..d176a1a30efb8 --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/IntegrationEnroll.tsx @@ -0,0 +1,41 @@ +/** + * 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 { Box } from 'design'; + +import { + FeatureBox, + FeatureHeader, + FeatureHeaderTitle, +} from 'teleport/components/Layout'; + +import { IntegrationTiles } from './IntegrationTiles'; +import { NoCodeIntegrationDescription } from './common'; + +export function IntegrationEnroll() { + return ( + + + Select Integration Type + + + + + + + ); +} diff --git a/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.test.tsx b/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.test.tsx new file mode 100644 index 0000000000000..8113c4c20143d --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.test.tsx @@ -0,0 +1,57 @@ +/** + * 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 { MemoryRouter } from 'react-router'; +import { render, screen } from 'design/utils/testing'; + +import { IntegrationTiles } from './IntegrationTiles'; + +test('render', async () => { + render( + + + + ); + + expect(screen.getByText(/amazon web services/i)).toBeInTheDocument(); + expect(screen.queryByText(/no permission/i)).not.toBeInTheDocument(); + expect(screen.getByRole('img')).toBeInTheDocument(); + expect(screen.getByRole('link')).toBeInTheDocument(); + + const tile = screen.getByTestId('tile'); + expect(tile).toBeEnabled(); + expect(tile.getAttribute('href')).toBeTruthy(); +}); + +test('render disabled', async () => { + render( + + + + ); + + expect(screen.getByText(/lacking permission/i)).toBeInTheDocument(); + expect(screen.queryByRole('link')).not.toBeInTheDocument(); + + const tile = screen.getByTestId('tile'); + expect(tile).not.toHaveAttribute('href'); + + // The element has disabled attribute, but it's in the format `disabled=""` + // so "toBeDisabled" interprets it as false. + // eslint-disable-next-line jest-dom/prefer-enabled-disabled + expect(tile).toHaveAttribute('disabled'); +}); diff --git a/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.tsx b/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.tsx new file mode 100644 index 0000000000000..69fde068658dd --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/IntegrationTiles.tsx @@ -0,0 +1,53 @@ +/** + * 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 { Link } from 'react-router-dom'; +import { Text, Image } from 'design'; +import awsIcon from 'design/assets/images/icons/aws.svg'; + +import cfg from 'teleport/config'; +import { ToolTipNoPermBadge } from 'teleport/components/ToolTipNoPermBadge'; + +import { IntegrationTile } from './common'; + +// IntegrationTiles is plural but at the moment we only +// support aws-oidc. Expecting this to grow. +export function IntegrationTiles({ + hasAccess = true, +}: { + hasAccess?: boolean; +}) { + return ( + + + + Amazon Web Services +
+ OIDC +
+ {!hasAccess && ( + + )} +
+ ); +} diff --git a/web/packages/teleport/src/IntegrationEnroll/common.tsx b/web/packages/teleport/src/IntegrationEnroll/common.tsx new file mode 100644 index 0000000000000..150d244161916 --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/common.tsx @@ -0,0 +1,64 @@ +/** + * 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 { Flex, Text, Box } from 'design'; +import styled from 'styled-components'; + +export type IntegrationTypes = 'aws-oidc'; + +export const IntegrationTile = styled(Flex).attrs({ + 'data-testid': 'tile', +})` + color: inherit; + text-decoration: none; + flex-direction: column; + align-items: center; + position: relative; + border-radius: 4px; + height: 170px; + width: 170px; + background-color: ${({ theme }) => theme.colors.buttons.secondary.default}; + text-align: center; + cursor: pointer; + + ${props => { + const pointerEvents = props.disabled ? 'none' : null; + if (props.$exists) { + return { pointerEvents }; + } + + return ` + opacity: ${props.disabled ? '0.45' : '1'}; + &:hover { + background-color: ${props.theme.colors.buttons.secondary.hover}; + } + `; + }} +`; + +export const NoCodeIntegrationDescription = () => ( + + + No-Code Integrations + + + Hosted Integrations eliminate the setup work so you can quickly connect + applications to Teleport for alerting and other useful functions. This + list is short for now, but it will grow with time! + + +); diff --git a/web/packages/teleport/src/IntegrationEnroll/index.ts b/web/packages/teleport/src/IntegrationEnroll/index.ts new file mode 100644 index 0000000000000..dc480dcb10b22 --- /dev/null +++ b/web/packages/teleport/src/IntegrationEnroll/index.ts @@ -0,0 +1,21 @@ +/** + * 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. + */ + +// export as default for use with React.lazy +export { IntegrationEnroll as default } from './IntegrationEnroll'; +export { IntegrationTiles } from './IntegrationTiles'; + +export * from './common'; diff --git a/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.story.tsx b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.story.tsx new file mode 100644 index 0000000000000..700d4ee47da55 --- /dev/null +++ b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.story.tsx @@ -0,0 +1,51 @@ +/* +Copyright 2019 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 styled from 'styled-components'; +import { Box } from 'design'; + +import { ToolTipNoPermBadge } from './ToolTipNoPermBadge'; + +export default { + title: 'Teleport/ToolTip', +}; + +export const NoPermissionBadgeString = () => ( + + I'm a sample container + + +); + +export const NoPermissionBadgeComp = () => ( + + I'm a sample container + I'm a box component with too much padding} + /> + +); + +const SomeBox = styled.div` + width: 240px; + border-radius: 8px; + padding: 16px; + display: flex; + position: relative; + align-items: center; + background: rgba(255, 255, 255, 0.05); +`; diff --git a/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.test.tsx b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.test.tsx new file mode 100644 index 0000000000000..1e8857c795dad --- /dev/null +++ b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.test.tsx @@ -0,0 +1,44 @@ +/** + * 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 styled from 'styled-components'; +import { render, screen, userEvent } from 'design/utils/testing'; + +import { ToolTipNoPermBadge } from './ToolTipNoPermBadge'; + +test('hovering renders tooltip msg and unhovering makes it disappear', async () => { + render( + + + + ); + + expect(screen.queryByTestId('tooltip-msg')).not.toBeInTheDocument(); + + const badge = screen.getByTestId('tooltip'); + + await userEvent.hover(badge); + expect(screen.getByTestId('tooltip-msg')).toBeInTheDocument(); + + await userEvent.unhover(badge); + expect(screen.queryByTestId('tooltip-msg')).not.toBeInTheDocument(); +}); + +const SomeBox = styled.div` + width: 240px; + padding: 16px; +`; diff --git a/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.tsx b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.tsx new file mode 100644 index 0000000000000..8e0c126fc9335 --- /dev/null +++ b/web/packages/teleport/src/components/ToolTipNoPermBadge/ToolTipNoPermBadge.tsx @@ -0,0 +1,86 @@ +/** + * 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, { useState } from 'react'; +import styled from 'styled-components'; +import { Text, Popover, Box } from 'design'; + +type Props = { + borderRadius?: number; +}; + +export const ToolTipNoPermBadge: React.FC = ({ + children, + borderRadius = 2, +}) => { + const [anchorEl, setAnchorEl] = useState(); + const open = Boolean(anchorEl); + + function handlePopoverOpen(event) { + setAnchorEl(event.currentTarget); + } + + function handlePopoverClose() { + setAnchorEl(null); + } + + return ( + <> + + Lacking Permissions + + `pointer-events: none;`} + onClose={handlePopoverClose} + open={open} + anchorEl={anchorEl} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'left', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'left', + }} + > + + {children} + + + + ); +}; + +const StyledOnHover = styled(Text)` + background-color: white; + color: black; + max-width: 350px; +`; diff --git a/web/packages/teleport/src/components/ToolTipNoPermBadge/index.ts b/web/packages/teleport/src/components/ToolTipNoPermBadge/index.ts new file mode 100644 index 0000000000000..f085834ad415d --- /dev/null +++ b/web/packages/teleport/src/components/ToolTipNoPermBadge/index.ts @@ -0,0 +1,17 @@ +/** + * 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. + */ + +export { ToolTipNoPermBadge } from './ToolTipNoPermBadge'; diff --git a/web/packages/teleport/src/features.tsx b/web/packages/teleport/src/features.tsx index 14cdb34e10d6e..1f86fb3bf61ff 100644 --- a/web/packages/teleport/src/features.tsx +++ b/web/packages/teleport/src/features.tsx @@ -86,7 +86,7 @@ const AuthConnectors = React.lazy( () => import(/* webpackChunkName: "auth-connectors" */ './AuthConnectors') ); const Locks = React.lazy( - () => import(/* webpackChunkName: "lazy" */ './Locks') + () => import(/* webpackChunkName: "locks" */ './Locks') ); const NewLock = React.lazy( () => import(/* webpackChunkName: "newLock" */ './Locks/NewLock') @@ -103,6 +103,10 @@ const Discover = React.lazy( const Integrations = React.lazy( () => import(/* webpackChunkName: "integrations" */ './Integrations') ); +const IntegrationEnroll = React.lazy( + () => + import(/* webpackChunkName: "integration-enroll" */ './IntegrationEnroll') +); // **************************** // Resource Features @@ -425,6 +429,36 @@ export class FeatureIntegrations implements TeleportFeature { } } +export class FeatureIntegrationEnroll implements TeleportFeature { + category = NavigationCategory.Management; + section = ManagementSection.Access; + + route = { + title: 'Enroll New Integration', + path: cfg.routes.integrationEnroll, + exact: false, + component: () => , + }; + + hasAccess(flags: FeatureFlags) { + return flags.enrollIntegrations; + } + + navigationItem = { + title: 'Enroll New Integration', + icon: , + getLink() { + return cfg.getIntegrationEnrollRoute(null); + }, + }; + + // getRoute allows child class extending this + // parent class to refer to this parent's route. + getRoute() { + return this.route; + } +} + // - Activity export class FeatureRecordings implements TeleportFeature { @@ -591,6 +625,7 @@ export function getOSSFeatures(): TeleportFeature[] { new FeatureNewLock(), new FeatureIntegrations(), new FeatureDiscover(), + new FeatureIntegrationEnroll(), // - Activity new FeatureRecordings(), diff --git a/web/packages/teleport/src/teleportContext.tsx b/web/packages/teleport/src/teleportContext.tsx index 62296519787ac..f757289082fb3 100644 --- a/web/packages/teleport/src/teleportContext.tsx +++ b/web/packages/teleport/src/teleportContext.tsx @@ -108,6 +108,7 @@ class TeleportContext implements types.Context { plugins: false, integrations: false, deviceTrust: false, + enrollIntegrationsOrPlugins: false, enrollIntegrations: false, }; } @@ -132,7 +133,8 @@ class TeleportContext implements types.Context { discover: userContext.hasDiscoverAccess(), plugins: userContext.getPluginsAccess().list, integrations: userContext.getIntegrationsAccess().list, - enrollIntegrations: + enrollIntegrations: userContext.getIntegrationsAccess().create, + enrollIntegrationsOrPlugins: userContext.getPluginsAccess().create || userContext.getIntegrationsAccess().create, deviceTrust: userContext.getDeviceTrustAccess().list, diff --git a/web/packages/teleport/src/types.ts b/web/packages/teleport/src/types.ts index 937d703059c6a..9c41d0ff02a70 100644 --- a/web/packages/teleport/src/types.ts +++ b/web/packages/teleport/src/types.ts @@ -91,6 +91,7 @@ export interface FeatureFlags { discover: boolean; plugins: boolean; integrations: boolean; + enrollIntegrationsOrPlugins: boolean; enrollIntegrations: boolean; deviceTrust: boolean; }