Skip to content

Commit

Permalink
Load user tasks into task table
Browse files Browse the repository at this point in the history
  • Loading branch information
michellescripts committed Dec 24, 2024
1 parent 4343740 commit 8f63bb3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,69 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import React from 'react';
import React, {useEffect} from 'react';
import Table from 'design/DataTable';

import { useParams } from 'react-router';
import {useAsync} from "shared/hooks/useAsync";

import {useParams} from "react-router";

import {Indicator} from "design";

import {Danger} from "design/Alert";

import { FeatureBox } from 'teleport/components/Layout';
import { AwsOidcHeader } from 'teleport/Integrations/status/AwsOidc/AwsOidcHeader';
import { AwsResource } from 'teleport/Integrations/status/AwsOidc/StatCard';
import { useAwsOidcStatus } from 'teleport/Integrations/status/AwsOidc/useAwsOidcStatus';
import { IntegrationKind } from 'teleport/services/integrations';
import {IntegrationKind, integrationService, UserTask} from "teleport/services/integrations";


export function Tasks() {
const { name } = useParams<{
type: IntegrationKind;
name: string;
}>();

const { integrationAttempt } = useAwsOidcStatus();
const { data: integration } = integrationAttempt;

const [attempt, fetchTasks] = useAsync(() =>
integrationService.fetchIntegrationUserTasksList(name)
);

useEffect(() => {
fetchTasks();
}, []);

if (attempt.status == 'processing') {
return <Indicator />;
}

if (attempt.status == 'error') {
return <Danger>{attempt.statusText}</Danger>;
}

if (!attempt.data) {
return null;
}

return (
<FeatureBox css={{ maxWidth: '1400px', paddingTop: '16px', gap: '30px' }}>
{integration && (
<AwsOidcHeader integration={integration} tasks={true} />
)}
<Table
data={[]}
{integration && <AwsOidcHeader integration={integration} tasks={true} />}
{/* todo (michellescripts) sync with Marco on timestamp field */}
<Table<UserTask>
data={attempt.data.items}
columns={[
{
key: 'type',
key: 'taskType',
headerText: 'Type',
isSortable: true,
},
{
key: 'details',
key: 'name',
headerText: 'Issue Details',
isSortable: true,
},
{
key: 'timestamp',
headerText: 'Timestamp',
isSortable: true,
},
]}
emptyText={`No pending tasks`}
isSearchable
Expand Down
10 changes: 10 additions & 0 deletions web/packages/teleport/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ const cfg = {
'/v1/webapi/sites/:clusterId/integrations/:name/stats',
integrationRulesPath:
'/v1/webapi/sites/:clusterId/integrations/:name/discoveryrules?resourceType=:resourceType?&startKey=:startKey?&query=:query?&search=:search?&sort=:sort?&limit=:limit?',
userTaskListByIntegrationPath:
'/v1/webapi/sites/:clusterId/usertask?integration=:name',

thumbprintPath: '/v1/webapi/thumbprint',
pingAwsOidcIntegrationPath:
Expand Down Expand Up @@ -1027,6 +1029,14 @@ const cfg = {
});
},

getIntegrationUserTasksListUrl(name: string) {
const clusterId = cfg.proxyCluster;
return generatePath(cfg.api.userTaskListByIntegrationPath, {
clusterId,
name,
});
},

getPingAwsOidcIntegrationUrl({
integrationName,
clusterId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,48 @@ test('fetch integration rules: fetchIntegrationRules()', async () => {
});
});

test('fetch integration user task list: fetchIntegrationUserTasksList()', async () => {
// test a valid response
jest.spyOn(api, 'get').mockResolvedValue({
items: [
{
name: "task-name",
taskType: "task-type",
state: "task-state",
issueType: "issue-type",
integration: "name",
},
],
nextKey: 'some-key',
});

let response = await integrationService.fetchIntegrationUserTasksList('name');
expect(api.get).toHaveBeenCalledWith(
cfg.getIntegrationUserTasksListUrl('name')
);
expect(response).toEqual({
nextKey: 'some-key',
items: [
{
name: "task-name",
taskType: "task-type",
state: "task-state",
issueType: "issue-type",
integration: "name",
},
],
});

// test null response
jest.spyOn(api, 'get').mockResolvedValue(null);

response = await integrationService.fetchIntegrationUserTasksList('name');
expect(response).toEqual({
nextKey: undefined,
items: [],
});
});

const nonAwsOidcIntegration = {
name: 'non-aws-oidc-integration',
subKind: 'abc',
Expand Down
14 changes: 14 additions & 0 deletions web/packages/teleport/src/services/integrations/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
AwsOidcPingRequest,
IntegrationWithSummary,
IntegrationDiscoveryRules,
UserTasksListResponse,
} from './types';

export const integrationService = {
Expand Down Expand Up @@ -446,6 +447,19 @@ export const integrationService = {
};
});
},

fetchIntegrationUserTasksList(
name: string,
): Promise<UserTasksListResponse> {
return api
.get(cfg.getIntegrationUserTasksListUrl(name))
.then(resp => {
return {
items: resp?.items || [],
nextKey: resp?.nextKey,
};
});
},
};

export function makeIntegrations(json: any): Integration[] {
Expand Down
25 changes: 25 additions & 0 deletions web/packages/teleport/src/services/integrations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,31 @@ export type IntegrationDiscoveryRules = {
nextKey: string;
};

// UserTasksListResponse contains a list of UserTasks.
// In case of exceeding the pagination limit (either via query param `limit` or the default 1000)
// a `nextToken` is provided and should be used to obtain the next page (as a query param `startKey`)
export type UserTasksListResponse = {
// items is a list of resources retrieved.
items: UserTask[];
// nextKey is the position to resume listing events.
nextKey: string;
};

// UserTask describes UserTask fields.
// Used for listing User Tasks without receiving all the details.
export type UserTask = {
// name is the UserTask name.
name: string;
// taskType identifies this task's type.
taskType: string;
// state is the state for the User Task.
state: string;
// issueType identifies this task's issue type.
issueType: string;
// integration is the Integration Name this User Task refers to.
integration: string;
};

// IntegrationDiscoveryRule describes a discovery rule associated with an integration.
export type IntegrationDiscoveryRule = {
// resourceType indicates the type of resource that this rule targets.
Expand Down

0 comments on commit 8f63bb3

Please sign in to comment.