Skip to content

Commit 4f5180b

Browse files
fix(ui): prevent duplicate notifications and improve search in cloud discovery
- Calculate notification counts from original data instead of filtered items to prevent re-triggering toast when search filters change - Expand search fields in subscriptions page (type, provider, region, status) - Add statusAdded field to search in databases result page - Add comprehensive search tests for subscriptions page Fixes #RI-7776
1 parent a618642 commit 4f5180b

File tree

3 files changed

+188
-34
lines changed

3 files changed

+188
-34
lines changed

redisinsight/ui/src/pages/autodiscover-cloud/redis-cloud-databases-result/RedisCloudDatabasesResult.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ const RedisCloudDatabaseListResult = ({
5757
(item.publicEndpoint || '')?.toLowerCase().indexOf(value) !== -1 ||
5858
item.subscriptionId?.toString()?.indexOf(value) !== -1 ||
5959
item.subscriptionName?.toLowerCase().indexOf(value) !== -1 ||
60-
item.databaseId?.toString()?.indexOf(value) !== -1,
60+
item.databaseId?.toString()?.indexOf(value) !== -1 ||
61+
item.statusAdded?.toLowerCase()?.indexOf(value) !== -1,
6162
)
6263

6364
if (!itemsTemp.length) {
Lines changed: 173 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,192 @@
11
import React from 'react'
22
import { instance, mock } from 'ts-mockito'
3+
import { faker } from '@faker-js/faker'
34
import {
45
RedisCloudSubscription,
56
RedisCloudSubscriptionStatus,
67
RedisCloudSubscriptionType,
78
} from 'uiSrc/slices/interfaces'
8-
import { render } from 'uiSrc/utils/test-utils'
9+
import { fireEvent, render, screen, waitFor } from 'uiSrc/utils/test-utils'
910
import RedisCloudSubscriptions, { Props } from './RedisCloudSubscriptions'
1011

1112
const mockedProps = mock<Props>()
1213

14+
const columnsMock = [
15+
{
16+
id: 'name',
17+
accessorKey: 'name',
18+
header: 'Name',
19+
enableSorting: true,
20+
},
21+
{
22+
id: 'id',
23+
accessorKey: 'id',
24+
header: 'Subscription ID',
25+
enableSorting: true,
26+
},
27+
]
28+
29+
const createSubscription = (
30+
overrides?: Partial<RedisCloudSubscription>,
31+
): RedisCloudSubscription => ({
32+
id: faker.number.int(),
33+
name: faker.company.name(),
34+
numberOfDatabases: faker.number.int({ min: 1, max: 10 }),
35+
provider: faker.helpers.arrayElement(['AWS', 'GCP', 'Azure']),
36+
region: faker.helpers.arrayElement(['us-east-1', 'eu-west-1', 'ap-south-1']),
37+
status: RedisCloudSubscriptionStatus.Active,
38+
type: RedisCloudSubscriptionType.Fixed,
39+
free: faker.datatype.boolean(),
40+
...overrides,
41+
})
42+
1343
describe('RedisCloudSubscriptions', () => {
44+
const defaultProps: Partial<Props> = {
45+
columns: columnsMock,
46+
subscriptions: [],
47+
selection: [],
48+
loading: false,
49+
account: null,
50+
error: '',
51+
onClose: jest.fn(),
52+
onBack: jest.fn(),
53+
onSubmit: jest.fn(),
54+
onSelectionChange: jest.fn(),
55+
}
56+
57+
const renderComponent = (propsOverride?: Partial<Props>) => {
58+
const props = { ...defaultProps, ...propsOverride } as Props
59+
return render(
60+
<RedisCloudSubscriptions {...instance(mockedProps)} {...props} />,
61+
)
62+
}
63+
1464
it('should render', () => {
15-
const columnsMock = [
16-
{
17-
id: 'subscriptionId',
18-
accessorKey: 'subscriptionId',
19-
header: 'Subscription ID',
20-
enableSorting: true,
21-
},
22-
]
65+
const subscriptionsMock: RedisCloudSubscription[] = [createSubscription()]
66+
expect(renderComponent({ subscriptions: subscriptionsMock })).toBeTruthy()
67+
})
2368

24-
const subscriptionsMock: RedisCloudSubscription[] = [
25-
{
26-
id: 123,
27-
name: 'name',
28-
numberOfDatabases: 123,
29-
provider: 'provider',
30-
region: 'region',
69+
describe('search functionality', () => {
70+
const subscriptions: RedisCloudSubscription[] = [
71+
createSubscription({
72+
id: 111,
73+
name: 'Production Database',
74+
provider: 'AWS',
75+
region: 'us-east-1',
76+
status: RedisCloudSubscriptionStatus.Active,
77+
type: RedisCloudSubscriptionType.Flexible,
78+
}),
79+
createSubscription({
80+
id: 222,
81+
name: 'Staging Environment',
82+
provider: 'GCP',
83+
region: 'eu-west-1',
3184
status: RedisCloudSubscriptionStatus.Active,
3285
type: RedisCloudSubscriptionType.Fixed,
33-
free: false,
34-
},
86+
}),
87+
createSubscription({
88+
id: 333,
89+
name: 'Development',
90+
provider: 'Azure',
91+
region: 'ap-south-1',
92+
status: RedisCloudSubscriptionStatus.Error,
93+
type: RedisCloudSubscriptionType.Fixed,
94+
}),
3595
]
36-
expect(
37-
render(
38-
<RedisCloudSubscriptions
39-
{...instance(mockedProps)}
40-
columns={columnsMock}
41-
subscriptions={subscriptionsMock}
42-
/>,
43-
),
44-
).toBeTruthy()
96+
97+
it('should filter by name', async () => {
98+
renderComponent({ subscriptions })
99+
100+
const searchInput = screen.getByTestId('search')
101+
fireEvent.change(searchInput, { target: { value: 'Production' } })
102+
103+
await waitFor(() => {
104+
expect(screen.getByText('Production Database')).toBeInTheDocument()
105+
expect(
106+
screen.queryByText('Staging Environment'),
107+
).not.toBeInTheDocument()
108+
})
109+
})
110+
111+
it('should filter by id', async () => {
112+
renderComponent({ subscriptions })
113+
114+
const searchInput = screen.getByTestId('search')
115+
fireEvent.change(searchInput, { target: { value: '222' } })
116+
117+
await waitFor(() => {
118+
expect(screen.getByText('Staging Environment')).toBeInTheDocument()
119+
expect(
120+
screen.queryByText('Production Database'),
121+
).not.toBeInTheDocument()
122+
})
123+
})
124+
125+
it('should filter by provider', async () => {
126+
renderComponent({ subscriptions })
127+
128+
const searchInput = screen.getByTestId('search')
129+
fireEvent.change(searchInput, { target: { value: 'AWS' } })
130+
131+
await waitFor(() => {
132+
expect(screen.getByText('Production Database')).toBeInTheDocument()
133+
expect(
134+
screen.queryByText('Staging Environment'),
135+
).not.toBeInTheDocument()
136+
})
137+
})
138+
139+
it('should filter by region', async () => {
140+
renderComponent({ subscriptions })
141+
142+
const searchInput = screen.getByTestId('search')
143+
fireEvent.change(searchInput, { target: { value: 'eu-west' } })
144+
145+
await waitFor(() => {
146+
expect(screen.getByText('Staging Environment')).toBeInTheDocument()
147+
expect(
148+
screen.queryByText('Production Database'),
149+
).not.toBeInTheDocument()
150+
})
151+
})
152+
153+
it('should filter by status', async () => {
154+
renderComponent({ subscriptions })
155+
156+
const searchInput = screen.getByTestId('search')
157+
fireEvent.change(searchInput, { target: { value: 'error' } })
158+
159+
await waitFor(() => {
160+
expect(screen.getByText('Development')).toBeInTheDocument()
161+
expect(
162+
screen.queryByText('Production Database'),
163+
).not.toBeInTheDocument()
164+
})
165+
})
166+
167+
it('should filter by type', async () => {
168+
renderComponent({ subscriptions })
169+
170+
const searchInput = screen.getByTestId('search')
171+
fireEvent.change(searchInput, { target: { value: 'flexible' } })
172+
173+
await waitFor(() => {
174+
expect(screen.getByText('Production Database')).toBeInTheDocument()
175+
expect(
176+
screen.queryByText('Staging Environment'),
177+
).not.toBeInTheDocument()
178+
})
179+
})
180+
181+
it('should be case-insensitive', async () => {
182+
renderComponent({ subscriptions })
183+
184+
const searchInput = screen.getByTestId('search')
185+
fireEvent.change(searchInput, { target: { value: 'PRODUCTION' } })
186+
187+
await waitFor(() => {
188+
expect(screen.getByText('Production Database')).toBeInTheDocument()
189+
})
190+
})
45191
})
46192
})

redisinsight/ui/src/pages/autodiscover-cloud/redis-cloud-subscriptions/RedisCloudSubscriptions/RedisCloudSubscriptions.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,15 @@ const RedisCloudSubscriptions = ({
7575
}
7676
}, [subscriptions, loading])
7777

78-
const countStatusActive = items.filter(
79-
({ status, numberOfDatabases }: RedisCloudSubscription) =>
80-
status === RedisCloudSubscriptionStatus.Active && numberOfDatabases !== 0,
81-
)?.length
78+
// Calculate counts from original subscriptions to prevent notification re-triggering on search
79+
const countStatusActive =
80+
subscriptions?.filter(
81+
({ status, numberOfDatabases }: RedisCloudSubscription) =>
82+
status === RedisCloudSubscriptionStatus.Active &&
83+
numberOfDatabases !== 0,
84+
)?.length || 0
8285

83-
const countStatusFailed = items.length - countStatusActive
86+
const countStatusFailed = (subscriptions?.length || 0) - countStatusActive
8487

8588
const handleSubmit = () => {
8689
onSubmit(
@@ -106,7 +109,11 @@ const RedisCloudSubscriptions = ({
106109
subscriptions?.filter(
107110
(item: RedisCloudSubscription) =>
108111
item.name?.toLowerCase()?.indexOf(value) !== -1 ||
109-
item.id?.toString()?.toLowerCase().indexOf(value) !== -1,
112+
item.id?.toString()?.indexOf(value) !== -1 ||
113+
item.type?.toLowerCase()?.indexOf(value) !== -1 ||
114+
item.provider?.toLowerCase()?.indexOf(value) !== -1 ||
115+
item.region?.toLowerCase()?.indexOf(value) !== -1 ||
116+
item.status?.toLowerCase()?.indexOf(value) !== -1,
110117
) ?? []
111118

112119
if (!itemsTemp?.length) {

0 commit comments

Comments
 (0)