diff --git a/src/app/config/router/instance.tsx b/src/app/config/router/instance.tsx
index e38b1f7..389e827 100644
--- a/src/app/config/router/instance.tsx
+++ b/src/app/config/router/instance.tsx
@@ -8,6 +8,7 @@ import { AuthProvider } from '@entities/auth';
import { CreateQueuePage, QueueDetailPage, QueueListPage, UpdateQueuePage } from '@pages/queue';
import { ConnectionDetailPage, ConnectionListPage } from '@pages/connection';
import { TransferDetailPage, TransferListPage } from '@pages/transfer';
+import { RunDetailPage } from '@pages/run';
import { ErrorBoundary, NotFoundError } from '../errorBoundary';
@@ -95,6 +96,10 @@ export const router = createBrowserRouter([
path: '/transfers/:id',
element: ,
},
+ {
+ path: '/transfers/runs/:id',
+ element: ,
+ },
],
},
{
diff --git a/src/entities/group/api/groupService.ts b/src/entities/group/api/groupService.ts
index 7acedf6..b343159 100644
--- a/src/entities/group/api/groupService.ts
+++ b/src/entities/group/api/groupService.ts
@@ -9,6 +9,7 @@ import {
GetGroupsRequest,
GetGroupUsersRequest,
Group,
+ GroupData,
GroupUser,
UpdateGroupRequest,
UpdateGroupUserRequest,
@@ -23,11 +24,11 @@ export const groupService = {
return axiosInstance.get(`groups/${id}`);
},
- createGroup: (data: CreateGroupRequest): Promise => {
+ createGroup: (data: CreateGroupRequest): Promise => {
return axiosInstance.post(`groups`, data);
},
- updateGroup: ({ id, ...data }: UpdateGroupRequest): Promise => {
+ updateGroup: ({ id, ...data }: UpdateGroupRequest): Promise => {
return axiosInstance.patch(`groups/${id}`, data);
},
diff --git a/src/entities/run/api/constants.ts b/src/entities/run/api/constants.ts
new file mode 100644
index 0000000..e4819c2
--- /dev/null
+++ b/src/entities/run/api/constants.ts
@@ -0,0 +1,8 @@
+export enum RunStatus {
+ CREATED = 'CREATED',
+ STARTED = 'STARTED',
+ FAILED = 'FAILED',
+ SEND_STOP_SIGNAL = 'SEND STOP SIGNAL',
+ STOPPED = 'STOPPED',
+ FINISHED = 'FINISHED',
+}
diff --git a/src/entities/run/api/hooks/index.ts b/src/entities/run/api/hooks/index.ts
new file mode 100644
index 0000000..5f20906
--- /dev/null
+++ b/src/entities/run/api/hooks/index.ts
@@ -0,0 +1 @@
+export * from './useGetRun';
diff --git a/src/entities/run/api/hooks/useGetRun/index.ts b/src/entities/run/api/hooks/useGetRun/index.ts
new file mode 100644
index 0000000..3846a5e
--- /dev/null
+++ b/src/entities/run/api/hooks/useGetRun/index.ts
@@ -0,0 +1,13 @@
+import { useSuspenseQuery, UseSuspenseQueryResult } from '@tanstack/react-query';
+
+import { GetRunRequest, Run } from '../../types';
+import { RunQueryKey } from '../../keys';
+import { runService } from '../../runService';
+
+/** Hook for getting run info from backend */
+export const useGetRun = ({ id }: GetRunRequest): UseSuspenseQueryResult => {
+ return useSuspenseQuery({
+ queryKey: [RunQueryKey.GET_RUN, id],
+ queryFn: () => runService.getRun({ id }),
+ });
+};
diff --git a/src/entities/run/api/index.ts b/src/entities/run/api/index.ts
new file mode 100644
index 0000000..8e7d299
--- /dev/null
+++ b/src/entities/run/api/index.ts
@@ -0,0 +1,5 @@
+export * from './runService';
+export * from './types';
+export * from './keys';
+export * from './hooks';
+export * from './constants';
diff --git a/src/entities/run/api/keys/index.ts b/src/entities/run/api/keys/index.ts
new file mode 100644
index 0000000..0aed69e
--- /dev/null
+++ b/src/entities/run/api/keys/index.ts
@@ -0,0 +1,4 @@
+export const RunQueryKey = {
+ GET_RUNS: 'GET_RUNS',
+ GET_RUN: 'GET_RUN',
+} as const;
diff --git a/src/entities/run/api/runService.ts b/src/entities/run/api/runService.ts
new file mode 100644
index 0000000..f7f5220
--- /dev/null
+++ b/src/entities/run/api/runService.ts
@@ -0,0 +1,14 @@
+import { axiosInstance } from '@shared/config';
+import { PaginationResponse } from '@shared/types';
+
+import { GetRunRequest, Run, GetRunsRequest } from './types';
+
+export const runService = {
+ getRuns: (params: GetRunsRequest): Promise> => {
+ return axiosInstance.get('runs', { params });
+ },
+
+ getRun: ({ id }: GetRunRequest): Promise => {
+ return axiosInstance.get(`runs/${id}`);
+ },
+};
diff --git a/src/entities/run/api/types.ts b/src/entities/run/api/types.ts
new file mode 100644
index 0000000..a138ad9
--- /dev/null
+++ b/src/entities/run/api/types.ts
@@ -0,0 +1,20 @@
+import { PaginationRequest } from '@shared/types';
+
+import { RunStatus } from './constants';
+
+export interface Run {
+ id: number;
+ transfer_id: number;
+ started_at: string | null;
+ ended_at: string | null;
+ status: keyof typeof RunStatus;
+ log_url: string | null;
+}
+
+export interface GetRunsRequest extends PaginationRequest {
+ transfer_id: number;
+}
+
+export interface GetRunRequest {
+ id: number;
+}
diff --git a/src/entities/run/index.ts b/src/entities/run/index.ts
new file mode 100644
index 0000000..1a554c5
--- /dev/null
+++ b/src/entities/run/index.ts
@@ -0,0 +1,2 @@
+export * from './api';
+export * from './ui';
diff --git a/src/entities/run/ui/RunStatusBadge/index.tsx b/src/entities/run/ui/RunStatusBadge/index.tsx
new file mode 100644
index 0000000..6791ef7
--- /dev/null
+++ b/src/entities/run/ui/RunStatusBadge/index.tsx
@@ -0,0 +1,11 @@
+import React, { memo } from 'react';
+import { Badge } from 'antd';
+import { RunStatus } from '@entities/run';
+
+import { RunStatusBadgeProps } from './types';
+import { getRunStatusColor } from './utils';
+
+export const RunStatusBadge = memo(({ status }: RunStatusBadgeProps) => {
+ const statusText = RunStatus[status];
+ return ;
+});
diff --git a/src/entities/run/ui/RunStatusBadge/types.ts b/src/entities/run/ui/RunStatusBadge/types.ts
new file mode 100644
index 0000000..bb0d643
--- /dev/null
+++ b/src/entities/run/ui/RunStatusBadge/types.ts
@@ -0,0 +1,5 @@
+import { RunStatus } from '../../api';
+
+export interface RunStatusBadgeProps {
+ status: keyof typeof RunStatus;
+}
diff --git a/src/entities/run/ui/RunStatusBadge/utils/getRunStatusColor/index.ts b/src/entities/run/ui/RunStatusBadge/utils/getRunStatusColor/index.ts
new file mode 100644
index 0000000..8f154bd
--- /dev/null
+++ b/src/entities/run/ui/RunStatusBadge/utils/getRunStatusColor/index.ts
@@ -0,0 +1,18 @@
+import { RunStatus } from '@entities/run';
+import { BadgeProps } from 'antd';
+
+/** Util for getting value of prop "status" for run status badge */
+export const getRunStatusColor = (status: RunStatus): BadgeProps['status'] => {
+ switch (status) {
+ case RunStatus.CREATED:
+ case RunStatus.STARTED:
+ return 'default';
+ case RunStatus.FAILED:
+ return 'error';
+ case RunStatus.SEND_STOP_SIGNAL:
+ case RunStatus.STOPPED:
+ return 'warning';
+ case RunStatus.FINISHED:
+ return 'success';
+ }
+};
diff --git a/src/entities/run/ui/RunStatusBadge/utils/index.ts b/src/entities/run/ui/RunStatusBadge/utils/index.ts
new file mode 100644
index 0000000..1ab3895
--- /dev/null
+++ b/src/entities/run/ui/RunStatusBadge/utils/index.ts
@@ -0,0 +1 @@
+export * from './getRunStatusColor';
diff --git a/src/entities/run/ui/index.ts b/src/entities/run/ui/index.ts
new file mode 100644
index 0000000..f74d651
--- /dev/null
+++ b/src/entities/run/ui/index.ts
@@ -0,0 +1 @@
+export * from './RunStatusBadge';
diff --git a/src/features/group/CreateGroup/index.tsx b/src/features/group/CreateGroup/index.tsx
index 18cb097..4825ba9 100644
--- a/src/features/group/CreateGroup/index.tsx
+++ b/src/features/group/CreateGroup/index.tsx
@@ -1,14 +1,14 @@
import React from 'react';
import { ControlButtons, ManagedForm } from '@shared/ui';
-import { Group, GroupQueryKey, groupService } from '@entities/group';
+import { GroupData, GroupQueryKey, groupService } from '@entities/group';
import { Form, Input } from 'antd';
import { useNavigate } from 'react-router-dom';
export const CreateGroup = () => {
const navigate = useNavigate();
- const onSuccess = (response: Group) => {
- navigate(`/groups/${response.data.id}`);
+ const onSuccess = (response: GroupData) => {
+ navigate(`/groups/${response.id}`);
};
const onCancel = () => {
diff --git a/src/features/group/UpdateGroup/index.tsx b/src/features/group/UpdateGroup/index.tsx
index df4ad6f..b2436dd 100644
--- a/src/features/group/UpdateGroup/index.tsx
+++ b/src/features/group/UpdateGroup/index.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { ControlButtons, ManagedForm, ManagedSelect } from '@shared/ui';
-import { Group, GroupQueryKey, groupService } from '@entities/group';
+import { GroupData, GroupQueryKey, groupService } from '@entities/group';
import { Form, Input } from 'antd';
import { useNavigate } from 'react-router-dom';
import { UserQueryKey, userService } from '@entities/user';
@@ -15,8 +15,8 @@ export const UpdateGroup = ({ group }: UpdateGroupProps) => {
return groupService.updateGroup({ ...values, id: group.id });
};
- const onSuccess = (response: Group) => {
- navigate(`/groups/${response.data.id}`);
+ const onSuccess = (response: GroupData) => {
+ navigate(`/groups/${response.id}`);
};
const onCancel = () => {
@@ -24,7 +24,7 @@ export const UpdateGroup = ({ group }: UpdateGroupProps) => {
};
return (
-
+
mutationFunction={handleUpdateGroup}
initialValues={getUpdateGroupInitialValues(group)}
onSuccess={onSuccess}
diff --git a/src/features/run/RunDetailInfo/index.tsx b/src/features/run/RunDetailInfo/index.tsx
new file mode 100644
index 0000000..ad19605
--- /dev/null
+++ b/src/features/run/RunDetailInfo/index.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Descriptions } from 'antd';
+import { Link } from 'react-router-dom';
+import { RunStatusBadge } from '@entities/run';
+import { Typography } from 'antd';
+
+const { Text } = Typography;
+
+import { RunDetailInfoProps } from './types';
+
+export const RunDetailInfo = ({ run, transfer, ...props }: RunDetailInfoProps) => {
+ return (
+
+
+ {run.id}
+
+
+
+
+
+ {/* //TODO: [DOP-20067] Rewrite on dayjs when "started_at" field will have not null value */}
+ {run.started_at || ''}
+
+
+ {/* //TODO: [DOP-20067] Rewrite on dayjs when "ended_at" field will have not null value */}
+ {run.ended_at || ''}
+
+
+ {run.log_url ? (
+
+
+ {run.log_url}
+
+
+ ) : (
+ ''
+ )}
+
+
+ {transfer.name}
+
+
+ );
+};
diff --git a/src/features/run/RunDetailInfo/types.ts b/src/features/run/RunDetailInfo/types.ts
new file mode 100644
index 0000000..743ad59
--- /dev/null
+++ b/src/features/run/RunDetailInfo/types.ts
@@ -0,0 +1,8 @@
+import { Run } from '@entities/run';
+import { Transfer } from '@entities/transfer';
+import { DescriptionsProps } from 'antd';
+
+export interface RunDetailInfoProps extends DescriptionsProps {
+ run: Run;
+ transfer: Transfer;
+}
diff --git a/src/features/run/RunList/constants.tsx b/src/features/run/RunList/constants.tsx
new file mode 100644
index 0000000..5f67ecd
--- /dev/null
+++ b/src/features/run/RunList/constants.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import { PaginationResponse } from '@shared/types';
+import { TableColumns } from '@shared/ui';
+import { Run, RunStatusBadge } from '@entities/run';
+import { Typography } from 'antd';
+import { Link } from 'react-router-dom';
+
+const { Text } = Typography;
+
+export const RUN_LIST_COLUMNS: TableColumns> = [
+ {
+ title: 'Id',
+ dataIndex: 'id',
+ render: (id, record) => {id},
+ width: 150,
+ },
+ {
+ title: 'Status',
+ dataIndex: 'status',
+ render: (value, record) => ,
+ width: 150,
+ },
+ {
+ title: 'Started at',
+ dataIndex: 'started_at',
+ //TODO: [DOP-20067] Rewrite on dayjs when "started_at" field will have not null value
+ width: 150,
+ },
+ {
+ title: 'Ended at',
+ dataIndex: 'ended_at',
+ //TODO: [DOP-20067] Rewrite on dayjs when "ended_at" field will have not null value
+ width: 150,
+ },
+ {
+ title: 'Log url',
+ dataIndex: 'log_url',
+ render: (value, record) =>
+ record.log_url ? (
+
+
+ {record.log_url}
+
+
+ ) : (
+ ''
+ ),
+ },
+];
diff --git a/src/features/run/RunList/index.tsx b/src/features/run/RunList/index.tsx
new file mode 100644
index 0000000..f3e6273
--- /dev/null
+++ b/src/features/run/RunList/index.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { ManagedTable } from '@shared/ui';
+import { PaginationRequest } from '@shared/types';
+import { RunQueryKey, runService } from '@entities/run';
+
+import { RUN_LIST_COLUMNS } from './constants';
+import { RunListProps } from './types';
+
+export const RunList = ({ transferId }: RunListProps) => {
+ const handleGetRuns = (params: PaginationRequest) => {
+ return runService.getRuns({ ...params, transfer_id: transferId });
+ };
+
+ return (
+
+ );
+};
diff --git a/src/features/run/RunList/types.ts b/src/features/run/RunList/types.ts
new file mode 100644
index 0000000..a94de52
--- /dev/null
+++ b/src/features/run/RunList/types.ts
@@ -0,0 +1,3 @@
+export interface RunListProps {
+ transferId: number;
+}
diff --git a/src/features/run/index.ts b/src/features/run/index.ts
new file mode 100644
index 0000000..f211f80
--- /dev/null
+++ b/src/features/run/index.ts
@@ -0,0 +1,2 @@
+export * from './RunList';
+export * from './RunDetailInfo';
diff --git a/src/features/transfer/TransferDetailInfo/index.tsx b/src/features/transfer/TransferDetailInfo/index.tsx
index b4b167d..24aa9b9 100644
--- a/src/features/transfer/TransferDetailInfo/index.tsx
+++ b/src/features/transfer/TransferDetailInfo/index.tsx
@@ -35,7 +35,7 @@ export const TransferDetailInfo = ({
{connectionTarget.name}
-
+
{queue.name}
diff --git a/src/pages/connection/ConnectionDetailPage/index.tsx b/src/pages/connection/ConnectionDetailPage/index.tsx
index 8a13b9e..c16d4d2 100644
--- a/src/pages/connection/ConnectionDetailPage/index.tsx
+++ b/src/pages/connection/ConnectionDetailPage/index.tsx
@@ -20,7 +20,7 @@ export const ConnectionDetailPage = () => {
return (
- {connection.name}
+ Connection: {connection.name}
);
diff --git a/src/pages/group/GroupDetailPage/index.tsx b/src/pages/group/GroupDetailPage/index.tsx
index 065e0e4..1a5dfe3 100644
--- a/src/pages/group/GroupDetailPage/index.tsx
+++ b/src/pages/group/GroupDetailPage/index.tsx
@@ -25,7 +25,7 @@ export const GroupDetailPage = () => {
return (
- {group.data.name}
+ Group: {group.data.name}
{
return (
- {queue.name}
+ Queue: {queue.name}
);
diff --git a/src/pages/run/RunDetailPage/index.tsx b/src/pages/run/RunDetailPage/index.tsx
new file mode 100644
index 0000000..5453bcb
--- /dev/null
+++ b/src/pages/run/RunDetailPage/index.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { PageDetailParams } from '@shared/types';
+import { PageContentWrapper } from '@shared/ui';
+import { Typography } from 'antd';
+import { useParams } from 'react-router-dom';
+import { useGetGroup } from '@entities/group';
+import { useGetRun } from '@entities/run';
+import { useGetQueue } from '@entities/queue';
+import { TransferDetailInfo } from '@features/transfer';
+import { ConnectionDetailInfo } from '@features/connection';
+import { useGetConnection } from '@entities/connection';
+import { useGetTransfer } from '@entities/transfer';
+import { RunDetailInfo } from '@features/run';
+
+import classes from './styles.module.less';
+
+const { Title } = Typography;
+
+export const RunDetailPage = () => {
+ const params = useParams();
+ const { data: run } = useGetRun({ id: Number(params.id) });
+ const { data: transfer } = useGetTransfer({ id: run.transfer_id });
+ const { data: group } = useGetGroup({ id: transfer.group_id });
+ const { data: connectionSource } = useGetConnection({ id: transfer.source_connection_id });
+ const { data: connectionTarget } = useGetConnection({ id: transfer.target_connection_id });
+ const { data: queue } = useGetQueue({ id: transfer.queue_id });
+
+ if (!run || !transfer || !group || !connectionSource || !connectionTarget || !queue) {
+ return null;
+ }
+
+ return (
+
+
+ Run: #{run.id}
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/run/RunDetailPage/styles.module.less b/src/pages/run/RunDetailPage/styles.module.less
new file mode 100644
index 0000000..18a4646
--- /dev/null
+++ b/src/pages/run/RunDetailPage/styles.module.less
@@ -0,0 +1,11 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: 60px;
+
+ .extra {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ }
+}
diff --git a/src/pages/run/index.ts b/src/pages/run/index.ts
new file mode 100644
index 0000000..58a0fd9
--- /dev/null
+++ b/src/pages/run/index.ts
@@ -0,0 +1 @@
+export * from './RunDetailPage';
diff --git a/src/pages/transfer/TransferDetailPage/index.tsx b/src/pages/transfer/TransferDetailPage/index.tsx
index 30ebaaa..526205f 100644
--- a/src/pages/transfer/TransferDetailPage/index.tsx
+++ b/src/pages/transfer/TransferDetailPage/index.tsx
@@ -8,6 +8,9 @@ import { useGetTransfer } from '@entities/transfer';
import { TransferDetail } from '@widgets/transfer';
import { useGetConnection } from '@entities/connection';
import { useGetQueue } from '@entities/queue';
+import { TransferRuns } from '@widgets/run';
+
+import classes from './styles.module.less';
const { Title } = Typography;
@@ -24,15 +27,18 @@ export const TransferDetailPage = () => {
}
return (
-
- {transfer.name}
-
-
+
+
+ Transfer: {transfer.name}
+
+
+
+
);
};
diff --git a/src/pages/transfer/TransferDetailPage/styles.module.less b/src/pages/transfer/TransferDetailPage/styles.module.less
new file mode 100644
index 0000000..a03274e
--- /dev/null
+++ b/src/pages/transfer/TransferDetailPage/styles.module.less
@@ -0,0 +1,5 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: 60px;
+}
diff --git a/src/pages/user/UserDetailPage/index.tsx b/src/pages/user/UserDetailPage/index.tsx
index 762d3bf..900b75f 100644
--- a/src/pages/user/UserDetailPage/index.tsx
+++ b/src/pages/user/UserDetailPage/index.tsx
@@ -17,7 +17,7 @@ export const UserDetailPage = () => {
return (
- {user.username}
+ User: {user.username}
);
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/index.tsx b/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/index.tsx
new file mode 100644
index 0000000..45be59d
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/index.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { DEFAULT_MODAL_WIDTH } from '@shared/constants';
+import { ModalWrapper } from '@shared/ui';
+
+import { CreateRunModalProps } from './types';
+
+export const CreateRunModal = ({ transferId, transferName, onClose, ...props }: CreateRunModalProps) => {
+ return (
+
+ {/* //TODO: [DOP-20067] add create run modal */}
+ {/* */}
+
+ );
+};
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/types.ts b/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/types.ts
new file mode 100644
index 0000000..8f91d3a
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/components/CreateRunModal/types.ts
@@ -0,0 +1,7 @@
+import { ModalProps } from 'antd';
+
+export interface CreateRunModalProps extends ModalProps {
+ transferId: number;
+ transferName: string;
+ onClose: () => void;
+}
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/components/index.ts b/src/widgets/run/TransferRuns/components/CreateRunButton/components/index.ts
new file mode 100644
index 0000000..def83d0
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/components/index.ts
@@ -0,0 +1 @@
+export * from './CreateRunModal';
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/index.tsx b/src/widgets/run/TransferRuns/components/CreateRunButton/index.tsx
new file mode 100644
index 0000000..f815eb2
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/index.tsx
@@ -0,0 +1,29 @@
+import React, { memo } from 'react';
+import { Button } from 'antd';
+import { useModalState } from '@shared/hooks';
+
+import { CreateRunModal } from './components';
+import classes from './styles.module.less';
+import { CreateRunButtonProps } from './types';
+
+export const CreateRunButton = memo(({ transferId, transferName }: CreateRunButtonProps) => {
+ const {
+ isOpened: isOpenedCreateRunModal,
+ handleOpen: handleOpenCreateRunModal,
+ handleClose: handleCloseCreateRunModal,
+ } = useModalState();
+
+ return (
+ <>
+
+
+ >
+ );
+});
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/styles.module.less b/src/widgets/run/TransferRuns/components/CreateRunButton/styles.module.less
new file mode 100644
index 0000000..5a56e88
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/styles.module.less
@@ -0,0 +1,3 @@
+.button {
+ align-self: flex-end;
+}
diff --git a/src/widgets/run/TransferRuns/components/CreateRunButton/types.ts b/src/widgets/run/TransferRuns/components/CreateRunButton/types.ts
new file mode 100644
index 0000000..d86d99f
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/CreateRunButton/types.ts
@@ -0,0 +1,4 @@
+export interface CreateRunButtonProps {
+ transferId: number;
+ transferName: string;
+}
diff --git a/src/widgets/run/TransferRuns/components/index.ts b/src/widgets/run/TransferRuns/components/index.ts
new file mode 100644
index 0000000..9339d48
--- /dev/null
+++ b/src/widgets/run/TransferRuns/components/index.ts
@@ -0,0 +1 @@
+export * from './CreateRunButton';
diff --git a/src/widgets/run/TransferRuns/index.tsx b/src/widgets/run/TransferRuns/index.tsx
new file mode 100644
index 0000000..4670ded
--- /dev/null
+++ b/src/widgets/run/TransferRuns/index.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { AccessWrapper, PageContentWrapper } from '@shared/ui';
+import { Typography } from 'antd';
+import { UserRole } from '@shared/types';
+import { RunList } from '@features/run';
+
+import { TransferRunsProps } from './types';
+import { CreateRunButton } from './components';
+import classes from './styles.module.less';
+
+const { Text } = Typography;
+
+export const TransferRuns = ({ group, transferId, transferName }: TransferRunsProps) => {
+ return (
+
+
+
+ Transfer runs
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/widgets/run/TransferRuns/styles.module.less b/src/widgets/run/TransferRuns/styles.module.less
new file mode 100644
index 0000000..8f6c909
--- /dev/null
+++ b/src/widgets/run/TransferRuns/styles.module.less
@@ -0,0 +1,9 @@
+.header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .subtitle {
+ font-size: 16px;
+ }
+}
diff --git a/src/widgets/run/TransferRuns/types.ts b/src/widgets/run/TransferRuns/types.ts
new file mode 100644
index 0000000..e727062
--- /dev/null
+++ b/src/widgets/run/TransferRuns/types.ts
@@ -0,0 +1,7 @@
+import { Group } from '@entities/group';
+
+export interface TransferRunsProps {
+ group: Group;
+ transferId: number;
+ transferName: string;
+}
diff --git a/src/widgets/run/index.ts b/src/widgets/run/index.ts
new file mode 100644
index 0000000..e12e170
--- /dev/null
+++ b/src/widgets/run/index.ts
@@ -0,0 +1 @@
+export * from './TransferRuns';