-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upcoming: [M3-7610] - Placement Groups Detail (#10096)
* Initial components * Wrap up with tests * Fix test! * Changeset and cleanup * Feedback * Add test and story * cleanup * feedback * oops fix test * Moar Feedback
- Loading branch information
1 parent
f0b774e
commit dfdab4b
Showing
13 changed files
with
306 additions
and
18 deletions.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
packages/manager/.changeset/pr-10096-upcoming-features-1706030600745.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@linode/manager": Upcoming Features | ||
--- | ||
|
||
Placement Groups Detail Page ([#10096](https://github.com/linode/manager/pull/10096)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
...manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsDetail.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import * as React from 'react'; | ||
|
||
import { placementGroupFactory } from 'src/factories'; | ||
import { renderWithTheme } from 'src/utilities/testHelpers'; | ||
|
||
import { PlacementGroupsDetail } from './PlacementGroupsDetail'; | ||
|
||
const queryMocks = vi.hoisted(() => ({ | ||
usePlacementGroupQuery: vi.fn().mockReturnValue({}), | ||
})); | ||
|
||
vi.mock('src/queries/placementGroups', async () => { | ||
const actual = await vi.importActual('src/queries/placementGroups'); | ||
return { | ||
...actual, | ||
usePlacementGroupQuery: queryMocks.usePlacementGroupQuery, | ||
}; | ||
}); | ||
|
||
describe('PlacementGroupsLanding', () => { | ||
it('renders a error page', () => { | ||
const { getByText } = renderWithTheme(<PlacementGroupsDetail />); | ||
|
||
expect(getByText('Not Found')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders a loading state', () => { | ||
queryMocks.usePlacementGroupQuery.mockReturnValue({ | ||
data: { | ||
data: placementGroupFactory.build({ | ||
id: 1, | ||
}), | ||
}, | ||
isLoading: true, | ||
}); | ||
|
||
const { getByRole } = renderWithTheme(<PlacementGroupsDetail />, { | ||
MemoryRouter: { | ||
initialEntries: [{ pathname: '/placement-groups/1' }], | ||
}, | ||
}); | ||
|
||
expect(getByRole('progressbar')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders breadcrumbs, docs link and tabs', () => { | ||
queryMocks.usePlacementGroupQuery.mockReturnValue({ | ||
data: placementGroupFactory.build({ | ||
affinity_type: 'anti_affinity', | ||
id: 1, | ||
label: 'My first PG', | ||
}), | ||
}); | ||
|
||
const { getByRole, getByText } = renderWithTheme( | ||
<PlacementGroupsDetail />, | ||
{ | ||
MemoryRouter: { | ||
initialEntries: [{ pathname: '/placement-groups/1' }], | ||
}, | ||
} | ||
); | ||
|
||
expect(getByText(/my first pg \(Anti-affinity\)/i)).toBeInTheDocument(); | ||
expect(getByText(/docs/i)).toBeInTheDocument(); | ||
expect(getByRole('tab', { name: 'Summary' })).toBeInTheDocument(); | ||
expect(getByRole('tab', { name: 'Linodes (3)' })).toBeInTheDocument(); | ||
}); | ||
}); |
117 changes: 117 additions & 0 deletions
117
...ages/manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsDetail.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import * as React from 'react'; | ||
import { useHistory, useParams } from 'react-router-dom'; | ||
|
||
import { CircleProgress } from 'src/components/CircleProgress'; | ||
import { DocumentTitleSegment } from 'src/components/DocumentTitle'; | ||
import { ErrorState } from 'src/components/ErrorState/ErrorState'; | ||
import { LandingHeader } from 'src/components/LandingHeader'; | ||
import { NotFound } from 'src/components/NotFound'; | ||
import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; | ||
import { TabLinkList } from 'src/components/Tabs/TabLinkList'; | ||
import { TabPanels } from 'src/components/Tabs/TabPanels'; | ||
import { Tabs } from 'src/components/Tabs/Tabs'; | ||
import { useFlags } from 'src/hooks/useFlags'; | ||
import { | ||
useMutatePlacementGroup, | ||
usePlacementGroupQuery, | ||
} from 'src/queries/placementGroups'; | ||
import { getErrorStringOrDefault } from 'src/utilities/errorUtils'; | ||
|
||
import { getAffinityLabel, getPlacementGroupLinodeCount } from '../utils'; | ||
|
||
export const PlacementGroupsDetail = () => { | ||
const flags = useFlags(); | ||
const { id, tab } = useParams<{ id: string; tab?: string }>(); | ||
const history = useHistory(); | ||
const placementGroupId = Number(id); | ||
const { | ||
data: placementGroup, | ||
error: placementGroupError, | ||
isLoading, | ||
} = usePlacementGroupQuery(placementGroupId, Boolean(flags.vmPlacement)); | ||
const { | ||
error: updatePlacementGroupError, | ||
mutateAsync: updatePlacementGroup, | ||
reset, | ||
} = useMutatePlacementGroup(placementGroupId); | ||
const errorText = getErrorStringOrDefault(updatePlacementGroupError ?? ''); | ||
|
||
if (!placementGroup) { | ||
return <NotFound />; | ||
} | ||
|
||
if (placementGroupError) { | ||
return ( | ||
<ErrorState errorText="There was a problem retrieving your Placement Group. Please try again." /> | ||
); | ||
} | ||
|
||
if (isLoading) { | ||
return <CircleProgress />; | ||
} | ||
|
||
const linodeCount = getPlacementGroupLinodeCount(placementGroup); | ||
const tabs = [ | ||
{ | ||
routeName: `/placement-groups/${id}`, | ||
title: 'Summary', | ||
}, | ||
{ | ||
routeName: `/placement-groups/${id}/linodes`, | ||
title: `Linodes (${linodeCount})`, | ||
}, | ||
]; | ||
const { affinity_type, label } = placementGroup; | ||
const affinityLabel = getAffinityLabel(affinity_type); | ||
const tabIndex = tab ? tabs.findIndex((t) => t.routeName.endsWith(tab)) : -1; | ||
|
||
const resetEditableLabel = () => { | ||
return `${label} (${affinityLabel})`; | ||
}; | ||
|
||
const handleLabelEdit = (newLabel: string) => { | ||
if (updatePlacementGroupError) { | ||
reset(); | ||
} | ||
|
||
return updatePlacementGroup({ label: newLabel }); | ||
}; | ||
|
||
return ( | ||
<> | ||
<DocumentTitleSegment segment={label} /> | ||
<LandingHeader | ||
breadcrumbProps={{ | ||
crumbOverrides: [ | ||
{ | ||
label: 'Placement Groups', | ||
position: 1, | ||
}, | ||
], | ||
onEditHandlers: { | ||
editableTextTitle: label, | ||
editableTextTitleSuffix: ` (${affinityLabel})`, | ||
errorText, | ||
onCancel: resetEditableLabel, | ||
onEdit: handleLabelEdit, | ||
}, | ||
pathname: `/placement-groups/${label}`, | ||
}} | ||
docsLabel="Docs" | ||
docsLink="TODO VM_Placement: add doc link" | ||
title="Placement Group Detail" | ||
/> | ||
<Tabs | ||
index={tabIndex === -1 ? 0 : tabIndex} | ||
onChange={(i) => history.push(tabs[i].routeName)} | ||
> | ||
<TabLinkList tabs={tabs} /> | ||
|
||
<TabPanels> | ||
<SafeTabPanel index={0}>TODO VM_Placement: summary</SafeTabPanel> | ||
<SafeTabPanel index={1}>TODO VM_Placement: linode list</SafeTabPanel> | ||
</TabPanels> | ||
</Tabs> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.