Skip to content

Commit

Permalink
Merge pull request #2077 from Gkrumbach07/admin-image-page
Browse files Browse the repository at this point in the history
Added accelerator column and field
  • Loading branch information
openshift-merge-bot[bot] authored Nov 15, 2023
2 parents 8c9e2ec + cbf7a92 commit 8aac844
Show file tree
Hide file tree
Showing 17 changed files with 582 additions and 125 deletions.
20 changes: 20 additions & 0 deletions backend/src/routes/api/images/imageUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ const mapImageStreamToBYONImage = (is: ImageStream): BYONImage => ({
imported_time: is.metadata.creationTimestamp,
url: is.metadata.annotations['opendatahub.io/notebook-image-url'],
provider: is.metadata.annotations['opendatahub.io/notebook-image-creator'],
recommendedAcceleratorIdentifiers: jsonParseRecommendedAcceleratorIdentifiers(
is.metadata.annotations['opendatahub.io/recommended-accelerators'],
),
});

export const postImage = async (
Expand Down Expand Up @@ -276,6 +279,9 @@ export const postImage = async (
'opendatahub.io/notebook-image-name': body.display_name,
'opendatahub.io/notebook-image-url': fullURL,
'opendatahub.io/notebook-image-creator': body.provider,
'opendatahub.io/recommended-accelerators': JSON.stringify(
body.recommendedAcceleratorIdentifiers ?? [],
),
},
name: `custom-${translateDisplayNameForK8s(body.display_name)}`,
namespace: namespace,
Expand Down Expand Up @@ -413,6 +419,12 @@ export const updateImage = async (
imageStream.metadata.annotations['opendatahub.io/notebook-image-desc'] = body.description;
}

if (body.recommendedAcceleratorIdentifiers !== undefined) {
imageStream.metadata.annotations['opendatahub.io/recommended-accelerators'] = JSON.stringify(
body.recommendedAcceleratorIdentifiers,
);
}

await customObjectsApi
.patchNamespacedCustomObject(
'image.openshift.io',
Expand Down Expand Up @@ -446,3 +458,11 @@ const jsonParsePackage = (unparsedPackage: string): BYONImagePackage[] => {
return [];
}
};

const jsonParseRecommendedAcceleratorIdentifiers = (unparsedRecommendations: string): string[] => {
try {
return JSON.parse(unparsedRecommendations) || [];
} catch {
return [];
}
};
1 change: 1 addition & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ export type BYONImage = {
visible: boolean;
software: BYONImagePackage[];
packages: BYONImagePackage[];
recommendedAcceleratorIdentifiers: string[];
};

export type ImageTag = {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/__mocks__/mockByon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const mockByon = (opts?: RecursivePartial<BYONImage[]>): BYONImage[] =>
name: 'byon-123',
display_name: 'Testing Custom Image',
description: 'A custom notebook image',
recommendedAcceleratorIdentifiers: [],
visible: true,
packages: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,30 @@ test('Invalid id in edit page', async ({ page }) => {
page.getByText('acceleratorprofiles.dashboard.opendatahub.io "test-accelerator" not found'),
).toHaveCount(1);
});

test('One preset identifier is auto filled and disabled', async ({ page }) => {
await page.goto(
navigateToStory(
'pages-acceleratorprofiles-manageacceleratorprofile',
'create-accelerator-with-one-set-identifier',
),
);

expect(await page.getByTestId('accelerator-identifier-input').inputValue()).toBe(
'test-identifier',
);

await expect(page.getByTestId('accelerator-identifier-input')).toBeDisabled();
});

test('Multiple preset identifiers show dropdown', async ({ page }) => {
await page.goto(
navigateToStory(
'pages-acceleratorprofiles-manageacceleratorprofile',
'create-accelerator-with-multiple-set-identifiers',
),
);

await page.getByRole('button', { name: 'Options menu' }).click();
await expect(page.getByRole('option', { name: 'test-identifier-3' })).toHaveCount(1);
});
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,54 @@ export const TolerationsModal: StoryObj = {
await userEvent.click(canvas.getByText('Add toleration', { selector: 'button' }));
},
};

export const CreateAcceleratorWithOneSetIdentifier: StoryObj = {
render: () => (
<RenderComponent>
<ManageAcceleratorProfileComponent />
</RenderComponent>
),
play: async ({ canvasElement }) => {
// load page and wait until settled
const canvas = within(canvasElement);
await canvas.findByText('Identifier', undefined, {
timeout: 5000,
});
},
parameters: {
reactRouter: {
routePath: '/create',
searchParams: {
identifiers: ['test-identifier'],
},
},
},
};

export const CreateAcceleratorWithMultipleSetIdentifiers: StoryObj = {
render: () => (
<RenderComponent>
<ManageAcceleratorProfileComponent />
</RenderComponent>
),
play: async ({ canvasElement }) => {
// load page and wait until settled
const canvas = within(canvasElement);
await canvas.findByText('Identifier', undefined, {
timeout: 5000,
});
},
parameters: {
reactRouter: {
routePath: '/create',
searchParams: {
identifiers: [
'test-identifier-1',
'test-identifier-2',
'test-identifier-3',
'test-identifier-3',
],
},
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ test('Table filtering, sorting, searching', async ({ page }) => {
await page.getByRole('button', { name: 'Provider' }).click();
expect(page.getByText('image-0'));

// by accelerator
await page.getByRole('button', { name: 'Recommended accelerators' }).click();
expect(page.getByText('test-accelerator')).toHaveCount(0);
await page.getByRole('button', { name: 'Recommended accelerators' }).click();
expect(page.getByText('test-accelerator'));

// by enabled
await page.getByRole('button', { name: 'Enable', exact: true }).click();
expect(page.getByText('image-14'));
Expand Down Expand Up @@ -114,6 +120,30 @@ test('Import form fields', async ({ page }) => {
await page.getByLabel('Name *').fill('image');
await expect(page.getByRole('button', { name: 'Import' })).toBeEnabled();

// test accelerator select field
// select accelerator from api call
await page.getByPlaceholder('Example, nvidia.com/gpu').click();
await page.getByRole('option', { name: 'nvidia.com/gpu' }).click();

// create new and select
await page.getByPlaceholder('Example, nvidia.com/gpu').click();
await page.getByPlaceholder('Example, nvidia.com/gpu').fill('test.com/gpu');
await page.getByRole('option', { name: 'Create "test.com/gpu"' }).click();
await page.getByRole('button', { name: 'Options menu' }).click();
expect(page.getByText('test.com/gpu'));

// remove custom
await page.getByRole('button', { name: 'Remove test.com/gpu' }).click();
await page.getByRole('button', { name: 'Options menu' }).click();
await expect(page.getByText('test.com/gpu')).toHaveCount(0);

// reselect custom
await page
.getByRole('dialog', { name: 'Import notebook image' })
.getByRole('button', { name: 'Options menu' })
.click();
await page.getByRole('option', { name: 'test.com/gpu' }).click();

// test form is disabled after entering software add form
await page.getByTestId('add-software-button').click();
await expect(page.getByRole('button', { name: 'Import' })).toBeDisabled();
Expand Down Expand Up @@ -204,7 +234,7 @@ test('Edit form fields match', async ({ page }) => {
expect(await page.getByLabel('Image Location *').inputValue()).toBe('test-image:latest');
expect(await page.getByLabel('Name *').inputValue()).toBe('Testing Custom Image');
expect(await page.getByLabel('Description').inputValue()).toBe('A custom notebook image');

expect(page.getByText('nvidia.com/gpu'));
// test software and packages have correct values
expect(page.getByRole('gridcell', { name: 'test-software' }));
expect(page.getByRole('gridcell', { name: '2.0' }));
Expand Down
Loading

0 comments on commit 8aac844

Please sign in to comment.