mirror of https://github.com/portainer/portainer
fix(helm): helm apps do not combine in applications view if different namespace [R8S-420] (#988)
parent
3f030394c6
commit
208534c9d9
|
@ -0,0 +1,161 @@
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
|
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
|
||||||
|
import { withTestRouter } from '@/react/test-utils/withRouter';
|
||||||
|
import { UserViewModel } from '@/portainer/models/user';
|
||||||
|
import { withUserProvider } from '@/react/test-utils/withUserProvider';
|
||||||
|
|
||||||
|
import { PodKubernetesInstanceLabel, PodManagedByLabel } from '../../constants';
|
||||||
|
|
||||||
|
import { ApplicationsDatatable } from './ApplicationsDatatable';
|
||||||
|
|
||||||
|
const mockUseCurrentStateAndParams = vi.fn();
|
||||||
|
const mockUseEnvironmentId = vi.fn();
|
||||||
|
|
||||||
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
|
...(await importOriginal()),
|
||||||
|
useCurrentStateAndParams: () => mockUseCurrentStateAndParams(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@/react/hooks/useEnvironmentId', () => ({
|
||||||
|
useEnvironmentId: () => mockUseEnvironmentId(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@/react/kubernetes/applications/queries/useApplications', () => ({
|
||||||
|
useApplications: () => ({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
Id: '1',
|
||||||
|
Name: 'app1',
|
||||||
|
CreationDate: '2021-10-01T00:00:00Z',
|
||||||
|
ResourcePool: 'namespace1',
|
||||||
|
Image: 'image1',
|
||||||
|
ApplicationType: 'Pod',
|
||||||
|
Kind: 'Pod',
|
||||||
|
DeploymentType: 'Replicated',
|
||||||
|
Status: 'status1',
|
||||||
|
TotalPodsCount: 1,
|
||||||
|
RunningPodsCount: 1,
|
||||||
|
Metadata: {
|
||||||
|
labels: {
|
||||||
|
[PodKubernetesInstanceLabel]: 'helm-release-1',
|
||||||
|
[PodManagedByLabel]: 'Helm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: '2',
|
||||||
|
Name: 'app2',
|
||||||
|
CreationDate: '2021-10-01T00:00:00Z',
|
||||||
|
ResourcePool: 'namespace1',
|
||||||
|
Image: 'image1',
|
||||||
|
ApplicationType: 'Pod',
|
||||||
|
Kind: 'Pod',
|
||||||
|
DeploymentType: 'Replicated',
|
||||||
|
Status: 'status1',
|
||||||
|
TotalPodsCount: 1,
|
||||||
|
RunningPodsCount: 1,
|
||||||
|
Metadata: {
|
||||||
|
labels: {
|
||||||
|
[PodKubernetesInstanceLabel]: 'helm-release-1',
|
||||||
|
[PodManagedByLabel]: 'Helm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: '3',
|
||||||
|
Name: 'app3',
|
||||||
|
CreationDate: '2021-10-01T00:00:00Z',
|
||||||
|
ResourcePool: 'namespace2',
|
||||||
|
Image: 'image1',
|
||||||
|
ApplicationType: 'Pod',
|
||||||
|
Kind: 'Pod',
|
||||||
|
DeploymentType: 'Replicated',
|
||||||
|
Status: 'status1',
|
||||||
|
TotalPodsCount: 1,
|
||||||
|
RunningPodsCount: 1,
|
||||||
|
Metadata: {
|
||||||
|
labels: {
|
||||||
|
[PodKubernetesInstanceLabel]: 'helm-release-1',
|
||||||
|
[PodManagedByLabel]: 'Helm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isLoading: false,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@@/Link', () => ({
|
||||||
|
Link: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<span data-testid="mock-link">{children}</span>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@/react/kubernetes/components/CreateFromManifestButton', () => ({
|
||||||
|
CreateFromManifestButton: ({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
'data-cy'?: string;
|
||||||
|
}) => (
|
||||||
|
<button type="button" data-testid="mock-create-manifest-button" {...props}>
|
||||||
|
{children || 'Create from manifest'}
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
function renderComponent() {
|
||||||
|
const user = new UserViewModel({ Username: 'user' });
|
||||||
|
|
||||||
|
const Wrapped = withTestQueryProvider(
|
||||||
|
withUserProvider(withTestRouter(ApplicationsDatatable), user)
|
||||||
|
);
|
||||||
|
|
||||||
|
return render(
|
||||||
|
<Wrapped
|
||||||
|
tableState={{
|
||||||
|
search: '',
|
||||||
|
setSearch: () => {},
|
||||||
|
namespace: '',
|
||||||
|
setNamespace: () => {},
|
||||||
|
showSystemResources: false,
|
||||||
|
autoRefreshRate: 0,
|
||||||
|
setAutoRefreshRate: () => {},
|
||||||
|
setShowSystemResources: () => {},
|
||||||
|
sortBy: { id: 'Name', desc: false },
|
||||||
|
setSortBy: () => {},
|
||||||
|
pageSize: 10,
|
||||||
|
setPageSize: () => {},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ApplicationsDatatable', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockUseEnvironmentId.mockReturnValue(3);
|
||||||
|
mockUseCurrentStateAndParams.mockReturnValue({
|
||||||
|
params: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should group helm apps by namespace and instance label', async () => {
|
||||||
|
renderComponent();
|
||||||
|
|
||||||
|
const helmReleases = await screen.findAllByText('helm-release-1');
|
||||||
|
expect(helmReleases).toHaveLength(2);
|
||||||
|
|
||||||
|
// Should show both namespaces in table cells
|
||||||
|
const namespace1Cells = await screen.findAllByRole('cell', {
|
||||||
|
name: 'namespace1',
|
||||||
|
});
|
||||||
|
const namespace2Cells = await screen.findAllByRole('cell', {
|
||||||
|
name: 'namespace2',
|
||||||
|
});
|
||||||
|
expect(namespace1Cells.length).toBeGreaterThan(0);
|
||||||
|
expect(namespace2Cells.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
|
@ -170,14 +170,18 @@ function separateHelmApps(applications: Application[]): ApplicationRowData[] {
|
||||||
|
|
||||||
const groupedHelmApps: Record<string, Application[]> = groupBy(
|
const groupedHelmApps: Record<string, Application[]> = groupBy(
|
||||||
helmApps,
|
helmApps,
|
||||||
(app) => app.Metadata?.labels[PodKubernetesInstanceLabel] ?? ''
|
(app) =>
|
||||||
|
`${app.ResourcePool}/${
|
||||||
|
app.Metadata?.labels[PodKubernetesInstanceLabel] ?? ''
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// build the helm apps row data from the grouped helm apps
|
// build the helm apps row data from the grouped helm apps
|
||||||
const helmAppsRowData = Object.entries(groupedHelmApps).reduce<
|
const helmAppsRowData = Object.entries(groupedHelmApps).reduce<
|
||||||
ApplicationRowData[]
|
ApplicationRowData[]
|
||||||
>((helmApps, [appName, apps]) => {
|
>((helmApps, [groupKey, apps]) => {
|
||||||
const helmApp = buildHelmAppRowData(appName, apps);
|
const instanceLabel = groupKey.split('/')[1];
|
||||||
|
const helmApp = buildHelmAppRowData(instanceLabel, apps);
|
||||||
return [...helmApps, helmApp];
|
return [...helmApps, helmApp];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue