Skip to content

feat: table component storybook #2600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
2 changes: 2 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const preview: Preview = {

<div id="animated-dialog-backdrop" />

<div id="visible-modal" />

<BaseConfirmationModal />
</ConfirmationModalProvider>
</ThemeProvider>
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "1.10.8",
"@devtron-labs/devtron-fe-common-lib": "1.10.9",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
Expand Down Expand Up @@ -66,7 +66,7 @@
"test:ci": "jest --watchAll=false --ci --json --coverage --testLocationInResults --outputFile=report.json",
"jest": "jest",
"lint-staged": "lint-staged",
"storybook": "IS_STORYBOOK=true storybook dev -p 6006",
"storybook": "IS_STORYBOOK=true GENERATE_SOURCEMAP=true storybook dev -p 6006",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice add-on!

"build-storybook": "IS_STORYBOOK=true storybook build",
"postinstall": "patch-package"
},
Expand Down
2 changes: 1 addition & 1 deletion src/css/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ $checkbox-hover-bg-image: url('../assets/icons/ic-checkbox-hover.svg');

// Class for checkbox parent container, if added to parent container, hover effect will be applied to checkbox
.checkbox__parent-container {
&:hover {
&--active, &:hover {
.form__checkbox-container {
background-image: $checkbox-hover-bg-image;
}
Expand Down
2 changes: 1 addition & 1 deletion src/css/iconTheming.scss
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ $svg-fill-hex-to-var: (

// Class for checkbox parent container, if added to parent container, hover effect will be applied to checkbox
.checkbox__parent-container {
&:hover {
&--active, &:hover {
.form__checkbox-container {
background-image: $checkbox-hover-bg-image;
}
Expand Down
245 changes: 245 additions & 0 deletions src/stories/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import { useEffect } from 'react'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add story for generic info card

import { Meta, StoryObj } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import {
Button,
ButtonComponentType,
ButtonStyleType,
ButtonVariantType,
ComponentSizeType,
FiltersTypeEnum,
PaginationEnum,
SearchBar,
SelectAllDialogStatus,
Table,
TableCellComponentProps,
TableProps,
TableViewWrapperProps,
TableSignalEnum,
} from '@devtron-labs/devtron-fe-common-lib'
import { ReactComponent as ICPlay } from '@Icons/ic-play-outline.svg'
import { ReactComponent as ICPause } from '@Icons/ic-pause.svg'
import { ReactComponent as ICWarning } from '@Icons/ic-warning-y6.svg'

const CellComponent = ({ field, value, signals, row, isRowActive }: TableCellComponentProps) => {
const handleButtonClick = () => {
action(`Row ${value} clicked`)
}

useEffect(() => {
const rowEnterPressedCallback = ({
detail: {
activeRowData: { id },
},
}) => {
if (id === row.id && field === 'name') {
handleButtonClick()
}
}

const getCallback =
(text: string) =>
({
detail: {
activeRowData: { id },
},
}) => {
if (id === row.id && field === 'name') {
action(text)
}
}

const deletePressedCallback = getCallback(`Delete pressed for ${value}`)
const openContextMenuCallback = getCallback(`Open context menu for ${value}`)

signals.addEventListener(TableSignalEnum.ENTER_PRESSED, rowEnterPressedCallback)
signals.addEventListener(TableSignalEnum.DELETE_PRESSED, deletePressedCallback)
signals.addEventListener(TableSignalEnum.OPEN_CONTEXT_MENU, openContextMenuCallback)

return () => {
signals.removeEventListener(TableSignalEnum.ENTER_PRESSED, rowEnterPressedCallback)
signals.removeEventListener(TableSignalEnum.DELETE_PRESSED, deletePressedCallback)
signals.removeEventListener(TableSignalEnum.OPEN_CONTEXT_MENU, openContextMenuCallback)
}
}, [])

if (field === 'name') {
return (
<div className="flexbox dc__align-items-center">
<Button
variant={ButtonVariantType.text}
text={value as string}
dataTestId={`${field}-${row.id}`}
style={isRowActive ? ButtonStyleType.default : ButtonStyleType.neutral}
onClick={handleButtonClick}
/>
</div>
)
}

return (
<div className="flexbox dc__gap-6 dc__align-items-center">
<ICWarning className="dc__no-shrink icon-dim-18" />

<span>{value}</span>
</div>
)
}

const COLUMNS: TableProps['columns'] = [
{
field: 'name',
size: { fixed: 300 },
label: 'Name',
comparator: (a: string, b: string) => a.localeCompare(b),
isSortable: true,
CellComponent,
},
{
field: 'value',
size: {
range: {
startWidth: 180,
minWidth: 100,
maxWidth: 600,
},
},
label: 'Value',
},
{
field: 'message',
size: {
fixed: 200,
},
label: 'Message',
CellComponent,
},
]

type RowDataType = {
name: string
value: string
message: string
}

const ROWS: TableProps['rows'] = [
{ id: '1', data: { name: 'Alice', value: '123', message: 'Something new' } },
{ id: '2', data: { name: 'Bob', value: '456', message: 'Another message' } },
{ id: '3', data: { name: 'Charlie', value: '789', message: 'Yet another one' } },
{ id: '4', data: { name: 'Diana', value: '101', message: 'Message here' } },
{ id: '5', data: { name: 'Eve', value: '202', message: 'Something else' } },
{ id: '6', data: { name: 'Frank', value: '303', message: 'New message' } },
{ id: '7', data: { name: 'Grace', value: '404', message: 'Important note' } },
{ id: '8', data: { name: 'Hank', value: '505', message: 'Final message' } },
{ id: '9', data: { name: 'Ivy', value: '606', message: 'Additional info' } },
{ id: '10', data: { name: 'Jack', value: '707', message: 'Critical update' } },
{ id: '11', data: { name: 'Karen', value: '808', message: 'New feature' } },
{ id: '12', data: { name: 'Leo', value: '909', message: 'Bug fix' } },
{ id: '13', data: { name: 'Mona', value: '1010', message: 'Performance improvement' } },
{ id: '14', data: { name: 'Nina', value: '1111', message: 'Security patch' } },
{ id: '15', data: { name: 'Oscar', value: '1212', message: 'UI enhancement' } },
{ id: '16', data: { name: 'Paul', value: '1313', message: 'Backend update' } },
{ id: '17', data: { name: 'Quinn', value: '1414', message: 'Database migration' } },
{ id: '18', data: { name: 'Rachel', value: '1515', message: 'API change' } },
{ id: '19', data: { name: 'Steve', value: '1616', message: 'Documentation update' } },
{ id: '20', data: { name: 'Tina', value: '1717', message: 'New integration' } },
{ id: '21', data: { name: 'Uma', value: '1818', message: 'Deprecated feature' } },
{ id: '22', data: { name: 'Victor', value: '1919', message: 'Hotfix applied' } },
{ id: '23', data: { name: 'Wendy', value: '2020', message: 'Code refactor' } },
{ id: '24', data: { name: 'Xander', value: '2121', message: 'New dependency' } },
{ id: '25', data: { name: 'Yara', value: '2222', message: 'Improved logging' } },
{ id: '26', data: { name: 'Zane', value: '2323', message: 'Monitoring added' } },
{ id: '27', data: { name: 'Amy', value: '2424', message: 'Analytics update' } },
{ id: '28', data: { name: 'Brian', value: '2525', message: 'Localization added' } },
{ id: '29', data: { name: 'Cathy', value: '2626', message: 'Accessibility fix' } },
{ id: '30', data: { name: 'David', value: '2727', message: 'New dashboard' } },
{ id: '31', data: { name: 'Ella', value: '2828', message: 'Improved UX' } },
{ id: '32', data: { name: 'Fred', value: '2929', message: 'Updated icons' } },
{ id: '33', data: { name: 'Gina', value: '3030', message: 'Enhanced security' } },
{ id: '34', data: { name: 'Harry', value: '3131', message: 'New theme' } },
{ id: '35', data: { name: 'Iris', value: '3232', message: 'Updated dependencies' } },
{ id: '36', data: { name: 'Jake', value: '3333', message: 'Improved performance' } },
{ id: '37', data: { name: 'Kara', value: '3434', message: 'New API endpoint' } },
{ id: '38', data: { name: 'Liam', value: '3535', message: 'Updated README' } },
]

const meta = {
component: Table,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add argTypes

} satisfies Meta<TableProps>

export default meta

type Story = StoryObj<typeof meta>

const BulkActionsComponent = () => (
<div className="flexbox dc__gap-4">
<Button
icon={<ICPause />}
dataTestId="rb-bulk-action__action-widget--cordon"
component={ButtonComponentType.button}
style={ButtonStyleType.negativeGrey}
variant={ButtonVariantType.borderLess}
ariaLabel="Pause"
size={ComponentSizeType.small}
onClick={() => action('Pause clicked')}
showAriaLabelInTippy
/>

<Button
icon={<ICPlay />}
dataTestId="rb-bulk-action__action-widget--uncordon"
component={ButtonComponentType.button}
style={ButtonStyleType.neutral}
variant={ButtonVariantType.borderLess}
ariaLabel="Play"
size={ComponentSizeType.small}
onClick={() => action('Play clicked!')}
showAriaLabelInTippy
/>
</div>
)

const ViewWrapper = ({ children, handleSearch, searchKey }: TableViewWrapperProps) => (
<div
style={{ height: '800px' }}
className="w-100 flexbox-col flex-grow-1 bg__primary dc__overflow-hidden dc__gap-16 py-12"
>
<div className="flexbox w-100 dc__align-start px-20">
<SearchBar handleSearchChange={handleSearch} initialSearchText={searchKey} containerClassName="w-300" />
</div>

{children}
</div>
)

export const TableTemplate: Story = {
args: {
columns: COLUMNS,
rows: ROWS,
filtersVariant: FiltersTypeEnum.STATE,
id: 'table__story',
paginationVariant: PaginationEnum.PAGINATED,
emptyStateConfig: {
noRowsConfig: {
title: 'No rows to display',
description: 'There are no rows to display.',
},
},
filter: (row, filterData) => {
const lowerCasedSearchKey = filterData.searchKey.toLowerCase()
return (row.data as RowDataType).name.toLowerCase().includes(lowerCasedSearchKey)
},
bulkSelectionConfig: {
BulkActionsComponent,
getSelectAllDialogStatus: () => SelectAllDialogStatus.CLOSED,
onBulkSelectionChanged: () => {},
},
stylesConfig: {
showSeparatorBetweenRows: true,
},
ViewWrapper,
additionalFilterProps: {
initialSortKey: 'name',
},
} as TableProps,
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1126,10 +1126,10 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"

"@devtron-labs/[email protected].8":
version "1.10.8"
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.10.8.tgz#6a182b39e222a9dc980156de090726e0bab07467"
integrity sha512-vg3VMfTFt0ak08J0FnhtfAIiD0u+0c2n0dFNuuPeJuCY3SIDBNM3CEgYrwq3KQtRrkbiNNyBONJuA3FY8rOzsw==
"@devtron-labs/[email protected].9":
version "1.10.9"
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.10.9.tgz#b64153a618c4ff0f4d13bca077a8ce24eda2af68"
integrity sha512-A/nXq/Y3AH1ULaBItEa+l+R5XjcdOjGHy4agurAdv/Zus/j6q3OD33zyuR7UwsghqPZMatO3O+Eew64l91D7xw==
dependencies:
"@codemirror/lang-json" "6.0.1"
"@codemirror/lang-yaml" "6.1.2"
Expand Down