From b6b692d6c2ffc77bb0d286e09f459a34374e621d Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Date: Wed, 7 Aug 2024 09:42:26 -0400 Subject: [PATCH] [RHOAIENG-2404] Replace simple deprecated PF selects with SimpleDropdownSelect --- .../cypress/pages/acceleratorProfile.ts | 6 +- .../cypress/pages/components/TableToolbar.ts | 2 +- .../cypress/cypress/pages/modelMetrics.ts | 4 + .../cypress/cypress/pages/modelServing.ts | 6 +- .../cypress/pages/pipelines/artifacts.ts | 2 +- .../cypress/pages/pipelines/createRunPage.ts | 4 +- .../cypress/pages/pipelines/executions.ts | 2 +- .../pages/pipelines/pipelineFilterBar.ts | 2 +- .../cypress/cypress/pages/servingRuntimes.ts | 8 +- .../cypress/cypress/pages/workbench.ts | 2 +- .../modelRegistry/modelVersionDeploy.cy.ts | 2 +- .../mocked/modelRegistry/modelVersions.cy.ts | 2 +- .../mocked/modelServing/modelMetrics.cy.ts | 40 ++----- .../modelServing/servingRuntimeList.cy.ts | 26 ++--- .../mocked/pipelines/pipelineCreateRuns.cy.ts | 4 +- .../mocked/pipelines/pipelinesTopology.cy.ts | 8 +- .../tests/mocked/projects/workbench.cy.ts | 6 +- .../src/components/SimpleDropdownSelect.tsx | 81 -------------- ...eDropdownSelect.scss => SimpleSelect.scss} | 0 frontend/src/components/SimpleSelect.tsx | 96 ++++++++++++++++ .../dashboard/DashboardSearchField.tsx | 4 +- .../metrics/MetricsRefreshIntervalSelect.tsx | 31 +++--- .../metrics/MetricsTimeRangeSelect.tsx | 28 +++-- frontend/src/concepts/metrics/utils.ts | 11 +- .../compareRuns/CompareRunTableToolbar.tsx | 9 +- .../contentSections/TriggerTypeField.tsx | 6 +- .../pipelineRun/PipelineRunTableToolbar.tsx | 4 +- ...eBindingPermissionsPermissionSelection.tsx | 45 +++----- .../manage/tolerations/TolerationFields.tsx | 6 +- .../screens/manage/tolerations/const.ts | 6 +- .../learningCenter/LearningCenterToolbar.tsx | 105 ++++++++---------- .../ModelVersions/ModelVersionListView.tsx | 4 +- .../ModelVersionsArchiveListView.tsx | 4 +- .../RegisteredModelListView.tsx | 4 +- .../RegisteredModelsArchiveListView.tsx | 4 +- ...ustomServingRuntimeAPIProtocolSelector.tsx | 4 +- .../CustomServingRuntimePlatformsSelector.tsx | 4 +- .../MetricTypeField.tsx | 53 ++++----- .../modelServing/screens/metrics/utils.tsx | 5 +- .../DataConnectionExistingField.tsx | 73 +++++------- .../InferenceServiceFrameworkSection.tsx | 67 ++++++----- .../InferenceServiceServingRuntimeSection.tsx | 51 ++++----- .../ServingRuntimeSizeSection.tsx | 26 ++--- .../ServingRuntimeTemplateSection.tsx | 4 +- .../server/AcceleratorProfileSelectField.tsx | 8 +- .../server/EnvironmentVariablesRow.tsx | 33 ++---- .../screens/server/SizeSelectField.tsx | 37 +++--- .../experiments/artifacts/ArtifactsTable.tsx | 4 +- .../executions/ExecutionsTableToolbar.tsx | 6 +- .../deploymentSize/ContainerSizeSelector.tsx | 66 +++++------ .../environmentVariables/EnvDataTypeField.tsx | 56 ++++------ .../EnvTypeSelectField.tsx | 105 ++++++++---------- .../imageSelector/ImageStreamSelector.tsx | 4 +- .../imageSelector/ImageVersionSelector.tsx | 64 +++++------ 54 files changed, 565 insertions(+), 679 deletions(-) delete mode 100644 frontend/src/components/SimpleDropdownSelect.tsx rename frontend/src/components/{SimpleDropdownSelect.scss => SimpleSelect.scss} (100%) create mode 100644 frontend/src/components/SimpleSelect.tsx diff --git a/frontend/src/__tests__/cypress/cypress/pages/acceleratorProfile.ts b/frontend/src/__tests__/cypress/cypress/pages/acceleratorProfile.ts index 707c5ea0bf..ba103e5b35 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/acceleratorProfile.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/acceleratorProfile.ts @@ -170,19 +170,19 @@ class TolerationsModal extends Modal { } findOperatorOptionExist() { - return this.findTolerationOperatorSelect().findDropdownItem( + return this.findTolerationOperatorSelect().findSelectOption( 'Exists A toleration "matches" a taint if the keys are the same and the effects are the same. No value should be specified.', ); } findOperatorOptionEqual() { - return this.findTolerationOperatorSelect().findDropdownItem( + return this.findTolerationOperatorSelect().findSelectOption( 'Equal A toleration "matches" a taint if the keys are the same, the effects are the same, and the values are equal.', ); } findEffectOptionNoExecute() { - return this.findTolerationEffectSelect().findDropdownItem( + return this.findTolerationEffectSelect().findSelectOption( 'NoExecute Pods will be evicted from the node if they do not tolerate the taint.', ); } diff --git a/frontend/src/__tests__/cypress/cypress/pages/components/TableToolbar.ts b/frontend/src/__tests__/cypress/cypress/pages/components/TableToolbar.ts index a005266550..53bfd3aded 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/components/TableToolbar.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/components/TableToolbar.ts @@ -6,7 +6,7 @@ export class TableToolbar extends Contextual { } findFilterMenuOption(id: string, name: string): Cypress.Chainable> { - return this.findToggleButton(id).parents().findByRole('menuitem', { name }); + return this.findToggleButton(id).parents().findByRole('option', { name }); } findSearchInput(): Cypress.Chainable> { diff --git a/frontend/src/__tests__/cypress/cypress/pages/modelMetrics.ts b/frontend/src/__tests__/cypress/cypress/pages/modelMetrics.ts index 720ec3508c..9b1ea5c601 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/modelMetrics.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/modelMetrics.ts @@ -96,6 +96,10 @@ class ModelMetricsBias extends ModelMetricsGlobal { return cy.findByTestId('bias-metric-config-toolbar').find('#bias-metric-config-selector'); } + selectMetric(name: string) { + cy.findByRole('option', { name }).click(); + } + shouldNotBeConfigured() { cy.findByTestId('bias-metrics-empty-state').should('exist'); } diff --git a/frontend/src/__tests__/cypress/cypress/pages/modelServing.ts b/frontend/src/__tests__/cypress/cypress/pages/modelServing.ts index 3279f246e8..cce91c2fa1 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/modelServing.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/modelServing.ts @@ -92,11 +92,11 @@ class InferenceServiceModal extends Modal { } findServingRuntimeSelect() { - return this.find().find('#inference-service-model-selection'); + return this.find().findByTestId('inference-service-model-selection'); } findModelFrameworkSelect() { - return this.find().find('#inference-service-framework-selection'); + return this.find().findByTestId('inference-service-framework-selection'); } findExistingDataConnectionOption() { @@ -198,7 +198,7 @@ class ServingRuntimeModal extends Modal { findModelServerSizeSelect() { return this.find() .findByRole('group', { name: 'Compute resources per replica' }) - .findByRole('button', { name: 'Options menu' }); + .findByTestId('model-server-size-selection'); } findModelServerReplicasMinusButton() { diff --git a/frontend/src/__tests__/cypress/cypress/pages/pipelines/artifacts.ts b/frontend/src/__tests__/cypress/cypress/pages/pipelines/artifacts.ts index 7af3819d38..786e1a2f51 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/pipelines/artifacts.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/pipelines/artifacts.ts @@ -33,7 +33,7 @@ class ArtifactsGlobal { } selectFilterType(type: string) { - cy.findByTestId('artifact-type-filter-select').findByTestId(`dropdown-item ${type}`).click(); + cy.findByTestId('artifact-type-filter-select').findByTestId(type).click(); } } diff --git a/frontend/src/__tests__/cypress/cypress/pages/pipelines/createRunPage.ts b/frontend/src/__tests__/cypress/cypress/pages/pipelines/createRunPage.ts index 469537949d..6cad297d8e 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/pipelines/createRunPage.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/pipelines/createRunPage.ts @@ -72,11 +72,11 @@ export class CreateRunPage { } findScheduledRunTypeSelectorPeriodic(): Cypress.Chainable> { - return this.find().findByRole('menuitem', { name: 'Periodic' }); + return this.find().findByRole('option', { name: 'Periodic' }); } findScheduledRunTypeSelectorCron(): Cypress.Chainable> { - return this.find().findByRole('menuitem', { name: 'Cron' }); + return this.find().findByRole('option', { name: 'Cron' }); } findScheduledRunRunEvery(): Cypress.Chainable> { diff --git a/frontend/src/__tests__/cypress/cypress/pages/pipelines/executions.ts b/frontend/src/__tests__/cypress/cypress/pages/pipelines/executions.ts index 060801986b..5cfe40599c 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/pipelines/executions.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/pipelines/executions.ts @@ -34,7 +34,7 @@ class ExecutionFilter { } findTypeSearchFilterItem(item: string) { - return this.find().findByTestId('filter-toolbar-text-field').findDropdownItem(item); + return this.find().findByTestId('filter-toolbar-text-field').findSelectOption(item); } } diff --git a/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelineFilterBar.ts b/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelineFilterBar.ts index a5512da8af..414a539402 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelineFilterBar.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelineFilterBar.ts @@ -52,7 +52,7 @@ class PipelineRunFilterBar extends PipelineFilterBar { } selectStatusByName(name: string) { - this.findStatusSelect().findDropdownItem(name).click(); + this.findStatusSelect().findSelectOption(name).click(); } selectPipelineVersionByName(name: string): void { diff --git a/frontend/src/__tests__/cypress/cypress/pages/servingRuntimes.ts b/frontend/src/__tests__/cypress/cypress/pages/servingRuntimes.ts index 8f1cc89aa7..2b1412e687 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/servingRuntimes.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/servingRuntimes.ts @@ -93,23 +93,23 @@ class ServingRuntimes { shouldDisplayServingRuntimeValues(values: string[]) { this.findSelectServingPlatformButton().click(); - values.forEach((value) => cy.findByRole('menuitem', { name: value }).should('exist')); + values.forEach((value) => cy.findByRole('option', { name: value }).should('exist')); return this; } shouldDisplayAPIProtocolValues(values: ServingRuntimeAPIProtocol[]) { this.findSelectAPIProtocolButton().click(); - values.forEach((value) => cy.findByRole('menuitem', { name: value }).should('exist')); + values.forEach((value) => cy.findByRole('option', { name: value }).should('exist')); return this; } selectPlatform(value: string) { this.findSelectServingPlatformButton().click(); - cy.findByRole('menuitem', { name: value }).click(); + cy.findByRole('option', { name: value }).click(); } selectAPIProtocol(value: string) { - cy.findByRole('menuitem', { name: value }).click(); + cy.findByRole('option', { name: value }).click(); } uploadYaml(filePath: string) { diff --git a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts index cd631d6cca..88e5d96f45 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts @@ -237,7 +237,7 @@ class CreateSpawnerPage { findNotebookImage(name: string) { return cy .findByTestId('workbench-image-stream-selection') - .findDropdownItemByTestId(`dropdown-item ${name}`) + .findDropdownItemByTestId(name) .scrollIntoView(); } diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersionDeploy.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersionDeploy.cy.ts index 09eaf92631..9b8a011e8b 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersionDeploy.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersionDeploy.cy.ts @@ -240,7 +240,7 @@ describe('Deploy model version', () => { // Validate model framework section kserveModal.findModelFrameworkSelect().should('be.disabled'); cy.findByText('The source model format is').should('not.exist'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Multi Platform').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Multi Platform').click(); kserveModal.findModelFrameworkSelect().should('be.enabled'); cy.findByText( `The source model format is ${modelArtifactMocked.modelFormatName} - ${modelArtifactMocked.modelFormatVersion}`, diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersions.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersions.cy.ts index 543d5051fb..0a598bc559 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersions.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/modelVersions.cy.ts @@ -153,7 +153,7 @@ describe('Model Versions', () => { modelRegistry.findModelVersionsTableSearch().focused().clear(); // filtering by owner - modelRegistry.findModelVersionsTableFilter().findDropdownItem('Owner').click(); + modelRegistry.findModelVersionsTableFilter().findSelectOption('Owner').click(); modelRegistry.findModelVersionsTableSearch().type('Test author'); modelRegistry.findModelVersionsTableRows().should('have.length', 1); modelRegistry.findModelVersionsTableRows().contains('Test author'); diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/modelMetrics.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/modelMetrics.cy.ts index c47e9c8e7d..091270adbe 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/modelMetrics.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/modelMetrics.cy.ts @@ -203,21 +203,11 @@ describe('Model Metrics', () => { modelMetricsBias.visit('test-project', 'test-inference-service'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan Acceptance 4') - .click() - .type('{esc}'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan acceptance 2') - .click() - .type('{esc}'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan acceptance 2 STRICT') - .click() - .type('{esc}'); + modelMetricsBias.findConfigSelector().click(); + modelMetricsBias.selectMetric('Loan Acceptance 4'); + modelMetricsBias.selectMetric('Loan acceptance 2'); + modelMetricsBias.selectMetric('Loan acceptance 2 STRICT'); + modelMetricsBias.findConfigSelector().click(); modelMetricsBias .getMetricsChart('Statistical parity difference (SPD)', 'Loan acceptance') @@ -243,21 +233,11 @@ describe('Model Metrics', () => { modelMetricsBias.visit('test-project', 'test-inference-service'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan Acceptance 4') - .click() - .type('{esc}'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan acceptance 2') - .click() - .type('{esc}'); - modelMetricsBias - .findConfigSelector() - .findSelectOption('Loan acceptance 2 STRICT') - .click() - .type('{esc}'); + modelMetricsBias.findConfigSelector().click(); + modelMetricsBias.selectMetric('Loan Acceptance 4'); + modelMetricsBias.selectMetric('Loan acceptance 2'); + modelMetricsBias.selectMetric('Loan acceptance 2 STRICT'); + modelMetricsBias.findConfigSelector().click(); modelMetricsBias .getMetricsChart('Statistical parity difference (SPD)', 'Loan acceptance') diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/servingRuntimeList.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/servingRuntimeList.cy.ts index 84a8a6aad8..aee681aeeb 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/servingRuntimeList.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/servingRuntimeList.cy.ts @@ -533,7 +533,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findSubmitButton().should('be.disabled'); // check external route, token should be checked and no alert @@ -613,7 +613,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findSubmitButton().should('be.disabled'); // check external route, token should be checked and no alert @@ -674,7 +674,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findExistingConnectionSelect().findSelectOption('Test Secret').click(); kserveModal.findNewDataConnectionOption().click(); @@ -898,7 +898,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findSubmitButton().should('be.disabled'); kserveModal.findExistingConnectionSelect().findSelectOption('Test Secret').click(); @@ -994,7 +994,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1156,7 +1156,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1213,7 +1213,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1266,7 +1266,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1329,7 +1329,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1405,7 +1405,7 @@ describe('Serving Runtime List', () => { createServingRuntimeModal.findModelServerNameInput().type('Test Name'); createServingRuntimeModal .findServingRuntimeTemplateDropdown() - .findDropdownItem('New OVMS Server') + .findSelectOption('New OVMS Server') .click(); createServingRuntimeModal.findSubmitButton().should('be.enabled'); @@ -1625,7 +1625,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findSubmitButton().should('be.disabled'); kserveModal.findExistingConnectionSelect().findSelectOption('Test Secret').click(); @@ -1658,7 +1658,7 @@ describe('Serving Runtime List', () => { // test filling in minimum required fields kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findSubmitButton().should('be.disabled'); kserveModal.findExistingConnectionSelect().findSelectOption('Test Secret').click(); @@ -1692,7 +1692,7 @@ describe('Serving Runtime List', () => { kserveModal.shouldBeOpen(); kserveModal.findModelNameInput().type('Test Name'); - kserveModal.findServingRuntimeTemplateDropdown().findDropdownItem('Caikit').click(); + kserveModal.findServingRuntimeTemplateDropdown().findSelectOption('Caikit').click(); kserveModal.findModelFrameworkSelect().findSelectOption('onnx - 1').click(); kserveModal.findNewDataConnectionOption().click(); diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelineCreateRuns.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelineCreateRuns.cy.ts index 106b8c804d..118301d4dc 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelineCreateRuns.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelineCreateRuns.cy.ts @@ -588,7 +588,7 @@ describe('Pipeline create runs', () => { it('creates a schedule with trigger type cron without whitespace', () => { // Fill out the form with a schedule and submit createScheduleRunCommonTest(); - createSchedulePage.findScheduledRunTypeSelector().findDropdownItem('Cron').click(); + createSchedulePage.findScheduledRunTypeSelector().findSelectOption('Cron').click(); createSchedulePage.findScheduledRunCron().fill('@every 5m'); createSchedulePage .mockCreateRecurringRun(projectName, mockPipelineVersion, createRecurringRunParams) @@ -623,7 +623,7 @@ describe('Pipeline create runs', () => { it('creates a schedule with trigger type cron with whitespace', () => { createScheduleRunCommonTest(); - createSchedulePage.findScheduledRunTypeSelector().findDropdownItem('Cron').click(); + createSchedulePage.findScheduledRunTypeSelector().findSelectOption('Cron').click(); createSchedulePage.findScheduledRunCron().fill('@every 5m '); createSchedulePage .mockCreateRecurringRun(projectName, mockPipelineVersion, createRecurringRunParams) diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelinesTopology.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelinesTopology.cy.ts index 27cbf34b1d..4d2102f263 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelinesTopology.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelinesTopology.cy.ts @@ -528,7 +528,9 @@ describe('Pipeline topology', () => { pipelineRecurringRunDetails.selectActionDropdownItem('Disable'); pipelineRecurringRunDetails.findActionsDropdown().click(); - cy.findByRole('menuitem', { name: 'Enable' }).should('be.visible'); + cy.get('[id="dashboard-page-main"]') + .findByRole('menuitem', { name: 'Enable' }) + .should('be.visible'); }); it('enables recurring run from action dropdown', () => { @@ -554,7 +556,9 @@ describe('Pipeline topology', () => { pipelineRecurringRunDetails.selectActionDropdownItem('Enable'); pipelineRecurringRunDetails.findActionsDropdown().click(); - cy.findByRole('menuitem', { name: 'Disable' }).should('be.visible'); + cy.get('[id="dashboard-page-main"]') + .findByRole('menuitem', { name: 'Disable' }) + .should('be.visible'); }); }); diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/workbench.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/workbench.cy.ts index b8af0ed3c4..6c65571f19 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/workbench.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/workbench.cy.ts @@ -542,11 +542,15 @@ describe('Workbench page', () => { }, ], }); + cy.interceptK8sList( + PVCModel, + mockK8sResourceList([mockPVCK8sResource({ name: 'test-notebook' })]), + ); editSpawnerPage.visit('test-notebook'); editSpawnerPage.findNameInput().should('have.value', 'Test Notebook'); editSpawnerPage.shouldHaveNotebookImageSelectInput('Test Image'); editSpawnerPage.shouldHaveContainerSizeInput('Small'); - editSpawnerPage.shouldHavePersistentStorage('test-notebook'); + editSpawnerPage.shouldHavePersistentStorage('Test Storage'); editSpawnerPage.findSubmitButton().should('be.enabled'); editSpawnerPage.findNameInput().fill('Updated Notebook'); diff --git a/frontend/src/components/SimpleDropdownSelect.tsx b/frontend/src/components/SimpleDropdownSelect.tsx deleted file mode 100644 index 42716df6d9..0000000000 --- a/frontend/src/components/SimpleDropdownSelect.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import * as React from 'react'; -import { Truncate, Dropdown, MenuToggle, DropdownList, DropdownItem } from '@patternfly/react-core'; -import './SimpleDropdownSelect.scss'; - -export type SimpleDropdownOption = { - key: string; - label: string; - description?: React.ReactNode; - dropdownLabel?: React.ReactNode; - isPlaceholder?: boolean; -}; - -type SimpleDropdownProps = { - options: SimpleDropdownOption[]; - value: string; - placeholder?: string; - onChange: (key: string, isPlaceholder: boolean) => void; - isFullWidth?: boolean; - isDisabled?: boolean; - icon?: React.ReactNode; - dataTestId?: string; -} & Omit, 'isOpen' | 'toggle' | 'dropdownItems' | 'onChange'>; - -const SimpleDropdownSelect: React.FC = ({ - isDisabled, - onChange, - options, - placeholder = 'Select...', - value, - isFullWidth, - icon, - dataTestId, - ...props -}) => { - const [open, setOpen] = React.useState(false); - const selectedOption = options.find(({ key }) => key === value); - const selectedLabel = selectedOption?.label ?? placeholder; - - return ( - setOpen(false)} - onOpenChange={(isOpen: boolean) => setOpen(isOpen)} - toggle={(toggleRef) => ( - setOpen(!open)} - isExpanded={open} - > - - - )} - shouldFocusToggleOnSelect - > - - {options - .toSorted((a, b) => (a.isPlaceholder === b.isPlaceholder ? 0 : a.isPlaceholder ? -1 : 1)) - .map(({ key, dropdownLabel, label, description, isPlaceholder }) => ( - { - onChange(key, !!isPlaceholder); - setOpen(false); - }} - > - {dropdownLabel ?? label} - - ))} - - - ); -}; - -export default SimpleDropdownSelect; diff --git a/frontend/src/components/SimpleDropdownSelect.scss b/frontend/src/components/SimpleSelect.scss similarity index 100% rename from frontend/src/components/SimpleDropdownSelect.scss rename to frontend/src/components/SimpleSelect.scss diff --git a/frontend/src/components/SimpleSelect.tsx b/frontend/src/components/SimpleSelect.tsx new file mode 100644 index 0000000000..bea5843ec7 --- /dev/null +++ b/frontend/src/components/SimpleSelect.tsx @@ -0,0 +1,96 @@ +import * as React from 'react'; +import { Truncate, MenuToggle, Select, SelectList, SelectOption } from '@patternfly/react-core'; +import { MenuToggleProps } from '@patternfly/react-core/src/components/MenuToggle/MenuToggle'; + +import './SimpleSelect.scss'; + +export type SimpleSelectOption = { + key: string; + label: string; + description?: React.ReactNode; + dropdownLabel?: React.ReactNode; + isPlaceholder?: boolean; + isDisabled?: boolean; +}; + +type SimpleSelectProps = { + options: SimpleSelectOption[]; + value?: string; + toggleLabel?: React.ReactNode; + placeholder?: string; + onChange: (key: string, isPlaceholder: boolean) => void; + isFullWidth?: boolean; + toggleProps?: MenuToggleProps; + isDisabled?: boolean; + icon?: React.ReactNode; + dataTestId?: string; +} & Omit< + React.ComponentProps, + 'isOpen' | 'toggle' | 'dropdownItems' | 'onChange' | 'selected' +>; + +const SimpleSelect: React.FC = ({ + isDisabled, + onChange, + options, + placeholder = 'Select...', + value, + toggleLabel, + isFullWidth, + icon, + dataTestId, + toggleProps, + ...props +}) => { + const [open, setOpen] = React.useState(false); + const selectedOption = options.find(({ key }) => key === value); + const selectedLabel = selectedOption?.label ?? placeholder; + + return ( + + ); +}; + +export default SimpleSelect; diff --git a/frontend/src/concepts/dashboard/DashboardSearchField.tsx b/frontend/src/concepts/dashboard/DashboardSearchField.tsx index 44d96fa0a0..909629b29f 100644 --- a/frontend/src/concepts/dashboard/DashboardSearchField.tsx +++ b/frontend/src/concepts/dashboard/DashboardSearchField.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { InputGroup, SearchInput, InputGroupItem } from '@patternfly/react-core'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { asEnumMember } from '~/utilities/utils'; // List all the possible search fields here @@ -40,7 +40,7 @@ const DashboardSearchField: React.FC = ({ }) => ( - ({ diff --git a/frontend/src/concepts/metrics/MetricsRefreshIntervalSelect.tsx b/frontend/src/concepts/metrics/MetricsRefreshIntervalSelect.tsx index 2a6e534198..5783d727f5 100644 --- a/frontend/src/concepts/metrics/MetricsRefreshIntervalSelect.tsx +++ b/frontend/src/concepts/metrics/MetricsRefreshIntervalSelect.tsx @@ -1,30 +1,29 @@ import * as React from 'react'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { MetricsCommonContext } from '~/concepts/metrics/MetricsCommonContext'; import { RefreshIntervalTitle } from '~/concepts/metrics/types'; import { isRefreshIntervalTitle } from '~/concepts/metrics/utils'; +import { asEnumMember, enumIterator } from '~/utilities/utils'; +import SimpleSelect from '~/components/SimpleSelect'; export const MetricsRefreshIntervalSelect: React.FC = () => { const { currentRefreshInterval, setCurrentRefreshInterval } = React.useContext(MetricsCommonContext); - const [isOpen, setIsOpen] = React.useState(false); + return ( - + /> ); }; diff --git a/frontend/src/concepts/metrics/MetricsTimeRangeSelect.tsx b/frontend/src/concepts/metrics/MetricsTimeRangeSelect.tsx index db1c3cd813..4a8d7cc838 100644 --- a/frontend/src/concepts/metrics/MetricsTimeRangeSelect.tsx +++ b/frontend/src/concepts/metrics/MetricsTimeRangeSelect.tsx @@ -1,28 +1,26 @@ import * as React from 'react'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { MetricsCommonContext } from '~/concepts/metrics/MetricsCommonContext'; import { TimeframeTitle } from '~/concepts/metrics/types'; import { isTimeframeTitle } from '~/concepts/metrics/utils'; +import { asEnumMember, enumIterator } from '~/utilities/utils'; +import SimpleSelect from '~/components/SimpleSelect'; export const MetricsTimeRangeSelect: React.FC = () => { const { currentTimeframe, setCurrentTimeframe } = React.useContext(MetricsCommonContext); - const [isOpen, setIsOpen] = React.useState(false); return ( - + /> ); }; diff --git a/frontend/src/concepts/metrics/utils.ts b/frontend/src/concepts/metrics/utils.ts index c88e5d2592..1ff88e9efe 100644 --- a/frontend/src/concepts/metrics/utils.ts +++ b/frontend/src/concepts/metrics/utils.ts @@ -1,12 +1,9 @@ -import { SelectOptionObject } from '@patternfly/react-core/deprecated'; import { TimeframeTitle, RefreshIntervalTitle } from '~/concepts/metrics/types'; import { isEnumMember } from '~/utilities/utils'; -export const isTimeframeTitle = ( - timeframe: string | SelectOptionObject, -): timeframe is TimeframeTitle => isEnumMember(timeframe.toString(), TimeframeTitle); +export const isTimeframeTitle = (timeframe?: string | null): timeframe is TimeframeTitle => + isEnumMember(timeframe, TimeframeTitle); export const isRefreshIntervalTitle = ( - refreshInterval: string | SelectOptionObject, -): refreshInterval is RefreshIntervalTitle => - isEnumMember(refreshInterval.toString(), RefreshIntervalTitle); + refreshInterval?: string | null, +): refreshInterval is RefreshIntervalTitle => isEnumMember(refreshInterval, RefreshIntervalTitle); diff --git a/frontend/src/concepts/pipelines/content/compareRuns/CompareRunTableToolbar.tsx b/frontend/src/concepts/pipelines/content/compareRuns/CompareRunTableToolbar.tsx index a8ba7c1c41..de736d9cba 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/CompareRunTableToolbar.tsx +++ b/frontend/src/concepts/pipelines/content/compareRuns/CompareRunTableToolbar.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Button, TextInput, ToolbarItem } from '@patternfly/react-core'; import { useNavigate, useParams } from 'react-router'; import PipelineFilterBar from '~/concepts/pipelines/content/tables/PipelineFilterBar'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { FilterOptions } from '~/concepts/pipelines/content/tables/usePipelineFilter'; import ExperimentSearchInput from '~/concepts/pipelines/content/tables/ExperimentSearchInput'; import { RuntimeStateKF, runtimeStateLabels } from '~/concepts/pipelines/kfTypes'; @@ -82,15 +82,16 @@ const CompareRunTableToolbar: React.FC = ({ ...toolbarProps }) => { /> ), [FilterOptions.STATUS]: ({ value, onChange, ...props }) => ( - ({ key: v, label: v, }))} - onChange={(v) => onChange(v)} + toggleLabel={value} + onChange={(selection) => onChange(selection)} dataTestId="runtime-status-dropdown" /> ), diff --git a/frontend/src/concepts/pipelines/content/createRun/contentSections/TriggerTypeField.tsx b/frontend/src/concepts/pipelines/content/createRun/contentSections/TriggerTypeField.tsx index ffcdaaf817..0c81b055b6 100644 --- a/frontend/src/concepts/pipelines/content/createRun/contentSections/TriggerTypeField.tsx +++ b/frontend/src/concepts/pipelines/content/createRun/contentSections/TriggerTypeField.tsx @@ -7,7 +7,7 @@ import { Stack, StackItem, } from '@patternfly/react-core'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { PeriodicOptions, RunTypeScheduledData, @@ -62,7 +62,7 @@ const TriggerTypeField: React.FC = ({ data, onChange }) = /> - ({ key: v, label: v, @@ -88,7 +88,7 @@ const TriggerTypeField: React.FC = ({ data, onChange }) = - = ({ /> ), [FilterOptions.STATUS]: ({ value, onChange, ...props }) => ( - = ({ selection, onSelect, permissionOptions }) => { - const [isOpen, setIsOpen] = React.useState(false); - - return ( - - ); -}; +> = ({ selection, onSelect, permissionOptions }) => ( + ({ + ...option, + label: roleLabel(option.type), + key: option.type, + }))} + value={selection} + toggleLabel={roleLabel(selection)} + onChange={(newSelection) => { + onSelect(castRoleBindingPermissionsRoleType(newSelection)); + }} + popperProps={{ direction: 'down' }} + /> +); export default RoleBindingPermissionsPermissionSelection; diff --git a/frontend/src/pages/acceleratorProfiles/screens/manage/tolerations/TolerationFields.tsx b/frontend/src/pages/acceleratorProfiles/screens/manage/tolerations/TolerationFields.tsx index 47b0012a07..9f36944e91 100644 --- a/frontend/src/pages/acceleratorProfiles/screens/manage/tolerations/TolerationFields.tsx +++ b/frontend/src/pages/acceleratorProfiles/screens/manage/tolerations/TolerationFields.tsx @@ -14,7 +14,7 @@ import { } from '@patternfly/react-core'; import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import { Toleration, TolerationEffect, TolerationOperator } from '~/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import NumberInputWrapper from '~/components/NumberInputWrapper'; import DashboardPopupIconButton from '~/concepts/dashboard/DashboardPopupIconButton'; import { effectDropdownOptions, operatorDropdownOptions } from './const'; @@ -36,7 +36,7 @@ const TolerationFields: React.FC = ({ toleration, onUpdat return ( <> - = ({ toleration, onUpdat - = ({ onToggleFiltersCollapsed, }) => { const navigate = useNavigate(); - const [isSortTypeDropdownOpen, setIsSortTypeDropdownOpen] = React.useState(false); - const [isSortOrderDropdownOpen, setIsSortOrderDropdownOpen] = React.useState(false); const queryParams = useQueryParams(); const categoryQuery = queryParams.get(CATEGORY_FILTER_KEY) || ''; const enabled = queryParams.get(ENABLED_FILTER_KEY); @@ -111,49 +110,49 @@ const LearningCenterToolbar: React.FC = ({ }, [searchInputText]); const onSortTypeSelect = React.useCallback( - (e: React.MouseEvent | React.ChangeEvent) => { - setIsSortTypeDropdownOpen(false); - const selection = e.target instanceof Element ? e.target.getAttribute('data-key') ?? '' : ''; - setQueryArgument(navigate, DOC_SORT_KEY, selection); - }, + (value: string) => setQueryArgument(navigate, DOC_SORT_KEY, value), [navigate], ); - const sortTypeDropdownItems = Object.entries(sortTypes).map(([key, val]) => ( - - - {val} - - )); + const sortTypeDropdownItems = Object.entries(sortTypes).map(([key, val]) => ({ + key, + label: key, + dropdownLabel: ( + <> + + {val} + + ), + })); const onSortOrderSelect = React.useCallback( - (e: React.MouseEvent | React.ChangeEvent) => { - setIsSortOrderDropdownOpen(false); - const selection = e.target instanceof Element ? e.target.getAttribute('data-key') ?? '' : ''; - setQueryArgument(navigate, DOC_SORT_ORDER_KEY, selection); - }, + (value: string) => setQueryArgument(navigate, DOC_SORT_ORDER_KEY, value), [navigate], ); - const sortOrderDropdownItems = Object.entries(sortOrders).map(([key, val]) => ( - - - {key === SORT_ASC ? ( - - ) : ( - - )} - - )); + const sortOrderDropdownItems = Object.entries(sortOrders).map(([key, val]) => ({ + key, + label: key, + dropdownLabel: ( + <> + + {key === SORT_ASC ? ( + + ) : ( + + )} + + ), + })); const handleTextChange = (val: string) => { if (val.length > 0) { @@ -215,34 +214,26 @@ const LearningCenterToolbar: React.FC = ({ {viewType === CARD_VIEW ? ( <> - + toggleLabel={`Sort by ${sortTypes[sortType]}`} + onChange={onSortTypeSelect} + /> - + onChange={onSortOrderSelect} + /> ) : null} diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx index 2bad667c01..76bface23e 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx @@ -17,7 +17,7 @@ import { EllipsisVIcon, FilterIcon } from '@patternfly/react-icons'; import { useNavigate } from 'react-router'; import { SearchType } from '~/concepts/dashboard/DashboardSearchField'; import { ModelVersion, RegisteredModel } from '~/concepts/modelRegistry/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; import { filterModelVersions } from '~/pages/modelRegistry/screens/utils'; import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; @@ -82,7 +82,7 @@ const ModelVersionListView: React.FC = ({ deleteChipGroup={() => setSearch('')} categoryName={searchType} > - ({ key, diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx index 800c4a3e21..67538acf90 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx @@ -10,7 +10,7 @@ import { import { FilterIcon } from '@patternfly/react-icons'; import { SearchType } from '~/concepts/dashboard/DashboardSearchField'; import { ModelVersion } from '~/concepts/modelRegistry/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { filterModelVersions } from '~/pages/modelRegistry/screens/utils'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; import { asEnumMember } from '~/utilities/utils'; @@ -57,7 +57,7 @@ const ModelVersionsArchiveListView: React.FC deleteChipGroup={() => setSearch('')} categoryName="Keyword" > - ({ key, label: key, diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx index 139cb36e66..a6a0aebdbb 100644 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx @@ -4,7 +4,7 @@ import { FilterIcon } from '@patternfly/react-icons'; import { useNavigate } from 'react-router'; import { SearchType } from '~/concepts/dashboard/DashboardSearchField'; import { RegisteredModel } from '~/concepts/modelRegistry/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { filterRegisteredModels } from '~/pages/modelRegistry/screens/utils'; import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; @@ -68,7 +68,7 @@ const RegisteredModelListView: React.FC = ({ deleteChipGroup={() => setSearch('')} categoryName="Keyword" > - ({ key, label: key, diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx index 86a0f2e9db..32658a3cef 100644 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx @@ -10,7 +10,7 @@ import { import { FilterIcon } from '@patternfly/react-icons'; import { SearchType } from '~/concepts/dashboard/DashboardSearchField'; import { RegisteredModel } from '~/concepts/modelRegistry/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { filterRegisteredModels } from '~/pages/modelRegistry/screens/utils'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; import { asEnumMember } from '~/utilities/utils'; @@ -62,7 +62,7 @@ const RegisteredModelsArchiveListView: React.FC setSearch('')} categoryName="Keyword" > - ({ key, label: key, diff --git a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx index b22321b07e..95ca5982ff 100644 --- a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx +++ b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { FormGroup } from '@patternfly/react-core'; import { ServingRuntimeAPIProtocol, ServingRuntimePlatform } from '~/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { asEnumMember } from '~/utilities/utils'; type CustomServingRuntimeAPIProtocolSelectorProps = { @@ -44,7 +44,7 @@ const CustomServingRuntimeAPIProtocolSelector: React.FC< fieldId="custom-serving-api-protocol-selection" isRequired > - - void; }; -const MetricTypeField: React.FC = ({ fieldId, value, onChange }) => { - const [isOpen, setOpen] = React.useState(false); - - return ( - - - - ); -}; +const MetricTypeField: React.FC = ({ fieldId, value, onChange }) => ( + + { + const selectedValue = asEnumMember(selection, BiasMetricType); + if (isMetricType(selectedValue)) { + onChange(selectedValue); + } + }} + options={enumIterator(BiasMetricType).map(([type, enumValue]) => ({ + key: enumValue, + label: METRIC_TYPE_DISPLAY_NAME[type], + description: METRIC_TYPE_DESCRIPTION[type], + }))} + placeholder="Select" + toggleLabel={value} + toggleProps={{ id: fieldId }} + /> + +); export default MetricTypeField; diff --git a/frontend/src/pages/modelServing/screens/metrics/utils.tsx b/frontend/src/pages/modelServing/screens/metrics/utils.tsx index 2f878d30cd..5aa4d8d290 100644 --- a/frontend/src/pages/modelServing/screens/metrics/utils.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/utils.tsx @@ -218,9 +218,8 @@ export const checkConfigurationFieldsValid = ( checkThresholdValid(metricType, configurations.thresholdDelta) && checkBatchSizeValid(configurations.batchSize); -export const isMetricType = ( - metricType: string | SelectOptionObject, -): metricType is BiasMetricType => isEnumMember(metricType.toString(), BiasMetricType); +export const isMetricType = (metricType: string | null): metricType is BiasMetricType => + isEnumMember(metricType, BiasMetricType); export const byId = (arg: U): ((arg: T) => boolean) => diff --git a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionExistingField.tsx b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionExistingField.tsx index 5543d4a9b8..7e833322be 100644 --- a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionExistingField.tsx +++ b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionExistingField.tsx @@ -1,15 +1,5 @@ import * as React from 'react'; -import { - Button, - Flex, - FlexItem, - FormGroup, - Label, - Popover, - Stack, - StackItem, -} from '@patternfly/react-core'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; +import { Button, FormGroup, Popover, Stack, StackItem } from '@patternfly/react-core'; import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import { @@ -18,6 +8,7 @@ import { } from '~/pages/modelServing/screens/types'; import { filterOutConnectionsWithoutBucket } from '~/pages/modelServing/screens/projects/utils'; import { getDataConnectionDisplayName } from '~/pages/projects/screens/detail/data-connections/utils'; +import SimpleSelect from '~/components/SimpleSelect'; import DataConnectionFolderPathField from './DataConnectionFolderPathField'; type DataConnectionExistingFieldType = { @@ -31,10 +22,15 @@ const DataConnectionExistingField: React.FC = ( setData, dataConnections, }) => { - const [isOpen, setOpen] = React.useState(false); const connectionsWithoutBucket = filterOutConnectionsWithoutBucket(dataConnections); const isDataConnectionsEmpty = connectionsWithoutBucket.length === 0; + const placeholderText = isDataConnectionsEmpty + ? 'No data connections available to select' + : 'Select...'; + const selectedDataConnection = connectionsWithoutBucket.find( + (connection) => connection.dataConnection.data.metadata.name === data.storage.dataConnection, + ); return ( @@ -54,44 +50,27 @@ const DataConnectionExistingField: React.FC = ( )} - + /> diff --git a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceFrameworkSection.tsx b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceFrameworkSection.tsx index c73a41ab94..dfc451ddd0 100644 --- a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceFrameworkSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceFrameworkSection.tsx @@ -7,10 +7,10 @@ import { HelperTextItem, Skeleton, } from '@patternfly/react-core'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import { CreatingInferenceServiceObject } from '~/pages/modelServing/screens/types'; import { SupportedModelFormats } from '~/k8sTypes'; +import SimpleSelect from '~/components/SimpleSelect'; import useModelFramework from './useModelFramework'; type InferenceServiceFrameworkSectionProps = { @@ -26,14 +26,19 @@ const InferenceServiceFrameworkSection: React.FC { - const [isOpen, setOpen] = React.useState(false); - const [modelsContextLoaded, loaded, loadError] = useModelFramework( modelContext ? undefined : data.servingRuntimeName, data.project, ); const models = modelContext || modelsContextLoaded; - + const { name: dataFormatName, version: dataFormatVersion } = data.format; + const selectedDataFormat = models.find((element) => + dataFormatVersion + ? element.name === dataFormatName && element.version === dataFormatVersion + : element.name === dataFormatName, + ); + const placeholderText = + models.length === 0 ? 'No frameworks available to select' : 'Select a framework'; if (!modelContext && !loaded && data.servingRuntimeName !== '') { return ; } @@ -48,41 +53,35 @@ const InferenceServiceFrameworkSection: React.FC - + isFullWidth + toggleLabel={ + selectedDataFormat && dataFormatVersion + ? `${dataFormatName} - ${dataFormatVersion}` + : dataFormatName || placeholderText + } + onChange={(option) => { + const [name, version] = option.split(' - '); + const valueSelected = models.find((element) => + version ? element.name === name && element.version === version : element.name === name, + ); + + if (valueSelected) { + setData('format', { name, version }); + } + }} + /> {registeredModelFormat && models.length !== 0 && ( diff --git a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceServingRuntimeSection.tsx b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceServingRuntimeSection.tsx index ee8c3da01e..869cf2a90f 100644 --- a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceServingRuntimeSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/InferenceServiceServingRuntimeSection.tsx @@ -1,11 +1,11 @@ import * as React from 'react'; import { Alert, FormGroup, Skeleton, Text } from '@patternfly/react-core'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import { CreatingInferenceServiceObject } from '~/pages/modelServing/screens/types'; import { ServingRuntimeKind } from '~/k8sTypes'; import useServingRuntimes from '~/pages/modelServing/useServingRuntimes'; import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils'; +import SimpleSelect from '~/components/SimpleSelect'; type InferenceServiceServingRuntimeSectionProps = { data: CreatingInferenceServiceObject; @@ -16,13 +16,18 @@ type InferenceServiceServingRuntimeSectionProps = { const InferenceServiceServingRuntimeSection: React.FC< InferenceServiceServingRuntimeSectionProps > = ({ data, setData, currentServingRuntime }) => { - const [isOpen, setOpen] = React.useState(false); - const [servingRuntimes, loaded, loadError] = useServingRuntimes( data.project, data.project === '' || !!currentServingRuntime, ); + const selectedServingRuntime = servingRuntimes.find( + (servingRuntime) => servingRuntime.metadata.name === data.servingRuntimeName, + ); + + const placeholderText = + servingRuntimes.length === 0 ? 'No model servers available to select' : 'Select a model server'; + if (!loaded && !currentServingRuntime && data.project !== '') { return ; } @@ -45,32 +50,24 @@ const InferenceServiceServingRuntimeSection: React.FC< return ( - + /> ); }; diff --git a/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection.tsx b/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection.tsx index 29b0b0e95c..d851053525 100644 --- a/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { FormGroup, FormSection, Stack, StackItem, Popover, Icon } from '@patternfly/react-core'; -import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import { @@ -13,6 +12,7 @@ import { isGpuDisabled } from '~/pages/modelServing/screens/projects/utils'; import AcceleratorProfileSelectField from '~/pages/notebookController/screens/server/AcceleratorProfileSelectField'; import { getCompatibleAcceleratorIdentifiers } from '~/pages/projects/screens/spawner/spawnerUtils'; import { AcceleratorProfileState } from '~/utilities/useAcceleratorProfileState'; +import SimpleSelect from '~/components/SimpleSelect'; import ServingRuntimeSizeExpandedField from './ServingRuntimeSizeExpandedField'; type ServingRuntimeSizeSectionProps = { @@ -36,7 +36,6 @@ const ServingRuntimeSizeSection: React.FC = ({ setAcceleratorProfileState, infoContent, }) => { - const [sizeDropdownOpen, setSizeDropdownOpen] = React.useState(false); const [supportedAcceleratorProfiles, setSupportedAcceleratorProfiles] = React.useState< string[] | undefined >(); @@ -50,7 +49,6 @@ const ServingRuntimeSizeSection: React.FC = ({ }, [servingRuntimeSelected]); const gpuDisabled = servingRuntimeSelected ? isGpuDisabled(servingRuntimeSelected) : false; - const sizeCustom = [ ...sizes, { @@ -69,7 +67,7 @@ const ServingRuntimeSizeSection: React.FC = ({ `Requests: ${size.resources.requests?.cpu || '??'} CPU, ` + `${size.resources.requests?.memory || '??'} Memory` : ''; - return ; + return { key: name, label: name, description: desc }; }); return ( @@ -88,23 +86,19 @@ const ServingRuntimeSizeSection: React.FC = ({ > - + popperProps={{ appendTo: document.body }} + /> {data.modelSize.name === 'Custom' && ( diff --git a/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection.tsx b/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection.tsx index b5abb286bd..4b88b1b99a 100644 --- a/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection.tsx @@ -9,7 +9,7 @@ import { isServingRuntimeKind, } from '~/pages/modelServing/customServingRuntimes/utils'; import { isCompatibleWithAccelerator as isCompatibleWithAcceleratorProfile } from '~/pages/projects/screens/spawner/spawnerUtils'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import SimpleSelect from '~/components/SimpleSelect'; import { AcceleratorProfileState } from '~/utilities/useAcceleratorProfileState'; type ServingRuntimeTemplateSectionProps = { @@ -60,7 +60,7 @@ const ServingRuntimeTemplateSection: React.FC - ac.spec.enabled); - const formatOption = (cr: AcceleratorProfileKind): SimpleDropdownOption => { + const formatOption = (cr: AcceleratorProfileKind): SimpleSelectOption => { const displayName = `${cr.spec.displayName}${!cr.spec.enabled ? ' (disabled)' : ''}`; return { @@ -97,7 +97,7 @@ const AcceleratorProfileSelectField: React.FC { const aSupported = isAcceleratorProfileSupported(a); const bSupported = isAcceleratorProfileSupported(b); @@ -168,7 +168,7 @@ const AcceleratorProfileSelectField: React.FC - = ({ categories, onUpdate, }) => { - const [typeDropdownOpen, setTypeDropdownOpen] = React.useState(false); - const categoryOptions = categories.map((category) => ( - - )); - const selectOptions = [ - , - ...categoryOptions, - ]; - const removeVariables = () => { onUpdate(); }; @@ -71,23 +63,22 @@ const EnvironmentVariablesRow: React.FC = ({ }; onUpdate(updatedRow); - setTypeDropdownOpen(false); }; return (
- + options={[ + { key: CUSTOM_VARIABLE, label: CUSTOM_VARIABLE }, + ...categories.map((category) => ({ key: category.name, label: category.name })), + ]} + popperProps={{ appendTo: getDashboardMainContainer() }} + onChange={updateVariableType} + />