Skip to content

Commit

Permalink
Add enroll option for resource cards
Browse files Browse the repository at this point in the history
  • Loading branch information
michellescripts committed Jan 28, 2025
1 parent a0eb14c commit 2aa9125
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 79 deletions.
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 @@ -18,6 +18,9 @@

import Table, { LabelCell } from 'design/DataTable';

{
/* TODO MBERG */
}
export function Agents() {
return (
<Table
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router';

import { Flex } from 'design';
import Table, { LabelCell } from 'design/DataTable';
import { MultiselectMenu } from 'shared/components/Controls/MultiselectMenu';

import { useServerSidePagination } from 'teleport/components/hooks';
import { AwsResource } from 'teleport/Integrations/status/AwsOidc/StatCard';
import {
awsRegionMap,
IntegrationDiscoveryRule,
IntegrationKind,
integrationService,
Regions,
} from 'teleport/services/integrations';

/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
Expand All @@ -16,105 +33,74 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { useEffect, useState } from 'react';
import { useParams } from 'react-router';

import Table, { LabelCell } from 'design/DataTable';
import { SortType } from 'design/DataTable/types';
import { SearchPanel } from 'shared/components/Search';

import { useServerSidePagination } from 'teleport/components/hooks';
import { AwsResource } from 'teleport/Integrations/status/AwsOidc/StatCard';
import {
IntegrationDiscoveryRule,
IntegrationKind,
integrationService,
} from 'teleport/services/integrations';

export function Rules() {
const { name, resourceKind } = useParams<{
type: IntegrationKind;
name: string;
resourceKind: AwsResource;
}>();

const [search, setSearch] = useState('');
const [sort, setSort] = useState<SortType>({
fieldName: 'region',
dir: 'ASC',
});
const [regionFilter, setRegionFilter] = useState<string[]>([]);
const serverSidePagination =
useServerSidePagination<IntegrationDiscoveryRule>({
pageSize: 20,
fetchFunc: async (_, params) => {
fetchFunc: async () => {
const { rules, nextKey } =
await integrationService.fetchIntegrationRules(
name,
resourceKind,
params
regionFilter
);
return { agents: rules, nextKey };
},
clusterId: '',
params: { search, sort },
params: {},
});

useEffect(() => {
serverSidePagination.fetch();
}, [search, sort]);
}, [regionFilter]);

return (
<Table<IntegrationDiscoveryRule>
data={serverSidePagination.fetchedData.agents || undefined}
columns={[
{
key: 'region',
headerText: 'Region',
isSortable: true,
},
{
key: 'labelMatcher',
headerText: getResourceTerm(resourceKind),
isSortable: true,
onSort: (a, b) => {
const aStr = a.labelMatcher.toString();
const bStr = b.labelMatcher.toString();

if (aStr < bStr) {
return -1;
}
if (aStr > bStr) {
return 1;
}

return 0;
},
render: ({ labelMatcher }) => (
<LabelCell data={labelMatcher.map(l => `${l.name}:${l.value}`)} />
<>
<MultiselectMenu
options={Object.keys(awsRegionMap).map(r => ({
value: r as Regions,
label: (
<Flex justifyContent="space-between">
<div>{awsRegionMap[r]}&nbsp;&nbsp;</div>
<div>{r}</div>
</Flex>
),
},
]}
emptyText={`No ${resourceKind} data`}
isSearchable
fetching={{
fetchStatus: serverSidePagination.fetchStatus,
onFetchNext: serverSidePagination.fetchNext,
onFetchPrev: serverSidePagination.fetchPrev,
}}
serversideProps={{
sort: sort,
setSort: setSort,
serversideSearchPanel: (
<SearchPanel
updateSearch={setSearch}
updateQuery={null}
hideAdvancedSearch={true}
filter={{ search }}
disableSearch={serverSidePagination.attempt.status === 'processing'}
/>
),
}}
/>
}))}
onChange={regions => setRegionFilter(regions)}
selected={regionFilter}
label="Region"
tooltip="Filter by region"
/>
<Table<IntegrationDiscoveryRule>
data={serverSidePagination.fetchedData.agents || undefined}
columns={[
{
key: 'region',
headerText: 'Region',
},
{
key: 'labelMatcher',
headerText: getResourceTerm(resourceKind),
render: ({ labelMatcher }) => (
<LabelCell data={labelMatcher.map(l => `${l.name}:${l.value}`)} />
),
},
]}
emptyText={`No ${resourceKind} data`}
fetching={{
fetchStatus: serverSidePagination.fetchStatus,
onFetchNext: serverSidePagination.fetchNext,
onFetchPrev: serverSidePagination.fetchPrev,
}}
/>
</>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useHistory } from 'react-router';
import styled from 'styled-components';

import { ButtonBorder, Card, Flex, H2, ResourceIcon } from 'design';

import cfg from 'teleport/config';
import { AwsResource } from 'teleport/Integrations/status/AwsOidc/StatCard';

type EnrollCardProps = {
resource: AwsResource;
};

export function EnrollCard({ resource }: EnrollCardProps) {
const history = useHistory();

const handleClick = () => {
history.push({
pathname: cfg.routes.discover,
state: { searchKeywords: resource },
});
};

// todo (michellescripts) update enroll design once ready
return (
<Enroll>
<Flex flexDirection="column" gap={4}>
<Flex alignItems="center" mb={2}>
<ResourceIcon name={resource} mr={2} width="32px" height="32px" />
<H2>{resource.toUpperCase()}</H2>
</Flex>
<ButtonBorder size="large" onClick={handleClick}>
Enroll {resource.toUpperCase()}
</ButtonBorder>
</Flex>
</Enroll>
);
}

const Enroll = styled(Card)`
width: 33%;
background-color: ${props => props.theme.colors.levels.surface};
padding: 12px;
border-radius: ${props => props.theme.radii[2]}px;
border: ${props => `1px solid ${props.theme.colors.levels.surface}`};
&:hover {
background-color: ${props => props.theme.colors.levels.elevated};
box-shadow: ${({ theme }) => theme.boxShadow[2]};
}
`;
17 changes: 17 additions & 0 deletions web/packages/teleport/src/Integrations/status/AwsOidc/StatCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import * as Icons from 'design/Icon';
import { ResourceIcon } from 'design/ResourceIcon';

import cfg from 'teleport/config';
import { EnrollCard } from 'teleport/Integrations/status/AwsOidc/EnrollCard';
import history from 'teleport/services/history';
import {
IntegrationKind,
Expand All @@ -48,6 +49,10 @@ export function StatCard({ name, resource, summary }: StatCardProps) {
: undefined;
const term = getResourceTerm(resource);

if (!foundResource(summary)) {
return <EnrollCard resource={resource} />;
}

return (
<SelectCard
data-testid={`${resource}-stats`}
Expand Down Expand Up @@ -124,6 +129,18 @@ function getResourceTerm(resource: AwsResource): string {
}
}

function foundResource(resource: ResourceTypeSummary): boolean {
if (Object.keys(resource).length == 0) {
return false;
}

if (resource.ecsDatabaseServiceCount != 0) {
return true;
}

return resource.rulesCount != 0 || resource.resourcesFound != 0;
}

export const SelectCard = styled(Card)`
width: 33%;
background-color: ${props => props.theme.colors.levels.surface};
Expand Down
4 changes: 2 additions & 2 deletions web/packages/teleport/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,14 +1051,14 @@ const cfg = {
getIntegrationRulesUrl(
name: string,
resourceType: AwsResource,
params?: UrlResourcesParams
regionFilter: string[]
) {
const clusterId = cfg.proxyCluster;
return generateResourcePath(cfg.api.integrationRulesPath, {
clusterId,
name,
resourceType,
...params,
regionFilter,
});
},

Expand Down
2 changes: 2 additions & 0 deletions web/packages/teleport/src/generateResourcePath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export default function generateResourcePath(
.replace(':searchAsRoles?', processedParams.searchAsRoles || '')
.replace(':sort?', processedParams.sort || '')
.replace(':startKey?', params.startKey || '')
// todo mberg - marco hmw handle regions ?
.replace(':regionPrefix?', params.regionPrefix || '')
.replace(
':includedResourceMode?',
processedParams.includedResourceMode || ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,10 @@ export const integrationService = {
fetchIntegrationRules(
name: string,
resourceType: AwsResource,
params?: UrlResourcesParams
region: string[]
): Promise<IntegrationDiscoveryRules> {
return api
.get(cfg.getIntegrationRulesUrl(name, resourceType, params))
.get(cfg.getIntegrationRulesUrl(name, resourceType, region))
.then(resp => {
return {
rules: resp?.rules || [],
Expand Down

0 comments on commit 2aa9125

Please sign in to comment.