Skip to content

Commit 40cd5e7

Browse files
committed
Refactor Sentinel database result columns into separate components
- Split column definitions into individual files for better organization - Updated ResultColumn to fix TypeScript error with onAddInstance type - Adjusted column properties (minSize to maxSize) for consistency - Moved handleBackAdding and handleViewDatabases to useCallback hooks - Updated imports and colFactory to use new component structure
1 parent 687526d commit 40cd5e7

File tree

10 files changed

+408
-294
lines changed

10 files changed

+408
-294
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react'
2+
import {
3+
CopyTextContainer,
4+
CopyPublicEndpointText,
5+
CopyBtn,
6+
} from 'uiSrc/components/auto-discover'
7+
import { RiTooltip } from 'uiSrc/components'
8+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
9+
import { ModifiedSentinelMaster } from 'uiSrc/slices/interfaces'
10+
11+
const handleCopy = (text = '') => {
12+
navigator.clipboard.writeText(text)
13+
}
14+
15+
export const AddressColumn = (): ColumnDef<ModifiedSentinelMaster> => {
16+
return {
17+
header: 'Address',
18+
id: 'host',
19+
accessorKey: 'host',
20+
enableSorting: true,
21+
cell: ({
22+
row: {
23+
original: { host, port },
24+
},
25+
}) => {
26+
const text = `${host}:${port}`
27+
return (
28+
<CopyTextContainer>
29+
<CopyPublicEndpointText className="copyHostPortText">
30+
{text}
31+
</CopyPublicEndpointText>
32+
<RiTooltip
33+
position="right"
34+
content="Copy"
35+
anchorClassName="copyPublicEndpointTooltip"
36+
>
37+
<CopyBtn
38+
aria-label="Copy address"
39+
className="copyPublicEndpointBtn"
40+
onClick={() => handleCopy(text)}
41+
tabIndex={-1}
42+
/>
43+
</RiTooltip>
44+
</CopyTextContainer>
45+
)
46+
},
47+
}
48+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react'
2+
import { CellText } from 'uiSrc/components/auto-discover'
3+
import { InputFieldSentinel } from 'uiSrc/components'
4+
import { SentinelInputFieldType } from 'uiSrc/components/input-field-sentinel/InputFieldSentinel'
5+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
6+
import {
7+
ModifiedSentinelMaster,
8+
AddRedisDatabaseStatus,
9+
} from 'uiSrc/slices/interfaces'
10+
11+
export const AliasColumn = (
12+
handleChangedInput: (name: string, value: string) => void,
13+
errorNotAuth: (
14+
error?: string | object | null,
15+
status?: AddRedisDatabaseStatus,
16+
) => boolean,
17+
): ColumnDef<ModifiedSentinelMaster> => {
18+
return {
19+
header: 'Database Alias*',
20+
id: 'alias',
21+
accessorKey: 'alias',
22+
enableSorting: true,
23+
cell: ({
24+
row: {
25+
original: { id, alias, error, loading = false, status },
26+
},
27+
}) => {
28+
if (errorNotAuth(error, status)) {
29+
return <CellText>{alias}</CellText>
30+
}
31+
return (
32+
<InputFieldSentinel
33+
name={`alias-${id}`}
34+
value={alias}
35+
placeholder="Database"
36+
disabled={loading}
37+
inputType={SentinelInputFieldType.Text}
38+
onChangedInput={handleChangedInput}
39+
maxLength={500}
40+
/>
41+
)
42+
},
43+
}
44+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react'
2+
import { InputFieldSentinel } from 'uiSrc/components'
3+
import { SentinelInputFieldType } from 'uiSrc/components/input-field-sentinel/InputFieldSentinel'
4+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
5+
import {
6+
ModifiedSentinelMaster,
7+
AddRedisDatabaseStatus,
8+
} from 'uiSrc/slices/interfaces'
9+
import { ApiStatusCode } from 'uiSrc/constants'
10+
11+
export const DbColumn = (
12+
handleChangedInput: (name: string, value: string) => void,
13+
): ColumnDef<ModifiedSentinelMaster> => {
14+
return {
15+
header: 'Database Index',
16+
id: 'db',
17+
accessorKey: 'db',
18+
size: 140,
19+
cell: ({
20+
row: {
21+
original: { db, id, loading = false, status, error },
22+
},
23+
}) => {
24+
if (status === AddRedisDatabaseStatus.Success) {
25+
return db || <i>not assigned</i>
26+
}
27+
const isDBInvalid =
28+
typeof error === 'object' &&
29+
error !== null &&
30+
'statusCode' in error &&
31+
error.statusCode === ApiStatusCode.BadRequest
32+
return (
33+
<div role="presentation" style={{ position: 'relative' }}>
34+
<InputFieldSentinel
35+
min={0}
36+
disabled={loading}
37+
value={`${db}` || '0'}
38+
name={`db-${id}`}
39+
isInvalid={isDBInvalid}
40+
placeholder="Enter Index"
41+
inputType={SentinelInputFieldType.Number}
42+
onChangedInput={handleChangedInput}
43+
/>
44+
</div>
45+
)
46+
},
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
2+
import { ModifiedSentinelMaster } from 'uiSrc/slices/interfaces'
3+
4+
export const NumberOfReplicasColumn = (): ColumnDef<ModifiedSentinelMaster> => {
5+
return {
6+
header: '# of replicas',
7+
id: 'numberOfSlaves',
8+
accessorKey: 'numberOfSlaves',
9+
enableSorting: true,
10+
maxSize: 120,
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react'
2+
import { InputFieldSentinel } from 'uiSrc/components'
3+
import { SentinelInputFieldType } from 'uiSrc/components/input-field-sentinel/InputFieldSentinel'
4+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
5+
import {
6+
ModifiedSentinelMaster,
7+
AddRedisDatabaseStatus,
8+
} from 'uiSrc/slices/interfaces'
9+
10+
export const PasswordColumn = (
11+
handleChangedInput: (name: string, value: string) => void,
12+
isInvalid: boolean,
13+
errorNotAuth: (
14+
error?: string | object | null,
15+
status?: AddRedisDatabaseStatus,
16+
) => boolean,
17+
): ColumnDef<ModifiedSentinelMaster> => {
18+
return {
19+
header: 'Password',
20+
id: 'password',
21+
accessorKey: 'password',
22+
cell: ({
23+
row: {
24+
original: { password, id, error, loading = false, status },
25+
},
26+
}) => {
27+
if (
28+
errorNotAuth(error, status) ||
29+
status === AddRedisDatabaseStatus.Success
30+
) {
31+
return password ? '************' : <i>not assigned</i>
32+
}
33+
return (
34+
<div role="presentation" style={{ position: 'relative' }}>
35+
<InputFieldSentinel
36+
isInvalid={isInvalid}
37+
value={password}
38+
name={`password-${id}`}
39+
placeholder="Enter Password"
40+
disabled={loading}
41+
inputType={SentinelInputFieldType.Password}
42+
onChangedInput={handleChangedInput}
43+
/>
44+
</div>
45+
)
46+
},
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react'
2+
import { CellText } from 'uiSrc/components/auto-discover'
3+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
4+
import { ModifiedSentinelMaster } from 'uiSrc/slices/interfaces'
5+
6+
export const PrimaryGroupColumn = (): ColumnDef<ModifiedSentinelMaster> => {
7+
return {
8+
header: 'Primary Group',
9+
id: 'name',
10+
accessorKey: 'name',
11+
enableSorting: true,
12+
maxSize: 200,
13+
cell: ({
14+
row: {
15+
original: { name },
16+
},
17+
}) => <CellText data-testid={`primary-group_${name}`}>{name}</CellText>,
18+
}
19+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import React from 'react'
2+
3+
import { FlexItem, Row } from 'uiSrc/components/base/layout/flex'
4+
import { Loader } from 'uiSrc/components/base/display'
5+
import {
6+
AddRedisDatabaseStatus,
7+
ModifiedSentinelMaster,
8+
} from 'uiSrc/slices/interfaces'
9+
import { CellText } from 'uiSrc/components/auto-discover'
10+
import { RiTooltip } from 'uiSrc/components'
11+
import { ColorText } from 'uiSrc/components/base/text'
12+
import { Spacer } from 'uiSrc/components/base/layout'
13+
import { InfoIcon, RiIcon } from 'uiSrc/components/base/icons'
14+
import { ColumnDef } from 'uiSrc/components/base/layout/table'
15+
import { ApiStatusCode } from 'uiSrc/constants'
16+
import { ApiEncryptionErrors } from 'uiSrc/constants/apiErrors'
17+
import validationErrors from 'uiSrc/constants/validationErrors'
18+
import { PrimaryButton } from 'uiSrc/components/base/forms/buttons'
19+
20+
const addError = (
21+
{ name, error, alias, loading }: ModifiedSentinelMaster,
22+
onAddInstance: (name: string) => void = () => {},
23+
) => {
24+
const isDisabled = !alias
25+
if (
26+
typeof error === 'object' &&
27+
error !== null &&
28+
'statusCode' in error &&
29+
error?.statusCode !== ApiStatusCode.Unauthorized &&
30+
!ApiEncryptionErrors.includes(error?.name || '') &&
31+
error?.statusCode !== ApiStatusCode.BadRequest
32+
) {
33+
return ''
34+
}
35+
return (
36+
<FlexItem padding role="presentation">
37+
<RiTooltip
38+
position="top"
39+
title={isDisabled ? validationErrors.REQUIRED_TITLE(1) : null}
40+
content={isDisabled ? <span>Database Alias</span> : null}
41+
>
42+
<PrimaryButton
43+
size="s"
44+
disabled={isDisabled}
45+
loading={loading}
46+
onClick={() => onAddInstance(name)}
47+
icon={isDisabled ? InfoIcon : undefined}
48+
>
49+
Add Primary Group
50+
</PrimaryButton>
51+
</RiTooltip>
52+
</FlexItem>
53+
)
54+
}
55+
56+
export const ResultColumn = (
57+
addActions?: boolean,
58+
onAddInstance?: (name: string) => void,
59+
): ColumnDef<ModifiedSentinelMaster> => {
60+
return {
61+
header: 'Result',
62+
id: 'message',
63+
accessorKey: 'message',
64+
enableSorting: true,
65+
maxSize: addActions ? 250 : 110,
66+
cell: ({
67+
row: {
68+
original: { status, message, name, error, alias, loading = false },
69+
},
70+
}) => {
71+
return (
72+
<Row
73+
data-testid={`status_${name}_${status}`}
74+
align="center"
75+
justify="between"
76+
gap="m"
77+
>
78+
{loading && <Loader size="L" />}
79+
{!loading && status === AddRedisDatabaseStatus.Success && (
80+
<CellText>{message}</CellText>
81+
)}
82+
{!loading && status !== AddRedisDatabaseStatus.Success && (
83+
<RiTooltip position="right" title="Error" content={message}>
84+
<FlexItem direction="row" grow={false}>
85+
<ColorText
86+
size="S"
87+
color="danger"
88+
style={{ cursor: 'pointer' }}
89+
>
90+
Error
91+
</ColorText>
92+
<Spacer size="s" direction="horizontal" />
93+
<RiIcon size="M" type="ToastDangerIcon" color="danger600" />
94+
</FlexItem>
95+
</RiTooltip>
96+
)}
97+
{addActions &&
98+
addError({ name, error, alias, loading }, onAddInstance)}
99+
</Row>
100+
)
101+
},
102+
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react'
2+
import { InputFieldSentinel } from 'uiSrc/components'
3+
import { SentinelInputFieldType } from 'uiSrc/components/input-field-sentinel/InputFieldSentinel'
4+
import { type ColumnDef } from 'uiSrc/components/base/layout/table'
5+
import {
6+
ModifiedSentinelMaster,
7+
AddRedisDatabaseStatus,
8+
} from 'uiSrc/slices/interfaces'
9+
10+
export const UsernameColumn = (
11+
handleChangedInput: (name: string, value: string) => void,
12+
isInvalid: boolean,
13+
errorNotAuth: (
14+
error?: string | object | null,
15+
status?: AddRedisDatabaseStatus,
16+
) => boolean,
17+
): ColumnDef<ModifiedSentinelMaster> => {
18+
return {
19+
header: 'Username',
20+
id: 'username',
21+
accessorKey: 'username',
22+
cell: ({
23+
row: {
24+
original: { username, id, loading = false, error, status },
25+
},
26+
}) => {
27+
if (
28+
errorNotAuth(error, status) ||
29+
status === AddRedisDatabaseStatus.Success
30+
) {
31+
return username || <i>Default</i>
32+
}
33+
return (
34+
<div role="presentation" style={{ position: 'relative' }}>
35+
<InputFieldSentinel
36+
isText
37+
isInvalid={isInvalid}
38+
value={username}
39+
name={`username-${id}`}
40+
placeholder="Enter Username"
41+
disabled={loading}
42+
inputType={SentinelInputFieldType.Text}
43+
onChangedInput={handleChangedInput}
44+
/>
45+
</div>
46+
)
47+
},
48+
}
49+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export * from './ResultColumn'
2+
export * from './PrimaryGroupColumn'
3+
export * from './AliasColumn'
4+
export * from './AddressColumn'
5+
export * from './NumberOfReplicasColumn'
6+
export * from './UsernameColumn'
7+
export * from './PasswordColumn'
8+
export * from './DbColumn'

0 commit comments

Comments
 (0)