From 3cbfff9c6bb18db91404e915e52efecbc4b3b7b5 Mon Sep 17 00:00:00 2001 From: Nancy <68706811+nancy-dassana@users.noreply.github.com> Date: Mon, 19 Jul 2021 16:22:10 -0700 Subject: [PATCH] v0.11.5 -> v0.11.6 (#395) * enhancement #387 - [Table ] Link enhancements (#388) * feat #386 - Table updates for policy hub (#390) * feat #391 - Update MadeWithLove icons (#394) * fix #392 - Return array values properly for getJSONPathValue (#393) --- package-lock.json | 8 +- package.json | 4 +- rollup.config.ts | 1 + src/__snapshots__/storybook.test.ts.snap | 98 ++++---- src/components/Link/index.tsx | 16 +- src/components/Pages/MadeWithLove.tsx | 8 +- src/components/Table/IconCell.tsx | 58 +++++ src/components/Table/__tests__/Table.test.tsx | 5 + src/components/Table/__tests__/utils.test.tsx | 1 + .../Table/fixtures/2_sample_data.ts | 18 +- .../Table/fixtures/3_sample_data.ts | 9 +- .../Table/fixtures/7_sample_data.ts | 44 +++- src/components/Table/types.ts | 32 ++- src/components/Table/utils.tsx | 180 ++++++++++----- src/components/assets/images/404_error_2.svg | 212 +++++++++++++++--- src/components/assets/images/candy.svg | 21 ++ src/components/assets/images/coffee.svg | 4 + src/components/assets/images/momo.svg | 27 +++ .../assets/images/with_love_coffee.svg | 13 -- .../assets/images/with_love_high_chews.svg | 37 --- .../assets/images/with_love_momos.svg | 191 ---------------- src/components/utils.ts | 17 +- 22 files changed, 589 insertions(+), 415 deletions(-) create mode 100644 src/components/Table/IconCell.tsx create mode 100644 src/components/assets/images/candy.svg create mode 100644 src/components/assets/images/coffee.svg create mode 100644 src/components/assets/images/momo.svg delete mode 100644 src/components/assets/images/with_love_coffee.svg delete mode 100644 src/components/assets/images/with_love_high_chews.svg delete mode 100644 src/components/assets/images/with_love_momos.svg diff --git a/package-lock.json b/package-lock.json index bf86368f..611dc6c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dassana-io/web-components", - "version": "0.11.14", + "version": "0.11.16", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1379,9 +1379,9 @@ "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==" }, "@dassana-io/web-utils": { - "version": "0.8.5", - "resolved": "https://npm.pkg.github.com/download/@dassana-io/web-utils/0.8.5/723b11d85ece3147e8440956e40b4b42872613dd3003ebcf2a8a2481161dce6c", - "integrity": "sha512-Fm9/MC/mmwnDtcPFdfOunWxuRJqCE6weire5PT60wgVbcyYi+3xYiJXGktkJHHTCfRLt8voYbqr81nqQWCNopQ==", + "version": "0.8.6", + "resolved": "https://npm.pkg.github.com/download/@dassana-io/web-utils/0.8.6/8e8c3ba390f8d66822cd5b19e86ff922d2a74fc6d43b6498b03045c31000192f", + "integrity": "sha512-J91VAr+W7b8bDMi3NZz31yJOru0a4TzHyhkmbFx+aIYHsklsPPjLgly+mwoB1+xJemblG8ddH9dC65A+s6D4kQ==", "requires": { "axios": "^0.21.1", "axios-retry": "^3.1.8", diff --git a/package.json b/package.json index f1d6e474..d921606d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dassana-io/web-components", - "version": "0.11.15", + "version": "0.11.16", "publishConfig": { "registry": "https://npm.pkg.github.com/dassana-io" }, @@ -11,7 +11,7 @@ }, "dependencies": { "@ant-design/icons": "^4.6.2", - "@dassana-io/web-utils": "^0.8.5", + "@dassana-io/web-utils": "^0.8.6", "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-brands-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.1", diff --git a/rollup.config.ts b/rollup.config.ts index 9d33bced..1650036b 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -55,6 +55,7 @@ export default { 'react-helmet', 'react-hook-form', 'react-jss', + 'react-scroll', 'remark-gfm', 'react-markdown', 'typescript', diff --git a/src/__snapshots__/storybook.test.ts.snap b/src/__snapshots__/storybook.test.ts.snap index 49fb1cb4..ce303573 100644 --- a/src/__snapshots__/storybook.test.ts.snap +++ b/src/__snapshots__/storybook.test.ts.snap @@ -3041,7 +3041,7 @@ exports[`Storyshots Made With Love With Love 1`] = `  momos
- - aws.svg - + + aws.svg + +
- - aws.svg - + + aws.svg + +
- - aws.svg - + + aws.svg + +
- - aws.svg - + + aws.svg + + - - aws.svg - + + aws.svg + +
Foo
+ + {label} +
+ ) + + case tooltip: + return ( + + + + ) + } + + return ( +
+ +
+ ) +} diff --git a/src/components/Table/__tests__/Table.test.tsx b/src/components/Table/__tests__/Table.test.tsx index 9ff02bf0..f8364944 100644 --- a/src/components/Table/__tests__/Table.test.tsx +++ b/src/components/Table/__tests__/Table.test.tsx @@ -129,7 +129,12 @@ describe('Table', () => { unixTS: 1519782342212 }) ], + buildHrefIconJSONPath: { + id: 'H', + label: 'H' + }, company: { id: 'c1', name: 'azure', value: 'azure' }, + icon: 'A', id: 0, key: 0, name: { id: 'n1', value: 'Lorem ipsum' }, diff --git a/src/components/Table/__tests__/utils.test.tsx b/src/components/Table/__tests__/utils.test.tsx index bc8afb93..20c791a9 100644 --- a/src/components/Table/__tests__/utils.test.tsx +++ b/src/components/Table/__tests__/utils.test.tsx @@ -186,6 +186,7 @@ describe('mapFilterKeys', () => { 'start_date', ['role', 'name'], 'linked_in', + 'company', 'company' ] diff --git a/src/components/Table/fixtures/2_sample_data.ts b/src/components/Table/fixtures/2_sample_data.ts index 434a9a9e..114d1941 100644 --- a/src/components/Table/fixtures/2_sample_data.ts +++ b/src/components/Table/fixtures/2_sample_data.ts @@ -1,6 +1,12 @@ import { fakeApiCallSuccess } from 'components/utils' import { IconName } from 'components/Icon' -import { ColumnFormats, ColumnType, ColumnTypes, TableProps } from '..' +import { + ColumnFormats, + ColumnType, + ColumnTypes, + TableIconLabelType, + TableProps +} from '..' const { component, number, string } = ColumnTypes const { date, icon, link, toggle, tag } = ColumnFormats @@ -55,6 +61,16 @@ const columns: ColumnType[] = [ title: 'Has Admin Access', type: component }, + { + dataIndex: 'company', + format: icon, + renderProps: { + label: { type: TableIconLabelType.inline }, + type: 'iconKey' + }, + title: 'Company', + type: component + }, { dataIndex: 'company', format: icon, diff --git a/src/components/Table/fixtures/3_sample_data.ts b/src/components/Table/fixtures/3_sample_data.ts index d2b07486..81b86c87 100644 --- a/src/components/Table/fixtures/3_sample_data.ts +++ b/src/components/Table/fixtures/3_sample_data.ts @@ -1,5 +1,11 @@ import { fakeApiCallSuccess } from 'components/utils' -import { ColumnFormats, ColumnType, ColumnTypes, TableProps } from '..' +import { + ColumnFormats, + ColumnType, + ColumnTypes, + TableIconLabelType, + TableProps +} from '..' const { component, number, string } = ColumnTypes const { date, icon, link, toggle, tag } = ColumnFormats @@ -63,6 +69,7 @@ const columns: ColumnType[] = [ googleCloudService: 'https://dummyimage.com/600x400/EA4335/fff&text=G' }, + label: { type: TableIconLabelType.tooltip }, type: 'icon' }, title: 'Company', diff --git a/src/components/Table/fixtures/7_sample_data.ts b/src/components/Table/fixtures/7_sample_data.ts index 0491258a..7ff6f14c 100644 --- a/src/components/Table/fixtures/7_sample_data.ts +++ b/src/components/Table/fixtures/7_sample_data.ts @@ -1,6 +1,12 @@ import { dateFormat } from '__mocks__/table_mock_data' import { IconName } from 'components/Icon' -import { ColumnFormats, ColumnType, ColumnTypes, TableProps } from '..' +import { + ColumnFormats, + ColumnType, + ColumnTypes, + TableIconLabelType, + TableProps +} from '..' // This file contains table data with col dataIndex as a JSONPath instead of string @@ -8,7 +14,9 @@ const { component, number, string } = ColumnTypes const { date, icon } = ColumnFormats export interface JSONPathData { + buildHrefIconJSONPath: { id: string; label: string } company: { id: string; name?: string; value: IconName } + icon: string id: number name: { id: string; value: string } start_date: { id: string; date: number } @@ -35,6 +43,7 @@ const columns: ColumnType[] = [ format: icon, renderProps: { iconKey: 'value', + label: { labelKey: 'value', type: TableIconLabelType.tooltip }, type: 'iconKey' }, title: 'Company', @@ -50,12 +59,39 @@ const columns: ColumnType[] = [ sort: false, title: 'Vendors', type: component + }, + { + dataIndex: 'icon', + format: icon, + renderProps: { + buildHref: name => + `https://dummyimage.com/300x300/${name}1DB3C/fff&text=${name}`, + label: { type: TableIconLabelType.tooltip }, + type: 'icon' + }, + title: 'Icon', + type: component + }, + { + dataIndex: 'buildHrefIconJSONPath', + format: icon, + renderProps: { + buildHref: (name, data = {}) => + `https://dummyimage.com/300x300/${name}848CF/fff&text=${name}${data.icon}`, + iconKey: 'id', + label: { labelKey: 'label', type: TableIconLabelType.tooltip }, + type: 'icon' + }, + title: 'Build Icon Link', + type: component } ] const data: JSONPathData[] = [ { + buildHrefIconJSONPath: { id: 'H', label: 'H' }, company: { id: 'c1', name: 'azure', value: 'azure' }, + icon: 'A', id: 0, name: { id: 'n1', value: 'Lorem ipsum' }, start_date: { date: 1519782342212, id: 'sd1' }, @@ -67,7 +103,9 @@ const data: JSONPathData[] = [ ] }, { + buildHrefIconJSONPath: { id: 'E', label: 'E' }, company: { id: 'c2', value: 'aws' }, + icon: 'B', id: 1, name: { id: 'n2', value: 'Dolor Sit' }, start_date: { date: 1593682342212, id: 'sd2' }, @@ -87,7 +125,9 @@ const data: JSONPathData[] = [ ] }, { + buildHrefIconJSONPath: { id: 'B', label: 'B' }, company: { id: 'c2', value: 'dassana' }, + icon: 'C', id: 2, name: { id: 'n2', value: 'Amet Consectetur Adipiscing Elit' }, start_date: { date: 1553932342212, id: 'sd3' }, @@ -151,7 +191,9 @@ const data: JSONPathData[] = [ ] }, { + buildHrefIconJSONPath: { id: 'D', label: 'D' }, company: { id: 'c2', value: 'googleCloudService' }, + icon: 'D', id: 3, name: { id: 'n2', value: 'Duis Irure' }, start_date: { date: 1531932342212, id: 'sd3' }, diff --git a/src/components/Table/types.ts b/src/components/Table/types.ts index 20188f4a..0c2908fa 100644 --- a/src/components/Table/types.ts +++ b/src/components/Table/types.ts @@ -1,6 +1,6 @@ import { ColoredDotProps } from '../ColoredDot' +import { LinkProps } from '../Link' import { SharedIconProps } from '../Icon' -import { SharedLinkProps } from '../Link' import { TableMethods } from './utils' import { Key, ReactNode } from 'react' @@ -84,29 +84,47 @@ interface PartialComponentType extends PartialColumnType { type: ColumnTypes.component } -interface SharedCompIcontype extends SharedIconProps { +export enum TableIconLabelType { + inline = 'inline', + tooltip = 'tooltip' +} + +interface SharedCompIconType extends SharedIconProps { filterKey?: string iconKey?: string + /** + * Whether to render a label with the icon or not. + */ + label?: { labelKey?: string; type: TableIconLabelType } } -export interface RenderPropsIcon extends SharedCompIcontype { +export interface RenderPropsIconMap extends SharedCompIconType { type: 'icon' iconMap: { [key: string]: string } } -interface RenderPropsIconKey extends SharedCompIcontype { +export interface RenderPropsIconBuildHref extends SharedCompIconType { + type: 'icon' + buildHref: (record?: string, data?: Record) => string +} + +interface RenderPropsIconKey extends SharedCompIconType { type: 'iconKey' } -interface RenderPropsIconUrl extends SharedCompIcontype { +interface RenderPropsIconUrl extends SharedCompIconType { type: 'iconUrl' } export interface ComponentIconType extends PartialComponentType { format: ColumnFormats.icon - renderProps: RenderPropsIcon | RenderPropsIconKey | RenderPropsIconUrl + renderProps: + | RenderPropsIconMap + | RenderPropsIconBuildHref + | RenderPropsIconKey + | RenderPropsIconUrl } export interface ComponentActionType extends PartialComponentType { @@ -128,7 +146,7 @@ interface ComponentColoredDotType extends PartialComponentType { } } -interface RenderPropsLink extends Pick { +interface RenderPropsLink extends Pick { buildHref: (record?: string, data?: Record) => string isDisabled?: (record?: string, data?: Record) => boolean } diff --git a/src/components/Table/utils.tsx b/src/components/Table/utils.tsx index 96654b06..aaec1955 100644 --- a/src/components/Table/utils.tsx +++ b/src/components/Table/utils.tsx @@ -3,6 +3,7 @@ import bytes from 'bytes' import { CellWithTooltip } from './CellWithTooltip' import { ColoredDot } from 'components/ColoredDot' import { EditableCell } from './EditableCell' +import { IconCell } from './IconCell' import isUndefined from 'lodash/isUndefined' import moment from 'moment' import { @@ -14,12 +15,11 @@ import { DataId, DateDisplayFormat, EditableCellTypes, - NumberDateType, - RenderPropsIcon + NumberDateType } from './types' import { defaultIconHeight, MultipleIcons } from './MultipleIcons' import { getJSONPathArr, getJSONPathValue } from 'components/utils' -import { Icon, IconName, IconProps } from '../Icon' +import { IconName, IconProps } from '../Icon' import { Link, LinkProps } from '../Link' import React, { Key, MouseEvent } from 'react' import { Tag, TagProps } from '../Tag' @@ -99,7 +99,10 @@ export function processData( columns.forEach(col => { const { dataIndex } = col - const value = getJSONPathValue(`$.${dataIndex}`, item) + const value = getJSONPathValue( + `$.${dataIndex}`, + item + ) as ProcessedData[keyof TableData] if (value) { partialData[dataIndex as keyof TableData] = value @@ -186,9 +189,9 @@ const compareIcons = ? `$.${dataIndex}.${iconKey}` : `$.${dataIndex}` - const compareValA = getJSONPathValue(jsonPath, a) || '' + const compareValA = getJSONPathValue(jsonPath, a)?.toString() || '' - const compareValB = getJSONPathValue(jsonPath, b) || '' + const compareValB = getJSONPathValue(jsonPath, b)?.toString() || '' return compareValA.localeCompare(compareValB) } @@ -290,6 +293,62 @@ function applySort( } } +/* -------- applyRender helper functions for icon -------- */ + +type IconRecord = IconName | string | Record + +const getIconOrIconKey = ( + record: IconRecord, + jsonPath: string +): string | IconName | undefined => { + if (typeof record === 'object') { + const value = getJSONPathValue(jsonPath, record)?.toString() + + if (value) return value + } else return record +} + +interface GetIconPropsParams { + data?: TableData + jsonPath: string + record: IconRecord + renderProps: ComponentIconType['renderProps'] +} + +// eslint-disable-next-line comma-spacing +const getIconProps = ({ + data, + jsonPath, + record, + renderProps +}: GetIconPropsParams): IconProps => { + const val = getIconOrIconKey(record, jsonPath) + + if (!val) return {} as IconProps + + switch (renderProps.type) { + case 'icon': { + if ('iconMap' in renderProps) { + const { iconMap } = renderProps + + return { icon: iconMap[val] } + } else { + const { buildHref } = renderProps + + return { icon: buildHref(val, data) } + } + } + + case 'iconUrl': + return { icon: val } + + case 'iconKey': + return { iconKey: val as IconName } + } +} + +/* ------------------------------------------------------- */ + /* Sets antD column render prop as appropriate render function depending on data type and format. Render function takes @@ -387,62 +446,30 @@ function applyRender( } case icon: { - type IconRecord = IconName | string | Record - const renderProps = column.renderProps - const { iconKey, height = defaultIconHeight } = renderProps - - const jsonPath = iconKey ? `$.${iconKey}` : '' - - const getIconOrIconKey = ( - record: IconRecord - ): string | IconName | undefined => { - if (typeof record === 'object') { - const value = getJSONPathValue(jsonPath, record) - - if (value) return value - } else return record - } - - type GetIconProps = ( - record: IconRecord, - renderProps: ComponentIconType['renderProps'] - ) => IconProps - - const getIconProps: GetIconProps = ( - record, - renderProps - ) => { - const val = getIconOrIconKey(record) - - if (!val) return {} as IconProps - const { type } = renderProps + const { + iconKey, + height = defaultIconHeight, + label + } = renderProps - switch (type) { - case 'icon': { - const { iconMap } = - renderProps as RenderPropsIcon - - return { icon: iconMap[val] } - } - - case 'iconUrl': - return { icon: val } - - case 'iconKey': - return { iconKey: val as IconName } - } - } + const jsonPath = iconKey ? `$.${iconKey}` : '' antDColumn.render = ( - record?: IconRecord | IconRecord[] + record?: IconRecord | IconRecord[], + data?: TableData ) => { if (!record) return '' if (Array.isArray(record)) { const iconPropsArr = record.map(icon => - getIconProps(icon, renderProps) + getIconProps({ + data, + jsonPath, + record: icon, + renderProps + }) ) return ( @@ -452,20 +479,48 @@ function applyRender( /> ) } else { - const iconProps = getIconProps(record, renderProps) + const iconProps = { + ...getIconProps({ + data, + jsonPath, + record, + renderProps + }), + height + } if (renderProps.type === 'icon' && !iconProps.icon) return record - /** - * Custom icons are defined as a map of key and url in the Column object. - * E.g. { renderProps: {iconMap: { example-icon: 'https://dummyimage.com/600x400/0072c6/fff&text=A' }, ...}, ...} - * Then in the data object, you reference the iconMap key - 'example-icon'. - * E.g. { demo_icon: 'example-icon', ... } - * If this mapping doesn't exist in the column object, the table renders just the key (or record). - * In this example, it will be 'example-icon'. - */ - return + if (!label) + return + + const labelKey = + !label.labelKey && typeof record === 'string' + ? record + : label.labelKey + + if (!labelKey) + return + else { + const jsonPath = `$.${labelKey}` + + const labelVal = + typeof record === 'string' + ? labelKey + : (getJSONPathValue( + jsonPath, + record + ) as string) // eslint-disable-line no-mixed-spaces-and-tabs + + return ( + + ) + } } } break @@ -496,6 +551,7 @@ function applyRender( const linkProps: LinkProps = { children: record, href: buildHref(record, data), + onClick: e => e.stopPropagation(), target } diff --git a/src/components/assets/images/404_error_2.svg b/src/components/assets/images/404_error_2.svg index 67933489..58283afe 100644 --- a/src/components/assets/images/404_error_2.svg +++ b/src/components/assets/images/404_error_2.svg @@ -1,38 +1,176 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/assets/images/candy.svg b/src/components/assets/images/candy.svg new file mode 100644 index 00000000..583b984e --- /dev/null +++ b/src/components/assets/images/candy.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/assets/images/coffee.svg b/src/components/assets/images/coffee.svg new file mode 100644 index 00000000..dd80e083 --- /dev/null +++ b/src/components/assets/images/coffee.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/assets/images/momo.svg b/src/components/assets/images/momo.svg new file mode 100644 index 00000000..a13ca281 --- /dev/null +++ b/src/components/assets/images/momo.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/assets/images/with_love_coffee.svg b/src/components/assets/images/with_love_coffee.svg deleted file mode 100644 index 02fb3bc3..00000000 --- a/src/components/assets/images/with_love_coffee.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/src/components/assets/images/with_love_high_chews.svg b/src/components/assets/images/with_love_high_chews.svg deleted file mode 100644 index c881d872..00000000 --- a/src/components/assets/images/with_love_high_chews.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - diff --git a/src/components/assets/images/with_love_momos.svg b/src/components/assets/images/with_love_momos.svg deleted file mode 100644 index 2cd6bdd5..00000000 --- a/src/components/assets/images/with_love_momos.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/utils.ts b/src/components/utils.ts index 1ea3298c..0a80a807 100644 --- a/src/components/utils.ts +++ b/src/components/utils.ts @@ -126,16 +126,27 @@ export const getDataTestAttributeProp = ( [TAG]: dataTag ? `${cmpName}-${dataTag}` : cmpName }) -export const getJSONPathValue = ( +export const getJSONPathValue = ( path: string, obj: Record ) => { - const value = JSONPath({ + const value = JSONPath({ json: obj, path }) - if (value && Array.isArray(value)) return value[0] + if (Array.isArray(value)) { + switch (value.length) { + case 0: + return undefined + case 1: + return value[0] as T + default: + return value as T[] + } + } + + return value } /**