From a5afe30e45ad8b6e5dc1fe70317703d2ad124469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Tib=C3=BArcio?= Date: Wed, 13 Nov 2024 15:04:56 -0300 Subject: [PATCH] docs: complex table filters example (#489) --- .eslintrc.cjs | 1 + .storybook/preview.tsx | 9 +- docs/UX Patterns/Table/Filters.mdx | 14 +- docs/UX Patterns/Table/Filters.stories.tsx | 278 ---------- docs/UX Patterns/Table/Table.mdx | 6 +- docs/UX Patterns/Table/Table.stories.tsx | 496 +++++++++++------- docs/UX Patterns/Table/TableStoryUtils.tsx | 201 +++++++ .../data-display/Collapse/Collapse.tsx | 2 +- 8 files changed, 522 insertions(+), 485 deletions(-) delete mode 100644 docs/UX Patterns/Table/Filters.stories.tsx create mode 100644 docs/UX Patterns/Table/TableStoryUtils.tsx diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ad9515584..b16e7e386 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -124,6 +124,7 @@ module.exports = { 'react/react-in-jsx-scope': 'off', 'import/no-duplicates': 'off', 'react/jsx-boolean-value': 'warn', + '@typescript-eslint/no-confusing-void-expression': ['error', { ignoreArrowShorthand: true }], }, globals: { React: true, diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index f82951939..41d49813b 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,9 +1,16 @@ import type { Preview } from '@storybook/react' +// import type { IndexEntry } from '@storybook/types' const preview: Preview = { parameters: { layout: 'centered', options: { + // TODO https://mparticle-eng.atlassian.net/browse/UNI-1214 + // storySort: (a: IndexEntry, b: IndexEntry) => { + // console.log('Ordering stories', { a, b }) + // const order = ['Documentation', 'Cell Types', 'Filters', 'Primary', 'Complex'] + // return order.indexOf(a[1].name) - order.indexOf(b[1].name) + // }, storySort: { order: [ 'About', @@ -38,7 +45,7 @@ const preview: Preview = { ], 'Candidate Components', 'UX Patterns', - ['Table', ['Table', 'Filters']], + ['Table', ['Table', ['Documentation', 'Cell Types', 'Filters', 'Primary', 'Complex']]], 'Contributing', ['Introduction', 'Commits', 'Testing in the platforms', 'Release Process', 'Maintainers'], ], diff --git a/docs/UX Patterns/Table/Filters.mdx b/docs/UX Patterns/Table/Filters.mdx index 7d3eae893..2b997dbe5 100644 --- a/docs/UX Patterns/Table/Filters.mdx +++ b/docs/UX Patterns/Table/Filters.mdx @@ -1,8 +1,8 @@ import { Meta, Story } from '@storybook/blocks' -import * as FiltersStories from './Filters.stories' +import * as TableStories from './Table.stories' - + # Filters @@ -11,24 +11,20 @@ import * as FiltersStories from './Filters.stories' _Note: This section covers filters specifically for tables. For query-related filters, please refer to the [Analytics Filters - Coming Soon](#coming)._ #### Filter Search + Located above the table on the right, the search filter allows users to quickly find specific data within the table by entering keywords. #### **Simple Filters** Simple filters are ideal when there are only a few filter options. These are straightforward and quick to use and appearing as dropdowns above the table. For examples, refer to the [Select Component](https://mparticle.github.io/aquarium/?path=/docs/components-data-entry-select--documentation). -Examples: - - - #### **Filters with Apply Button** Complex filters provide more advanced filtering options, allowing users to apply multiple criteria at once. These filters often include dropdowns, checkboxes, and text fields. Complex filters are particularly useful when multiple filters need to be applied simultaneously or when load times might be a concern. -- daterange -- modal: sorting, filters: one of each input type: checkboxes, input, tree select and placeholder for tags +Example: - + #### **Date Range Filters** diff --git a/docs/UX Patterns/Table/Filters.stories.tsx b/docs/UX Patterns/Table/Filters.stories.tsx deleted file mode 100644 index 138eb3423..000000000 --- a/docs/UX Patterns/Table/Filters.stories.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import type { ReactNode } from 'react' -import { CopyOutlined } from '@ant-design/icons' -import { faker } from '@faker-js/faker' -import type { Meta, StoryObj } from '@storybook/react' -import { - Flex, - Icon, - Input, - Select, - Badge, - type IBadgeProps, - Table, - type TableProps, - Tag, - type ITagProps, - Typography, - Space, - Tooltip, -} from 'src/components' -import { DatePickerWithDisabledYears } from 'src/components/data-entry/DatePicker/DatePicker.stories' -import { SelectWithRangePicker } from 'docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker' - -interface DataType { - key: string - name: string - id: string - timestamp: number - output: string - environment: Environment - status: Status - mpId: string -} - -type Environment = 'unknown' | 'development' | 'production' -type Status = 'draft' | 'error' | 'ready' - -const EnvironmentColors: Record = { - production: 'blue', - development: 'purple', - unknown: 'default', -} - -const EnvironmentNames: Record = { - production: 'Prod', - development: 'Dev', - unknown: 'Unknown', -} - -const getTagColorForEnvironment = (env: Environment): ITagProps['color'] => EnvironmentColors[env] - -const getNameForEnvironment = (env: Environment) => EnvironmentNames[env] - -const StatusColors: Record = { - draft: 'cyan', - error: 'red', - ready: 'green', -} - -const StatusNames: Record = { - draft: 'Draft', - error: 'Error', - ready: 'Ready', -} - -const getStatusColor = (status: Status) => StatusColors[status] - -const getStatusName = (status: Status) => StatusNames[status] - -const columns: TableProps['columns'] = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - render: (name: string) => { - const path = window.location.pathname.split('/') - path.pop() - const route = `${path.join('/')}/${name}` - - return {name} - }, - }, - { - title: () => ( - - Help lorem ipsum. - - Learn More - - - }> - - ID - - - - ), - dataIndex: 'id', - key: 'id', - }, - { - title: 'Timestamp (UTC)', - dataIndex: 'timestamp', - key: 'timestamp', - render: (timestampInMicroseconds: number): string => { - return new Date(timestampInMicroseconds / (1000 * 1000)).toLocaleString(undefined, { - month: 'short', - day: '2-digit', - year: 'numeric', - hour: 'numeric', - minute: '2-digit', - second: '2-digit', - timeZone: 'UTC', - hour12: false, - }) - }, - }, - { - title: 'mPID', - dataIndex: 'mpId', - key: 'mpId', - render: (mpId: string): ReactNode => { - return }}>{mpId} - }, - }, - { - title: 'Output', - dataIndex: 'output', - key: 'output', - }, - { - title: 'Environment', - key: 'environment', - dataIndex: 'environment', - render: (env: Environment): React.ReactNode => { - return {getNameForEnvironment(env)} - }, - }, - { - title: 'Status', - dataIndex: 'status', - key: 'status', - render: (status: Status): React.ReactNode => , - }, - { - title: 'Actions', - dataIndex: 'actions', - key: 'actions', - render: (): ReactNode => ( - } - placeholder="Search" - style={{ width: '240px' }} - /> - - - columns={columns} dataSource={data} scroll={{ x: 'max-content' }} /> - - ), -} - -const TIME_OPTIONS = [ - { - value: 'last12hours', - label: 'Last 12 hours', - } as const, - { - value: 'last7days', - label: 'Last 7 days', - } as const, - { - value: 'last14days', - label: 'Last 14 days', - } as const, -] - -export const WithComplexFilters: Story = { - name: 'Complex', - render: () => ( - - - - - onUpdateFilters({ time })} - rangePickerProps={{ - showTime: true, - showHour: true, - showMinute: true, - showSecond: false, - disabledDate: (antdDayJS: any) => { - const fourteenDaysInMs = 14 * 24 * 60 * 60 * 1000 - return antdDayJS.isBefore(new Date(Date.now() - fourteenDaysInMs)) - }, - }} - /> - - } - placeholder="Search" - style={{ width: '240px' }} - /> - - - columns={columns} dataSource={data} scroll={{ x: 'max-content' }} /> - - ), -} diff --git a/docs/UX Patterns/Table/Table.mdx b/docs/UX Patterns/Table/Table.mdx index 33dacf04a..9ad581a53 100644 --- a/docs/UX Patterns/Table/Table.mdx +++ b/docs/UX Patterns/Table/Table.mdx @@ -29,7 +29,6 @@ A table row with expand and collapse functionality, allowing users to toggle add -> Insert Example - ### Pagination Use pagination in tables to improve performance and reduce load times by fetching only the data needed for the current page. @@ -40,14 +39,11 @@ Use pagination in tables to improve performance and reduce load times by fetchin Filters help users narrow down large datasets within tables. Learn more about the variety of filter types available in the mParticle table [here.](https://mparticle.github.io/aquarium/?path=/docs/ux-patterns-table-filters--documentation) - ### Table Example
- - - + ### Related Links diff --git a/docs/UX Patterns/Table/Table.stories.tsx b/docs/UX Patterns/Table/Table.stories.tsx index bb0f6eb45..c774dd819 100644 --- a/docs/UX Patterns/Table/Table.stories.tsx +++ b/docs/UX Patterns/Table/Table.stories.tsx @@ -1,200 +1,30 @@ -import type { ReactNode } from 'react' -import { CopyOutlined } from '@ant-design/icons' -import { faker } from '@faker-js/faker' import type { Meta, StoryObj } from '@storybook/react' import { Flex, Icon, Input, - Select, - Badge, - type IBadgeProps, Table, - type TableProps, - Tag, - type ITagProps, - Typography, Space, - Tooltip, + Button, + Checkbox, + Collapse, + ConfigProvider, + Divider, + type ICollapseProps, + Modal, + Select, + Typography, + TreeSelect, + Row, + Col, } from 'src/components' import { DatePickerWithDisabledYears } from 'src/components/data-entry/DatePicker/DatePicker.stories' -import { ColorError, ColorSuccess, ColorTextPlaceholder } from 'src/styles/style' - -interface DataType { - key: string - name: string - id: string - timestamp: number - output: string - environment: Environment - status: Status - mpId: string -} - -type Environment = 'development' | 'production' -type Status = 'draft' | 'error' | 'ready' - -const EnvironmentColors: Record = { - production: 'blue', - development: 'purple', -} - -const EnvironmentNames: Record = { - production: 'Prod', - development: 'Dev', -} - -const getTagColorForEnvironment = (env: Environment): ITagProps['color'] => EnvironmentColors[env] - -const getNameForEnvironment = (env: Environment) => EnvironmentNames[env] - -const StatusColors: Record = { - draft: ColorTextPlaceholder, - error: ColorError, - ready: ColorSuccess, -} - -const StatusNames: Record = { - draft: 'Draft', - error: 'Error', - ready: 'Ready', -} - -const getStatusColor = (status: Status) => StatusColors[status] - -const getStatusName = (status: Status) => StatusNames[status] - -const columns: TableProps['columns'] = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - render: (name: string) => { - const path = window.location.pathname.split('/') - path.pop() - const route = `${path.join('/')}/${name}` - - return {name} - }, - }, - { - title: () => ( - - ID - - Help lorem ipsum. - - Learn More - - - }> - - - - ), - dataIndex: 'id', - key: 'id', - }, - { - title: 'Timestamp (UTC)', - dataIndex: 'timestamp', - key: 'timestamp', - render: (timestampInMicroseconds: number): string => { - return new Date(timestampInMicroseconds / (1000 * 1000)).toLocaleString(undefined, { - month: 'short', - day: '2-digit', - year: 'numeric', - hour: 'numeric', - minute: '2-digit', - second: '2-digit', - timeZone: 'UTC', - hour12: false, - }) - }, - }, - { - title: 'mPID', - dataIndex: 'mpId', - key: 'mpId', - render: (mpId: string): ReactNode => { - return }}>{mpId} - }, - }, - { - title: 'Output', - dataIndex: 'output', - key: 'output', - }, - { - title: 'Environment', - key: 'environment', - dataIndex: 'environment', - render: (env: Environment): React.ReactNode => { - return {getNameForEnvironment(env)} - }, - }, - { - title: 'Status', - dataIndex: 'status', - key: 'status', - render: (status: Status): React.ReactNode => , - }, - { - title: 'Actions', - dataIndex: 'actions', - key: 'actions', - render: (): ReactNode => ( - + Recent first + Oldest first + + + + + + + + + + + + + + + + } + placeholder="Search" + style={{ width: '240px' }} + /> + + + + columns={tableColumns} + dataSource={tableData.slice(0, 2)} + scroll={{ x: 'max-content' }} + /> + + + ) + }, +} diff --git a/docs/UX Patterns/Table/TableStoryUtils.tsx b/docs/UX Patterns/Table/TableStoryUtils.tsx new file mode 100644 index 000000000..55600a6e0 --- /dev/null +++ b/docs/UX Patterns/Table/TableStoryUtils.tsx @@ -0,0 +1,201 @@ +import type { ReactNode } from 'react' +import { faker } from '@faker-js/faker' +import { CopyOutlined } from '@ant-design/icons' +import { type TableProps, Typography, Flex, Tooltip, Tag, Badge, Select } from 'src/components' +import { type ITagProps, type IBadgeProps, Icon } from 'src/components' +import { ColorTextPlaceholder, ColorError, ColorSuccess } from 'src/styles/style' + +export interface TableDataType { + key: string + name: string + id: string + timestamp: number + output: string + environment: Environment + status: Status + mpId: string +} + +type Environment = 'development' | 'production' +type Status = 'draft' | 'error' | 'ready' + +const EnvironmentColors: Record = { + production: 'blue', + development: 'purple', +} + +const EnvironmentNames: Record = { + production: 'Prod', + development: 'Dev', +} + +const getTagColorForEnvironment = (env: Environment): ITagProps['color'] => EnvironmentColors[env] + +const getNameForEnvironment = (env: Environment) => EnvironmentNames[env] + +const StatusColors: Record = { + draft: ColorTextPlaceholder, + error: ColorError, + ready: ColorSuccess, +} + +const StatusNames: Record = { + draft: 'Draft', + error: 'Error', + ready: 'Ready', +} + +const getStatusColor = (status: Status) => StatusColors[status] + +const getStatusName = (status: Status) => StatusNames[status] + +export const tableColumns: TableProps['columns'] = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + render: (name: string): ReactNode => { + const path = window.location.pathname.split('/') + path.pop() + const route = `${path.join('/')}/${name}` + + return {name} + }, + }, + { + title: () => ( + + ID + + Help lorem ipsum. + + Learn More + + + }> + + + + ), + dataIndex: 'id', + key: 'id', + }, + { + title: 'Timestamp (UTC)', + dataIndex: 'timestamp', + key: 'timestamp', + render: (timestampInMicroseconds: number): string => { + return new Date(timestampInMicroseconds / (1000 * 1000)).toLocaleString(undefined, { + month: 'short', + day: '2-digit', + year: 'numeric', + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + timeZone: 'UTC', + hour12: false, + }) + }, + }, + { + title: 'mPID', + dataIndex: 'mpId', + key: 'mpId', + render: (mpId: string): ReactNode => { + return }}>{mpId} + }, + }, + { + title: 'Output', + dataIndex: 'output', + key: 'output', + }, + { + title: 'Environment', + key: 'environment', + dataIndex: 'environment', + render: (env: Environment): React.ReactNode => { + return {getNameForEnvironment(env)} + }, + }, + { + title: 'Status', + dataIndex: 'status', + key: 'status', + render: (status: Status): React.ReactNode => , + }, + { + title: 'Actions', + dataIndex: 'actions', + key: 'actions', + render: (): ReactNode => ( +