Skip to content

Commit

Permalink
update preview panel to align with latest ux (opendatahub-io#3115)
Browse files Browse the repository at this point in the history
  • Loading branch information
christianvogt authored and emilys314 committed Aug 27, 2024
1 parent 4ceae5d commit c5d7fae
Show file tree
Hide file tree
Showing 25 changed files with 371 additions and 202 deletions.
2 changes: 2 additions & 0 deletions frontend/src/__mocks__/mockConnectionType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type MockConnectionTypeConfigMap = {
username?: string;
preInstalled?: boolean;
fields?: ConnectionTypeField[];
category?: string[];
};

export const mockConnectionTypeConfigMap = (
Expand Down Expand Up @@ -60,6 +61,7 @@ export const mockConnectionTypeConfigMapObj = ({
: undefined),
},
data: {
category: 'category' in rest ? rest.category : ['Database', 'Testing'],
fields: 'fields' in rest ? rest.fields : mockFields,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ describe('duplicate', () => {
// Row 1 - Short text field
const row1 = createConnectionTypePage.getFieldsTableRow(1);
row1.findName().should('contain.text', 'Short text 1');
row1.findType().should('have.text', 'Short text');
row1.findType().should('have.text', 'Text - Short');
row1.findDefault().should('have.text', '-');
row1.findRequired().not('be.checked');

// Row 2 - Short text field
const row2 = createConnectionTypePage.getFieldsTableRow(2);
row2.findName().should('contain.text', 'Short text 2');
row2.findType().should('have.text', 'Short text');
row2.findType().should('have.text', 'Text - Short');
row2.findDefault().should('have.text', 'This is the default value');
row2.findRequired().should('be.checked');
});
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/concepts/connectionTypes/CategoryLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from 'react';
import { Label } from '@patternfly/react-core';

type Props = {
category: string;
};

const CategoryLabel: React.FC<Props> = ({ category }) => <Label color="purple">{category}</Label>;

export default CategoryLabel;
131 changes: 100 additions & 31 deletions frontend/src/concepts/connectionTypes/ConnectionTypePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,113 @@
import * as React from 'react';
import { Divider, Form, FormGroup, FormSection, Title } from '@patternfly/react-core';
import FormGroupText from '~/components/FormGroupText';
import {
Button,
DescriptionList,
DescriptionListDescription,
DescriptionListGroup,
DescriptionListTerm,
Form,
FormGroup,
FormSection,
HelperText,
HelperTextItem,
LabelGroup,
MenuToggleStatus,
Popover,
Title,
} from '@patternfly/react-core';
import ConnectionTypeFormFields from '~/concepts/connectionTypes/fields/ConnectionTypeFormFields';
import { ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types';
import NameDescriptionField from '~/concepts/k8s/NameDescriptionField';
import { getDescriptionFromK8sResource, getDisplayNameFromK8sResource } from '~/concepts/k8s/utils';
import { getDescriptionFromK8sResource } from '~/concepts/k8s/utils';
import UnspecifiedValue from '~/concepts/connectionTypes/fields/UnspecifiedValue';
import SimpleSelect from '~/components/SimpleSelect';
import CategoryLabel from '~/concepts/connectionTypes/CategoryLabel';
import TruncatedText from '~/components/TruncatedText';

type Props = {
obj?: ConnectionTypeConfigMapObj;
};

const ConnectionTypePreview: React.FC<Props> = ({ obj }) => (
<Form>
<Title headingLevel="h1">Add connection</Title>
<FormSection title="Connection type details" style={{ marginTop: 0 }}>
<FormGroup label="Connection type name" fieldId="connection-type-name">
<FormGroupText id="connection-type-name">
{(obj && getDisplayNameFromK8sResource(obj)) || <UnspecifiedValue />}
</FormGroupText>
// TODO consider refactoring this form for reuse when creating connection type instances
const ConnectionTypePreview: React.FC<Props> = ({ obj }) => {
const connectionTypeName = obj && obj.metadata.annotations?.['openshift.io/display-name'];
const connectionTypeDescription = (obj && getDescriptionFromK8sResource(obj)) ?? undefined;
return (
<Form>
<Title headingLevel="h1">Add connection</Title>
<FormGroup label="Connection type" fieldId="connection-type" isRequired>
<SimpleSelect
id="connection-type"
isFullWidth
toggleLabel={connectionTypeName || 'Unspecified'}
isDisabled={!!connectionTypeName}
toggleProps={connectionTypeName ? undefined : { status: MenuToggleStatus.danger }}
onChange={() => undefined}
/>
<HelperText>
{connectionTypeDescription ? (
<HelperTextItem>
<TruncatedText maxLines={2} content={connectionTypeDescription} />
</HelperTextItem>
) : undefined}
<HelperTextItem>
<Popover
headerContent="Connection type details"
bodyContent={
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Connection type name</DescriptionListTerm>
<DescriptionListDescription>
{connectionTypeName || <UnspecifiedValue />}
</DescriptionListDescription>
</DescriptionListGroup>
{connectionTypeDescription ? (
<DescriptionListGroup>
<DescriptionListTerm>Connection type description</DescriptionListTerm>
<DescriptionListDescription>
{connectionTypeDescription || <UnspecifiedValue />}
</DescriptionListDescription>
</DescriptionListGroup>
) : undefined}
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDescription>
{obj?.data?.category?.length ? (
<LabelGroup>
{obj.data.category.map((category) => (
<CategoryLabel key={category} category={category} />
))}
</LabelGroup>
) : (
<UnspecifiedValue />
)}
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
}
>
<Button variant="link" isInline>
View connection type details
</Button>
</Popover>
</HelperTextItem>
</HelperText>
</FormGroup>
<FormGroup label="Connection type description" fieldId="connection-type-description">
<FormGroupText id="connection-type-description">
{(obj && getDescriptionFromK8sResource(obj)) || <UnspecifiedValue />}
</FormGroupText>
</FormGroup>
</FormSection>
<Divider />
<FormSection title="Connection details" style={{ marginTop: 0 }}>
<NameDescriptionField
nameFieldId="connection-details-name"
descriptionFieldId="connection-details-description"
data={{
name: '',
description: '',
}}
/>
<ConnectionTypeFormFields fields={obj?.data?.fields} isPreview />
</FormSection>
</Form>
);
<FormSection title="Connection details" style={{ marginTop: 0 }}>
<NameDescriptionField
nameFieldId="connection-details-name"
descriptionFieldId="connection-details-description"
nameFieldLabel="Connection name"
descriptionFieldLabel="Connection description"
data={{
name: '',
description: '',
}}
/>
<ConnectionTypeFormFields fields={obj?.data?.fields} isPreview />
</FormSection>
</Form>
);
};

export default ConnectionTypePreview;
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import {
DrawerCloseButton,
DrawerContent,
Title,
DrawerPanelBody,
Card,
CardBody,
Text,
Divider,
DrawerContentBody,
} from '@patternfly/react-core';
import ConnectionTypePreview from '~/concepts/connectionTypes/ConnectionTypePreview';
import { ConnectionTypeConfigMapObj } from '~/concepts/connectionTypes/types';
Expand All @@ -24,44 +24,39 @@ type Props = {

const ConnectionTypePreviewDrawer: React.FC<Props> = ({ children, isExpanded, onClose, obj }) => {
const panelContent = (
<DrawerPanelContent
isResizable
style={{
backgroundColor: 'var(--pf-v5-global--BackgroundColor--200)',
}}
>
<DrawerHead>
<Title headingLevel="h2" size="xl">
Preview connection type
</Title>
<DrawerActions>
<DrawerCloseButton onClick={() => onClose()} />
</DrawerActions>
</DrawerHead>

<DrawerPanelBody>
<DrawerPanelContent isResizable>
<DrawerContentBody>
<DrawerHead hasNoPadding>
<Title headingLevel="h2" size="xl">
Preview connection type
</Title>
<DrawerActions>
<DrawerCloseButton onClick={() => onClose()} />
</DrawerActions>
</DrawerHead>
<div
style={{
paddingBottom: 'var(--pf-v5-global--spacer--lg)',
fontSize: 'var(--pf-v5-global--FontSize--sm)',
paddingTop: 'var(--pf-v5-global--spacer--sm)',
}}
>
<Text component="small">
This preview shows the user view of the connection type form, and is for reference only.
Updates in the developer view are automatically in the user view.
</Text>
<Card
isFlat
isRounded
style={{
marginTop: 'var(--pf-v5-global--spacer--md)',
}}
>
<CardBody>
<ConnectionTypePreview obj={obj} />
</CardBody>
</Card>
This preview shows the user view of the connection type form, and is for reference only.
Updates in the developer view are automatically in the user view.
</div>
</DrawerPanelBody>
</DrawerContentBody>
<Divider />
<DrawerContentBody
style={{
backgroundColor: 'var(--pf-v5-global--BackgroundColor--200)',
overflow: 'auto',
}}
>
<Card isFlat isRounded>
<CardBody>
<ConnectionTypePreview obj={obj} />
</CardBody>
</Card>
</DrawerContentBody>
</DrawerPanelContent>
);

Expand Down
47 changes: 23 additions & 24 deletions frontend/src/concepts/connectionTypes/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { mockConnectionTypeConfigMapObj } from '~/__mocks__/mockConnectionType';
import { DropdownField, HiddenField, TextField, UriField } from '~/concepts/connectionTypes/types';
import {
ConnectionTypeFieldType,
DropdownField,
HiddenField,
TextField,
} from '~/concepts/connectionTypes/types';
import {
defaultValueToString,
fieldNameToEnvVar,
Expand All @@ -12,13 +17,15 @@ describe('toConnectionTypeConfigMap / toConnectionTypeConfigMapObj', () => {
it('should serialize / deserialize connection type fields', () => {
const ct = mockConnectionTypeConfigMapObj({});
const configMap = toConnectionTypeConfigMap(ct);
expect(typeof configMap.data?.category).toBe('string');
expect(typeof configMap.data?.fields).toBe('string');
expect(ct).toEqual(toConnectionTypeConfigMapObj(toConnectionTypeConfigMap(ct)));
});

it('should serialize / deserialize connection type with missing fields', () => {
const ct = mockConnectionTypeConfigMapObj({ fields: undefined });
const ct = mockConnectionTypeConfigMapObj({ fields: undefined, category: undefined });
const configMap = toConnectionTypeConfigMap(ct);
expect(configMap.data?.category).toBeUndefined();
expect(configMap.data?.fields).toBeUndefined();
expect(ct).toEqual(toConnectionTypeConfigMapObj(configMap));
});
Expand Down Expand Up @@ -83,7 +90,7 @@ describe('defaultValueToString', () => {
defaultValue: 'test value',
},
} satisfies HiddenField),
).toBe('••••••••••');
).toBe('test value');
});

it('should return single variant dropdown value as string', () => {
Expand Down Expand Up @@ -133,7 +140,7 @@ describe('defaultValueToString', () => {
defaultValue: ['2'],
},
} satisfies DropdownField),
).toBe('Two');
).toBe('Two (Value: 2)');
expect(
defaultValueToString({
type: 'dropdown',
Expand All @@ -150,7 +157,7 @@ describe('defaultValueToString', () => {
defaultValue: ['2', '3'],
},
} satisfies DropdownField),
).toBe('Two');
).toBe('Two (Value: 2)');
});

it('should return multi variant dropdown value as string', () => {
Expand Down Expand Up @@ -200,30 +207,22 @@ describe('defaultValueToString', () => {
defaultValue: ['2', '3'],
},
} satisfies DropdownField),
).toBe('Two, Three');
).toBe('Two (Value: 2), Three (Value: 3)');
});
});

describe('fieldTypeToString', () => {
it('should return default value as string', () => {
expect(
fieldTypeToString({
type: 'text',
name: 'test',
envVar: 'test',
properties: {},
} satisfies TextField),
).toBe('Text');
expect(
fieldTypeToString({
type: 'uri',
name: 'test',
envVar: 'test',
properties: {
defaultValue: '',
},
} satisfies UriField),
).toBe('URI');
expect(fieldTypeToString('text')).toBe('Text - Long');
expect(fieldTypeToString(ConnectionTypeFieldType.Text)).toBe('Text - Long');
expect(fieldTypeToString('short-text')).toBe('Text - Short');
expect(fieldTypeToString(ConnectionTypeFieldType.ShortText)).toBe('Text - Short');
expect(fieldTypeToString('hidden')).toBe('Text - Hidden');
expect(fieldTypeToString(ConnectionTypeFieldType.Hidden)).toBe('Text - Hidden');
expect(fieldTypeToString('uri')).toBe('URI');
expect(fieldTypeToString(ConnectionTypeFieldType.URI)).toBe('URI');
expect(fieldTypeToString('numeric')).toBe('Numeric');
expect(fieldTypeToString(ConnectionTypeFieldType.Numeric)).toBe('Numeric');
});
});

Expand Down
Loading

0 comments on commit c5d7fae

Please sign in to comment.