diff --git a/frontend/src/__mocks__/mockConnection.ts b/frontend/src/__mocks__/mockConnection.ts index 7195f8ad8a..ae57e2d976 100644 --- a/frontend/src/__mocks__/mockConnection.ts +++ b/frontend/src/__mocks__/mockConnection.ts @@ -7,6 +7,7 @@ type MockConnection = { displayName?: string; description?: string; data?: { [key: string]: string }; + managed?: boolean; }; export const mockConnection = ({ @@ -16,13 +17,17 @@ export const mockConnection = ({ displayName, description, data = {}, + managed = true, }: MockConnection): Connection => ({ kind: 'Secret', apiVersion: 'v1', metadata: { name, namespace, - labels: { 'opendatahub.io/dashboard': 'true', 'opendatahub.io/managed': 'true' }, + labels: { + 'opendatahub.io/dashboard': 'true', + ...(managed ? { 'opendatahub.io/managed': 'true' } : {}), + }, annotations: { 'opendatahub.io/connection-type': connectionType, ...(displayName && { 'openshift.io/display-name': displayName }), diff --git a/frontend/src/__tests__/cypress/cypress/pages/connectionTypes.ts b/frontend/src/__tests__/cypress/cypress/pages/connectionTypes.ts index 532cfcd907..8004fa97c5 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/connectionTypes.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/connectionTypes.ts @@ -171,11 +171,6 @@ class ConnectionTypeRow extends TableRow { return this; } - shouldHaveModelServingCompatibility() { - this.findConnectionTypeCompatibility().should('have.text', 'Model serving'); - return this; - } - shouldHaveCreator(creator: string) { this.findConnectionTypeCreator().should('have.text', creator); return this; diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/connectionTypes/connectionTypes.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/connectionTypes/connectionTypes.cy.ts index 411eb448dc..6a3531feaf 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/connectionTypes/connectionTypes.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/connectionTypes/connectionTypes.cy.ts @@ -83,7 +83,7 @@ describe('Connection types', () => { row2.shouldHaveDescription('description 2'); row2.shouldShowPreInstalledLabel(); row2.shouldBeDisabled(); - row2.shouldHaveModelServingCompatibility(); + row2.findConnectionTypeCompatibility().should('have.text', 'S3 compatible object storage'); row2.findKebabAction('Preview').click(); connectionTypePreviewModal.shouldBeOpen(); diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/connections.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/connections.cy.ts index 2b57e609f7..defa5c312d 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/connections.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/projects/connections.cy.ts @@ -58,11 +58,11 @@ describe('Connections', () => { const row1 = connectionsPage.getConnectionRow('test1'); row1.find().findByText('test1').should('exist'); row1.find().findByText('s3').should('exist'); - row1.find().findByText('Model serving').should('exist'); + row1.find().findByText('S3 compatible object storage').should('exist'); const row2 = connectionsPage.getConnectionRow('test2'); row2.find().findByText('test2').should('exist'); row2.find().findByText('postgres').should('exist'); - row1.find().findByText('Model serving').should('exist'); + row2.find().findByText('S3 compatible object storage').should('not.exist'); }); it('Delete a connection', () => { diff --git a/frontend/src/concepts/connectionTypes/CompatibilityLabel.tsx b/frontend/src/concepts/connectionTypes/CompatibilityLabel.tsx index 0bb95d018b..729d0f0c3e 100644 --- a/frontend/src/concepts/connectionTypes/CompatibilityLabel.tsx +++ b/frontend/src/concepts/connectionTypes/CompatibilityLabel.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { Label } from '@patternfly/react-core'; -import { CompatibleTypes } from '~/concepts/connectionTypes/utils'; +import { ModelServingCompatibleTypes } from '~/concepts/connectionTypes/utils'; type Props = { - type: CompatibleTypes; + type: ModelServingCompatibleTypes; }; const CompatibilityLabel: React.FC = ({ type }) => ; diff --git a/frontend/src/concepts/connectionTypes/__tests__/utils.spec.ts b/frontend/src/concepts/connectionTypes/__tests__/utils.spec.ts index 8bbcd78d25..afaaccfda2 100644 --- a/frontend/src/concepts/connectionTypes/__tests__/utils.spec.ts +++ b/frontend/src/concepts/connectionTypes/__tests__/utils.spec.ts @@ -1,3 +1,4 @@ +import { mockConnection } from '~/__mocks__/mockConnection'; import { mockConnectionTypeConfigMapObj } from '~/__mocks__/mockConnectionType'; import { ConnectionTypeFieldType, @@ -6,15 +7,14 @@ import { TextField, } from '~/concepts/connectionTypes/types'; import { - CompatibleTypes, defaultValueToString, fieldNameToEnvVar, fieldTypeToString, - getCompatibleTypes, - isModelServingCompatible, + getConnectionModelServingCompatibleTypes, + isModelServingCompatibleConnection, isModelServingTypeCompatible, isValidEnvVar, - ModelServingCompatibleConnectionTypes, + ModelServingCompatibleTypes, toConnectionTypeConfigMap, toConnectionTypeConfigMapObj, } from '~/concepts/connectionTypes/utils'; @@ -268,75 +268,164 @@ describe('isValidEnvVar', () => { }); }); -describe('isModelServingCompatible', () => { - it('should identify model serving compatible env vars', () => { - expect(isModelServingCompatible([])).toBe(false); +describe('isModelServingCompatibleConnection', () => { + it('should identify model serving compatible connections', () => { + expect(isModelServingCompatibleConnection(mockConnection({}))).toBe(false); expect( - isModelServingCompatible([ - 'AWS_ACCESS_KEY_ID', - 'AWS_SECRET_ACCESS_KEY', - 'AWS_S3_ENDPOINT', - 'AWS_S3_BUCKET', - ]), + isModelServingCompatibleConnection( + mockConnection({ + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), ).toBe(true); - expect(isModelServingCompatible(['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'])).toBe(false); expect( - isModelServingCompatible([ - 'AWS_ACCESS_KEY_ID', - 'AWS_SECRET_ACCESS_KEY', - 'AWS_S3_ENDPOINT', - 'AWS_S3_BUCKET', - 'URI', - ]), + isModelServingCompatibleConnection( + mockConnection({ + connectionType: 'test', + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), + ).toBe(false); + expect( + isModelServingCompatibleConnection( + mockConnection({ + managed: false, + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), + ).toBe(false); + expect( + isModelServingCompatibleConnection( + mockConnection({ + data: { + AWS_ACCESS_KEY_ID: 'test', + }, + }), + ), + ).toBe(false); + expect( + isModelServingCompatibleConnection( + mockConnection({ + data: { + URI: 'test', + }, + }), + ), ).toBe(true); }); }); -describe('getCompatibleTypes', () => { - it('should return compatible types', () => { - expect(getCompatibleTypes(['AWS_ACCESS_KEY_ID'])).toEqual([]); +describe('getConnectionModelServingCompatibleTypes', () => { + it('should identify model serving compatible connections', () => { + expect(getConnectionModelServingCompatibleTypes(mockConnection({}))).toEqual([]); + expect( + getConnectionModelServingCompatibleTypes( + mockConnection({ + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), + ).toEqual([ModelServingCompatibleTypes.S3ObjectStorage]); expect( - getCompatibleTypes([ - 'AWS_ACCESS_KEY_ID', - 'AWS_SECRET_ACCESS_KEY', - 'AWS_S3_ENDPOINT', - 'AWS_S3_BUCKET', - ]), - ).toEqual([CompatibleTypes.ModelServing]); + getConnectionModelServingCompatibleTypes( + mockConnection({ + connectionType: 'test', + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), + ).toEqual([]); + expect( + getConnectionModelServingCompatibleTypes( + mockConnection({ + managed: false, + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + }, + }), + ), + ).toEqual([]); + expect( + getConnectionModelServingCompatibleTypes( + mockConnection({ + data: { + AWS_ACCESS_KEY_ID: 'test', + }, + }), + ), + ).toEqual([]); + expect( + getConnectionModelServingCompatibleTypes( + mockConnection({ + data: { + URI: 'test', + }, + }), + ), + ).toEqual([ModelServingCompatibleTypes.OCI, ModelServingCompatibleTypes.URI]); expect( - getCompatibleTypes([ - 'AWS_ACCESS_KEY_ID', - 'AWS_SECRET_ACCESS_KEY', - 'AWS_S3_ENDPOINT', - 'AWS_S3_BUCKET', - 'URI', - ]), - ).toEqual([CompatibleTypes.ModelServing]); + getConnectionModelServingCompatibleTypes( + mockConnection({ + data: { + AWS_ACCESS_KEY_ID: 'test', + AWS_SECRET_ACCESS_KEY: 'test', + AWS_S3_ENDPOINT: 'test', + AWS_S3_BUCKET: 'test', + URI: 'test', + }, + }), + ), + ).toEqual([ + ModelServingCompatibleTypes.S3ObjectStorage, + ModelServingCompatibleTypes.OCI, + ModelServingCompatibleTypes.URI, + ]); }); }); describe('isModelServingTypeCompatible', () => { it('should identify model serving compatible env vars', () => { expect( - isModelServingTypeCompatible(['invalid'], ModelServingCompatibleConnectionTypes.ModelServing), + isModelServingTypeCompatible( + ['AWS_ACCESS_KEY_ID'], + ModelServingCompatibleTypes.S3ObjectStorage, + ), ).toBe(false); expect( isModelServingTypeCompatible( ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_S3_ENDPOINT', 'AWS_S3_BUCKET'], - ModelServingCompatibleConnectionTypes.ModelServing, + ModelServingCompatibleTypes.S3ObjectStorage, ), ).toBe(true); - expect( - isModelServingTypeCompatible(['invalid'], ModelServingCompatibleConnectionTypes.OCI), - ).toBe(false); - expect(isModelServingTypeCompatible(['URI'], ModelServingCompatibleConnectionTypes.OCI)).toBe( - true, - ); - expect( - isModelServingTypeCompatible(['invalid'], ModelServingCompatibleConnectionTypes.URI), - ).toBe(false); - expect(isModelServingTypeCompatible(['URI'], ModelServingCompatibleConnectionTypes.URI)).toBe( - true, - ); + expect(isModelServingTypeCompatible(['invalid'], ModelServingCompatibleTypes.OCI)).toBe(false); + expect(isModelServingTypeCompatible(['URI'], ModelServingCompatibleTypes.OCI)).toBe(true); + expect(isModelServingTypeCompatible(['invalid'], ModelServingCompatibleTypes.URI)).toBe(false); + expect(isModelServingTypeCompatible(['URI'], ModelServingCompatibleTypes.URI)).toBe(true); }); }); diff --git a/frontend/src/concepts/connectionTypes/types.ts b/frontend/src/concepts/connectionTypes/types.ts index 4559666075..4415075bc3 100644 --- a/frontend/src/concepts/connectionTypes/types.ts +++ b/frontend/src/concepts/connectionTypes/types.ts @@ -147,7 +147,7 @@ export type ConnectionTypeValueType = ConnectionTypeDataField['properties']['def export type Connection = SecretKind & { metadata: { labels: DashboardLabels & { - 'opendatahub.io/managed': 'true'; + 'opendatahub.io/managed'?: 'true'; }; annotations: DisplayNameAnnotations & { 'opendatahub.io/connection-type': string; diff --git a/frontend/src/concepts/connectionTypes/utils.ts b/frontend/src/concepts/connectionTypes/utils.ts index eddfed5d8e..94141d47eb 100644 --- a/frontend/src/concepts/connectionTypes/utils.ts +++ b/frontend/src/concepts/connectionTypes/utils.ts @@ -1,5 +1,5 @@ import { SecretKind } from '~/k8sTypes'; -import { translateDisplayNameForK8s } from '~/concepts/k8s/utils'; +import { getDisplayNameFromK8sResource, translateDisplayNameForK8s } from '~/concepts/k8s/utils'; import { K8sNameDescriptionFieldData } from '~/concepts/k8s/K8sNameDescriptionField/types'; import { Connection, @@ -25,10 +25,7 @@ export const isConnectionTypeDataField = ( ): field is ConnectionTypeDataField => field.type !== ConnectionTypeFieldType.Section; export const isConnection = (secret: SecretKind): secret is Connection => - !!secret.metadata.annotations && - 'opendatahub.io/connection-type' in secret.metadata.annotations && - !!secret.metadata.labels && - secret.metadata.labels['opendatahub.io/managed'] === 'true'; + !!secret.metadata.annotations && 'opendatahub.io/connection-type' in secret.metadata.annotations; export const toConnectionTypeConfigMapObj = ( configMap: ConnectionTypeConfigMap, @@ -121,56 +118,83 @@ export const S3ConnectionTypeKeys = [ 'AWS_S3_BUCKET', ]; -export enum ModelServingCompatibleConnectionTypes { - ModelServing = 's3', - OCI = 'oci-compliant-registry-v1', - URI = 'uri-v1', +export enum ModelServingCompatibleTypes { + S3ObjectStorage = 'S3 compatible object storage', + OCI = 'OCI compliant registry', + URI = 'URI', } -const modelServinConnectionTypes: Record< - ModelServingCompatibleConnectionTypes, +const modelServingCompatibleTypesMetadata: Record< + ModelServingCompatibleTypes, { name: string; + resource: string; envVars: string[]; + isConnectionCompatible?: (connection: Connection) => boolean; } > = { - [ModelServingCompatibleConnectionTypes.ModelServing]: { - name: 'S3 compatible object storage', + [ModelServingCompatibleTypes.S3ObjectStorage]: { + name: ModelServingCompatibleTypes.S3ObjectStorage, + resource: 's3', envVars: S3ConnectionTypeKeys, + isConnectionCompatible: (connection) => + connection.metadata.annotations['opendatahub.io/connection-type'] === 's3' && + connection.metadata.labels['opendatahub.io/managed'] === 'true', }, - [ModelServingCompatibleConnectionTypes.OCI]: { - name: 'OCI compliant registry', + [ModelServingCompatibleTypes.OCI]: { + name: ModelServingCompatibleTypes.OCI, + resource: 'oci-compliant-registry-v1', envVars: ['URI'], }, - [ModelServingCompatibleConnectionTypes.URI]: { - name: 'URI', + [ModelServingCompatibleTypes.URI]: { + name: ModelServingCompatibleTypes.URI, + resource: 'uri-v1', envVars: ['URI'], }, }; export const isModelServingTypeCompatible = ( envVars: string[], - type: ModelServingCompatibleConnectionTypes, -): boolean => modelServinConnectionTypes[type].envVars.every((envVar) => envVars.includes(envVar)); + type: ModelServingCompatibleTypes, +): boolean => + modelServingCompatibleTypesMetadata[type].envVars.every((envVar) => envVars.includes(envVar)); -export const isModelServingCompatible = (envVars: string[]): boolean => - S3ConnectionTypeKeys.every((envVar) => envVars.includes(envVar)) || envVars.includes('URI'); +const getModelServingCompatibleTypes = (envVars: string[]): ModelServingCompatibleTypes[] => + enumIterator(ModelServingCompatibleTypes).reduce( + (acc, [, value]) => { + if (isModelServingTypeCompatible(envVars, value)) { + acc.push(value); + } + return acc; + }, + [], + ); -export enum CompatibleTypes { - ModelServing = 'Model serving', -} +export const isModelServingCompatibleConnection = (connection: Connection): boolean => + getConnectionModelServingCompatibleTypes(connection).length > 0; -const compatibilities: Record boolean> = { - [CompatibleTypes.ModelServing]: isModelServingCompatible, -}; +export const isModelServingCompatibleConnectionType = ( + connectionType: ConnectionTypeConfigMapObj, +): boolean => getConnectionTypeModelServingCompatibleTypes(connectionType).length > 0; -export const getCompatibleTypes = (envVars: string[]): CompatibleTypes[] => - enumIterator(CompatibleTypes).reduce((acc, [, value]) => { - if (compatibilities[value](envVars)) { - acc.push(value); - } - return acc; - }, []); +export const getConnectionModelServingCompatibleTypes = ( + connection: Connection, +): ModelServingCompatibleTypes[] => + getModelServingCompatibleTypes( + Object.entries(connection.data ?? {}) + .filter(([, value]) => !!value) + .map(([key]) => key), + ).filter( + (type) => + modelServingCompatibleTypesMetadata[type].isConnectionCompatible?.(connection) ?? true, + ); + +export const getConnectionTypeModelServingCompatibleTypes = ( + connectionType: ConnectionTypeConfigMapObj, +): ModelServingCompatibleTypes[] => + getModelServingCompatibleTypes( + connectionType.data?.fields?.filter(isConnectionTypeDataField).map((f) => f.envVar) ?? [], + ); export const getDefaultValues = ( connectionType: ConnectionTypeConfigMapObj, @@ -292,10 +316,9 @@ export const getConnectionTypeDisplayName = ( type.metadata.name === connection.metadata.annotations['opendatahub.io/connection-type'], ) : connectionTypes; - return ( - matchingType?.metadata.annotations?.['openshift.io/display-name'] || - connection.metadata.annotations['opendatahub.io/connection-type'] - ); + return matchingType + ? getDisplayNameFromK8sResource(matchingType) + : connection.metadata.annotations['opendatahub.io/connection-type']; }; export const filterEnabledConnectionTypes = < @@ -316,18 +339,19 @@ export const findSectionFields = ( return fields.slice(sectionIndex + 1, nextSectionIndex === -1 ? undefined : nextSectionIndex); }; -export const filterModelServingCompatibleTypes = ( +export const filterModelServingConnectionTypes = ( connectionTypes: ConnectionTypeConfigMapObj[], ): { - key: ModelServingCompatibleConnectionTypes; + key: ModelServingCompatibleTypes; name: string; type: ConnectionTypeConfigMapObj; }[] => - enumIterator(ModelServingCompatibleConnectionTypes) + enumIterator(ModelServingCompatibleTypes) .map(([, value]) => { - const connectionType = connectionTypes.find((t) => t.metadata.name === value); + const typeMetadata = modelServingCompatibleTypesMetadata[value]; + const connectionType = connectionTypes.find((t) => t.metadata.name === typeMetadata.resource); return connectionType - ? { key: value, name: modelServinConnectionTypes[value].name, type: connectionType } + ? { key: value, name: typeMetadata.name, type: connectionType } : undefined; }) .filter((t) => t != null); diff --git a/frontend/src/pages/connectionTypes/ConnectionTypesTableRow.tsx b/frontend/src/pages/connectionTypes/ConnectionTypesTableRow.tsx index a7cf5f5fff..f68a14ae34 100644 --- a/frontend/src/pages/connectionTypes/ConnectionTypesTableRow.tsx +++ b/frontend/src/pages/connectionTypes/ConnectionTypesTableRow.tsx @@ -22,7 +22,7 @@ import { } from '~/concepts/k8s/utils'; import { connectionTypeColumns } from '~/pages/connectionTypes/columns'; import CategoryLabel from '~/concepts/connectionTypes/CategoryLabel'; -import { getCompatibleTypes, isConnectionTypeDataField } from '~/concepts/connectionTypes/utils'; +import { getConnectionTypeModelServingCompatibleTypes } from '~/concepts/connectionTypes/utils'; import CompatibilityLabel from '~/concepts/connectionTypes/CompatibilityLabel'; import ConnectionTypePreviewModal from '~/concepts/connectionTypes/ConnectionTypePreviewModal'; @@ -78,12 +78,11 @@ const ConnectionTypesTableRow: React.FC = ({ }); }; - const compatibleTypes = getCompatibleTypes( - obj.data?.fields - ?.filter(isConnectionTypeDataField) - .filter((field) => field.required) - .map((field) => field.envVar) ?? [], + const compatibleTypes = React.useMemo( + () => getConnectionTypeModelServingCompatibleTypes(obj), + [obj], ); + return ( diff --git a/frontend/src/pages/connectionTypes/columns.ts b/frontend/src/pages/connectionTypes/columns.ts index e687e4ed24..1319414849 100644 --- a/frontend/src/pages/connectionTypes/columns.ts +++ b/frontend/src/pages/connectionTypes/columns.ts @@ -42,19 +42,20 @@ export const connectionTypeColumns: SortableData[] = label: 'Name', field: 'name', sortable: sorter, - width: 20, + width: 25, }, { label: 'Category', field: 'category', sortable: false, - width: 20, + width: 15, }, { - label: 'Compatibility', + label: 'Model serving compatibility', field: 'compatibility', sortable: false, width: 15, + modifier: 'wrap', }, { label: 'Creator', diff --git a/frontend/src/pages/connectionTypes/manage/ManageConnectionTypePage.tsx b/frontend/src/pages/connectionTypes/manage/ManageConnectionTypePage.tsx index 10beaad782..a973b7cd4d 100644 --- a/frontend/src/pages/connectionTypes/manage/ManageConnectionTypePage.tsx +++ b/frontend/src/pages/connectionTypes/manage/ManageConnectionTypePage.tsx @@ -43,9 +43,8 @@ import { } from '~/concepts/connectionTypes/validationUtils'; import { useWatchConnectionTypes } from '~/utilities/useWatchConnectionTypes'; import { - filterModelServingCompatibleTypes, - isConnectionTypeDataField, - isModelServingTypeCompatible, + filterModelServingConnectionTypes, + getConnectionTypeModelServingCompatibleTypes, } from '~/concepts/connectionTypes/utils'; import DashboardPopupIconButton from '~/concepts/dashboard/DashboardPopupIconButton'; import SimpleMenuActions from '~/components/SimpleMenuActions'; @@ -65,8 +64,8 @@ const ManageConnectionTypePage: React.FC = ({ prefill, isEdit, onSave }) const { username: currentUsername } = useUser(); const [connectionTypes] = useWatchConnectionTypes(); - const modelServingCompatibleTypes = React.useMemo( - () => filterModelServingCompatibleTypes(connectionTypes), + const modelServingConnectionTypesMetadata = React.useMemo( + () => filterModelServingConnectionTypes(connectionTypes), [connectionTypes], ); @@ -122,10 +121,10 @@ const ManageConnectionTypePage: React.FC = ({ prefill, isEdit, onSave }) [connectionNameDesc, enabled, fields, username, category], ); - const matchedModelServingCompatibleTypes = React.useMemo(() => { - const envVars = fields.filter(isConnectionTypeDataField).map((f) => f.envVar); - return modelServingCompatibleTypes.filter((t) => isModelServingTypeCompatible(envVars, t.key)); - }, [fields, modelServingCompatibleTypes]); + const modelServingCompatibleTypes = React.useMemo( + () => getConnectionTypeModelServingCompatibleTypes(connectionTypeObj), + [connectionTypeObj], + ); const isValid = React.useMemo(() => isK8sNameDescriptionDataValid(connectionNameDesc), [connectionNameDesc]) && @@ -232,14 +231,14 @@ const ManageConnectionTypePage: React.FC = ({ prefill, isEdit, onSave }) title={ Fields - {modelServingCompatibleTypes.length > 0 ? ( + {modelServingConnectionTypesMetadata.length > 0 ? ( <> ({ + dropdownItems={modelServingConnectionTypesMetadata.map((t) => ({ key: t.key, label: t.name, onClick: () => { @@ -286,14 +285,14 @@ const ManageConnectionTypePage: React.FC = ({ prefill, isEdit, onSave }) > - {matchedModelServingCompatibleTypes.length > 0 ? ( + {modelServingCompatibleTypes.length > 0 ? ( t.name), + modelServingCompatibleTypes, { singlePrefix: 'the ', singleSuffix: ' model serving type.', diff --git a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx index 87ff7a7eb4..5b25cb2d50 100644 --- a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx +++ b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx @@ -5,7 +5,10 @@ import { ExclamationTriangleIcon } from '@patternfly/react-icons'; import { Connection, ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types'; import { TableRowTitleDescription } from '~/components/table'; import { getDescriptionFromK8sResource, getDisplayNameFromK8sResource } from '~/concepts/k8s/utils'; -import { getCompatibleTypes, getConnectionTypeDisplayName } from '~/concepts/connectionTypes/utils'; +import { + getConnectionModelServingCompatibleTypes, + getConnectionTypeDisplayName, +} from '~/concepts/connectionTypes/utils'; import CompatibilityLabel from '~/concepts/connectionTypes/CompatibilityLabel'; import ConnectedResources from '~/pages/projects/screens/detail/connections/ConnectedResources'; @@ -31,13 +34,7 @@ const ConnectionsTableRow: React.FC = ({ [obj, connectionTypes], ); - const compatibleTypes = obj.data - ? getCompatibleTypes( - Object.entries(obj.data) - .filter(([, value]) => !!value) - .map(([key]) => key), - ) - : []; + const compatibleTypes = getConnectionModelServingCompatibleTypes(obj); return ( diff --git a/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts b/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts index 601bed9031..a23e540957 100644 --- a/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts +++ b/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts @@ -22,9 +22,10 @@ export const columns: SortableData[] = [ }, { field: 'compatibility', - label: 'Compatibility', + label: 'Model serving compatibility', width: 20, sortable: false, + modifier: 'wrap', }, { field: 'connections', diff --git a/frontend/src/pages/projects/screens/detail/connections/useConnections.ts b/frontend/src/pages/projects/screens/detail/connections/useConnections.ts index fda3303428..f0a528a1ea 100644 --- a/frontend/src/pages/projects/screens/detail/connections/useConnections.ts +++ b/frontend/src/pages/projects/screens/detail/connections/useConnections.ts @@ -6,8 +6,8 @@ import useFetchState, { NotReadyError, } from '~/utilities/useFetchState'; import { Connection } from '~/concepts/connectionTypes/types'; -import { LABEL_SELECTOR_DASHBOARD_RESOURCE, LABEL_SELECTOR_DATA_CONNECTION_AWS } from '~/const'; -import { isConnection, isModelServingCompatible } from '~/concepts/connectionTypes/utils'; +import { LABEL_SELECTOR_DASHBOARD_RESOURCE } from '~/const'; +import { isConnection, isModelServingCompatibleConnection } from '~/concepts/connectionTypes/utils'; const useConnections = ( namespace?: string, @@ -20,16 +20,14 @@ const useConnections = ( } const secrets = await getSecretsByLabel( - `${LABEL_SELECTOR_DASHBOARD_RESOURCE},${LABEL_SELECTOR_DATA_CONNECTION_AWS}`, + `${LABEL_SELECTOR_DASHBOARD_RESOURCE}`, namespace, opts, ); let connections = secrets.filter((secret) => isConnection(secret)); if (modelServingCompatible) { - connections = connections.filter( - (secret) => !!secret.data && isModelServingCompatible(Object.keys(secret.data)), - ); + connections = connections.filter(isModelServingCompatibleConnection); } return connections; diff --git a/frontend/src/utilities/useWatchConnectionTypes.tsx b/frontend/src/utilities/useWatchConnectionTypes.tsx index 683241d48a..5cf5f9b4d1 100644 --- a/frontend/src/utilities/useWatchConnectionTypes.tsx +++ b/frontend/src/utilities/useWatchConnectionTypes.tsx @@ -1,10 +1,6 @@ import React from 'react'; import { ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types'; -import { - CompatibleTypes, - getCompatibleTypes, - isConnectionTypeDataField, -} from '~/concepts/connectionTypes/utils'; +import { isModelServingCompatibleConnectionType } from '~/concepts/connectionTypes/utils'; import { fetchConnectionTypes } from '~/services/connectionTypesService'; import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState'; @@ -16,13 +12,7 @@ export const useWatchConnectionTypes = ( >(async () => { let connectionTypes = await fetchConnectionTypes(); if (modelServingCompatible) { - connectionTypes = connectionTypes.filter((type) => { - const compatibleTypes = getCompatibleTypes( - type.data?.fields?.filter(isConnectionTypeDataField).map((field) => field.envVar) ?? [], - ); - - return compatibleTypes.includes(CompatibleTypes.ModelServing); - }); + connectionTypes = connectionTypes.filter(isModelServingCompatibleConnectionType); } return connectionTypes;