Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { appInfoSelector } from 'uiSrc/slices/app/info'
import { cleanup, mockedStore, render, screen, fireEvent } from 'uiSrc/utils/test-utils'

import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
import { appContextSelector } from 'uiSrc/slices/app/context'
import NavigationMenu from './NavigationMenu'

let store: typeof mockedStore
Expand All @@ -17,6 +18,13 @@ beforeEach(() => {

const mockAppInfoSelector = jest.requireActual('uiSrc/slices/app/info')

jest.mock('uiSrc/slices/app/context', () => ({
...jest.requireActual('uiSrc/slices/app/context'),
appContextSelector: jest.fn().mockReturnValue({
workspace: 'database',
}),
}))

jest.mock('uiSrc/slices/app/info', () => ({
...jest.requireActual('uiSrc/slices/app/info'),
appInfoSelector: jest.fn().mockReturnValue({
Expand All @@ -31,6 +39,13 @@ jest.mock('uiSrc/slices/instances/instances', () => ({
}),
}))

jest.mock('uiSrc/slices/rdi/instances', () => ({
...jest.requireActual('uiSrc/slices/rdi/instances'),
connectedInstanceSelector: jest.fn().mockReturnValue({
id: 'mockRdiId',
}),
}))

jest.mock('uiSrc/slices/app/features', () => ({
...jest.requireActual('uiSrc/slices/app/features'),
appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({
Expand Down Expand Up @@ -157,4 +172,16 @@ describe('NavigationMenu', () => {
expect(githubBtn?.getAttribute('href')).toEqual(EXTERNAL_LINKS.githubRepo)
})
})

it('should render private routes with connectedRdiInstanceId', () => {
(appContextSelector as jest.Mock).mockImplementation(() => ({
...appContextSelector,
workspace: 'redisDataIntegration'
}))

render(<NavigationMenu />)

expect(screen.getByTestId('pipeline-status-page-btn')).toBeTruthy()
expect(screen.getByTestId('pipeline-management-page-btn')).toBeTruthy()
})
})
1 change: 1 addition & 0 deletions redisinsight/ui/src/pages/rdi/home/RdiPage.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ describe('RdiPage', () => {

expect(createInstanceAction).toBeCalledWith(
{ name: 'name', url: 'url', username: 'username', password: 'password' },
expect.any(Function),
expect.any(Function)
)
})
Expand Down
22 changes: 21 additions & 1 deletion redisinsight/ui/src/pages/rdi/home/RdiPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from 'uiSrc/telemetry'
import HomePageTemplate from 'uiSrc/templates/home-page-template'
import { setTitle } from 'uiSrc/utils'
import { Rdi as RdiInstanceResponse } from 'apiSrc/modules/rdi/models/rdi'
import EmptyMessage from './empty-message/EmptyMessage'
import ConnectionForm from './connection-form/ConnectionForm'
import RdiHeader from './header/RdiHeader'
Expand Down Expand Up @@ -62,7 +63,26 @@ const RdiPage = () => {
if (editInstance) {
dispatch(editInstanceAction(editInstance.id, instance, onSuccess))
} else {
dispatch(createInstanceAction({ ...instance }, onSuccess))
dispatch(createInstanceAction(
{ ...instance },
(data: RdiInstanceResponse) => {
sendEventTelemetry({
event: TelemetryEvent.RDI_ENDPOINT_ADDED,
eventData: {
rdiId: data.id,
}
})
onSuccess()
},
(error) => {
sendEventTelemetry({
event: TelemetryEvent.RDI_ENDPOINT_ADD_FAILED,
eventData: {
error,
}
})
}
))
}

sendEventTelemetry({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,22 @@ describe('RdiInstancesListWrapper', () => {
});
(sendEventTelemetry as jest.Mock).mockRestore()
})

it('should call proper telemetry on instance click', async () => {
const sendEventTelemetryMock = jest.fn();
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)
render(<RdiInstancesListWrapper {...instance(mockedProps)} />)

await act(() => {
fireEvent.click(screen.getByTestId('rdi-alias-1'))
})

expect(sendEventTelemetry).toBeCalledWith({
event: TelemetryEvent.OPEN_RDI_CLICKED,
eventData: {
rdiId: '1',
}
});
(sendEventTelemetry as jest.Mock).mockRestore()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ const RdiInstancesListWrapper = ({ width, onEditInstance, editedInstance, onDele
}, [width])

const handleCheckConnectToInstance = (id: string) => {
sendEventTelemetry({
event: TelemetryEvent.OPEN_RDI_CLICKED,
eventData: {
rdiId: id,
}
})
dispatch(checkConnectToRdiInstanceAction(
id,
(id: string) => history.push(Pages.rdiPipeline(id)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ const TemplateButton = ({ setFieldValue, value }: TemplateButtonProps) => {
<EuiButton
fill
size="s"
color="secondary"
className={styles.btn}
aria-label="Insert template"
isLoading={loading}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
.btn {
display: flex;
align-items: center;
color: var(--recommendationsCountBgColor) !important;
background-color: var(--tableRowSelectedColor) !important;
background-color: var(--insightsTriggerBgColor) !important;
border-radius: 4px;
border-color: var(--tableRowSelectedColor) !important;

> span {
color: var(--recommendationsCountBgColor) !important;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ const TemplatePopover = (props: Props) => {
<EuiButton
fill
size="s"
color="secondary"
className={styles.btn}
aria-label="Insert template"
disabled={loading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,8 @@
.btn {
display: flex;
align-items: center;
color: var(--recommendationsCountBgColor) !important;
background-color: var(--tableRowSelectedColor) !important;
background-color: var(--insightsTriggerBgColor) !important;
border-radius: 4px;
border-color: var(--tableRowSelectedColor) !important;

> span {
color: var(--recommendationsCountBgColor) !important;
}
}
}
8 changes: 8 additions & 0 deletions redisinsight/ui/src/slices/interfaces/rdi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ export interface RdiInstance extends RdiInstanceResponse {
error: string
}

export interface IErrorData {
message: string
statusCode: number
error: string
errorCode?: number
errors?: string[]
}

export interface InitialStateRdiInstances {
loading: boolean
error: string
Expand Down
12 changes: 9 additions & 3 deletions redisinsight/ui/src/slices/rdi/instances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { AxiosError } from 'axios'
import { ApiEndpoints } from 'uiSrc/constants'
import { apiService } from 'uiSrc/services'
import successMessages from 'uiSrc/components/notifications/success-messages'
import { getApiErrorMessage, isStatusSuccessful, Nullable } from 'uiSrc/utils'
import { getApiErrorMessage, isStatusSuccessful, Maybe, Nullable } from 'uiSrc/utils'
import { Rdi as RdiInstanceResponse } from 'apiSrc/modules/rdi/models/rdi'

import { AppDispatch, RootState } from '../store'
import { addErrorNotification, addMessageNotification } from '../app/notifications'
import { InitialStateRdiInstances, RdiInstance } from '../interfaces/rdi'
import { IErrorData, InitialStateRdiInstances, RdiInstance } from '../interfaces/rdi'

export const initialState: InitialStateRdiInstances = {
loading: true,
Expand Down Expand Up @@ -189,7 +189,11 @@ export function fetchInstancesAction(onSuccess?: (data: RdiInstance[]) => void)
}

// Asynchronous thunk action
export function createInstanceAction(payload: Partial<RdiInstance>, onSuccess?: (data: RdiInstanceResponse) => void) {
export function createInstanceAction(
payload: Partial<RdiInstance>,
onSuccess?: (data: RdiInstanceResponse) => void,
onFail?: (error: Maybe<string | number>) => void,
) {
return async (dispatch: AppDispatch) => {
dispatch(defaultInstanceChanging())

Expand All @@ -207,6 +211,8 @@ export function createInstanceAction(payload: Partial<RdiInstance>, onSuccess?:
const error = _err as AxiosError
const errorMessage = getApiErrorMessage(error)
dispatch(defaultInstanceChangingFailure(errorMessage))
const errorData = error?.response?.data as IErrorData
onFail?.(errorData?.errorCode || errorData?.error)
dispatch(addErrorNotification(error))
}
}
Expand Down
60 changes: 58 additions & 2 deletions redisinsight/ui/src/slices/tests/rdi/instances.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import reducer, {
instancesSelector,
fetchConnectedInstanceAction,
checkConnectToRdiInstanceAction,
editInstanceAction,
createInstanceAction,
defaultInstanceChanging,
defaultInstanceChangingSuccess,
defaultInstanceChangingFailure,
editInstanceAction,
updateConnectedInstance } from 'uiSrc/slices/rdi/instances'
import { apiService } from 'uiSrc/services'
import { addErrorNotification, IAddInstanceErrorPayload } from 'uiSrc/slices/app/notifications'
import { addErrorNotification, addMessageNotification, IAddInstanceErrorPayload } from 'uiSrc/slices/app/notifications'
import { RdiInstance } from 'uiSrc/slices/interfaces'
import successMessages from 'uiSrc/components/notifications/success-messages'
import { Rdi } from 'apiSrc/modules/rdi/models'

let store: typeof mockedStore
Expand Down Expand Up @@ -240,6 +242,60 @@ describe('rdi instances slice', () => {
})
})

describe('createInstanceAction', () => {
const onSuccess = jest.fn()
const onFail = jest.fn()
it('succeed to create data and call success callback', async () => {
const responsePayload = { data: mockRdiInstance, status: 200 }

apiService.post = jest.fn().mockResolvedValue(responsePayload)
apiService.get = jest.fn().mockResolvedValue({ status: 200, data: [] })

// Act
await store.dispatch<any>(
createInstanceAction(mockRdiInstance, onSuccess, onFail)
)

// Assert
const expectedActions = [
defaultInstanceChanging(),
defaultInstanceChangingSuccess(),
addMessageNotification(successMessages.ADDED_NEW_RDI_INSTANCE(mockRdiInstance.name))
]

expect(store.getActions()).toEqual(expect.arrayContaining(expectedActions))
expect(onSuccess).toBeCalledWith(mockRdiInstance)
})

it('failed to create data and call onFail callback', async () => {
const errorMessage = 'Something was wrong!'
const errorCode = 11403
const responsePayload = {
response: {
status: 500,
data: { message: errorMessage, errorCode },
},
}

apiService.post = jest.fn().mockRejectedValue(responsePayload)

// Act
await store.dispatch<any>(
createInstanceAction(mockRdiInstance, onSuccess, onFail)
)

// Assert
const expectedActions = [
defaultInstanceChanging(),
defaultInstanceChangingFailure(errorMessage),
addErrorNotification(responsePayload as AxiosError),
]

expect(store.getActions()).toEqual(expectedActions)
expect(onFail).toBeCalledWith(errorCode)
})
})

describe('editInstanceAction', () => {
it('succeed to edit data and calls a success callback', async () => {
const onSuccess = jest.fn()
Expand Down
3 changes: 3 additions & 0 deletions redisinsight/ui/src/telemetry/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ export enum TelemetryEvent {
RDI_INSTANCE_ADD_CLICKED = 'RDI_INSTANCE_ADD_CLICKED',
RDI_INSTANCE_ADD_CANCELLED = 'RDI_INSTANCE_ADD_CANCELLED',
RDI_INSTANCE_SUBMITTED = 'RDI_INSTANCE_SUBMITTED',
OPEN_RDI_CLICKED = 'OPEN_RDI_CLICKED',
RDI_ENDPOINT_ADDED = 'RDI_ENDPOINT_ADDED',
RDI_ENDPOINT_ADD_FAILED = 'RDI_ENDPOINT_ADD_FAILED',
RDI_PIPELINE_UPLOAD_FROM_SERVER_CLICKED = 'RDI_PIPELINE_UPLOAD_FROM_SERVER_CLICKED',
RDI_DEPLOY_CLICKED = 'RDI_DEPLOY_CLICKED',
RDI_PIPELINE_RESET_CLICKED = 'RDI_PIPELINE_RESET_CLICKED',
Expand Down
Loading