Skip to content

Commit a2e14f3

Browse files
authored
RI-7197 Rework the manage index section (#4785)
- remove the custom styles from the table - update the table columns to include "identifier" and "no index", and remove "separator" - added index summary details below the table re #RI-7197
1 parent 793b983 commit a2e14f3

File tree

7 files changed

+238
-99
lines changed

7 files changed

+238
-99
lines changed

redisinsight/ui/src/mocks/factories/redisearch/IndexInfo.factory.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
IndexAttibuteDto,
77
IndexInfoDto,
88
} from 'apiSrc/modules/browser/redisearch/dto'
9-
import { INDEX_INFO_SEPARATORS } from './IndexInfoTableData.factory'
9+
10+
export const INDEX_INFO_SEPARATORS: string[] = [',', ';', '|', ':']
1011

1112
// Note: Current data is replica of the sample data, but we can make it more realistic/diverse in the future
1213
export const indexInfoFactory = Factory.define<IndexInfoDto>(() => ({
@@ -76,21 +77,43 @@ export const indexInfoFactory = Factory.define<IndexInfoDto>(() => ({
7677
'field statistics': indexInfoFieldStatisticsFactory.buildList(3),
7778
}))
7879

79-
export const indexInfoAttributeFactory = Factory.define<IndexAttibuteDto>(
80-
() => {
81-
const name = faker.word.noun()
80+
type IndexInfoAttributeFactoryTransientParams = {
81+
includeWeight?: boolean
82+
includeSeparator?: boolean
83+
includeNoIndex?: boolean
84+
}
8285

83-
return {
84-
identifier: `$.${name}`,
85-
attribute: name,
86-
type: faker.helpers.enumValue(FieldTypes).toString(),
86+
export const indexInfoAttributeFactory = Factory.define<
87+
IndexAttibuteDto,
88+
IndexInfoAttributeFactoryTransientParams
89+
>(({ transientParams }) => {
90+
const name = faker.word.noun()
91+
92+
const {
93+
includeWeight = faker.datatype.boolean(),
94+
includeSeparator = faker.datatype.boolean(),
95+
includeNoIndex = faker.datatype.boolean(),
96+
} = transientParams
97+
98+
return {
99+
identifier: `$.${name}`,
100+
attribute: name,
101+
type: faker.helpers.enumValue(FieldTypes).toString(),
102+
103+
// Optional fields
104+
...(includeWeight && {
87105
WEIGHT: faker.number
88106
.float({ min: 0.1, max: 10, fractionDigits: 1 })
89107
.toString(),
108+
}),
109+
...(includeSeparator && {
90110
SEPARATOR: faker.helpers.arrayElement(INDEX_INFO_SEPARATORS),
91-
}
92-
},
93-
)
111+
}),
112+
...(includeNoIndex && {
113+
NOINDEX: faker.datatype.boolean(),
114+
}),
115+
}
116+
})
94117

95118
export const indexInfoFieldStatisticsFactory =
96119
Factory.define<FieldStatisticsDto>(() => {

redisinsight/ui/src/mocks/factories/redisearch/IndexInfoTableData.factory.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import React from 'react'
22
import { cleanup, render, screen } from 'uiSrc/utils/test-utils'
3-
import { indexInfoTableDataFactory } from 'uiSrc/mocks/factories/redisearch/IndexInfoTableData.factory'
3+
import {
4+
indexInfoAttributeFactory,
5+
indexInfoFactory,
6+
} from 'uiSrc/mocks/factories/redisearch/IndexInfo.factory'
47
import {
58
IndexAttributesList,
69
IndexAttributesListProps,
710
} from './IndexAttributesList'
811

912
const renderComponent = (props?: Partial<IndexAttributesListProps>) => {
1013
const defaultProps: IndexAttributesListProps = {
11-
data: indexInfoTableDataFactory.buildList(3),
14+
indexInfo: indexInfoFactory.build(),
1215
}
1316

1417
return render(<IndexAttributesList {...defaultProps} {...props} />)
@@ -21,12 +24,41 @@ describe('IndexAttributesList', () => {
2124

2225
it('should render', () => {
2326
const props: IndexAttributesListProps = {
24-
data: [
25-
indexInfoTableDataFactory.build(
26-
{},
27-
{ transient: { includeWeight: true, includeSeparator: true } },
28-
),
29-
],
27+
indexInfo: indexInfoFactory.build(),
28+
}
29+
30+
const { container } = renderComponent(props)
31+
expect(container).toBeTruthy()
32+
33+
const list = screen.getByTestId('index-attributes-list')
34+
expect(list).toBeInTheDocument()
35+
36+
const table = screen.getByTestId('index-attributes-list--table')
37+
const summaryInfo = screen.getByTestId(
38+
'index-attributes-list--summary-info',
39+
)
40+
41+
expect(table).toBeInTheDocument()
42+
expect(summaryInfo).toBeInTheDocument()
43+
})
44+
45+
it('should render loader when index info is not provided', () => {
46+
renderComponent({ indexInfo: undefined })
47+
48+
const loader = screen.getByTestId('index-attributes-list--loader')
49+
expect(loader).toBeInTheDocument()
50+
})
51+
52+
it('should render index attributes in the table', () => {
53+
const mockIndexAttribute = indexInfoAttributeFactory.build(
54+
{},
55+
{ transient: { includeWeight: true, includeNoIndex: true } },
56+
)
57+
58+
const props: IndexAttributesListProps = {
59+
indexInfo: indexInfoFactory.build({
60+
attributes: [mockIndexAttribute],
61+
}),
3062
}
3163

3264
const { container } = renderComponent(props)
@@ -36,14 +68,67 @@ describe('IndexAttributesList', () => {
3668
expect(list).toBeInTheDocument()
3769

3870
// Verify data is rendered correctly
39-
const attribute = screen.getByText(props.data[0].attribute)
40-
const type = screen.getByText(props.data[0].type)
41-
const weight = screen.getByText(props.data[0].weight!)
42-
const separator = screen.getByText(props.data[0].separator!)
71+
const identifier = screen.getByText(mockIndexAttribute.identifier)
72+
const attribute = screen.getByText(mockIndexAttribute.attribute)
73+
const type = screen.getByText(mockIndexAttribute.type)
74+
const weight = screen.getByText(mockIndexAttribute.WEIGHT!)
75+
const noIndex = screen.getByTestId('index-attributes-list--noindex-icon')
4376

77+
expect(identifier).toBeInTheDocument()
4478
expect(attribute).toBeInTheDocument()
4579
expect(type).toBeInTheDocument()
4680
expect(weight).toBeInTheDocument()
47-
expect(separator).toBeInTheDocument()
81+
expect(noIndex).toBeInTheDocument()
82+
expect(noIndex).toHaveAttribute(
83+
'data-attribute',
84+
mockIndexAttribute.NOINDEX?.toString(),
85+
)
86+
})
87+
88+
it('should display index summary info', () => {
89+
const mockIndexInfo = indexInfoFactory.build()
90+
91+
const props: IndexAttributesListProps = {
92+
indexInfo: mockIndexInfo,
93+
}
94+
95+
renderComponent(props)
96+
97+
const summaryInfo = screen.getByTestId(
98+
'index-attributes-list--summary-info',
99+
)
100+
expect(summaryInfo).toBeInTheDocument()
101+
102+
// Verify Number of documents
103+
const numberOfDocumentLabel = screen.getByText(/Number of docs:/)
104+
const numberOfDocumentValue = screen.getByText(
105+
new RegExp(mockIndexInfo.num_docs),
106+
)
107+
expect(numberOfDocumentLabel).toBeInTheDocument()
108+
expect(numberOfDocumentValue).toBeInTheDocument()
109+
110+
// Verify Max document ID
111+
const maxDocumentIdLabel = screen.getByText(/max/)
112+
const maxDocumentIdValue = screen.getByText(
113+
new RegExp(mockIndexInfo.max_doc_id!),
114+
)
115+
expect(maxDocumentIdLabel).toBeInTheDocument()
116+
expect(maxDocumentIdValue).toBeInTheDocument()
117+
118+
// Verify Number of records
119+
const numberOfRecordsLabel = screen.getByText(/Number of records:/)
120+
const numberOfRecordsValue = screen.getByText(
121+
new RegExp(mockIndexInfo.num_records!),
122+
)
123+
expect(numberOfRecordsLabel).toBeInTheDocument()
124+
expect(numberOfRecordsValue).toBeInTheDocument()
125+
126+
// Verify Number of terms
127+
const numberOfTermsLabel = screen.getByText(/Number of terms:/)
128+
const numberOfTermsValue = screen.getByText(
129+
new RegExp(mockIndexInfo.num_terms!),
130+
)
131+
expect(numberOfTermsLabel).toBeInTheDocument()
132+
expect(numberOfTermsValue).toBeInTheDocument()
48133
})
49134
})
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import styled from 'styled-components'
22

33
export const StyledIndexAttributesList = styled.div`
4-
> *:first-child {
5-
box-shadow: none !important;
6-
border-radius: 0;
7-
margin: -30px 0;
8-
}
4+
display: flex;
5+
gap: ${({ theme }) => theme.core.space.space150};
6+
flex-direction: column;
7+
`
8+
9+
export const StyledIndexAttributesTable = styled.div`
10+
// Drawer width (60rem) minus its padding (2 * 3.2rem), we don't have them as variables in Redis UI
11+
width: calc(60rem - 2 * 3.2rem);
12+
`
13+
14+
export const StyledIndexSummaryInfo = styled.div`
15+
font-size: ${({ theme }) => theme.core.font.fontSize.s12};
916
`
Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
import React from 'react'
22
import { ColumnDefinition, Table } from 'uiSrc/components/base/layout/table'
3-
import { StyledIndexAttributesList } from './IndexAttributesList.styles'
3+
import { RiIcon } from 'uiSrc/components/base/icons'
4+
import { Loader } from 'uiSrc/components/base/display'
5+
import { IndexInfoDto } from 'apiSrc/modules/browser/redisearch/dto'
6+
import {
7+
StyledIndexAttributesList,
8+
StyledIndexAttributesTable,
9+
StyledIndexSummaryInfo,
10+
} from './IndexAttributesList.styles'
411

512
export interface IndexInfoTableData {
13+
identifier: string
614
attribute: string
715
type: string
816
weight?: string
9-
separator?: string
17+
noindex?: boolean
1018
}
1119

1220
const tableColumns: ColumnDefinition<IndexInfoTableData>[] = [
21+
{
22+
header: 'Identifier',
23+
id: 'identifier',
24+
accessorKey: 'identifier',
25+
},
1326
{
1427
header: 'Attribute',
1528
id: 'attribute',
@@ -28,20 +41,59 @@ const tableColumns: ColumnDefinition<IndexInfoTableData>[] = [
2841
enableSorting: false,
2942
},
3043
{
31-
header: 'Separator',
32-
id: 'separator',
33-
accessorKey: 'separator',
44+
header: 'Noindex',
45+
id: 'noindex',
46+
accessorKey: 'noindex',
3447
enableSorting: false,
48+
cell: ({ row }) => (
49+
<RiIcon
50+
type={row.original.noindex ? 'CheckBoldIcon' : 'CancelIcon'}
51+
color={row.original.noindex ? 'primary400' : 'danger500'}
52+
data-testid="index-attributes-list--noindex-icon"
53+
data-attribute={row.original.noindex}
54+
/>
55+
),
3556
},
3657
]
3758

3859
export interface IndexAttributesListProps {
39-
data: IndexInfoTableData[]
60+
indexInfo: IndexInfoDto | undefined
61+
}
62+
63+
export const IndexAttributesList = ({
64+
indexInfo,
65+
}: IndexAttributesListProps) => {
66+
// eslint-disable-next-line @typescript-eslint/naming-convention
67+
const { num_docs, max_doc_id, num_records, num_terms } = indexInfo || {}
68+
69+
if (!indexInfo) {
70+
return <Loader data-testid="index-attributes-list--loader" />
71+
}
72+
73+
return (
74+
<StyledIndexAttributesList data-testid="index-attributes-list" as="div">
75+
<StyledIndexAttributesTable
76+
as="div"
77+
data-testid="index-attributes-list--table"
78+
>
79+
<Table columns={tableColumns} data={parseIndexAttributes(indexInfo)} />
80+
</StyledIndexAttributesTable>
81+
82+
<StyledIndexSummaryInfo>
83+
<p data-testid="index-attributes-list--summary-info">
84+
Number of docs: {num_docs} (max {max_doc_id}) | Number of records:{' '}
85+
{num_records} | Number of terms: {num_terms}
86+
</p>
87+
</StyledIndexSummaryInfo>
88+
</StyledIndexAttributesList>
89+
)
4090
}
4191

42-
export const IndexAttributesList = ({ data }: IndexAttributesListProps) => (
43-
// @ts-expect-error - styled-components typing issue: The TypeScript definitions for styled-components
44-
<StyledIndexAttributesList data-testid="index-attributes-list">
45-
<Table columns={tableColumns} data={data} />
46-
</StyledIndexAttributesList>
47-
)
92+
const parseIndexAttributes = (indexInfo: IndexInfoDto): IndexInfoTableData[] =>
93+
indexInfo.attributes.map((field) => ({
94+
identifier: field.identifier,
95+
attribute: field.attribute,
96+
type: field.type,
97+
weight: field.WEIGHT,
98+
noindex: field.NOINDEX ?? true,
99+
}))

0 commit comments

Comments
 (0)