Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react'

import { ColumnDef, Table } from 'uiSrc/components/base/layout/table'
import { RDI_COLUMN_FIELD_NAME_MAP, RdiListColumn } from 'uiSrc/constants'
import { RdiInstance } from 'uiSrc/slices/interfaces'

import RdiInstancesListCellSelect from './components/RdiInstancesListCellSelect/RdiInstancesListCellSelect'
import RdiInstancesListCellControls from './components/RdiInstancesListCellControls/RdiInstancesListCellControls'
import RdiInstancesListCell from './components/RdiInstancesListCell/RdiInstancesListCell'

Expand All @@ -17,21 +16,14 @@ export const BASE_COLUMNS: ColumnDef<RdiInstance>[] = [
isHeaderCustom: true,
enableSorting: false,
header: Table.HeaderMultiRowSelectionButton,
cell: (props) => (
<Table.RowSelectionButton
{...props}
onClick={(e: any) => e.stopPropagation()}
/>
),
cell: RdiInstancesListCellSelect,
},
{
id: RdiListColumn.Name,
accessorKey: RdiListColumn.Name,
header: RDI_COLUMN_FIELD_NAME_MAP.get(RdiListColumn.Name),
enableSorting: true,
cell: (props) => (
<RdiInstancesListCell {...props} field={RdiListColumn.Name} />
),
cell: RdiInstancesListCell,
sortingFn: (rowA, rowB) =>
`${rowA.original.name?.toLowerCase()}`.localeCompare(
`${rowB.original.name?.toLowerCase()}`,
Expand All @@ -42,9 +34,7 @@ export const BASE_COLUMNS: ColumnDef<RdiInstance>[] = [
accessorKey: RdiListColumn.Url,
header: RDI_COLUMN_FIELD_NAME_MAP.get(RdiListColumn.Url),
enableSorting: true,
cell: (props) => (
<RdiInstancesListCell {...props} field={RdiListColumn.Url} withCopyIcon />
),
cell: RdiInstancesListCell,
sortingFn: (rowA, rowB) =>
`${rowA.original.url?.toLowerCase()}`.localeCompare(
`${rowB.original.url?.toLowerCase()}`,
Expand All @@ -55,18 +45,14 @@ export const BASE_COLUMNS: ColumnDef<RdiInstance>[] = [
accessorKey: RdiListColumn.Version,
header: RDI_COLUMN_FIELD_NAME_MAP.get(RdiListColumn.Version),
enableSorting: true,
cell: (props) => (
<RdiInstancesListCell {...props} field={RdiListColumn.Version} />
),
cell: RdiInstancesListCell,
},
{
id: RdiListColumn.LastConnection,
accessorKey: RdiListColumn.LastConnection,
header: RDI_COLUMN_FIELD_NAME_MAP.get(RdiListColumn.LastConnection),
enableSorting: true,
cell: (props) => (
<RdiInstancesListCell {...props} field={RdiListColumn.LastConnection} />
),
cell: RdiInstancesListCell,
sortingFn: (rowA, rowB) => {
const a = rowA.original.lastConnection
const b = rowB.original.lastConnection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@ import type { CellContext } from 'uiSrc/components/base/layout/table'
import type { RdiInstance } from 'uiSrc/slices/interfaces'

export type IRdiListCell = (
props: CellContext<RdiInstance, unknown> & {
field?: keyof RdiInstance
withCopyIcon?: boolean
},
props: CellContext<RdiInstance, unknown>,
) => ReactElement<any, any> | null
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react'
import { render, screen, userEvent } from 'uiSrc/utils/test-utils'

import { rdiInstanceFactory } from 'uiSrc/mocks/rdi/RdiInstance.factory'

import RdiInstancesListCell from './RdiInstancesListCell'
import { lastConnectionFormat } from 'uiSrc/utils'

Expand All @@ -19,7 +17,8 @@ jest.mock('uiSrc/utils', () => ({
lastConnectionFormat: jest.fn(() => '3 min ago'),
}))

const buildRow = (
const makeProps = (
columnId: string,
overrides: Partial<ReturnType<typeof rdiInstanceFactory.build>> = {},
) => {
const instance = rdiInstanceFactory.build({
Expand All @@ -28,49 +27,55 @@ const buildRow = (
url: 'https://example',
...overrides,
})
return { row: { original: instance } as any, instance }
return {
row: { original: instance } as any,
column: { id: columnId } as any,
instance,
}
}

describe('RdiInstancesListCell', () => {
beforeEach(() => {
jest.clearAllMocks()
})

it('should render null when field is not provided', () => {
const { row } = buildRow()
const { container } = render(<RdiInstancesListCell {...({ row } as any)} />)
it('should render null when value is missing for the column', () => {
const { row, column } = makeProps('version', { version: undefined as any })
const { container } = render(
<RdiInstancesListCell {...({ row, column } as any)} />,
)
expect(container.firstChild).toBeNull()
})

it('should render text value and data-testid for a string field (name)', () => {
const { row, instance } = buildRow({ id: 'cell-1', name: 'My Endpoint' })
const { row, column, instance } = makeProps('name', {
id: 'cell-1',
name: 'My Endpoint',
})

render(<RdiInstancesListCell {...({ row } as any)} field="name" />)
render(<RdiInstancesListCell {...({ row, column } as any)} />)

expect(screen.getByText('My Endpoint')).toBeInTheDocument()
// data-testid includes id and text
expect(
screen.getByTestId(`rdi-list-cell-${instance.id}-${instance.name}`),
).toBeInTheDocument()
})

it('should not show copy icon by default', () => {
const { row } = buildRow()
it('should not show copy icon for non-url field', () => {
const { row, column } = makeProps('name')

render(<RdiInstancesListCell {...({ row } as any)} field="url" />)
render(<RdiInstancesListCell {...({ row, column } as any)} />)

expect(screen.queryByRole('button')).not.toBeInTheDocument()
})

it('should show copy icon and call handleCopyUrl with url text and id', async () => {
const { row, instance } = buildRow({
const { row, column, instance } = makeProps('url', {
id: 'cpy-1',
url: 'https://ri.example',
})

render(
<RdiInstancesListCell {...({ row } as any)} field="url" withCopyIcon />,
)
render(<RdiInstancesListCell {...({ row, column } as any)} />)

const btn = screen.getByRole('button')
await userEvent.click(btn, { pointerEventsCheck: 0 })
Expand All @@ -82,27 +87,17 @@ describe('RdiInstancesListCell', () => {
expect(id).toBe(instance.id)
})

it('should format lastConnection via lastConnectionFormat and pass formatted text to handler', async () => {
it('should format lastConnection via lastConnectionFormat and render formatted text (no copy icon)', async () => {
const date = new Date('2023-01-01T00:00:00.000Z')
const { row, instance } = buildRow({ id: 'last-1', lastConnection: date })

render(
<RdiInstancesListCell
{...({ row } as any)}
field="lastConnection"
withCopyIcon
/>,
)
const { row, column } = makeProps('lastConnection', {
id: 'last-1',
lastConnection: date,
})

render(<RdiInstancesListCell {...({ row, column } as any)} />)

// Uses mocked formatter
expect(lastConnectionFormat).toHaveBeenCalledWith(date as any)
expect(screen.getByText('3 min ago')).toBeInTheDocument()

const btn = screen.getByRole('button')
await userEvent.click(btn, { pointerEventsCheck: 0 })

const [, text, id] = mockHandleCopyUrl.mock.calls[0]
expect(text).toBe('3 min ago')
expect(id).toBe(instance.id)
expect(screen.queryByRole('button')).not.toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,32 @@ import { IconButton } from 'uiSrc/components/base/forms/buttons'
import { CopyIcon } from 'uiSrc/components/base/icons'
import { Text } from 'uiSrc/components/base/text'
import { lastConnectionFormat } from 'uiSrc/utils'
import { RdiInstance } from 'uiSrc/slices/interfaces'
import { RdiListColumn } from 'uiSrc/constants'

import { handleCopyUrl } from '../../methods/handlers'
import { IRdiListCell } from '../../RdiInstancesList.types'
import { CellContainer } from './RdiInstancesListCell.styles'

const RdiInstancesListCell: IRdiListCell = ({ row, field, withCopyIcon }) => {
const instance = row.original as RdiInstance
const fieldCopyIcon: Record<string, boolean> = {
[RdiListColumn.Url]: true,
}

const fieldFormatters: Record<string, (v: any) => string> = {
[RdiListColumn.LastConnection]: lastConnectionFormat,
}

const RdiInstancesListCell: IRdiListCell = ({ row, column }) => {
const item = row.original
const id = item.id
const field = column.id as keyof typeof item
const value = item[field]

if (!field) {
if (!field || !value) {
return null
}

const id = instance.id
const value = instance[field]
const text =
// lastConnection is returned as a string
field === 'lastConnection'
? lastConnectionFormat(value as any)
: value?.toString()
const text = fieldFormatters[field]?.(value) ?? value?.toString()
const withCopyIcon = fieldCopyIcon[field]

return (
<CellContainer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'

import { Table } from 'uiSrc/components/base/layout/table'
import { IRdiListCell } from '../../RdiInstancesList.types'

const RdiInstancesListCellSelect: IRdiListCell = (props) => (
<Table.RowSelectionButton
{...props}
onClick={(e: any) => e.stopPropagation()}

Check warning on line 9 in redisinsight/ui/src/pages/rdi/home/components/rdi-instances-list/components/RdiInstancesListCellSelect/RdiInstancesListCellSelect.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 9 in redisinsight/ui/src/pages/rdi/home/components/rdi-instances-list/components/RdiInstancesListCellSelect/RdiInstancesListCellSelect.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
/>
)

export default RdiInstancesListCellSelect
Loading