diff --git a/frontend/src/__mocks__/mockConnection.ts b/frontend/src/__mocks__/mockConnection.ts new file mode 100644 index 0000000000..7195f8ad8a --- /dev/null +++ b/frontend/src/__mocks__/mockConnection.ts @@ -0,0 +1,33 @@ +import { Connection } from '~/concepts/connectionTypes/types'; + +type MockConnection = { + name?: string; + namespace?: string; + connectionType?: string; + displayName?: string; + description?: string; + data?: { [key: string]: string }; +}; + +export const mockConnection = ({ + name = 's3-connection', + namespace = 'ds-project-1', + connectionType = 's3', + displayName, + description, + data = {}, +}: MockConnection): Connection => ({ + kind: 'Secret', + apiVersion: 'v1', + metadata: { + name, + namespace, + labels: { 'opendatahub.io/dashboard': 'true', 'opendatahub.io/managed': 'true' }, + annotations: { + 'opendatahub.io/connection-type': connectionType, + ...(displayName && { 'openshift.io/display-name': displayName }), + ...(description && { 'openshift.io/description': description }), + }, + }, + data, +}); diff --git a/frontend/src/concepts/connectionTypes/types.ts b/frontend/src/concepts/connectionTypes/types.ts index 5104715333..19524fb31d 100644 --- a/frontend/src/concepts/connectionTypes/types.ts +++ b/frontend/src/concepts/connectionTypes/types.ts @@ -1,5 +1,5 @@ import { K8sResourceCommon } from '@openshift/dynamic-plugin-sdk-utils'; -import { DashboardLabels, DisplayNameAnnotations } from '~/k8sTypes'; +import { DashboardLabels, DisplayNameAnnotations, SecretKind } from '~/k8sTypes'; export enum ConnectionTypeFieldType { Boolean = 'boolean', @@ -135,3 +135,23 @@ export type ConnectionTypeConfigMapObj = Omit & fields?: ConnectionTypeField[]; }; }; + +export type Connection = SecretKind & { + metadata: { + labels: DashboardLabels & { + 'opendatahub.io/managed': 'true'; + }; + annotations: DisplayNameAnnotations & { + 'opendatahub.io/connection-type': string; + }; + }; + data: { + [key: string]: string; + }; +}; + +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'; diff --git a/frontend/src/pages/projects/ProjectDetailsContext.tsx b/frontend/src/pages/projects/ProjectDetailsContext.tsx index afa6b2c0c1..ef58a5d2bb 100644 --- a/frontend/src/pages/projects/ProjectDetailsContext.tsx +++ b/frontend/src/pages/projects/ProjectDetailsContext.tsx @@ -25,6 +25,7 @@ import useTemplateDisablement from '~/pages/modelServing/customServingRuntimes/u import { useDashboardNamespace } from '~/redux/selectors'; import { getTokenNames } from '~/pages/modelServing/utils'; import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas'; +import { Connection } from '~/concepts/connectionTypes/types'; import { useGroups, useTemplates } from '~/api'; import { NotebookState } from './notebook/types'; import { DataConnection } from './types'; @@ -32,7 +33,6 @@ import useDataConnections from './screens/detail/data-connections/useDataConnect import useProjectNotebookStates from './notebook/useProjectNotebookStates'; import useProjectPvcs from './screens/detail/storage/useProjectPvcs'; import useProjectSharing from './projectSharing/useProjectSharing'; -import { Connection } from './screens/detail/connections/types'; import useConnections from './screens/detail/connections/useConnections'; type ProjectDetailsContextType = { diff --git a/frontend/src/pages/projects/screens/detail/ProjectDetails.tsx b/frontend/src/pages/projects/screens/detail/ProjectDetails.tsx index 8bbcd1a085..1f2c4ff95b 100644 --- a/frontend/src/pages/projects/screens/detail/ProjectDetails.tsx +++ b/frontend/src/pages/projects/screens/detail/ProjectDetails.tsx @@ -87,13 +87,12 @@ const ProjectDetails: React.FC = () => { component: , }, ] - : [ - { - id: ProjectSectionID.DATA_CONNECTIONS, - title: 'Data connections', - component: , - }, - ]), + : []), + { + id: ProjectSectionID.DATA_CONNECTIONS, + title: 'Data connections', + component: , + }, ...(projectSharingEnabled && allowCreate ? [ { diff --git a/frontend/src/pages/projects/screens/detail/connections/ConnectionsList.tsx b/frontend/src/pages/projects/screens/detail/connections/ConnectionsList.tsx index 9904508bf5..b7dfb3d2f2 100644 --- a/frontend/src/pages/projects/screens/detail/connections/ConnectionsList.tsx +++ b/frontend/src/pages/projects/screens/detail/connections/ConnectionsList.tsx @@ -8,6 +8,7 @@ import DetailsSection from '~/pages/projects/screens/detail/DetailsSection'; import EmptyDetailsView from '~/components/EmptyDetailsView'; import DashboardPopupIconButton from '~/concepts/dashboard/DashboardPopupIconButton'; import { ProjectObjectType, typedEmptyImage } from '~/concepts/design/utils'; +import { useWatchConnectionTypes } from '~/utilities/useWatchConnectionTypes'; import ConnectionsTable from './ConnectionsTable'; const ConnectionsDescription = @@ -17,6 +18,7 @@ const ConnectionsList: React.FC = () => { const { connections: { data: connections, loaded, error }, } = React.useContext(ProjectDetailsContext); + const [connectionTypes, connectionTypesLoaded, connectionTypesError] = useWatchConnectionTypes(); return ( { Add connection , ]} - isLoading={!loaded} + isLoading={!loaded || !connectionTypesLoaded} isEmpty={connections.length === 0} - loadError={error} + loadError={error || connectionTypesError} emptyState={ { /> } > - + ); }; diff --git a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTable.tsx b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTable.tsx index da3fb9c11a..b1fd940535 100644 --- a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTable.tsx +++ b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTable.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; +import { Connection, ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types'; import { Table } from '~/components/table'; import ConnectionsTableRow from './ConnectionsTableRow'; import { columns } from './connectionsTableColumns'; -import { Connection } from './types'; type ConnectionsTableProps = { connections: Connection[]; + connectionTypes?: ConnectionTypeConfigMapObj[]; }; -const ConnectionsTable: React.FC = ({ connections }) => ( +const ConnectionsTable: React.FC = ({ connections, connectionTypes }) => ( = ({ connections }) => ( undefined} onDeleteConnection={() => undefined} /> diff --git a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx index dac70092ec..df063dd513 100644 --- a/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx +++ b/frontend/src/pages/projects/screens/detail/connections/ConnectionsTableRow.tsx @@ -1,50 +1,63 @@ import * as React from 'react'; import { ActionsColumn, Td, Tr } from '@patternfly/react-table'; +import { Connection, ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types'; import { TableRowTitleDescription } from '~/components/table'; -import { Connection } from './types'; type ConnectionsTableRowProps = { obj: Connection; + connectionTypes?: ConnectionTypeConfigMapObj[]; onEditConnection: (pvc: Connection) => void; onDeleteConnection: (dataConnection: Connection) => void; }; const ConnectionsTableRow: React.FC = ({ obj, + connectionTypes, onEditConnection, onDeleteConnection, -}) => ( - - - - - - + + + + - -); + ]} + /> + + + ); +}; export default ConnectionsTableRow; diff --git a/frontend/src/pages/projects/screens/detail/connections/__tests__/ConnectionsTable.spec.tsx b/frontend/src/pages/projects/screens/detail/connections/__tests__/ConnectionsTable.spec.tsx index 2be3c8006c..76778fcffe 100644 --- a/frontend/src/pages/projects/screens/detail/connections/__tests__/ConnectionsTable.spec.tsx +++ b/frontend/src/pages/projects/screens/detail/connections/__tests__/ConnectionsTable.spec.tsx @@ -1,32 +1,37 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import ConnectionsTable from '~/pages/projects/screens/detail/connections/ConnectionsTable'; -import { Connection } from '~/pages/projects/screens/detail/connections/types'; - -const connections: Connection[] = [ - { - kind: 'Secret', - apiVersion: 'v1', - metadata: { - name: 'connection1', - namespace: 'ds-project', - labels: { 'opendatahub.io/dashboard': 'true', 'opendatahub.io/managed': 'true' }, - annotations: { - 'opendatahub.io/connection-type': 's3', - 'openshift.io/display-name': 'connection1', - 'openshift.io/description': 'desc1', - }, - }, - data: {}, - }, -]; +import { mockConnectionTypeConfigMapObj } from '~/__mocks__/mockConnectionType'; +import { mockConnection } from '~/__mocks__/mockConnection'; describe('ConnectionsTable', () => { it('should render table', () => { - render(); + render( + , + ); + + expect(screen.getByTestId('connection-table')).toBeTruthy(); + expect(screen.getByText('connection1')).toBeTruthy(); + expect(screen.getByText('desc1')).toBeTruthy(); + expect(screen.getByText('s3')).toBeTruthy(); + }); + + it('should show display name of connection type if available', () => { + render( + , + ); expect(screen.getByTestId('connection-table')).toBeTruthy(); expect(screen.getByText('connection1')).toBeTruthy(); expect(screen.getByText('desc1')).toBeTruthy(); + expect(screen.queryByText('s3')).toBeFalsy(); + expect(screen.getByText('S3 Buckets')).toBeTruthy(); }); }); diff --git a/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts b/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts index 89b4ff661f..1056cdb012 100644 --- a/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts +++ b/frontend/src/pages/projects/screens/detail/connections/connectionsTableColumns.ts @@ -1,11 +1,11 @@ +import { Connection } from '~/concepts/connectionTypes/types'; import { SortableData } from '~/components/table'; -import { Connection } from './types'; export const columns: SortableData[] = [ { field: 'name', label: 'Name', - width: 25, + width: 35, sortable: (a, b) => (a.metadata.annotations['openshift.io/display-name'] ?? '').localeCompare( b.metadata.annotations['openshift.io/display-name'] ?? '', @@ -14,22 +14,16 @@ export const columns: SortableData[] = [ { field: 'type', label: 'Type', - width: 20, + width: 25, sortable: (a, b) => a.metadata.annotations['opendatahub.io/connection-type'].localeCompare( b.metadata.annotations['opendatahub.io/connection-type'], ), }, - { - field: 'compatibility', - label: 'Compatibility', - width: 20, - sortable: true, - }, { field: 'connections', label: 'Connected resources', - width: 30, + width: 35, sortable: false, }, { diff --git a/frontend/src/pages/projects/screens/detail/connections/types.ts b/frontend/src/pages/projects/screens/detail/connections/types.ts deleted file mode 100644 index 79fdbe046a..0000000000 --- a/frontend/src/pages/projects/screens/detail/connections/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DashboardLabels, DisplayNameAnnotations, SecretKind } from '~/k8sTypes'; - -export type Connection = SecretKind & { - metadata: { - labels: DashboardLabels & { - 'opendatahub.io/managed': 'true'; - }; - annotations: DisplayNameAnnotations & { - 'opendatahub.io/connection-type': string; - }; - }; - data: { - [key: string]: string; - }; -}; - -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'; diff --git a/frontend/src/pages/projects/screens/detail/connections/useConnections.ts b/frontend/src/pages/projects/screens/detail/connections/useConnections.ts index 05754fb82d..1674b64318 100644 --- a/frontend/src/pages/projects/screens/detail/connections/useConnections.ts +++ b/frontend/src/pages/projects/screens/detail/connections/useConnections.ts @@ -5,8 +5,8 @@ import useFetchState, { FetchStateCallbackPromise, NotReadyError, } from '~/utilities/useFetchState'; +import { Connection, isConnection } from '~/concepts/connectionTypes/types'; import { LABEL_SELECTOR_DASHBOARD_RESOURCE, LABEL_SELECTOR_DATA_CONNECTION_AWS } from '~/const'; -import { Connection, isConnection } from './types'; const useConnections = (namespace?: string): FetchState => { const callback = React.useCallback>(
- - {obj.metadata.annotations['opendatahub.io/connection-type']}-- - { - onEditConnection(obj); +}) => { + const connectionTypeDisplayName = React.useMemo(() => { + const matchingType = connectionTypes?.find( + (type) => type.metadata.name === obj.metadata.annotations['opendatahub.io/connection-type'], + ); + return ( + matchingType?.metadata.annotations?.['openshift.io/display-name'] || + obj.metadata.annotations['opendatahub.io/connection-type'] + ); + }, [obj, connectionTypes]); + + return ( +
+ + {connectionTypeDisplayName}- + { + onEditConnection(obj); + }, }, - }, - { - title: 'Delete', - onClick: () => { - onDeleteConnection(obj); + { + title: 'Delete', + onClick: () => { + onDeleteConnection(obj); + }, }, - }, - ]} - /> -