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
3 changes: 2 additions & 1 deletion redisinsight/api/src/modules/rdi/client/api.rdi.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export class ApiRdiClient extends RdiClient {
}

async getPipeline(): Promise<RdiPipeline> {
return null;
const response = await this.client.get(RdiUrl.GetPipeline);
return response.data;
}

async deploy(pipeline: RdiPipeline): Promise<RdiPipeline> {
Expand Down
1 change: 1 addition & 0 deletions redisinsight/api/src/modules/rdi/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum RdiUrl {
GetSchema = '/schema',
GetPipeline = '/pipeline',
}
13 changes: 12 additions & 1 deletion redisinsight/api/src/modules/rdi/rdi-pipeline.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
ClassSerializerInterceptor, Controller, Get, UseInterceptors, UsePipes, ValidationPipe,
} from '@nestjs/common';
import { Rdi, RdiClientMetadata } from 'src/modules/rdi/models';
import { Rdi, RdiPipeline, RdiClientMetadata } from 'src/modules/rdi/models';
import { ApiTags } from '@nestjs/swagger';
import { ApiEndpoint } from 'src/decorators/api-endpoint.decorator';
import { RdiPipelineService } from 'src/modules/rdi/rdi-pipeline.service';
Expand All @@ -26,4 +26,15 @@ export class RdiPipelineController {
): Promise<object> {
return this.rdiPipelineService.getSchema(rdiClientMetadata);
}

@Get('/')
@ApiEndpoint({
description: 'Get pipeline',
responses: [{ status: 200, type: RdiPipeline }],
})
async getPipeline(
@RequestRdiClientMetadata() rdiClientMetadata: RdiClientMetadata,
): Promise<object> {
return this.rdiPipelineService.getPipeline(rdiClientMetadata);
}
}
8 changes: 5 additions & 3 deletions redisinsight/api/src/modules/rdi/rdi-pipeline.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ export class RdiPipelineService {
async getSchema(rdiClientMetadata: RdiClientMetadata): Promise<object> {
const client = await this.rdiClientProvider.getOrCreate(rdiClientMetadata);

const schema = await client.getSchema();
return await client.getSchema();
}

// todo: process somehow
async getPipeline(rdiClientMetadata: RdiClientMetadata): Promise<object> {
const client = await this.rdiClientProvider.getOrCreate(rdiClientMetadata);

return schema;
return await client.getPipeline();
}
}
10 changes: 10 additions & 0 deletions redisinsight/ui/src/assets/img/icons/file.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import WorkbenchPage from 'uiSrc/pages/workbench'
import PubSubPage from 'uiSrc/pages/pub-sub'
import AnalyticsPage from 'uiSrc/pages/analytics'
import TriggeredFunctionsPage from 'uiSrc/pages/triggered-functions'
import RdiList from 'uiSrc/pages/rdi/home'
import RdiList from 'uiSrc/pages/rdi/home/RDIList'
import RdiPipeline from 'uiSrc/pages/rdi/pipeline/PipelinePage'
import { ANALYTICS_ROUTES, RDI_ROUTES, TRIGGERED_FUNCTIONS_ROUTES } from './sub-routes'

import COMMON_ROUTES from './commonRoutes'
Expand Down Expand Up @@ -77,9 +78,8 @@ const ROUTES: IRoute[] = [
],
},
{
path: Pages.rdi,
// todo: add home rdi component - list of instances
component: RdiList,
path: '/integrate/:rdiInstanceId',
component: RdiPipeline,
routes: RDI_ROUTES,
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { IRoute } from 'uiSrc/constants'
import RdiList from 'uiSrc/pages/rdi/home'
import { IRoute, Pages } from 'uiSrc/constants'
import PreparePage from 'uiSrc/pages/rdi/pipeline/pages/prepare'
import ConfigPage from 'uiSrc/pages/rdi/pipeline/pages/config'

export const RDI_ROUTES: IRoute[] = [
{
// todo: rename path
path: '/:rdiId',
// todo add component like Instance page
component: RdiList,
routes: [
// todo: add page routes here
],
path: Pages.rdiPipelinePrepare(':rdiInstanceId'),
component: PreparePage,
},
{
path: Pages.rdiPipelineConfig(':rdiInstanceId'),
component: ConfigPage,
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import { render } from 'uiSrc/utils/test-utils'

import MonacoYaml from './MonacoYaml'

describe('MonacoYaml', () => {
it('should render', () => {
expect(render(<MonacoYaml value="val" onChange={jest.fn()} />)).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'

import { MonacoEditor } from 'uiSrc/components/monaco-editor'
import { CommonProps } from 'uiSrc/components/monaco-editor/MonacoEditor'

const MonacoYaml = (props: CommonProps) => {
const editorDidMount = (
editor: monacoEditor.editor.IStandaloneCodeEditor,
monaco: typeof monacoEditor,
) => {
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemaValidation: 'error',
schemaRequest: 'error',
trailingCommas: 'error'
})
const messageContribution = editor.getContribution('editor.contrib.messageController')
editor.onDidAttemptReadOnlyEdit(() => messageContribution.dispose())
}

return (
<MonacoEditor
{...props}
language="yaml"
className="yaml-monaco-editor"
onEditorDidMount={editorDidMount}
/>
)
}

export default MonacoYaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import MonacoYaml from './MonacoYaml'

export default MonacoYaml
2 changes: 2 additions & 0 deletions redisinsight/ui/src/components/monaco-editor/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import MonacoEditor from './MonacoEditor'
import MonacoJS from './components/monaco-js'
import MonacoJson from './components/monaco-json'
import MonacoYaml from './components/monaco-yaml'

export {
MonacoEditor,
MonacoJS,
MonacoJson,
MonacoYaml,
}
2 changes: 2 additions & 0 deletions redisinsight/ui/src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ enum ApiEndpoints {

ANALYTICS_SEND_EVENT = 'analytics/send-event',
ANALYTICS_SEND_PAGE = 'analytics/send-page',

RDI_PIPELINE = 'rdi/pipeline'
}

export enum CustomHeaders {
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/src/constants/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const EXTERNAL_LINKS = {
cloudConsole: 'https://app.redislabs.com/#/databases',
tryFree: 'https://redis.com/try-free',
docker: 'https://redis.io/docs/getting-started/install-stack/docker',
rdiQuickStart: 'https://docs.redis.com/latest/rdi/quickstart/',
}

export const UTM_CAMPAINGS: Record<any, string> = {
Expand Down
3 changes: 3 additions & 0 deletions redisinsight/ui/src/constants/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ export const Pages = {
`/${instanceId}/${PageNames.triggeredFunctions}/${PageNames.triggeredFunctionsFunctions}`,
// rdi pages
rdi: '/integrate',
rdiPipeline: (rdiInstance: string) => `integrate/${rdiInstance}/pipeline}`,
rdiPipelineConfig: (rdiInstance: string) => `/integrate/${rdiInstance}/pipeline/config`,
rdiPipelinePrepare: (rdiInstance: string) => `/integrate/${rdiInstance}/pipeline/prepare`,
}
45 changes: 45 additions & 0 deletions redisinsight/ui/src/pages/rdi/pipeline/PipelinePage.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react'
import { cloneDeep } from 'lodash'

import { BrowserRouter } from 'react-router-dom'
import { instance, mock } from 'ts-mockito'
import { act, render, cleanup, mockedStore } from 'uiSrc/utils/test-utils'
import { getPipeline } from 'uiSrc/slices/rdi/pipeline'
import PipelinePage, { Props } from './PipelinePage'

const mockedProps = mock<Props>()

let store: typeof mockedStore
beforeEach(() => {
cleanup()
store = cloneDeep(mockedStore)
store.clearActions()
})

describe('PipelinePage', () => {
it('should render', () => {
expect(
render(
<BrowserRouter>
<PipelinePage {...instance(mockedProps)} />
</BrowserRouter>
)
).toBeTruthy()
})

it('should dispatch fetchRdiPipeline on render', async () => {
await act(() => {
render(
<BrowserRouter>
<PipelinePage {...instance(mockedProps)} />
</BrowserRouter>
)
})

const expectedActions = [
getPipeline(),
]

expect(store.getActions()).toEqual(expectedActions)
})
})
35 changes: 35 additions & 0 deletions redisinsight/ui/src/pages/rdi/pipeline/PipelinePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useEffect } from 'react'
import { useLocation, useParams } from 'react-router-dom'
import { useDispatch } from 'react-redux'

import { fetchRdiPipeline } from 'uiSrc/slices/rdi/pipeline'

import Navigation from './components/navigation'
import PipelinePageRouter from './PipelinePageRouter'
import styles from './styles.module.scss'

export interface Props {
routes: any[]
}

const Pipeline = ({ routes = [] }: Props) => {
const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>()

const { pathname } = useLocation()
const dispatch = useDispatch()

const path = pathname?.split('/').pop() || ''

useEffect(() => {
dispatch(fetchRdiPipeline(rdiInstanceId))
}, [])

return (
<div className={styles.wrapper}>
<Navigation path={path} />
<PipelinePageRouter routes={routes} />
</div>
)
}

export default Pipeline
17 changes: 17 additions & 0 deletions redisinsight/ui/src/pages/rdi/pipeline/PipelinePageRouter.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { render } from 'uiSrc/utils/test-utils'
import PipelinePageRouter from './PipelinePageRouter'

const mockedRoutes = [
{
path: '/page',
},
]

describe('PipelinePageRouter', () => {
it('should render', () => {
expect(
render(<PipelinePageRouter routes={mockedRoutes} />, { withRouter: true })
).toBeTruthy()
})
})
17 changes: 17 additions & 0 deletions redisinsight/ui/src/pages/rdi/pipeline/PipelinePageRouter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { Switch } from 'react-router-dom'
import RouteWithSubRoutes from 'uiSrc/utils/routerWithSubRoutes'

export interface Props {
routes: any[];
}
const PipelinePageRouter = ({ routes }: Props) => (
<Switch>
{routes.map((route, i) => (
// eslint-disable-next-line react/no-array-index-key
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
)

export default React.memo(PipelinePageRouter)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import reactRouterDom from 'react-router-dom'
import { render, screen, fireEvent } from 'uiSrc/utils/test-utils'

import Navigation from './Navigation'

jest.mock('uiSrc/telemetry', () => ({
...jest.requireActual('uiSrc/telemetry'),
sendEventTelemetry: jest.fn(),
}))

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: jest.fn,
}),
}))

describe('Navigation', () => {
it('should render', () => {
expect(render(<Navigation path="" />)).toBeTruthy()
})

it('should call proper history push after click on tabs', () => {
const pushMock = jest.fn()
reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock })

render(<Navigation path="" />)

fireEvent.click(screen.getByTestId('rdi-nav-btn-config'))
expect(pushMock).toBeCalledWith('/integrate/undefined/pipeline/config')

fireEvent.click(screen.getByTestId('rdi-nav-btn-prepare'))
expect(pushMock).toBeCalledWith('/integrate/undefined/pipeline/prepare')
})
})
Loading