Skip to content

Commit 37a218c

Browse files
committed
#RI-6265 - update home page
1 parent acf0bc8 commit 37a218c

File tree

26 files changed

+559
-711
lines changed

26 files changed

+559
-711
lines changed
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading

redisinsight/ui/src/components/item-list/ItemList.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import {
44
EuiTableFieldDataColumnType,
55
EuiTableSelectionType,
66
PropertySort,
7+
EuiBasicTableProps
78
} from '@elastic/eui'
89
import cx from 'classnames'
910
import React, { useEffect, useRef, useState } from 'react'
10-
import { Maybe, Nullable } from 'uiSrc/utils'
11+
import { Maybe } from 'uiSrc/utils'
1112
import { findColumn, getColumnWidth, hideColumn } from './utils'
1213

1314
import { ActionBar, DeleteAction, ExportAction } from './components'
@@ -16,13 +17,14 @@ import styles from './styles.module.scss'
1617

1718
export interface Props<T> {
1819
width: number
19-
editedInstance: Nullable<T>
2020
columns: EuiTableFieldDataColumnType<T>[]
2121
columnsToHide?: string[]
2222
onDelete: (ids: T[]) => void
2323
hideExport?: boolean
2424
onExport?: (ids: T[], withSecrets: boolean) => void
2525
onWheel: () => void
26+
rowProps?: EuiBasicTableProps<T>['rowProps']
27+
getSelectableItems?: (item: T) => boolean
2628
loading: boolean
2729
data: T[]
2830
onTableChange: ({ sort, page }: Criteria<T>) => void
@@ -37,7 +39,8 @@ function ItemList<T extends { id: string; visible?: boolean }>({
3739
hideExport = false,
3840
onExport,
3941
onWheel,
40-
editedInstance,
42+
rowProps,
43+
getSelectableItems,
4144
loading,
4245
data: instances,
4346
onTableChange,
@@ -143,7 +146,10 @@ function ItemList<T extends { id: string; visible?: boolean }>({
143146
}
144147

145148
const selectionValue: EuiTableSelectionType<T> = {
146-
onSelectionChange: (selected: T[]) => setSelection(selected)
149+
selectable: (item) => (getSelectableItems ? getSelectableItems?.(item) : true),
150+
onSelectionChange: (selected: T[]) => {
151+
setSelection(selected)
152+
}
147153
}
148154

149155
const handleResetSelection = () => {
@@ -159,12 +165,6 @@ function ItemList<T extends { id: string; visible?: boolean }>({
159165
tableRef.current?.setSelection([])
160166
}
161167

162-
const toggleSelectedRow = (instance: T) => ({
163-
className: cx({
164-
'euiTableRow-isSelected': instance?.id === editedInstance?.id
165-
})
166-
})
167-
168168
const actionMsg = (action: string) => `
169169
Selected
170170
${' '}
@@ -183,7 +183,7 @@ function ItemList<T extends { id: string; visible?: boolean }>({
183183
loading={loading}
184184
message={message}
185185
columns={columns ?? []}
186-
rowProps={toggleSelectedRow}
186+
rowProps={rowProps}
187187
sorting={{ sort }}
188188
selection={selectionValue}
189189
onWheel={onWheel}

redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ describe('NavigationMenu', () => {
143143
expect(screen.getByTestId('settings-page-btn')).toBeTruthy()
144144
})
145145

146+
it('should render cloud link', () => {
147+
const { container } = render(<NavigationMenu />)
148+
149+
const createCloudLink = container.querySelector('[data-test-subj="create-cloud-nav-link"]')
150+
expect(createCloudLink).toBeTruthy()
151+
})
152+
146153
it('should render github btn with proper link', () => {
147154
(appInfoSelector as jest.Mock).mockImplementation(() => ({
148155
...mockAppInfoSelector,

redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { FeatureFlagComponent } from 'uiSrc/components'
4343

4444
import { appContextSelector } from 'uiSrc/slices/app/context'
4545
import { AppWorkspace } from 'uiSrc/slices/interfaces'
46+
import CreateCloud from './components/create-cloud'
4647
import HelpMenu from './components/help-menu/HelpMenu'
4748
import NotificationMenu from './components/notifications-center'
4849

@@ -309,6 +310,7 @@ const NavigationMenu = () => {
309310
</div>
310311
<div className={styles.bottomContainer}>
311312
<FeatureFlagComponent name={FeatureFlags.disabledByEnv} enabledByDefault>
313+
<CreateCloud />
312314
<NotificationMenu />
313315
</FeatureFlagComponent>
314316
<HelpMenu />
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react'
2+
import { cloneDeep } from 'lodash'
3+
import { cleanup, mockedStore, render, fireEvent } from 'uiSrc/utils/test-utils'
4+
5+
import { setSSOFlow } from 'uiSrc/slices/instances/cloud'
6+
import { OAuthSocialAction, OAuthSocialSource } from 'uiSrc/slices/interfaces'
7+
import { setSocialDialogState } from 'uiSrc/slices/oauth/cloud'
8+
import CreateCloud from './CreateCloud'
9+
10+
jest.mock('uiSrc/slices/app/features', () => ({
11+
...jest.requireActual('uiSrc/slices/app/features'),
12+
appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({
13+
cloudSso: {
14+
flag: true
15+
}
16+
}),
17+
}))
18+
19+
let store: typeof mockedStore
20+
beforeEach(() => {
21+
cleanup()
22+
store = cloneDeep(mockedStore)
23+
store.clearActions()
24+
})
25+
26+
describe('CreateCloud', () => {
27+
it('should render', () => {
28+
expect(render(<CreateCloud />)).toBeTruthy()
29+
})
30+
31+
it('should call proper actions on click cloud button', () => {
32+
const { container } = render(<CreateCloud />)
33+
const createCloudLink = container.querySelector('[data-test-subj="create-cloud-nav-link"]')
34+
35+
fireEvent.click(createCloudLink as Element)
36+
37+
expect(store.getActions()).toEqual([
38+
setSSOFlow(OAuthSocialAction.Create),
39+
setSocialDialogState(OAuthSocialSource.NavigationMenu)
40+
])
41+
})
42+
})
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 cx from 'classnames'
3+
import { EuiIcon, EuiLink, EuiToolTip } from '@elastic/eui'
4+
5+
import { OAuthSsoHandlerDialog } from 'uiSrc/components'
6+
import { OAuthSocialAction, OAuthSocialSource } from 'uiSrc/slices/interfaces'
7+
import { EXTERNAL_LINKS } from 'uiSrc/constants/links'
8+
import CloudIcon from 'uiSrc/assets/img/oauth/cloud_centered.svg?react'
9+
10+
import { getUtmExternalLink } from 'uiSrc/utils/links'
11+
import styles from '../../styles.module.scss'
12+
13+
const CreateCloud = () => (
14+
<EuiToolTip
15+
content="Create FREE Redis Cloud database"
16+
position="right"
17+
>
18+
<span className={cx(styles.iconNavItem)}>
19+
<OAuthSsoHandlerDialog>
20+
{(ssoCloudHandlerClick) => (
21+
<EuiLink
22+
external={false}
23+
onClick={(e) => {
24+
ssoCloudHandlerClick(e,
25+
{ source: OAuthSocialSource.NavigationMenu, action: OAuthSocialAction.Create })
26+
}}
27+
className={styles.cloudLink}
28+
href={getUtmExternalLink(EXTERNAL_LINKS.tryFree, { campaign: 'navigation_menu' })}
29+
target="_blank"
30+
data-test-subj="create-cloud-nav-link"
31+
>
32+
<EuiIcon
33+
className={styles.cloudIcon}
34+
type={CloudIcon}
35+
data-testid="cloud-db-icon"
36+
/>
37+
</EuiLink>
38+
)}
39+
</OAuthSsoHandlerDialog>
40+
</span>
41+
</EuiToolTip>
42+
)
43+
44+
export default CreateCloud
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import CreateCloud from './CreateCloud'
2+
3+
export default CreateCloud

redisinsight/ui/src/components/navigation-menu/styles.module.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,16 @@ $sideBarWidth: 60px;
182182
background-color: #465282 !important;
183183
}
184184
}
185+
186+
.cloudLink {
187+
border-radius: 8px;
188+
border: 1px solid #8BA2FF;
189+
max-width: 44px;
190+
max-height: 44px;
191+
192+
.cloudIcon {
193+
fill:none;
194+
max-width: 26px;
195+
color: #BDC3D7;
196+
}
197+
}

redisinsight/ui/src/pages/home/HomePage.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ import {
2929
} from 'uiSrc/slices/instances/instances'
3030
import { localStorageService } from 'uiSrc/services'
3131
import { resetDataSentinel, sentinelSelector } from 'uiSrc/slices/instances/sentinel'
32-
import { fetchContentAction as fetchCreateRedisButtonsAction } from 'uiSrc/slices/content/create-redis-buttons'
32+
import {
33+
contentSelector,
34+
fetchContentAction as fetchCreateRedisButtonsAction
35+
} from 'uiSrc/slices/content/create-redis-buttons'
3336
import { sendEventTelemetry, sendPageViewTelemetry, TelemetryEvent, TelemetryPageView } from 'uiSrc/telemetry'
3437
import { appRedirectionSelector, setUrlHandlingInitialState } from 'uiSrc/slices/app/url-handling'
3538
import { UrlHandlingActions } from 'uiSrc/slices/interfaces/urlHandling'
36-
import { AddDbType } from 'uiSrc/pages/home/constants'
39+
import { AddDbType, CREATE_CLOUD_DB_ID } from 'uiSrc/pages/home/constants'
3740

3841
import DatabasesList from './components/database-list-component'
3942
import DatabaseListHeader from './components/database-list-header'
@@ -58,6 +61,7 @@ const HomePage = () => {
5861
const { credentials: cloudCredentials } = useSelector(cloudSelector)
5962
const { instance: sentinelInstance } = useSelector(sentinelSelector)
6063
const { action, dbConnection } = useSelector(appRedirectionSelector)
64+
const { data: createDbContent } = useSelector(contentSelector)
6165

6266
const {
6367
loading,
@@ -73,6 +77,11 @@ const HomePage = () => {
7377

7478
const { contextInstanceId } = useSelector(appContextSelector)
7579

80+
const predefinedInstances = createDbContent?.cloud_list_of_databases ? [
81+
{ id: CREATE_CLOUD_DB_ID, ...createDbContent.cloud_list_of_databases } as Instance
82+
] : []
83+
const isInstanceExists = instances.length > 0 || predefinedInstances.length > 0
84+
7685
useEffect(() => {
7786
setTitle('Redis databases')
7887

@@ -199,7 +208,7 @@ const HomePage = () => {
199208
const onResizeTrottled = useCallback(throttle(onResize, 100), [])
200209

201210
const InstanceList = () =>
202-
(!instances.length && !loading && !loadingChanging ? (
211+
(!isInstanceExists && !loading && !loadingChanging ? (
203212
<EuiPanel className={styles.emptyPanel} borderRadius="none">
204213
<EmptyMessage onAddInstanceClick={handleAddInstance} />
205214
</EuiPanel>
@@ -208,6 +217,9 @@ const HomePage = () => {
208217
{(resizeRef) => (
209218
<div ref={resizeRef} style={{ height: '100%' }}>
210219
<DatabasesList
220+
loading={loading}
221+
instances={instances}
222+
predefinedInstances={predefinedInstances}
211223
width={width}
212224
editedInstance={editedInstance}
213225
onEditInstance={handleEditInstance}
@@ -241,7 +253,7 @@ const HomePage = () => {
241253
className: cx('home__resizePanelLeft', {
242254
fullWidth: !openRightPanel,
243255
openedRightPanel: !!openRightPanel,
244-
hidden: !!openRightPanel && !instances.length,
256+
hidden: !!openRightPanel && !isInstanceExists,
245257
})
246258
}}
247259
>
@@ -250,7 +262,7 @@ const HomePage = () => {
250262

251263
<EuiResizableButton
252264
className={cx('home__resizableButton', {
253-
hidden: !openRightPanel || !instances.length,
265+
hidden: !openRightPanel || !isInstanceExists,
254266
})}
255267
style={{ margin: 0 }}
256268
/>
@@ -261,7 +273,7 @@ const HomePage = () => {
261273
wrapperProps={{
262274
className: cx('home__resizePanelRight', {
263275
hidden: !openRightPanel,
264-
fullWidth: !instances.length,
276+
fullWidth: !isInstanceExists,
265277
})
266278
}}
267279
id="form"
@@ -286,7 +298,7 @@ const HomePage = () => {
286298
: handleClose
287299
}
288300
onDbEdited={onDbEdited}
289-
isFullWidth={!instances.length}
301+
isFullWidth={!isInstanceExists}
290302
initConnectionType={initialDbTypeRef.current}
291303
/>
292304
)}

0 commit comments

Comments
 (0)