Skip to content

Commit

Permalink
Compound: Add components and apis for transfer
Browse files Browse the repository at this point in the history
- Components: Add components for transfers and statistics display
- App: Add pages for transfers and statistics
- api: Add gateway, usecase, feature, controller, presenter for
  list-transfer-stats and list-transfers

Provide E2E feature for rucio#359
  • Loading branch information
fno2010 committed Dec 7, 2023
1 parent 26baf37 commit 317f4b4
Show file tree
Hide file tree
Showing 34 changed files with 1,032 additions and 65 deletions.
30 changes: 30 additions & 0 deletions src/app/(rucio)/transfer/page/[source]/[dest]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ListTransfer as ListTransferStory } from "@/component-library/Pages/Transfers/ListTransfer";
import { TransferViewModel } from "@/lib/infrastructure/data/view-model/request";
import useComDOM from "@/lib/infrastructure/hooks/useComDOM";

export default function Page({ params }: { params: { source: string, dest: string }}) {
const TransferSearchComDOM = useComDOM<TransferViewModel>(
'list-transfer-query',
[],
false,
Infinity,
200,
true
)
TransferSearchComDOM.setRequest({
url: new URL(`${process.env.NEXT_PUBLIC_WEBUI_HOST}/api/feature/list-transfers`),
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json'
} as HeadersInit),
params: {
"sourceRSE": params.source,
"destRSE": params.dest
}
})
return (
<ListTransferStory
comdom={TransferSearchComDOM}
/>
)
}
2 changes: 1 addition & 1 deletion src/component-library/Pages/Transfers/ListTransfer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import useReponsiveHook from "@/component-library/Helpers/ResponsiveHook"
import { TableFilterDiscrete } from "@/component-library/StreamedTables/TableFilterDiscrete"
import { TableFilterString } from "@/component-library/StreamedTables/TableFilterString"
import { RequestTypeTag } from "@/component-library/Tags/RequestTypeTag"
import { RequestType } from "@/lib/core/entity/rucio"
import { TransferViewModel } from "@/lib/infrastructure/data/view-model/request"
Expand Down Expand Up @@ -59,6 +58,7 @@ export const ListTransfer = (
>
<Heading
title="List Active Transfers"
subtitle={`For Pair (RSE)`}
/>
<Body>
<StreamedTable<TransferViewModel>
Expand Down
40 changes: 27 additions & 13 deletions src/component-library/Pages/Transfers/ListTransferStatistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"
import { Heading } from "../Helpers/Heading"
import { createColumnHelper } from "@tanstack/react-table"
import { Body } from "../Helpers/Body"
import { Contenttd, Generaltable, Titleth } from "@/component-library/Helpers/Metatable"
import { H3 } from "@/component-library/Text/Headings/H3"
import { TransferStatistics } from "./TransferStatistics"
import { RequestState } from "@/lib/core/entity/rucio"
import { TableFilterDiscrete } from "@/component-library/StreamedTables/TableFilterDiscrete"
import { RequestStateTag } from "@/component-library/Tags/RequestStateTag"
import { HiDotsHorizontal } from "react-icons/hi"

export const ListTransferStatistics = (
props: {
Expand All @@ -15,17 +16,30 @@ export const ListTransferStatistics = (
) => {
const columnHelper = createColumnHelper<TransferStatsViewModel>()
const tablecolumns = [
columnHelper.accessor("source_rse", {
}),
columnHelper.accessor("dest_rse", {
}),
columnHelper.accessor("request_stats", {
id: "request_stats",
header: info => <H3>Transfer Statistics</H3>,
cell: info => {
return <TransferStatistics request_stats={info.getValue()} />
columnHelper.accessor("source_rse", {}),
columnHelper.accessor("dest_rse", {}),
columnHelper.accessor("activity", {}),
columnHelper.accessor("state", {
id: "state",
header: info => {
return (
<TableFilterDiscrete<RequestState>
name="Request Type"
keys={Object.values(RequestState)}
renderFunc={key => key === undefined ? <HiDotsHorizontal className="text-2xl text-gray-500 dark:text-gray-200" /> : <RequestStateTag state={key} forcesmall />}
column={info.column}
stack
/>
)
},
cell: info => <RequestStateTag state={info.getValue()} />,
meta: {
style: "w-8 md:w-32"
}
})
}),
columnHelper.accessor("activity", {}),
columnHelper.accessor("counter", {}),
columnHelper.accessor("bytes", {}),
]

return (
Expand Down

This file was deleted.

26 changes: 0 additions & 26 deletions src/component-library/Pages/Transfers/TransferStatistics.tsx

This file was deleted.

15 changes: 15 additions & 0 deletions src/component-library/Tags/RequestStateTag.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { RequestState } from "@/lib/core/entity/rucio";
import { Meta, StoryFn } from "@storybook/react";
import { RequestStateTag as R } from "./RequestStateTag";

export default {
title: 'Components/Tags',
component: R,
} as Meta<typeof R>;

const Template: StoryFn<typeof R> = (args) => <R {...args} />;

export const RequestStateTag = Template.bind({});
RequestStateTag.args = {
state: RequestState.FAILED
}
83 changes: 83 additions & 0 deletions src/component-library/Tags/RequestStateTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { RequestState } from "@/lib/core/entity/rucio"
import React, { useEffect, useState } from "react";
import { twMerge } from "tailwind-merge";

type RequestStateTagProps = JSX.IntrinsicElements["span"] & {
state: RequestState;
forcesmall?: boolean;
neversmall?: boolean;
};

export const RequestStateTag: React.FC<RequestStateTagProps> = (
{
state = RequestState.SUBMITTED,
forcesmall = false,
neversmall = false,
...props
}
) => {
const { className, ...restprops } = props

const [windowWidth, setWindowWidth] = useState(720)
useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth)
handleResize()
window.addEventListener('resize', handleResize)
}, [])
const belowMedium = (windowWidth < 768) || forcesmall
const stringMatch = {
[RequestState.PREPARING]: "Preparing",
[RequestState.DONE]: "Done",
[RequestState.FAILED]: "Failed",
[RequestState.LOST]: "Lost",
[RequestState.MISMATCH_SCHEME]: "Mismatch Scheme",
[RequestState.NO_SOURCES]: "No Source",
[RequestState.ONLY_TAPE_SOURCES]: "Only Tape Sources",
[RequestState.QUEUED]: "Queued",
[RequestState.SUBMISSION_FAILED]: "Submission Failed",
[RequestState.SUBMITTED]: "Submitted",
[RequestState.SUBMITTING]: "Submitting",
[RequestState.SUSPEND]: "Suspend",
[RequestState.WAITING]: "Waiting"
}

const colPicker = (state: RequestState) => {
switch (state) {
case RequestState.SUBMITTED:
return "emerald"
case RequestState.DONE:
return "blue"
case RequestState.PREPARING:
case RequestState.SUSPEND:
case RequestState.QUEUED:
case RequestState.SUBMITTING:
case RequestState.WAITING:
return "rose"
case RequestState.FAILED:
case RequestState.LOST:
case RequestState.SUBMISSION_FAILED:
return "amber"
case RequestState.MISMATCH_SCHEME:
case RequestState.NO_SOURCES:
case RequestState.ONLY_TAPE_SOURCES:
return "gray"
}
}

const color = colPicker(state)

return (
<span
className={twMerge(
"h-6 rounded text-center flex justify-center items-center",
"font-bold",
!neversmall ? "w-6 md:w-24 rounded-full md:rounded" : "w-24",
forcesmall ? "w-6 md:w-6 rounded-full md:rounded-full" : "",
`bg-${color}-100 text-${color}-800 dark:bg-${color}-900 dark:text-${color}-300`,
className ?? ""
)}
>
{belowMedium && !neversmall ? state : stringMatch[state]}
</span>
);
}
1 change: 0 additions & 1 deletion src/component-library/Tags/RequestTypeTag.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { RequestType } from "@/lib/core/entity/rucio";
import { RowSelection } from "@tanstack/react-table";
import React, { useEffect, useState } from "react";
import { twMerge } from "tailwind-merge";

Expand Down
60 changes: 60 additions & 0 deletions src/lib/core/dto/transfer-dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { BaseDTO, BaseStreamableDTO } from "@/lib/sdk/dto";
import { DIDType, Request, RequestState, RequestStats, RequestType } from "../entity/rucio";

/**
* The Data Transfer Object for the ListTransferStatistics which contains the stream
*/
export interface ListTransferStatisticsDTO extends BaseStreamableDTO {}

/**
* The Data Transfer Object for the Statistics of a single Transfer Group
*/
export interface TransferStatisticsDTO extends BaseDTO, RequestStats {}

/**
* The Data Transfer Object for the ListTransfer which contains the stream
*/
export interface ListTransfersDTO extends BaseStreamableDTO {}

/**
* The Data Transfer Object for a single Transfer
*/
export interface TransferDTO extends BaseDTO, Request {}

export function getEmptyTransferStatsDTO(): TransferStatisticsDTO {
return {
status: 'error',
account: '',
source_rse: '',
dest_rse: '',
source_rse_id: '',
dest_rse_id: '',
state: RequestState.FAILED,
activity: '',
counter: 0,
bytes: 0,
}
}

export function getEmptyTransferDTO(): TransferDTO {
return {
status: 'error',
id: '',
account: '',
request_type: RequestType.TRANSFER,
scope: '',
name: '',
did_type: DIDType.UNKNOWN,
source_rse_id: '',
dest_rse_id: '',
source_rse: '',
dest_rse: '',
state: RequestState.FAILED,
activity: '',
attributes: '',
priority: 0,
bytes: 0,
requested_at: '',
transfertool: '',
}
}
12 changes: 4 additions & 8 deletions src/lib/core/entity/rucio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,16 @@ export type Request = {
* Represents statistics for the nubmer of transfer requests over dest_rse and
* source_rse in Rucio.
*/
export type RequestStatsPerPair = {
activity: string,
counter: number,
bytes: number,
}

export type RequestStats = {
account: string,
state: RequestState,
dest_rse_id: string,
source_rse_id: string,
dest_rse: string,
source_rse: string,
request_stats: RequestStatsPerPair[],
activity: string,
state: RequestState,
counter: number,
bytes: number,
}

/*
Expand Down
13 changes: 13 additions & 0 deletions src/lib/core/port/primary/list-transfer-stats-ports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TransferStatsViewModel } from "@/lib/infrastructure/data/view-model/request-stats";
import { BaseAuthenticatedInputPort, BaseStreamingOutputPort } from "@/lib/sdk/primary-ports";
import { ListTransferStatsError, ListTransferStatsRequest, ListTransferStatsResponse } from "../../usecase-models/list-transfer-stats-usecase-models";

/**
* @interface ListTransferStatsInputPort that abstracts usecase.
*/
export interface ListTransferStatsInputPort extends BaseAuthenticatedInputPort<ListTransferStatsRequest> {}

/**
* @interface ListTransferStatsOutputPort that abstracts usecase.
*/
export interface ListTransferStatsOutputPort extends BaseStreamingOutputPort<ListTransferStatsResponse, ListTransferStatsError, TransferStatsViewModel> {}
13 changes: 13 additions & 0 deletions src/lib/core/port/primary/list-transfers-ports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BaseAuthenticatedInputPort, BaseStreamingOutputPort } from "@/lib/sdk/primary-ports";
import { ListTransfersError, ListTransfersRequest, ListTransfersResponse } from "../../usecase-models/list-transfers-usecase-models";
import { TransferViewModel } from "@/lib/infrastructure/data/view-model/request";

/**
* @interface ListTransfersInputPort that abstracts the usecase.
*/
export interface ListTransfersInputPort extends BaseAuthenticatedInputPort<ListTransfersRequest> {}

/**
* @interface ListTransfersOutputPort that abstracts the usecase.
*/
export interface ListTransfersOutputPort extends BaseStreamingOutputPort<ListTransfersResponse, ListTransfersError, TransferViewModel> {}
18 changes: 18 additions & 0 deletions src/lib/core/port/secondary/transfer-gateway-output-port.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ListTransfersDTO, ListTransferStatisticsDTO } from "../../dto/transfer-dto";

export default interface TransferGatewayOutputPort {

/**
* Gets the list of all transfer statistics
* @param rucioAuthToken A valid Rucio Auth Token.
*/
listTransferStatistics(rucioAuthToken: string): Promise<ListTransferStatisticsDTO>

/**
* Lists all active transfers over a given source-destination RSE pair
* @param rucioAuthToken A valid Rucio Auth Token.
* @param sourceRse The source RSE.
* @param destRse The destination RSE.
*/
listTransfers(rucioAuthToken: string, sourceRse: string, destRse: string): Promise<ListTransfersDTO>
}

0 comments on commit 317f4b4

Please sign in to comment.