Skip to content

Commit c5c9e80

Browse files
committed
#RI-1788 - [Workbench] Add placeholder text for empty output in workbench
1 parent feee13c commit c5c9e80

File tree

5 files changed

+122
-31
lines changed

5 files changed

+122
-31
lines changed
Lines changed: 13 additions & 0 deletions
Loading
Lines changed: 13 additions & 0 deletions
Loading

redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/WBResults.spec.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
import { cloneDeep } from 'lodash'
22
import React from 'react'
33
import { instance, mock } from 'ts-mockito'
4-
import { WORKBENCH_HISTORY_WRAPPER_NAME } from 'uiSrc/pages/workbench/constants'
54
import { WBHistoryObject } from 'uiSrc/pages/workbench/interfaces'
6-
import HistoryContainer from 'uiSrc/services/queryHistory'
75
import { cleanup, mockedStore, render } from 'uiSrc/utils/test-utils'
86
import WBResults, { Props } from './WBResults'
97

108
const mockedProps = mock<Props>()
119

1210
let store: typeof mockedStore
13-
let history: HistoryContainer<WBHistoryObject>
1411
beforeEach(() => {
1512
cleanup()
1613
store = cloneDeep(mockedStore)
1714
store.clearActions()
18-
history = new HistoryContainer<WBHistoryObject>(WORKBENCH_HISTORY_WRAPPER_NAME)
1915
})
2016

2117
jest.mock('uiSrc/services', () => ({
@@ -37,11 +33,11 @@ describe('WBResults', () => {
3733

3834
// sendCliClusterCommandAction.mockImplementation(() => sendCliClusterActionMock);
3935

40-
expect(render(<WBResults {...instance(mockedProps)} history={history} />)).toBeTruthy()
36+
expect(render(<WBResults {...instance(mockedProps)} />)).toBeTruthy()
4137
})
4238

4339
it('should render with custom props', () => {
44-
const historyObjectsMock: WBHistoryObject[] = [
40+
const historyItemsMock: WBHistoryObject[] = [
4541
{
4642
query: 'query1',
4743
data: 'data1',
@@ -56,10 +52,27 @@ describe('WBResults', () => {
5652
},
5753
]
5854

59-
const historyProp = {
60-
getData: () => historyObjectsMock,
61-
}
55+
expect(render(<WBResults {...instance(mockedProps)} historyItems={historyItemsMock} />)).toBeTruthy()
56+
})
57+
58+
it('should not render NoResults component with empty history', () => {
59+
const { getByTestId } = render(<WBResults {...instance(mockedProps)} historyItems={[]} />)
60+
61+
expect(getByTestId('wb_no-results')).toBeInTheDocument()
62+
})
63+
64+
it('should render NoResults component with history', () => {
65+
const historyItemsMock: WBHistoryObject[] = [{
66+
query: 'query1',
67+
data: 'data1',
68+
id: 1,
69+
fromPersistentStore: true,
70+
}]
71+
72+
const { queryByTestId } = render(<WBResults {...instance(mockedProps)} historyItems={historyItemsMock} />)
73+
74+
const noResultsEl = queryByTestId('wb_no-results')
6275

63-
expect(render(<WBResults {...instance(mockedProps)} history={historyProp} />)).toBeTruthy()
76+
expect(noResultsEl).not.toBeInTheDocument()
6477
})
6578
})
Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import React from 'react'
1+
import React, { useContext } from 'react'
22
import cx from 'classnames'
3+
import { EuiIcon, EuiText } from '@elastic/eui'
34

5+
import { Theme } from 'uiSrc/constants'
46
import QueryCard from 'uiSrc/components/query-card'
57
import { WBHistoryObject } from 'uiSrc/pages/workbench/interfaces'
68
import { WBQueryType } from 'uiSrc/pages/workbench/constants'
9+
import { ThemeContext } from 'uiSrc/contexts/themeContext'
10+
import MultiPlayIconDark from 'uiSrc/assets/img/multi_play_icon_dark.svg'
11+
import MultiPlayIconLight from 'uiSrc/assets/img/multi_play_icon_light.svg'
712
import styles from './styles.module.scss'
813

914
export interface Props {
@@ -12,26 +17,44 @@ export interface Props {
1217
onQueryRun: (query: string, historyId?: number, type?: WBQueryType) => void;
1318
onQueryDelete: (historyId: number) => void
1419
}
15-
const WBResults = ({ historyItems = [], onQueryRun, onQueryDelete, scrollDivRef }: Props) => (
16-
<div className={cx(styles.container)}>
17-
<div ref={scrollDivRef} />
18-
{historyItems.map(({ query, data, id, time, fromPersistentStore, matched, loading, status }) => (
19-
<QueryCard
20-
id={id}
21-
key={id}
22-
data={data}
23-
status={status}
24-
loading={loading}
25-
query={query}
26-
matched={matched}
27-
time={time}
28-
fromStore={!!fromPersistentStore}
29-
onQueryRun={(queryType: WBQueryType) => onQueryRun(query, id, queryType)}
30-
onQueryReRun={() => onQueryRun(query)}
31-
onQueryDelete={() => onQueryDelete(id)}
20+
const WBResults = ({ historyItems = [], onQueryRun, onQueryDelete, scrollDivRef }: Props) => {
21+
const { theme } = useContext(ThemeContext)
22+
23+
const NoResults = (
24+
<div className={styles.noResults} data-testid="wb_no-results">
25+
<EuiIcon
26+
type={theme === Theme.Dark ? MultiPlayIconDark : MultiPlayIconLight}
27+
className={styles.playIcon}
3228
/>
33-
))}
34-
</div>
35-
)
29+
<EuiText className={styles.noResultsTitle} color="subdued">No results to display.</EuiText>
30+
<EuiText className={styles.noResultsText} color="subdued">
31+
Run Redis commands to get results or see the left menu to learn more.
32+
</EuiText>
33+
</div>
34+
)
35+
36+
return (
37+
<div className={cx(styles.container)}>
38+
<div ref={scrollDivRef} />
39+
{historyItems.map(({ query, data, id, time, fromPersistentStore, matched, loading, status }) => (
40+
<QueryCard
41+
id={id}
42+
key={id}
43+
data={data}
44+
status={status}
45+
loading={loading}
46+
query={query}
47+
matched={matched}
48+
time={time}
49+
fromStore={!!fromPersistentStore}
50+
onQueryRun={(queryType: WBQueryType) => onQueryRun(query, id, queryType)}
51+
onQueryReRun={() => onQueryRun(query)}
52+
onQueryDelete={() => onQueryDelete(id)}
53+
/>
54+
))}
55+
{!historyItems.length && NoResults}
56+
</div>
57+
)
58+
}
3659

3760
export default React.memo(WBResults)

redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/styles.module.scss

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,32 @@
1313
border: 1px solid var(--euiColorLightShade);
1414
overflow: auto;
1515
}
16+
17+
.noResults {
18+
width: 326px;
19+
height: 100%;
20+
min-height: 140px;
21+
display: flex;
22+
margin: 0 auto;
23+
flex-direction: column;
24+
align-items: center;
25+
justify-content: center;
26+
text-align: center;
27+
overflow: hidden;
28+
}
29+
30+
.noResultsTitle {
31+
padding-top: 18px;
32+
font: normal normal 500 15px/24px 'Graphik', sans-serif !important;
33+
}
34+
35+
.noResultsText {
36+
font: normal normal normal 13px/18px 'Graphik', sans-serif !important;
37+
letter-spacing: -0.13px;
38+
padding-top: 12px;
39+
}
40+
41+
.playIcon {
42+
width: 42px !important;
43+
height: 42px !important;
44+
}

0 commit comments

Comments
 (0)