Skip to content

Commit 9a6c5bc

Browse files
authored
Merge pull request #3981 from RedisInsight/fe/feature/RI-6220-remove-rdi-pipeline-template
RI-6220 removed rdi pipeline template
2 parents 20c5027 + 66be879 commit 9a6c5bc

File tree

12 files changed

+193
-54
lines changed

12 files changed

+193
-54
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react'
2+
import { cloneDeep } from 'lodash'
3+
import { instance, mock } from 'ts-mockito'
4+
5+
import { fireEvent, render, cleanup, mockedStore, screen } from 'uiSrc/utils/test-utils'
6+
import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/telemetry'
7+
import { RdiPipelineTabs } from 'uiSrc/slices/interfaces'
8+
import { rdiPipelineStrategiesSelector } from 'uiSrc/slices/rdi/pipeline'
9+
import TemplateButton, { TemplateButtonProps } from './TemplateButton'
10+
11+
const mockedProps = mock<TemplateButtonProps>()
12+
13+
let store: typeof mockedStore
14+
beforeEach(() => {
15+
cleanup()
16+
store = cloneDeep(mockedStore)
17+
store.clearActions()
18+
})
19+
20+
jest.mock('uiSrc/telemetry', () => ({
21+
...jest.requireActual('uiSrc/telemetry'),
22+
sendPageViewTelemetry: jest.fn(),
23+
sendEventTelemetry: jest.fn(),
24+
}))
25+
26+
jest.mock('uiSrc/slices/rdi/pipeline', () => ({
27+
...jest.requireActual('uiSrc/slices/rdi/pipeline'),
28+
rdiPipelineStrategiesSelector: jest.fn().mockReturnValue({
29+
loading: false,
30+
data: [{
31+
strategy: 'test'
32+
}],
33+
}),
34+
}))
35+
36+
describe('TemplateForm', () => {
37+
it('should render', () => {
38+
expect(
39+
render(<TemplateButton {...instance(mockedProps)} />)
40+
).toBeTruthy()
41+
})
42+
43+
it('should be disabled if no templateOption', () => {
44+
(rdiPipelineStrategiesSelector as jest.Mock).mockImplementationOnce(() => ({
45+
loading: false,
46+
data: []
47+
}))
48+
49+
render(<TemplateButton {...instance(mockedProps)} />)
50+
51+
expect(screen.getByTestId('template-btn')).toBeDisabled()
52+
})
53+
54+
it('should send telemetry on Click', () => {
55+
const sendEventTelemetryMock = jest.fn();
56+
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)
57+
58+
render(<TemplateButton {...instance(mockedProps)} />)
59+
60+
expect(screen.getByTestId('template-btn')).toBeEnabled()
61+
62+
fireEvent.click(screen.getByTestId('template-btn'))
63+
64+
expect(sendEventTelemetry).toBeCalledWith({
65+
event: TelemetryEvent.RDI_TEMPLATE_CLICKED,
66+
eventData: {
67+
id: 'rdiInstanceId',
68+
page: RdiPipelineTabs.Jobs,
69+
mode: 'test',
70+
}
71+
})
72+
})
73+
})
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from 'react'
2+
import { useDispatch, useSelector } from 'react-redux'
3+
import { EuiButton, EuiToolTip } from '@elastic/eui'
4+
5+
import { useParams } from 'react-router-dom'
6+
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
7+
import { fetchJobTemplate, rdiPipelineStrategiesSelector } from 'uiSrc/slices/rdi/pipeline'
8+
import { RdiPipelineTabs } from 'uiSrc/slices/interfaces'
9+
import { getTooltipContent } from '../template-form/TemplateForm'
10+
import { INGEST_OPTION } from '../template-form/constants'
11+
import styles from './styles.module.scss'
12+
13+
export interface TemplateButtonProps {
14+
value: string
15+
setFieldValue: (template: string) => void
16+
}
17+
18+
const TemplateButton = ({ setFieldValue, value }: TemplateButtonProps) => {
19+
const dispatch = useDispatch()
20+
const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>()
21+
const { loading, data } = useSelector(rdiPipelineStrategiesSelector)
22+
23+
const templateOption = data?.length
24+
? (data.find((strategy) => strategy.strategy === INGEST_OPTION)?.strategy || data[0].strategy)
25+
: ''
26+
27+
const handleApply = () => {
28+
dispatch(fetchJobTemplate(rdiInstanceId, templateOption, (template: string) => {
29+
setFieldValue(template)
30+
}))
31+
sendEventTelemetry({
32+
event: TelemetryEvent.RDI_TEMPLATE_CLICKED,
33+
eventData: {
34+
id: rdiInstanceId,
35+
page: RdiPipelineTabs.Jobs,
36+
mode: templateOption,
37+
}
38+
})
39+
}
40+
41+
return (
42+
<EuiToolTip
43+
content={getTooltipContent(value, !templateOption)}
44+
position="bottom"
45+
display="inlineBlock"
46+
anchorClassName="flex-row"
47+
>
48+
<EuiButton
49+
fill
50+
size="s"
51+
color="secondary"
52+
className={styles.btn}
53+
aria-label="Insert template"
54+
isLoading={loading}
55+
isDisabled={!templateOption || !!value}
56+
onClick={handleApply}
57+
data-testid="template-btn"
58+
>
59+
Insert template
60+
</EuiButton>
61+
</EuiToolTip>
62+
)
63+
}
64+
65+
export default TemplateButton
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import TemplateButton from './TemplateButton'
2+
3+
export default TemplateButton
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.btn {
2+
display: flex;
3+
align-items: center;
4+
color: var(--recommendationsCountBgColor) !important;
5+
background-color: var(--tableRowSelectedColor) !important;
6+
border-radius: 4px;
7+
border-color: var(--tableRowSelectedColor) !important;
8+
9+
> span {
10+
color: var(--recommendationsCountBgColor) !important;
11+
}
12+
}

redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.spec.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,12 @@ describe('TemplateForm', () => {
7979
it('should display db type select when source is "config"', () => {
8080
render(<TemplateForm {...instance(mockedProps)} source={RdiPipelineTabs.Config} />)
8181

82-
expect(screen.getByTestId('pipeline-type-select')).toBeInTheDocument()
8382
expect(screen.getByTestId('db-type-select')).toBeInTheDocument()
8483
})
8584

8685
it('should not render db type select when source is "jobs"', () => {
8786
render(<TemplateForm {...instance(mockedProps)} source={RdiPipelineTabs.Jobs} />)
8887

89-
expect(screen.getByTestId('pipeline-type-select')).toBeInTheDocument()
90-
9188
const dbTypeSelect = screen.queryByTestId('db-type-select')
9289

9390
expect(dbTypeSelect).toBeNull()
@@ -96,7 +93,6 @@ describe('TemplateForm', () => {
9693
it('should select "No template" value', () => {
9794
render(<TemplateForm {...instance(mockedProps)} source={RdiPipelineTabs.Config} />)
9895

99-
expect(screen.getByTestId('pipeline-type-select')).toHaveTextContent(NO_TEMPLATE_LABEL)
10096
expect(screen.getByTestId('db-type-select')).toHaveTextContent(NO_TEMPLATE_LABEL)
10197
})
10298

redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface Props {
3232
value: string
3333
}
3434

35-
const getTooltipContent = (value: string, isNoTemplateOptions: boolean) => {
35+
export const getTooltipContent = (value: string, isNoTemplateOptions: boolean) => {
3636
if (isNoTemplateOptions) {
3737
return (
3838
<>
@@ -57,7 +57,7 @@ const TemplateForm = (props: Props) => {
5757

5858
const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>()
5959

60-
const [pipelineTypeOptions, setPipelineTypeOptions] = useState<EuiSuperSelectOption<string>[]>(NO_OPTIONS)
60+
const [pipelineTypeOptions, setPipelineTypeOptions] = useState<EuiSuperSelectOption<string>[]>([])
6161
const [dbTypeOptions, setDbTypeOptions] = useState<EuiSuperSelectOption<string>[]>(NO_OPTIONS)
6262
const [selectedDbType, setSelectedDbType] = useState<string>('')
6363
const [selectedPipelineType, setSelectedPipelineType] = useState<string>('')
@@ -144,6 +144,7 @@ const TemplateForm = (props: Props) => {
144144
<EuiSpacer size="s" />
145145
<EuiForm component="form">
146146
<EuiSpacer size="xs" />
147+
{(pipelineTypeOptions?.length > 1) && (
147148
<EuiFormRow className={styles.formRow}>
148149
<>
149150
<div className={styles.rowLabel}>Pipeline type</div>
@@ -156,6 +157,7 @@ const TemplateForm = (props: Props) => {
156157
/>
157158
</>
158159
</EuiFormRow>
160+
)}
159161
{source === RdiPipelineTabs.Config && (
160162
<EuiFormRow className={styles.formRow}>
161163
<>

redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ import { monaco as monacoEditor } from 'react-monaco-editor'
88

99
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
1010
import { EXTERNAL_LINKS, UTM_MEDIUMS } from 'uiSrc/constants/links'
11-
import { deleteChangedFile, rdiPipelineSelector, setChangedFile } from 'uiSrc/slices/rdi/pipeline'
12-
import { FileChangeType, IPipeline, RdiPipelineTabs } from 'uiSrc/slices/interfaces'
11+
import { deleteChangedFile, fetchPipelineStrategies, rdiPipelineSelector, setChangedFile } from 'uiSrc/slices/rdi/pipeline'
12+
import { FileChangeType, IPipeline } from 'uiSrc/slices/interfaces'
1313
import MonacoYaml from 'uiSrc/components/monaco-editor/components/monaco-yaml'
1414
import DryRunJobPanel from 'uiSrc/pages/rdi/pipeline-management/components/jobs-panel'
1515
import { rdiErrorMessages } from 'uiSrc/pages/rdi/constants'
1616
import { DSL, KEYBOARD_SHORTCUTS } from 'uiSrc/constants'
17-
import TemplatePopover from 'uiSrc/pages/rdi/pipeline-management/components/template-popover'
1817
import { createAxiosError, isEqualPipelineFile, Maybe, yamlToJson } from 'uiSrc/utils'
1918
import { getUtmExternalLink } from 'uiSrc/utils/links'
2019
import { KeyboardShortcut } from 'uiSrc/components'
2120

2221
import { addErrorNotification } from 'uiSrc/slices/app/notifications'
22+
import TemplateButton from '../../components/template-button'
2323
import styles from './styles.module.scss'
2424

2525
export interface Props {
@@ -34,7 +34,6 @@ const Job = (props: Props) => {
3434
const { name, value = '', deployedJobValue, jobIndex, rdiInstanceId } = props
3535

3636
const [isPanelOpen, setIsPanelOpen] = useState<boolean>(false)
37-
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false)
3837
const [shouldOpenDedicatedEditor, setShouldOpenDedicatedEditor] = useState<boolean>(false)
3938

4039
const dispatch = useDispatch()
@@ -48,12 +47,12 @@ const Job = (props: Props) => {
4847
const { setFieldValue } = useFormikContext<IPipeline>()
4948

5049
useEffect(() => {
51-
setIsPanelOpen(false)
52-
}, [name])
50+
dispatch(fetchPipelineStrategies(rdiInstanceId))
51+
}, [])
5352

5453
useEffect(() => {
55-
setIsPopoverOpen(!value)
56-
}, [value, name])
54+
setIsPanelOpen(false)
55+
}, [name])
5756

5857
useEffect(() => {
5958
deployedJobValueRef.current = deployedJobValue
@@ -147,7 +146,7 @@ const Job = (props: Props) => {
147146
<div className={cx('content', { isSidePanelOpen: isPanelOpen })}>
148147
<div className="rdi__content-header">
149148
<EuiText className={cx('rdi__title', 'line-clamp-2')}>{name}</EuiText>
150-
<div>
149+
<div className={styles.actionContainer}>
151150
<EuiToolTip
152151
position="top"
153152
className={styles.tooltip}
@@ -174,13 +173,9 @@ const Job = (props: Props) => {
174173
SQL and JMESPath Editor
175174
</EuiButton>
176175
</EuiToolTip>
177-
<TemplatePopover
178-
isPopoverOpen={isPopoverOpen}
179-
setIsPopoverOpen={setIsPopoverOpen}
176+
<TemplateButton
180177
value={value}
181178
setFieldValue={(template) => setFieldValue(`jobs.${jobIndexRef.current ?? -1}.value`, template)}
182-
loading={loading}
183-
source={RdiPipelineTabs.Jobs}
184179
/>
185180
</div>
186181
</div>

redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/styles.module.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@
66
display: flex;
77
align-items: baseline;
88
}
9+
10+
.actionContainer {
11+
display: flex;
12+
align-items: center;
13+
}
14+

tests/e2e/pageObjects/rdi-instance-page.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export class RdiInstancePage extends BaseOverviewPage {
5252
templateButton = Selector('[data-testid^=template-trigger-]');
5353
templateApplyButton = Selector('[data-testid=template-apply-btn]');
5454
templateCancelButton = Selector('[data-testid=template-cancel-btn]');
55-
pipelineDropdown = Selector('[data-testid=pipeline-type-select]');
5655
databaseDropdown = Selector('[data-testid=db-type-select]');
5756

5857
//dialog
@@ -77,17 +76,12 @@ export class RdiInstancePage extends BaseOverviewPage {
7776

7877
/**
7978
* Select value from template dropdowns
80-
* @param pipeline value of pipeline dropdown
8179
* @param database value of database dropdown
8280
*/
83-
async setTemplateDropdownValue(pipeline: RdiTemplatePipelineType, database?: RdiTemplateDatabaseType): Promise<void> {
84-
await t.click(this.pipelineDropdown);
85-
let selector = Selector(`[id='${pipeline}']`);
86-
await t.click(selector);
81+
async setTemplateDropdownValue(database?: RdiTemplateDatabaseType): Promise<void> {
8782
if(database != null) {
8883
await t.click(this.databaseDropdown);
89-
selector = Selector(`[id='${database}']`);
90-
await t.click(selector);
84+
await t.click(Selector(`[id='${database}']`));
9185
}
9286
await t.click(this.templateApplyButton);
9387
}
@@ -97,8 +91,8 @@ export class RdiInstancePage extends BaseOverviewPage {
9791
* @param option option to select
9892
*/
9993
async selectStartPipelineOption(option: RdiPopoverOptions): Promise<void> {
100-
10194
const selector = Selector(`[data-testid='${option}-source-pipeline-dialog']`);
95+
10296
await t.click(selector);
10397
}
10498

tests/e2e/tests/web/critical-path/rdi/add-job.e2e.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,24 @@ test('Verify that user can add, edit and delete job', async() => {
8080
test('Verify that user insert template for jobs', async() => {
8181
const jobName = 'testJob';
8282
const disabledAttribute = 'isDisabled';
83-
const defaultValue = 'ingest';
8483
const templateWords = 'server_name: chinook';
85-
// should be empty config
84+
const templateInsertedTooltip = 'Templates can be accessed only with the empty Editor to prevent potential data loss.';
85+
// Should be empty config
8686
await rdiInstancePage.PipelineManagementPanel.addJob(jobName);
8787

8888
await rdiInstancePage.PipelineManagementPanel.openJobByName(jobName);
89-
await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded');
90-
const buttonClass = rdiInstancePage.templateApplyButton.getAttribute('class');
91-
await t.expect(buttonClass).notContains(disabledAttribute, 'Apply button is disabled');
92-
await t.click(rdiInstancePage.templateCancelButton);
93-
await t.expect(rdiInstancePage.templateApplyButton.exists).notOk('the template popover is not closed');
94-
9589
await t.click(rdiInstancePage.templateButton);
96-
await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded');
97-
await t.expect(rdiInstancePage.pipelineDropdown.textContent).eql(defaultValue, 'the default value is set incorrectly');
98-
await rdiInstancePage.setTemplateDropdownValue(RdiTemplatePipelineType.Ingest);
9990

100-
//verify uniq templates words - should be undated when templates are added
91+
// Verify uniq templates words - should be undated when templates are added
10192
const enteredText = await rdiInstancePage.MonacoEditor.getTextFromMonaco();
93+
// Verify that user can see the template is inserted for the empty editor when clicking on the “Insert template” in jobs
10294
await t.expect(enteredText).contains(templateWords, 'template is incorrect');
10395

104-
await t.click(rdiInstancePage.templateButton);
105-
await t.expect(buttonClass).contains(disabledAttribute, 'Apply button is active');
96+
// Verify that user can see a standard validation on disabled Insert template button when the editor is not empty
97+
await t.hover(myRedisDatabasePage.AddRedisDatabase.testConnectionBtn);
98+
await rdiInstancePage.verifyTooltipContainsText(templateInsertedTooltip);
99+
const buttonClass = rdiInstancePage.templateButton.getAttribute('class');
100+
await t.expect(buttonClass).contains(disabledAttribute, 'Insert Template button is not disabled');
106101
});
107102
test('Verify that user can change job config', async() => {
108103
const jobName = 'testJob';

0 commit comments

Comments
 (0)