Skip to content

Commit

Permalink
Add rules tables for aws resources
Browse files Browse the repository at this point in the history
  • Loading branch information
michellescripts committed Jan 28, 2025
1 parent 5791a98 commit b379aa3
Show file tree
Hide file tree
Showing 21 changed files with 1,219 additions and 88 deletions.
57 changes: 57 additions & 0 deletions web/packages/design/src/Tabs/Tabs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { NavLink } from 'react-router-dom';
import styled from 'styled-components';

export const TabsContainer = styled.div`
position: relative;
display: flex;
gap: ${p => p.theme.space[5]}px;
align-items: center;
padding: 0 ${p => p.theme.space[5]}px;
border-bottom: 1px solid ${p => p.theme.colors.spotBackground[0]};
`;

export const TabContainer = styled(NavLink)<{ selected?: boolean }>`
padding: ${p => p.theme.space[1] + p.theme.space[2]}px
${p => p.theme.space[2]}px;
position: relative;
cursor: pointer;
z-index: 2;
opacity: ${p => (p.selected ? 1 : 0.5)};
transition: opacity 0.3s linear;
color: ${p => p.theme.colors.text.main};
font-weight: 300;
font-size: 22px;
line-height: ${p => p.theme.space[5]}px;
white-space: nowrap;
text-decoration: none;
&:hover {
opacity: 1;
}
`;

export const TabBorder = styled.div`
position: absolute;
bottom: -1px;
background: ${p => p.theme.colors.brand};
height: 2px;
transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1);
`;
2 changes: 1 addition & 1 deletion web/packages/teleport/src/Integrations/IntegrationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function IntegrationList(props: Props<IntegrationLike>) {
}

function getRowStyle(row: IntegrationLike): React.CSSProperties {
if (row.kind !== 'okta') return;
if (row.kind !== 'okta' && row.kind !== IntegrationKind.AwsOidc) return;
return { cursor: 'pointer' };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,20 @@ test('renders header and stats cards', () => {
</MockAwsOidcStatusProvider>
);

expect(screen.getByRole('link', { name: 'back' })).toHaveAttribute(
const breadcrumbs = screen.getByTestId('aws-oidc-header');
expect(within(breadcrumbs).getByText('integration-one')).toBeInTheDocument();

const title = screen.getByTestId('aws-oidc-title');
expect(within(title).getByRole('link', { name: 'back' })).toHaveAttribute(
'href',
'/web/integrations'
);
expect(screen.getByText('integration-one')).toBeInTheDocument();
expect(screen.getByLabelText('status')).toHaveAttribute('kind', 'success');
expect(screen.getByLabelText('status')).toHaveTextContent('Running');
expect(within(title).getByLabelText('status')).toHaveAttribute(
'kind',
'success'
);
expect(within(title).getByLabelText('status')).toHaveTextContent('Running');
expect(within(title).getByText('integration-one')).toBeInTheDocument();

const ec2 = screen.getByTestId('ec2-stats');
expect(within(ec2).getByTestId('sync')).toHaveTextContent(
Expand Down Expand Up @@ -136,3 +143,66 @@ test('renders header and stats cards', () => {
'Failed Clusters 0'
);
});

test('renders enroll cards', () => {
const zeroCount = {
rulesCount: 0,
resourcesFound: 0,
resourcesEnrollmentFailed: 0,
resourcesEnrollmentSuccess: 0,
discoverLastSync: new Date().getTime(),
ecsDatabaseServiceCount: 0,
};

render(
<MockAwsOidcStatusProvider
value={{
integrationAttempt: {
status: 'success',
statusText: '',
data: {
resourceType: 'integration',
name: 'integration-one',
kind: IntegrationKind.AwsOidc,
spec: {
roleArn: 'arn:aws:iam::111456789011:role/bar',
},
statusCode: 1,
},
},
statsAttempt: {
status: 'success',
statusText: '',
data: {
name: 'integration-one',
subKind: IntegrationKind.AwsOidc,
awsoidc: {
roleArn: 'arn:aws:iam::111456789011:role/bar',
},
awsec2: zeroCount,
awsrds: zeroCount,
awseks: zeroCount,
},
},
}}
>
<AwsOidcDashboard />
</MockAwsOidcStatusProvider>
);

expect(
within(screen.getByTestId('ec2-enroll')).getByRole('button', {
name: 'Enroll EC2',
})
).toBeInTheDocument();
expect(
within(screen.getByTestId('rds-enroll')).getByRole('button', {
name: 'Enroll RDS',
})
).toBeInTheDocument();
expect(
within(screen.getByTestId('eks-enroll')).getByRole('button', {
name: 'Enroll EKS',
})
).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { Flex, H2, Indicator } from 'design';
import React from 'react';

import { Box, Flex, H2, Indicator } from 'design';
import { Danger } from 'design/Alert';

import { FeatureBox } from 'teleport/components/Layout';
import { AwsOidcHeader } from 'teleport/Integrations/status/AwsOidc/AwsOidcHeader';
import { AwsOidcTitle } from 'teleport/Integrations/status/AwsOidc/AwsOidcTitle';
import {
AwsResource,
StatCard,
Expand All @@ -30,28 +33,52 @@ import { useAwsOidcStatus } from 'teleport/Integrations/status/AwsOidc/useAwsOid
export function AwsOidcDashboard() {
const { statsAttempt, integrationAttempt } = useAwsOidcStatus();

if (statsAttempt.status == 'processing') {
return <Indicator />;
if (
statsAttempt.status == 'processing' ||
integrationAttempt.status == 'processing'
) {
return (
<Box textAlign="center" mt={4}>
<Indicator />
</Box>
);
}
if (statsAttempt.status == 'error') {

if (integrationAttempt.status == 'error') {
return <Danger>{statsAttempt.statusText}</Danger>;
}
if (!statsAttempt.data) {

if (!statsAttempt.data || !integrationAttempt.data) {
return null;
}

// todo (michellescripts) after routing, ensure this view can be sticky
// todo (michellescripts) after routing, ensure this view can be sticky; relies on https://github.com/gravitational/teleport/pull/51529
const { awsec2, awseks, awsrds } = statsAttempt.data;
const { data: integration } = integrationAttempt;
return (
<FeatureBox css={{ maxWidth: '1400px', paddingTop: '16px' }}>
{integration && <AwsOidcHeader integration={integration} />}
<H2 my={3}>Auto-Enrollment</H2>
<Flex gap={3}>
<StatCard resource={AwsResource.ec2} summary={awsec2} />
<StatCard resource={AwsResource.rds} summary={awsrds} />
<StatCard resource={AwsResource.eks} summary={awseks} />
</Flex>
</FeatureBox>
<>
<AwsOidcHeader integration={integration} />
<FeatureBox css={{ maxWidth: '1400px', paddingTop: '16px' }}>
{integration && <AwsOidcTitle integration={integration} />}
<H2 my={3}>Auto-Enrollment</H2>
<Flex gap={3}>
<StatCard
name={integration.name}
resource={AwsResource.ec2}
summary={awsec2}
/>
<StatCard
name={integration.name}
resource={AwsResource.eks}
summary={awseks}
/>
<StatCard
name={integration.name}
resource={AwsResource.rds}
summary={awsrds}
/>
</Flex>
</FeatureBox>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,81 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { useHistory } from 'react-router';
import { Link as InternalLink } from 'react-router-dom';

import { ButtonIcon, Flex, Label, Text } from 'design';
import { ArrowLeft } from 'design/Icon';
import { ButtonIcon, ButtonText, Flex, Text } from 'design';
import { Plugs } from 'design/Icon';
import { HoverTooltip } from 'design/Tooltip';

import cfg from 'teleport/config';
import { getStatusAndLabel } from 'teleport/Integrations/helpers';
import { AwsResource } from 'teleport/Integrations/status/AwsOidc/StatCard';
import { Integration } from 'teleport/services/integrations';

export function AwsOidcHeader({ integration }: { integration: Integration }) {
const { status, labelKind } = getStatusAndLabel(integration);
export function AwsOidcHeader({
integration,
resource = undefined,
}: {
integration: Integration;
resource?: AwsResource;
}) {
const history = useHistory();
const divider = (
<Text typography="body3" color="text.slightlyMuted">
/
</Text>
);

return (
<Flex alignItems="center">
<Flex
alignItems="center"
borderBottom={1}
borderColor="levels.surface"
width={'100%'}
pl={5}
py={1}
data-testid="aws-oidc-header"
>
<HoverTooltip position="bottom" tipContent="Back to Integrations">
<ButtonIcon
size="small"
as={InternalLink}
to={cfg.routes.integrations}
aria-label="back"
aria-label="integrations-table"
color="text.slightlyMuted"
>
<ArrowLeft size="medium" />
<Plugs size="small" />
</ButtonIcon>
</HoverTooltip>
<Text bold fontSize={6} mx={2}>
{integration.name}
</Text>
<Label kind={labelKind} aria-label="status" px={3}>
{status}
</Label>
{!resource ? (
<>
{divider}
<Text typography="body3" color="text.slightlyMuted" ml={2}>
{integration.name}
</Text>
</>
) : (
<>
{divider}
<ButtonText
size="small"
onClick={() =>
history.push(
cfg.getIntegrationStatusRoute(
integration.kind,
integration.name
)
)
}
>
{integration.name}
</ButtonText>
{divider}
<Text typography="body3" color="text.slightlyMuted" ml={2}>
{resource.toUpperCase()}
</Text>
</>
)}
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import { Route, Switch } from 'teleport/components/Router';
import cfg from 'teleport/config';
import { Details } from 'teleport/Integrations/status/AwsOidc/Details/Details';
import { AwsOidcStatusProvider } from 'teleport/Integrations/status/AwsOidc/useAwsOidcStatus';

import { AwsOidcDashboard } from './AwsOidcDashboard';
Expand All @@ -27,7 +28,13 @@ export function AwsOidcRoutes() {
<AwsOidcStatusProvider>
<Switch>
<Route
key="aws-oidc-resources-list"
key="aws-oidc-resource-table"
exact
path={cfg.routes.integrationStatusResources}
component={Details}
/>
<Route
key="aws-oidc-dashboard"
exact
path={cfg.routes.integrationStatus}
component={AwsOidcDashboard}
Expand Down
Loading

0 comments on commit b379aa3

Please sign in to comment.