diff --git a/frontend/src/libs/fleet.ts b/frontend/src/libs/fleet.ts index 9bbef8b25..1d5310e33 100644 --- a/frontend/src/libs/fleet.ts +++ b/frontend/src/libs/fleet.ts @@ -55,10 +55,13 @@ const getInstanceFields = (instance: IInstance) => ({ spot: instance.instance_type?.resources.spot, }); -export const getFleetInstancesLinkText = (fleet: IFleet): string | null => { +export const getFleetInstancesLinkText = (fleet: IFleet): string => { const instances = fleet.instances.filter((i) => i.status !== 'terminated'); + const hasPending = instances.some((i) => i.status !== 'pending'); - if (!instances.length) return null; + if (!instances.length) return '0 instances'; + + if (hasPending) return `${instances.length} instances`; const isSameInstances = instances.every((i) => isEqual(getInstanceFields(instances[0]), getInstanceFields(i))); diff --git a/frontend/src/pages/Fleets/Details/index.tsx b/frontend/src/pages/Fleets/Details/index.tsx index 1f012cbee..13d2f3687 100644 --- a/frontend/src/pages/Fleets/Details/index.tsx +++ b/frontend/src/pages/Fleets/Details/index.tsx @@ -1,10 +1,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import { useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { format } from 'date-fns'; import { Box, + Button, ColumnLayout, Container, ContentLayout, @@ -18,19 +19,24 @@ import { import { DATE_TIME_FORMAT } from 'consts'; import { useBreadcrumbs } from 'hooks'; -import { getFleetStatusIconType } from 'libs/fleet'; +import { getFleetInstancesLinkText, getFleetPrice, getFleetStatusIconType } from 'libs/fleet'; import { ROUTES } from 'routes'; import { useGetFleetDetailsQuery } from 'services/fleet'; +import { useDeleteFleet } from '../List/useDeleteFleet'; + export const FleetDetails: React.FC = () => { const { t } = useTranslation(); const params = useParams(); - const paramFleetName = params.fleetName ?? ''; + const paramFleetId = params.fleetId ?? ''; const paramProjectName = params.projectName ?? ''; + const navigate = useNavigate(); + + const { deleteFleets, isDeleting } = useDeleteFleet(); const { data, isLoading } = useGetFleetDetailsQuery({ projectName: paramProjectName, - fleetName: paramFleetName, + fleetId: paramFleetId, }); useBreadcrumbs([ @@ -47,13 +53,46 @@ export const FleetDetails: React.FC = () => { href: ROUTES.FLEETS.LIST, }, { - text: paramFleetName, - href: ROUTES.FLEETS.DETAILS.FORMAT(paramProjectName, paramFleetName), + text: data?.name ?? '', + href: ROUTES.FLEETS.DETAILS.FORMAT(paramProjectName, paramFleetId), }, ]); + const deleteClickHandle = () => { + if (!data) return; + + deleteFleets([data]) + .then(() => { + navigate(ROUTES.FLEETS.LIST); + }) + .catch(console.log); + }; + + const renderPrice = (fleet: IFleet) => { + const price = getFleetPrice(fleet); + + if (typeof price === 'number') return `$${price}`; + + return '-'; + }; + + const isDisabledDeleteButton = !data || isDeleting; + return ( - }> + + + + } + /> + } + > {isLoading && ( @@ -89,18 +128,13 @@ export const FleetDetails: React.FC = () => {
- {t('fleets.instances.backend')} -
{data.spec.configuration?.backends?.join(', ')}
-
- -
- {t('fleets.instances.region')} -
{data.spec.configuration.regions?.join(', ')}
-
+ {t('fleets.instances.title')} -
- {t('fleets.instances.region')} -
{data.spec.configuration?.spot_policy === 'spot' && }
+
+ + {getFleetInstancesLinkText(data)} + +
@@ -110,17 +144,7 @@ export const FleetDetails: React.FC = () => {
{t('fleets.instances.price')} -
{data.spec.configuration?.max_price && `$${data.spec.configuration?.max_price}`}
-
- -
- {t('fleets.instances.title')} - -
- - Show fleet's instances - -
+
{renderPrice(data)}
diff --git a/frontend/src/pages/Fleets/List/hooks.tsx b/frontend/src/pages/Fleets/List/hooks.tsx index 6388fa2c4..9631fc4ae 100644 --- a/frontend/src/pages/Fleets/List/hooks.tsx +++ b/frontend/src/pages/Fleets/List/hooks.tsx @@ -52,7 +52,7 @@ export const useColumnsDefinitions = () => { id: 'fleet_name', header: t('fleets.fleet'), cell: (item) => ( - {item.name} + {item.name} ), }, { @@ -74,14 +74,11 @@ export const useColumnsDefinitions = () => { { id: 'instances', header: t('fleets.instances.title'), - cell: (item) => { - const linkText = getFleetInstancesLinkText(item); - - if (linkText) - return {linkText}; - - return '-'; - }, + cell: (item) => ( + + {getFleetInstancesLinkText(item)} + + ), }, { id: 'started', @@ -205,7 +202,8 @@ export const useFleetsData = ({ project_name, only_active }: TFleetListRequestPa if (result.length > 0) { setPagesCount((count) => count - 1); - setData(result); + const reversedData = [...result].reverse(); + setData(reversedData); } else { setPagesCount(1); } diff --git a/frontend/src/pages/Instances/List/hooks/useColumnDefinitions.tsx b/frontend/src/pages/Instances/List/hooks/useColumnDefinitions.tsx index 5a2124272..941f87c65 100644 --- a/frontend/src/pages/Instances/List/hooks/useColumnDefinitions.tsx +++ b/frontend/src/pages/Instances/List/hooks/useColumnDefinitions.tsx @@ -18,7 +18,7 @@ export const useColumnsDefinitions = () => { header: t('fleets.fleet'), cell: (item) => item.fleet_name && item.project_name ? ( - + {item.fleet_name} ) : ( diff --git a/frontend/src/pages/Instances/List/hooks/useInstanceListData.ts b/frontend/src/pages/Instances/List/hooks/useInstanceListData.ts index fabdb484b..fe834bc6f 100644 --- a/frontend/src/pages/Instances/List/hooks/useInstanceListData.ts +++ b/frontend/src/pages/Instances/List/hooks/useInstanceListData.ts @@ -76,7 +76,8 @@ export const useInstanceListData = ({ project_names, only_active, fleet_ids }: T if (result.length > 0) { setPagesCount((count) => count - 1); - setData(result); + const reversedData = [...result].reverse(); + setData(reversedData); } else { setPagesCount(1); } diff --git a/frontend/src/routes.ts b/frontend/src/routes.ts index 07065aee4..b403b5588 100644 --- a/frontend/src/routes.ts +++ b/frontend/src/routes.ts @@ -80,9 +80,9 @@ export const ROUTES = { FLEETS: { LIST: '/fleets', DETAILS: { - TEMPLATE: `/projects/:projectName/fleets/:fleetName`, - FORMAT: (projectName: string, fleetName: string) => - buildRoute(ROUTES.FLEETS.DETAILS.TEMPLATE, { projectName, fleetName }), + TEMPLATE: `/projects/:projectName/fleets/:fleetId`, + FORMAT: (projectName: string, fleetId: string) => + buildRoute(ROUTES.FLEETS.DETAILS.TEMPLATE, { projectName, fleetId }), }, }, diff --git a/frontend/src/services/fleet.ts b/frontend/src/services/fleet.ts index d0b37b695..e74753b3c 100644 --- a/frontend/src/services/fleet.ts +++ b/frontend/src/services/fleet.ts @@ -37,13 +37,17 @@ export const fleetApi = createApi({ result ? [...result.map(({ name }) => ({ type: 'Fleet' as const, id: name })), 'Fleets'] : ['Fleets'], }), - getFleetDetails: builder.query({ - query: ({ projectName, fleetName }) => { + getFleetDetails: builder.query< + IFleet, + { projectName: IProject['project_name']; fleetName?: IFleet['name']; fleetId?: IFleet['id'] } + >({ + query: ({ projectName, fleetName, fleetId }) => { return { url: API.PROJECTS.FLEETS_DETAILS(projectName), method: 'POST', body: { name: fleetName, + id: fleetId, }, }; },