Skip to content

Commit

Permalink
fix(explorer): header label if no values
Browse files Browse the repository at this point in the history
  • Loading branch information
TdyP authored Nov 28, 2024
1 parent 7338b86 commit 8cec779
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 64 deletions.
77 changes: 72 additions & 5 deletions libs/ui/src/components/Explorer/Explorer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ const linkMockAttribute: gqlTypes.AttributePropertiesFragment = {
type: gqlTypes.AttributeType.advanced_link
};

const multivalLinkMockAttribute: gqlTypes.AttributePropertiesFragment = {
...linkMockAttribute,
id: 'link_attribute_multival',
label: {
fr: 'Mon attribut liaison multival',
en: 'My link attribute multi-valued'
},
multiple_values: true
};

describe('Explorer', () => {
const recordId1 = '613982168';
const recordId2 = '612694174';
Expand Down Expand Up @@ -76,6 +86,45 @@ describe('Explorer', () => {
linkPayload: {id: mockRecord.id, whoAmI: mockRecord}
}
]
},
{
attributeId: multivalLinkMockAttribute.id,
attributeProperties: multivalLinkMockAttribute,
values: [
{
linkPayload: {
id: 'multivalRecord1',
whoAmI: {...mockRecord, preview: null, label: 'Record A'}
}
},
{
linkPayload: {
id: 'multivalRecord2',
whoAmI: {...mockRecord, preview: null, label: 'Record B'}
}
},
{
linkPayload: {
id: 'multivalRecord3',
whoAmI: {...mockRecord, preview: null, label: 'Record C'}
}
},
{
linkPayload: {
id: 'multivalRecord4',
whoAmI: {...mockRecord, preview: null, label: 'Record D'}
}
},
{
linkPayload: {id: 'multivalRecord5', whoAmI: {...mockRecord, label: 'Record E'}}
},
{
linkPayload: {id: 'multivalRecord6', whoAmI: {...mockRecord, label: 'Record F'}}
},
{
linkPayload: {id: 'multivalRecord7', whoAmI: {...mockRecord, label: 'Record G'}}
}
]
}
]
},
Expand Down Expand Up @@ -113,6 +162,11 @@ describe('Explorer', () => {
linkPayload: {id: mockRecord.id, whoAmI: mockRecord}
}
]
},
{
attributeId: multivalLinkMockAttribute.id,
attributeProperties: multivalLinkMockAttribute,
values: []
}
]
}
Expand Down Expand Up @@ -205,7 +259,9 @@ describe('Explorer', () => {
render(
<Explorer
library="campaigns"
defaultViewSettings={{fields: [simpleMockAttribute.id, linkMockAttribute.id]}}
defaultViewSettings={{
fields: [simpleMockAttribute.id, linkMockAttribute.id, multivalLinkMockAttribute.id]
}}
/>
);

Expand All @@ -214,11 +270,22 @@ describe('Explorer', () => {
expect(tableRows).toHaveLength(1 + mockRecords.length); // 1 header row + 2 records
const [_headerRow, firstRecordRow] = tableRows;
const [record1] = mockRecords;
const [_selectionCell, whoAmICell, simpleAttributeCell, linkCell, multivalLinkCell] =
within(firstRecordRow).getAllByRole('cell');

expect(within(whoAmICell).getByText(record1.whoAmI.label)).toBeInTheDocument();

expect(within(simpleAttributeCell).getByText(recordId1)).toBeVisible();

expect(within(linkCell).getByText(mockRecord.label)).toBeVisible();
expect(within(linkCell).getByText(mockRecord.subLabel)).toBeVisible();

expect(within(firstRecordRow).getByText(record1.whoAmI.label)).toBeInTheDocument();
expect(within(firstRecordRow).getByText(recordId1)).toBeVisible();
expect(within(firstRecordRow).getByText(mockRecord.label)).toBeVisible();
expect(within(firstRecordRow).getByText(mockRecord.subLabel)).toBeVisible();
expect(within(multivalLinkCell).getByText('RA')).toBeVisible();
expect(within(multivalLinkCell).getByText('RB')).toBeVisible();
expect(within(multivalLinkCell).getByText('RC')).toBeVisible();
expect(within(multivalLinkCell).getByText('RD')).toBeVisible();
expect(within(multivalLinkCell).getByRole('img')).toHaveAttribute('src', mockRecord.preview?.small);
expect(within(multivalLinkCell).getByText('+2')).toBeVisible();
});

test('Should be able to deactivate a record with default actions', async () => {
Expand Down
157 changes: 98 additions & 59 deletions libs/ui/src/components/Explorer/TableCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,36 @@ import {
PropertyValueValueFragment
} from '_ui/_gqlTypes';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {KitTag, KitTypography} from 'aristid-ds';
import {FunctionComponent} from 'react';
import {KitAvatar, KitTag, KitTypography} from 'aristid-ds';
import {FunctionComponent, ReactNode} from 'react';
import styled from 'styled-components';
import {IdCard} from './IdCard';
import {IKitTag, IKitTagConfig} from 'aristid-ds/dist/Kit/DataDisplay/Tag/types';
import {TableTagGroup} from './TableTagGroup';

const isStandardValue = (
v: PropertyValueFragment,
attribute: AttributePropertiesFragment
): v is PropertyValueValueFragment => [AttributeType.simple, AttributeType.advanced].includes(attribute.type);
const isStandardValues = (
values: PropertyValueFragment[],
attribute: AttributePropertiesFragment
): values is PropertyValueValueFragment[] => values.every(value => isStandardValue(value, attribute));

const isLinkValue = (
v: PropertyValueFragment,
attribute: AttributePropertiesFragment
): v is PropertyValueLinkValueFragment =>
[AttributeType.simple_link, AttributeType.advanced_link].includes(attribute.type);
const isLinkValues = (
values: PropertyValueFragment[],
attribute: AttributePropertiesFragment
): values is PropertyValueLinkValueFragment[] => values.every(value => isLinkValue(value, attribute));

const isTreeValue = (
v: PropertyValueFragment,
attribute: AttributePropertiesFragment
): v is PropertyValueTreeValueFragment => [AttributeType.tree].includes(attribute.type);
const isStandardValue = (
v: PropertyValueFragment,
attribute: AttributePropertiesFragment
): v is PropertyValueValueFragment => [AttributeType.simple, AttributeType.advanced].includes(attribute.type);

const StyledCenteringWrapper = styled.div`
display: flex;
Expand All @@ -45,66 +55,95 @@ interface ITableCellProps {

export const TableCell: FunctionComponent<ITableCellProps> = ({values, attributeProperties}) => {
const {t} = useSharedTranslation();
if (values.length > 1 && values.every(value => isStandardValue(value, attributeProperties))) {
const tags: IKitTagConfig[] = values.map(value => {

if (attributeProperties.multiple_values) {
if (isStandardValues(values, attributeProperties)) {
const tags: IKitTagConfig[] = values.map(value => {
switch (attributeProperties.format) {
case AttributeFormat.boolean:
return {
idCardProps: {
description: value.valuePayload ? String(t('global.yes')) : String(t('global.no'))
},
type: value.valuePayload ? 'primary' : ('neutral' as IKitTag['type'])
};
default:
const valueContent =
attributeProperties.format === AttributeFormat.encrypted
? '●●●●●●●●●●●●'
: value.valuePayload;
return {
idCardProps: {description: valueContent},
type: 'primary'
};
}
});
return <TableTagGroup tags={tags} />;
} else if (isLinkValues(values, attributeProperties)) {
return (
<KitAvatar.Group maxCount={5}>
{values.map((value, index) => {
if (!isLinkValue(value, attributeProperties)) {
return null;
}

return (
<KitAvatar
key={index}
label={String(value?.linkPayload?.whoAmI.label)}
src={value?.linkPayload?.whoAmI.preview?.small}
color="primary"
secondaryColorInvert
/>
);
})}
</KitAvatar.Group>
);
} else {
//TODO: handle multiple tree values
return null;
}
} else {
const value = values[0]; // Not multiple_values attribute should not have more than one value
if (!value) {
return null;
}

let content: ReactNode = null;
if (isStandardValue(value, attributeProperties)) {
switch (attributeProperties.format) {
case AttributeFormat.boolean:
return {
idCardProps: {
description: value.valuePayload ? String(t('global.yes')) : String(t('global.no'))
},
type: value.valuePayload ? 'primary' : ('neutral' as IKitTag['type'])
};
const valueToDisplay = value.valuePayload ? t('global.yes') : t('global.no');
content = (
<KitTag
key={attributeProperties.id}
type={!!value.valuePayload ? 'primary' : 'neutral'}
idCardProps={{description: valueToDisplay}}
/>
);
break;
default:
const valueContent =
attributeProperties.format === AttributeFormat.encrypted ? '●●●●●●●●●●●●' : value.valuePayload;
return {
idCardProps: {description: valueContent},
type: 'primary'
};
content = (
<KitTypography.Text key={attributeProperties.id} ellipsis={{tooltip: valueContent}}>
{valueContent}
</KitTypography.Text>
);
break;
}
});
return <TableTagGroup tags={tags} />;
}
}

return (
<StyledCenteringWrapper>
{values.map((value: PropertyValueFragment) => {
if (isStandardValue(value, attributeProperties)) {
switch (attributeProperties.format) {
case AttributeFormat.boolean:
const valueToDisplay = value.valuePayload ? t('global.yes') : t('global.no');
return (
<KitTag
key={attributeProperties.id}
type={!!value.valuePayload ? 'primary' : 'neutral'}
idCardProps={{description: valueToDisplay}}
/>
);
default:
const valueContent =
attributeProperties.format === AttributeFormat.encrypted
? '●●●●●●●●●●●●'
: value.valuePayload;
return (
<KitTypography.Text key={attributeProperties.id} ellipsis={{tooltip: valueContent}}>
{valueContent}
</KitTypography.Text>
);
}
}
if (isTreeValue(value, attributeProperties)) {
content = value.treePayload?.record.id ?? '';
}

const defaultValue = '';
if (isTreeValue(value, attributeProperties)) {
return value.treePayload?.record.id ?? defaultValue;
}
if (isLinkValue(value, attributeProperties)) {
content = value.linkPayload?.whoAmI ? (
<IdCard key={attributeProperties.id} item={value.linkPayload?.whoAmI} />
) : null;
}

if (isLinkValue(value, attributeProperties)) {
return value.linkPayload?.whoAmI ? (
<IdCard key={attributeProperties.id} item={value.linkPayload?.whoAmI} />
) : null;
}
})}
</StyledCenteringWrapper>
);
return <StyledCenteringWrapper>{content}</StyledCenteringWrapper>;
}
};

0 comments on commit 8cec779

Please sign in to comment.