- {data.map(({ title, tutorial, icon }) => (
+ {data.map(({ title, tutorialId, icon }) => (
{}}
- onClick={() => handleLinkClick(tutorial, title)}
+ onClick={() => handleLinkClick(tutorialId, title)}
className={styles.btn}
data-testid={`guide-button-${title}`}
>
diff --git a/redisinsight/ui/src/constants/index.ts b/redisinsight/ui/src/constants/index.ts
index 6ae5c0a6c8..0e40368cc8 100644
--- a/redisinsight/ui/src/constants/index.ts
+++ b/redisinsight/ui/src/constants/index.ts
@@ -16,7 +16,6 @@ export * from './pages'
export * from './workbenchResults'
export * from './socketEvents'
export * from './mocks/mock-redis-commands'
-export * from './mocks/mock-guides'
export * from './mocks/mock-tutorials'
export * from './mocks/mock-custom-tutorials'
export * from './socketErrors'
diff --git a/redisinsight/ui/src/constants/mocks/mock-guides.ts b/redisinsight/ui/src/constants/mocks/mock-guides.ts
deleted file mode 100644
index 8e38901fae..0000000000
--- a/redisinsight/ui/src/constants/mocks/mock-guides.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
-
-export const MOCK_GUIDES_ITEMS: IEnablementAreaItem[] = [
- {
- type: EnablementAreaComponent.Group,
- id: 'quick-guides',
- label: 'Quick Guides',
- children: [
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'document-capabilities',
- label: 'Document Capabilities',
- args: {
- path: '/static/workbench/quick-guides/document/learn-more.md',
- },
- },
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'working-with-json',
- label: 'Working with JSON',
- args: {
- path: '/quick-guides/working-with-json.html',
- },
- _path: '/123123-123123'
- },
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'working-with-hash',
- label: 'Working with HASH',
- args: {
- path: 'quick-guides/working-with-hash.html',
- },
- },
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'working-with-hash-2',
- label: 'Working with HASH',
- args: {
- path: '\\quick-guides\\working-with-hash.html',
- },
- }
- ]
- },
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'internal-page',
- label: 'Internal Page',
- args: {
- path: 'quick-guides/document-capabilities.html'
- },
- },
- {
- type: EnablementAreaComponent.InternalLink,
- id: 'second-internal-page',
- label: 'Second Internal Page',
- args: {
- path: 'quick-guides/document-capabilities.html'
- },
- },
- {
- type: EnablementAreaComponent.CodeButton,
- id: 'manual',
- label: 'Manual',
- args: {
- path: '_scripts/manual.txt'
- },
- },
-]
-
-export const MOCK_GUIDES = {
- type: EnablementAreaComponent.Group,
- id: 'quick-guides',
- label: 'Quick Guides',
- children: MOCK_GUIDES_ITEMS
-}
diff --git a/redisinsight/ui/src/constants/mocks/mock-recommendations.ts b/redisinsight/ui/src/constants/mocks/mock-recommendations.ts
index 3ab6677f76..244c7a46bb 100644
--- a/redisinsight/ui/src/constants/mocks/mock-recommendations.ts
+++ b/redisinsight/ui/src/constants/mocks/mock-recommendations.ts
@@ -77,7 +77,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
telemetryEvent: 'shardHashes',
title: 'Shard big hashes to small hashes',
redisStack: true,
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'ds-hashes',
content: [
{
type: 'paragraph',
@@ -135,6 +135,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
combineSmallStringsToHashes: {
id: 'combineSmallStringsToHashes',
title: 'Combine small strings to hashes',
+ tutorialId: 'ds-hashes',
content: [
{
type: 'span',
@@ -382,7 +383,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
bigStrings: {
id: 'bigStrings',
title: 'Avoid large strings',
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'ds-json-intro',
content: [
{
type: 'span',
@@ -517,7 +518,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
id: 'bigSets',
telemetryEvent: 'optimizeExistenceChecks',
title: 'Consider using probabilistic data structures such as Bloom Filter or HyperLogLog',
- tutorial: '/quick-guides/probabilistic-data-structures/introduction.md',
+ tutorialId: 'ds-prob-intro',
redisStack: true,
content: [
{
@@ -663,7 +664,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
telemetryEvent: 'optimizeTimeSeries',
title: 'Try using the Redis native time series data structure and querying capabilities',
redisStack: true,
- tutorial: '/quick-guides/time-series/introduction.md',
+ tutorialId: 'ds-ts-intro',
content: [
{
type: 'span',
@@ -868,7 +869,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
title: 'Optimize your query and search experience',
deprecated: true,
redisStack: true,
- tutorial: '/redis_stack/working_with_json.md',
+ tutorialId: 'ds-json-intro',
content: [
{
type: 'link',
@@ -918,7 +919,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
id: 'searchIndexes',
title: 'Try using the indexing, querying, and full-text search, natively developed in Redis',
redisStack: true,
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'sq-intro',
content: [
{
type: 'paragraph',
@@ -1041,7 +1042,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
id: 'searchJSON',
title: 'Try indexing your JSON documents for efficient data retrieval',
redisStack: true,
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'sq-intro',
content: [
{
type: 'span',
@@ -1132,7 +1133,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
id: 'stringToJson',
title: 'Try using our JSON native document store',
redisStack: true,
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'ds-json-intro',
content: [
{
type: 'paragraph',
@@ -1249,7 +1250,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
searchVisualization: {
id: 'searchVisualization',
title: 'Try Workbench, the advanced command-line interface',
- tutorial: '',
+ tutorialId: '',
content: [
{
type: 'paragraph',
@@ -1312,7 +1313,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
searchHash: {
id: 'searchHash',
title: 'Try indexing your hash documents to query and retrieve data',
- tutorial: '/quick-guides/document/introduction.md',
+ tutorialId: 'sq-intro',
redisStack: true,
content: [
{
@@ -1442,7 +1443,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
luaToFunctions: {
id: 'luaToFunctions',
title: 'Consider using triggers and functions',
- tutorial: '/quick-guides/triggers-and-functions/introduction.md',
+ tutorialId: 'tf-intro',
content: [
{
type: 'paragraph',
@@ -1503,7 +1504,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
functionsWithStreams: {
id: 'functionsWithStreams',
title: 'Consider using triggers and functions to react in real-time to stream entries',
- tutorial: '/quick-guides/triggers-and-functions/introduction.md',
+ tutorialId: 'tf-intro',
content: [
{
type: 'paragraph',
@@ -1580,7 +1581,7 @@ export const MOCK_RECOMMENDATIONS: IRecommendationsStatic = {
functionsWithKeyspace: {
id: 'functionsWithKeyspace',
title: 'Consider using triggers and functions to react in real-time to database changes',
- tutorial: '/quick-guides/triggers-and-functions/introduction.md',
+ tutorialId: 'tf-intro',
content: [
{
type: 'paragraph',
diff --git a/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.spec.tsx b/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.spec.tsx
index d41a968f45..f8692d20e7 100644
--- a/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.spec.tsx
+++ b/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.spec.tsx
@@ -7,6 +7,7 @@ import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { recommendationsSelector } from 'uiSrc/slices/recommendations/recommendations'
import { MOCK_RECOMMENDATIONS } from 'uiSrc/constants/mocks/mock-recommendations'
+import { findTutorialPath } from 'uiSrc/utils'
import Recommendations from './Recommendations'
const recommendationsContent = MOCK_RECOMMENDATIONS
@@ -57,6 +58,11 @@ jest.mock('uiSrc/slices/instances/instances', () => ({
}),
}))
+jest.mock('uiSrc/utils', () => ({
+ ...jest.requireActual('uiSrc/utils'),
+ findTutorialPath: jest.fn(),
+}))
+
beforeEach(() => {
(recommendationsSelector as jest.Mock).mockImplementation(() => ({
...mockRecommendationsSelector,
@@ -440,7 +446,7 @@ describe('Recommendations', () => {
expect(screen.getByTestId('bigHashes-to-tutorial-btn')).toBeInTheDocument()
})
- it('should call proper history push after click go tutorial button', () => {
+ it('should call proper telemetry after click go tutorial button', () => {
const sendEventTelemetryMock = jest.fn();
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock);
@@ -467,9 +473,11 @@ describe('Recommendations', () => {
(sendEventTelemetry as jest.Mock).mockRestore()
})
- it('should call proper telemetry after click go tutorial button', () => {
+ it('should call proper history push after click go tutorial button', () => {
const pushMock = jest.fn()
+ const path = 'path'
reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock });
+ (findTutorialPath as jest.Mock).mockImplementation(() => path);
(dbAnalysisSelector as jest.Mock).mockImplementation(() => ({
...mockdbAnalysisSelector,
data: {
@@ -483,7 +491,7 @@ describe('Recommendations', () => {
fireEvent.click(screen.getByTestId('bigHashes-to-tutorial-btn'))
expect(pushMock).toBeCalledWith({
- search: 'guidePath=/quick-guides/document/introduction.md'
+ search: 'path=tutorials/path'
})
pushMock.mockRestore()
})
diff --git a/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.tsx b/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.tsx
index 05195be6fe..c7a3ca9e12 100644
--- a/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.tsx
+++ b/redisinsight/ui/src/pages/database-analysis/components/recommendations-view/Recommendations.tsx
@@ -36,6 +36,7 @@ import {
} from 'uiSrc/utils/recommendation/utils'
import { openTutorialByPath } from 'uiSrc/slices/panels/insights'
+import { findTutorialPath } from 'uiSrc/utils'
import styles from './styles.module.scss'
const Recommendations = () => {
@@ -60,7 +61,7 @@ const Recommendations = () => {
}
})
- const goToTutorial = (mdPath: string, id: string) => {
+ const goToTutorial = (tutorialId: string, id: string) => {
sendEventTelemetry({
event: TelemetryEvent.DATABASE_TIPS_TUTORIAL_CLICKED,
eventData: {
@@ -70,7 +71,8 @@ const Recommendations = () => {
}
})
- dispatch(openTutorialByPath(mdPath || '', history))
+ const tutorialPath = findTutorialPath({ id: tutorialId || '' })
+ dispatch(openTutorialByPath(tutorialPath || '', history))
}
const onRedisStackClick = (event: React.MouseEvent
) => event.stopPropagation()
@@ -145,7 +147,7 @@ const Recommendations = () => {
content = [],
badges = [],
redisStack = false,
- tutorial,
+ tutorialId,
telemetryEvent
} = recommendationsContent[name] || {}
@@ -180,12 +182,12 @@ const Recommendations = () => {
- {tutorial && (
+ {tutorialId && (
goToTutorial(tutorial, id)}
+ onClick={() => goToTutorial(tutorialId, id)}
data-testid={`${id}-to-tutorial-btn`}
>
Tutorial
diff --git a/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.spec.tsx b/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.spec.tsx
index 50402f3587..7adb5e9ef5 100644
--- a/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.spec.tsx
+++ b/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.spec.tsx
@@ -6,6 +6,7 @@ import { cleanup, clearStoreActions, render, fireEvent, screen, mockedStore } fr
import { changeSelectedTab, toggleInsightsPanel } from 'uiSrc/slices/panels/insights'
import { InsightsPanelTabs } from 'uiSrc/slices/interfaces/insights'
+import { findTutorialPath } from 'uiSrc/utils'
import NoLibrariesScreen, { IProps } from './NoLibrariesScreen'
const mockedProps = mock()
@@ -17,8 +18,13 @@ beforeEach(() => {
store.clearActions()
})
-jest.mock('uiSrc/slices/workbench/wb-guides', () => ({
- ...jest.requireActual('uiSrc/slices/workbench/wb-guides'),
+jest.mock('uiSrc/utils', () => ({
+ ...jest.requireActual('uiSrc/utils'),
+ findTutorialPath: jest.fn(),
+}))
+
+jest.mock('uiSrc/slices/workbench/wb-tutorials', () => ({
+ ...jest.requireActual('uiSrc/slices/workbench/wb-tutorials'),
workbenchGuidesSelector: jest.fn().mockReturnValue({
items: [{
label: 'Quick guides',
@@ -50,7 +56,8 @@ describe('NoLibrariesScreen', () => {
it('should call proper actions and push to quick guides page ', () => {
const pushMock = jest.fn()
- reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock })
+ reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock });
+ (findTutorialPath as jest.Mock).mockImplementation(() => 'path')
render()
@@ -62,7 +69,7 @@ describe('NoLibrariesScreen', () => {
]
expect(clearStoreActions(store.getActions())).toEqual(clearStoreActions(expectedActions))
expect(pushMock).toBeCalledWith({
- search: 'guidePath=/quick-guides/triggers-and-functions/introduction.md'
+ search: 'path=tutorials/path'
})
})
diff --git a/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.tsx b/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.tsx
index ba8028d548..b9361785e5 100644
--- a/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.tsx
+++ b/redisinsight/ui/src/pages/triggered-functions/components/NoLibrariesScreen/NoLibrariesScreen.tsx
@@ -20,7 +20,7 @@ import { OAuthSocialSource, RedisDefaultModules } from 'uiSrc/slices/interfaces'
import { OAuthConnectFreeDb, OAuthSsoHandlerDialog } from 'uiSrc/components'
import { freeInstancesSelector } from 'uiSrc/slices/instances/instances'
-import { getDbWithModuleLoaded } from 'uiSrc/utils'
+import { findTutorialPath, getDbWithModuleLoaded } from 'uiSrc/utils'
import { openTutorialByPath } from 'uiSrc/slices/panels/insights'
import styles from './styles.module.scss'
@@ -30,7 +30,7 @@ export interface IProps {
onAddLibrary?: () => void
}
-const mdPath = '/quick-guides/triggers-and-functions/introduction.md'
+const tutorialId = 'tf-intro'
const ListItem = ({ item }: { item: string }) => (
@@ -54,7 +54,8 @@ const NoLibrariesScreen = (props: IProps) => {
const freeDbWithModule = getDbWithModuleLoaded(freeInstances, RedisDefaultModules.RedisGears)
const goToTutorial = () => {
- dispatch(openTutorialByPath(mdPath, history))
+ const tutorialPath = findTutorialPath({ id: tutorialId ?? '' })
+ dispatch(openTutorialByPath(tutorialPath ?? '', history))
}
return (
diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.spec.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.spec.tsx
index 6025098f50..9c003775ee 100644
--- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.spec.tsx
+++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.spec.tsx
@@ -23,16 +23,6 @@ jest.mock('uiSrc/utils/workbench', () => ({
updateWBHistoryStorage: jest.fn(),
}))
-jest.mock('uiSrc/slices/workbench/wb-guides', () => {
- const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-guides').initialState
- return {
- ...jest.requireActual('uiSrc/slices/workbench/wb-guides'),
- workbenchGuidesSelector: jest.fn().mockReturnValue({
- ...defaultState,
- }),
- }
-})
-
describe('WBView', () => {
it('should render', () => {
expect(render()).toBeTruthy()
diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx
index ab36b8ee40..c0d9cf9787 100644
--- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx
+++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx
@@ -21,7 +21,6 @@ import {
workbenchResultsSelector
} from 'uiSrc/slices/workbench/wb-results'
-import { getWBCustomTutorials } from 'uiSrc/slices/workbench/wb-custom-tutorials'
import WBViewWrapper from './WBViewWrapper'
let store: typeof mockedStore
@@ -81,16 +80,6 @@ jest.mock('uiSrc/slices/workbench/wb-results', () => ({
})
}))
-jest.mock('uiSrc/slices/workbench/wb-guides', () => {
- const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-guides').initialState
- return {
- ...jest.requireActual('uiSrc/slices/workbench/wb-guides'),
- workbenchGuidesSelector: jest.fn().mockReturnValue({
- ...defaultState,
- }),
- }
-})
-
jest.mock('uiSrc/slices/workbench/wb-tutorials', () => {
const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-tutorials').initialState
return {
diff --git a/redisinsight/ui/src/slices/interfaces/content.ts b/redisinsight/ui/src/slices/interfaces/content.ts
index d9fe983402..9f44aecb91 100644
--- a/redisinsight/ui/src/slices/interfaces/content.ts
+++ b/redisinsight/ui/src/slices/interfaces/content.ts
@@ -34,7 +34,7 @@ export interface StateContentGuideLinks {
export interface ContentGuideLinks {
title: string
- tutorial: string
+ tutorialId: string
icon: string
description?: string
}
diff --git a/redisinsight/ui/src/slices/interfaces/recommendations.ts b/redisinsight/ui/src/slices/interfaces/recommendations.ts
index f45b708f57..96c46d0c5c 100644
--- a/redisinsight/ui/src/slices/interfaces/recommendations.ts
+++ b/redisinsight/ui/src/slices/interfaces/recommendations.ts
@@ -37,7 +37,7 @@ export interface IRecommendationsStatic {
liveTitle?: string
telemetryEvent?: string
redisStack?: boolean
- tutorial?: string
+ tutorialId?: string
content?: IRecommendationContent[]
badges?: string[]
}
diff --git a/redisinsight/ui/src/slices/panels/insights.ts b/redisinsight/ui/src/slices/panels/insights.ts
index 0724ae6a75..b1fab188cd 100644
--- a/redisinsight/ui/src/slices/panels/insights.ts
+++ b/redisinsight/ui/src/slices/panels/insights.ts
@@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom'
import { Maybe } from 'uiSrc/utils'
import { InsightsPanelState, InsightsPanelTabs } from 'uiSrc/slices/interfaces/insights'
import { sessionStorageService } from 'uiSrc/services'
-import { BrowserStorageItem } from 'uiSrc/constants'
+import { BrowserStorageItem, EAManifestFirstKey } from 'uiSrc/constants'
import { AppDispatch, RootState } from '../store'
const getTabSelected = (tab?: string): InsightsPanelTabs => {
@@ -85,14 +85,16 @@ export const {
setExplorePanelManifest,
} = insightsPanelSlice.actions
-export function openTutorialByPath(guidePath: string, history: ReturnType) {
+export function openTutorialByPath(path: string, history: ReturnType) {
return async (dispatch: AppDispatch) => {
dispatch(changeSelectedTab(InsightsPanelTabs.Explore))
dispatch(toggleInsightsPanel(true))
- history.push({
- search: `guidePath=${guidePath}`
- })
+ if (path) {
+ history.push({
+ search: `path=${EAManifestFirstKey.TUTORIALS}/${path}`
+ })
+ }
}
}
diff --git a/redisinsight/ui/src/slices/store.ts b/redisinsight/ui/src/slices/store.ts
index e96ae89903..fe326835c2 100644
--- a/redisinsight/ui/src/slices/store.ts
+++ b/redisinsight/ui/src/slices/store.ts
@@ -30,7 +30,6 @@ import appFeaturesReducer from './app/features'
import appUrlHandlingReducer from './app/url-handling'
import appOauthReducer from './oauth/cloud'
import workbenchResultsReducer from './workbench/wb-results'
-import workbenchGuidesReducer from './workbench/wb-guides'
import workbenchTutorialsReducer from './workbench/wb-tutorials'
import workbenchCustomTutorialsReducer from './workbench/wb-custom-tutorials'
import contentCreateRedisButtonReducer from './content/create-redis-buttons'
@@ -89,7 +88,6 @@ export const rootReducer = combineReducers({
}),
workbench: combineReducers({
results: workbenchResultsReducer,
- guides: workbenchGuidesReducer,
tutorials: workbenchTutorialsReducer,
customTutorials: workbenchCustomTutorialsReducer,
}),
diff --git a/redisinsight/ui/src/slices/tests/workbench/wb-guides.spec.ts b/redisinsight/ui/src/slices/tests/workbench/wb-guides.spec.ts
deleted file mode 100644
index ce7bc7e4bd..0000000000
--- a/redisinsight/ui/src/slices/tests/workbench/wb-guides.spec.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { cloneDeep } from 'lodash'
-import { cleanup, initialStateDefault, mockedStore, } from 'uiSrc/utils/test-utils'
-import { IEnablementAreaItem } from 'uiSrc/slices/interfaces'
-import { MOCK_GUIDES } from 'uiSrc/constants'
-import { resourcesService } from 'uiSrc/services'
-
-import reducer, {
- initialState,
- workbenchGuidesSelector,
- getWBGuides,
- getWBGuidesFailure,
- getWBGuidesSuccess,
- fetchGuides,
- defaultItems,
-} from '../../workbench/wb-guides'
-
-let store: typeof mockedStore
-beforeEach(() => {
- cleanup()
- store = cloneDeep(mockedStore)
- store.clearActions()
-})
-
-describe('slices', () => {
- describe('reducer, actions and selectors', () => {
- it('should return the initial state on first run', () => {
- // Arrange
- const nextState = initialState
-
- // Act
- const result = reducer(undefined, {})
-
- // Assert
- expect(result).toEqual(nextState)
- })
- })
-
- describe('getWBGuides', () => {
- it('should properly set loading', () => {
- // Arrange
- const loading = true
- const state = {
- ...initialState,
- loading
- }
-
- // Act
- const nextState = reducer(initialState, getWBGuides())
-
- // Assert
- const rootState = Object.assign(initialStateDefault, {
- workbench: {
- guides: nextState,
- },
- })
-
- expect(workbenchGuidesSelector(rootState)).toEqual(state)
- })
- })
-
- describe('getWBGuidesSuccess', () => {
- it('should properly set state after success', () => {
- // Arrange
- const guides: IEnablementAreaItem = MOCK_GUIDES
- const state = {
- ...initialState,
- items: [guides],
- }
-
- // Act
- const nextState = reducer(initialState, getWBGuidesSuccess(guides))
-
- // Assert
- const rootState = Object.assign(initialStateDefault, {
- workbench: {
- guides: nextState,
- },
- })
-
- expect(workbenchGuidesSelector(rootState)).toEqual(state)
- })
- })
-
- describe('getWBGuidesFailure', () => {
- it('should properly set error', () => {
- // Arrange
- const error = 'error'
- const state = {
- ...initialState,
- loading: false,
- items: defaultItems,
- error
- }
-
- // Act
- const nextState = reducer(initialState, getWBGuidesFailure(error))
-
- // Assert
- const rootState = Object.assign(initialStateDefault, {
- workbench: {
- guides: nextState,
- },
- })
-
- expect(workbenchGuidesSelector(rootState)).toEqual(state)
- })
- })
-
- // thunks
-
- describe('fetchGuides', () => {
- it('succeed to fetch guides items', async () => {
- // Arrange
- const data = MOCK_GUIDES
- const responsePayload = { status: 200, data }
-
- resourcesService.get = jest.fn().mockResolvedValue(responsePayload)
-
- // Act
- await store.dispatch(fetchGuides(jest.fn()))
-
- // Assert
- const expectedActions = [
- getWBGuides(),
- getWBGuidesSuccess(data),
- ]
-
- expect(mockedStore.getActions()).toEqual(expectedActions)
- })
-
- it('failed to fetch guides items', async () => {
- // Arrange
- const errorMessage = 'Something was wrong!'
- const responsePayload = {
- response: {
- status: 500,
- data: { message: errorMessage },
- },
- }
- resourcesService.get = jest.fn().mockRejectedValue(responsePayload)
-
- // Act
- await store.dispatch(fetchGuides())
-
- // Assert
- const expectedActions = [
- getWBGuides(),
- getWBGuidesFailure(errorMessage),
- ]
-
- expect(mockedStore.getActions()).toEqual(expectedActions)
- })
- })
-})
diff --git a/redisinsight/ui/src/slices/workbench/wb-guides.ts b/redisinsight/ui/src/slices/workbench/wb-guides.ts
deleted file mode 100644
index d7f2264719..0000000000
--- a/redisinsight/ui/src/slices/workbench/wb-guides.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { createSlice } from '@reduxjs/toolkit'
-import { ApiEndpoints } from 'uiSrc/constants'
-import { getApiErrorMessage, isStatusSuccessful, } from 'uiSrc/utils'
-import { resourcesService } from 'uiSrc/services'
-import { IEnablementAreaItem, StateWorkbenchEnablementArea } from 'uiSrc/slices/interfaces'
-
-import { AppDispatch, RootState } from '../store'
-
-export const defaultItems: IEnablementAreaItem[] = []
-
-export const initialState: StateWorkbenchEnablementArea = {
- loading: false,
- error: '',
- items: [],
-}
-
-// A slice for recipes
-const workbenchGuidesSlice = createSlice({
- name: 'workbenchGuides',
- initialState,
- reducers: {
- getWBGuides: (state) => {
- state.loading = true
- },
- getWBGuidesSuccess: (state, { payload }: { payload: IEnablementAreaItem }) => {
- state.loading = false
- state.items = [payload]
- },
- getWBGuidesFailure: (state, { payload }) => {
- state.loading = false
- state.error = payload
- state.items = defaultItems
- },
- }
-})
-
-// A selector
-export const workbenchGuidesSelector = (state: RootState) => state.workbench.guides
-
-// Actions generated from the slice
-export const {
- getWBGuides,
- getWBGuidesSuccess,
- getWBGuidesFailure,
-} = workbenchGuidesSlice.actions
-
-// The reducer
-export default workbenchGuidesSlice.reducer
-
-// Asynchronous thunk action
-export function fetchGuides(onSuccessAction?: () => void, onFailAction?: () => void) {
- return async (dispatch: AppDispatch) => {
- dispatch(getWBGuides())
-
- try {
- const { data, status } = await resourcesService.get(ApiEndpoints.GUIDES)
- if (isStatusSuccessful(status)) {
- dispatch(getWBGuidesSuccess(data))
- onSuccessAction?.()
- }
- } catch (error) {
- const errorMessage = getApiErrorMessage(error)
- dispatch(getWBGuidesFailure(errorMessage))
- onFailAction?.()
- }
- }
-}
diff --git a/redisinsight/ui/src/utils/capability.ts b/redisinsight/ui/src/utils/capability.ts
index b280fb0ee0..38c162962f 100644
--- a/redisinsight/ui/src/utils/capability.ts
+++ b/redisinsight/ui/src/utils/capability.ts
@@ -1,14 +1,14 @@
-import { IEnablementAreaItem, OAuthSocialSource, RedisDefaultModules } from 'uiSrc/slices/interfaces'
+import { OAuthSocialSource, RedisDefaultModules } from 'uiSrc/slices/interfaces'
import { store } from 'uiSrc/slices/store'
import { Nullable } from 'uiSrc/utils'
-import { findMarkdownPathById } from 'uiSrc/utils/workbench'
+import { findMarkdownPath } from 'uiSrc/utils/workbench'
const getCapability = (
telemetryName: string = '',
name: string = '',
- tutorialPage: Nullable = null
+ path: Nullable = null
) => ({
- telemetryName, name, tutorialPage
+ telemetryName, name, path
})
export const getSourceTutorialByCapability = (moduleName = '') => `${moduleName}_tutorial`
@@ -25,7 +25,7 @@ export const getTutorialCapability = (source: any = '') => {
return getCapability(
'searchAndQuery',
'Search and query capability',
- findMarkdownPathById(store.getState()?.workbench?.tutorials?.items, 'vector_similarity_search')
+ findMarkdownPath(store.getState()?.workbench?.tutorials?.items, { id: 'sq-intro' })
)
// RedisJSON
@@ -34,7 +34,7 @@ export const getTutorialCapability = (source: any = '') => {
return getCapability(
'JSON',
'JSON capability',
- findMarkdownPathById(store.getState()?.workbench?.tutorials?.items, 'working_with_json')
+ findMarkdownPath(store.getState()?.workbench?.tutorials?.items, { id: 'ds-json-intro' })
)
// TimeSeries
@@ -43,7 +43,7 @@ export const getTutorialCapability = (source: any = '') => {
return getCapability(
'timeSeries',
'Time series data structure',
- findMarkdownPathById(store.getState()?.workbench?.tutorials?.items, 'redis_for_time_series')
+ findMarkdownPath(store.getState()?.workbench?.tutorials?.items, { id: 'ds-ts-intro' })
)
// Bloom
@@ -52,7 +52,7 @@ export const getTutorialCapability = (source: any = '') => {
return getCapability(
'probabilistic',
'Probabilistic data structures',
- findMarkdownPathById(store.getState()?.workbench?.tutorials?.items, 'probabilistic_data_structures')
+ findMarkdownPath(store.getState()?.workbench?.tutorials?.items, { id: 'ds-prob-intro' })
)
default:
diff --git a/redisinsight/ui/src/utils/routing.ts b/redisinsight/ui/src/utils/routing.ts
index 0cdca57dcd..9964c8409a 100644
--- a/redisinsight/ui/src/utils/routing.ts
+++ b/redisinsight/ui/src/utils/routing.ts
@@ -28,7 +28,7 @@ export const getRedirectionPage = (pageInput: string, databaseId?: string): Null
const pageUrl = new URL(page, window.location.origin)
const { pathname, searchParams } = pageUrl
- if (searchParams.has('guidePath')) {
+ if (searchParams.has('guidePath') || searchParams.has('tutorialId')) {
page += '&insights=open'
}
diff --git a/redisinsight/ui/src/utils/test-utils.tsx b/redisinsight/ui/src/utils/test-utils.tsx
index 68879390b1..278bdac05a 100644
--- a/redisinsight/ui/src/utils/test-utils.tsx
+++ b/redisinsight/ui/src/utils/test-utils.tsx
@@ -36,7 +36,6 @@ import { initialState as initialStateCliOutput } from 'uiSrc/slices/cli/cli-outp
import { initialState as initialStateMonitor } from 'uiSrc/slices/cli/monitor'
import { initialState as initialStateUserSettings } from 'uiSrc/slices/user/user-settings'
import { initialState as initialStateWBResults } from 'uiSrc/slices/workbench/wb-results'
-import { initialState as initialStateWBEGuides } from 'uiSrc/slices/workbench/wb-guides'
import { initialState as initialStateWBETutorials } from 'uiSrc/slices/workbench/wb-tutorials'
import { initialState as initialStateWBECustomTutorials } from 'uiSrc/slices/workbench/wb-custom-tutorials'
import { initialState as initialStateCreateRedisButtons } from 'uiSrc/slices/content/create-redis-buttons'
@@ -104,7 +103,6 @@ const initialStateDefault: RootState = {
},
workbench: {
results: cloneDeep(initialStateWBResults),
- guides: cloneDeep(initialStateWBEGuides),
tutorials: cloneDeep(initialStateWBETutorials),
customTutorials: cloneDeep(initialStateWBECustomTutorials),
},
diff --git a/redisinsight/ui/src/utils/tests/capability.spec.ts b/redisinsight/ui/src/utils/tests/capability.spec.ts
index a69ca2ee4e..7df5df04bb 100644
--- a/redisinsight/ui/src/utils/tests/capability.spec.ts
+++ b/redisinsight/ui/src/utils/tests/capability.spec.ts
@@ -15,11 +15,11 @@ describe('getSourceTutorialByCapability', () => {
})
})
-const emptyCapability = { name: '', telemetryName: '', tutorialPage: null, }
-const searchCapability = { name: 'Search and query capability', telemetryName: 'searchAndQuery', tutorialPage: null, }
-const jsonCapability = { name: 'JSON capability', telemetryName: 'JSON', tutorialPage: null, }
-const tsCapability = { name: 'Time series data structure', telemetryName: 'timeSeries', tutorialPage: null, }
-const bloomCapability = { name: 'Probabilistic data structures', telemetryName: 'probabilistic', tutorialPage: null, }
+const emptyCapability = { name: '', telemetryName: '', path: null, }
+const searchCapability = { name: 'Search and query capability', telemetryName: 'searchAndQuery', path: null, }
+const jsonCapability = { name: 'JSON capability', telemetryName: 'JSON', path: null, }
+const tsCapability = { name: 'Time series data structure', telemetryName: 'timeSeries', path: null, }
+const bloomCapability = { name: 'Probabilistic data structures', telemetryName: 'probabilistic', path: null, }
const getTutorialCapabilityTests: any[] = [
[OAuthSocialSource.RediSearch, searchCapability],
diff --git a/redisinsight/ui/src/utils/tests/workbench.spec.ts b/redisinsight/ui/src/utils/tests/workbench.spec.ts
index f250f22bf8..733a20ef38 100644
--- a/redisinsight/ui/src/utils/tests/workbench.spec.ts
+++ b/redisinsight/ui/src/utils/tests/workbench.spec.ts
@@ -1,6 +1,6 @@
import { ExecuteQueryParams, ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces'
-import { getExecuteParams, getParsedParamsInQuery, findMarkdownPathByPath, parseParams, findMarkdownPathById } from 'uiSrc/utils'
-import { CodeButtonParams, MOCK_GUIDES_ITEMS, MOCK_TUTORIALS_ITEMS } from 'uiSrc/constants'
+import { getExecuteParams, getParsedParamsInQuery, parseParams, findMarkdownPath } from 'uiSrc/utils'
+import { CodeButtonParams, MOCK_TUTORIALS_ITEMS } from 'uiSrc/constants'
const paramsState: ExecuteQueryParams = {
activeRunQueryMode: RunQueryMode.ASCII,
@@ -51,21 +51,28 @@ describe('getParsedParamsInQuery', () => {
})
})
-const findMarkdownPathByPathTests = [
- { input: '/static/workbench/quick-guides/document/learn-more.md', expected: '0/0' },
- { input: 'quick-guides/working-with-hash.html', expected: '0/2' },
- { input: 'quick-guides/working-with-hash.html', expected: '0/2' },
- { input: 'quick-guides/document-capabilities.html', expected: '1' },
- { input: '/redis_stack/working_with_json.md', manifest: MOCK_TUTORIALS_ITEMS, expected: '4' },
- { input: 'quick-guides', expected: '0/0' },
+const findMarkdownPathTests = [
+ // mdPath
+ { input: { mdPath: '/static/workbench/quick-guides/document/learn-more.md' }, expected: '0/0' },
+ { input: { mdPath: 'quick-guides/working-with-hash.html' }, expected: '0/2' },
+ { input: { mdPath: 'quick-guides/working-with-json.html' }, expected: '0/1' },
+ { input: { mdPath: 'quick-guides/document-capabilities.html' }, expected: '1' },
+ { input: { mdPath: '/redis_stack/working_with_json.md' }, expected: '4' },
+
+ // id
+ { input: { id: 'document-capabilities' }, expected: '0/0' },
+ { input: { id: 'working-with-hash' }, expected: '0/2' },
+ { input: { id: 'working-with-json' }, expected: '0/1' },
+ { input: { id: 'second-internal-page' }, expected: '2' },
+ { input: { id: 'working_with_json' }, expected: '4' },
]
-describe('findMarkdownPathByPath', () => {
- test.each(findMarkdownPathByPathTests)(
+describe('findMarkdownPath', () => {
+ test.each(findMarkdownPathTests)(
'%j',
- ({ input, manifest = MOCK_GUIDES_ITEMS, expected }) => {
+ ({ input, expected }) => {
// @ts-ignore
- const result = findMarkdownPathByPath(manifest, input)
+ const result = findMarkdownPath(MOCK_TUTORIALS_ITEMS, input)
expect(result).toEqual(expected)
}
)
@@ -90,17 +97,3 @@ describe('parseParams', () => {
expect(result).toEqual(expected)
})
})
-
-const findMarkdownPathByIdTests: any[] = [
- ['123', null],
- ['second-internal-page', { args: { path: 'quick-guides/document-capabilities.html' }, id: 'second-internal-page', label: 'Second Internal Page', type: 'internal-link' }],
- ['document-capabilities', { args: { path: '/static/workbench/quick-guides/document/learn-more.md' }, id: 'document-capabilities', label: 'Document Capabilities', type: 'internal-link' }],
-]
-
-describe('findMarkdownPathById', () => {
- it.each(findMarkdownPathByIdTests)('for input: %s (id), should be output: %s',
- (id, expected) => {
- const result = findMarkdownPathById(MOCK_TUTORIALS_ITEMS, id)
- expect(result).toEqual(expected)
- })
-})
diff --git a/redisinsight/ui/src/utils/workbench.ts b/redisinsight/ui/src/utils/workbench.ts
index aa1d76ed11..612fd4a1a6 100644
--- a/redisinsight/ui/src/utils/workbench.ts
+++ b/redisinsight/ui/src/utils/workbench.ts
@@ -3,6 +3,7 @@ import { CodeButtonResults, CodeButtonRunQueryMode, CodeButtonParams } from 'uiS
import { WBQueryType } from 'uiSrc/pages/workbench/constants'
import { EnablementAreaComponent, ExecuteQueryParams, IEnablementAreaItem, IPluginVisualization, ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces'
import { getVisualizationsByCommand } from 'uiSrc/utils/plugins'
+import { store } from 'uiSrc/slices/store'
import { getMonacoLines, isParamsLine } from './monaco'
import { Maybe, Nullable } from './types'
@@ -65,55 +66,40 @@ export const getParsedParamsInQuery = (query: string) => {
return parsedParams
}
-export const findMarkdownPathByPath = (manifest: IEnablementAreaItem[], markdownPath: string) => {
+export const findMarkdownPath = (
+ manifest: IEnablementAreaItem[],
+ { mdPath = '', id = '' }: { mdPath?: string, id?: string }
+): Nullable => {
if (!manifest) return null
- const findPath = (data: IEnablementAreaItem[], mdPath: string, path: number[] = []): Nullable => {
+ const stack: { data: IEnablementAreaItem[]; mdPath: string; id: string; path: number[] }[] = [
+ { data: manifest, mdPath, id, path: [] }
+ ]
+
+ while (stack.length > 0) {
+ const { data, mdPath, id, path } = stack.pop()!
+
for (let i = 0; i < data.length; i++) {
const obj = data[i]
const currentPath = [...path, i]
+ const isCurrentObject = (id && obj.id === id) || (mdPath && obj.args?.path?.includes(mdPath))
- if (obj.type === EnablementAreaComponent.InternalLink && obj.args?.path?.includes(mdPath)) {
- return currentPath
+ if (obj.type === EnablementAreaComponent.InternalLink && isCurrentObject) {
+ return currentPath.join('/')
}
if (obj.type === EnablementAreaComponent.Group && obj.children) {
- const result = findPath(obj.children, mdPath, currentPath)
-
- if (result) {
- return result
- }
+ stack.push({ data: obj.children, mdPath, id, path: currentPath })
}
}
-
- return null
- }
-
- const result = findPath(manifest, markdownPath)
- return result ? result.join('/') : null
-}
-
-export const findMarkdownPathById = (
- manifest: IEnablementAreaItem[] = [],
- id: string = '',
-): Nullable => {
- const stack = [...manifest]
-
- while (stack.length > 0) {
- const currentObject = stack.pop()
-
- if (currentObject?.id === id) {
- return currentObject
- }
-
- if (currentObject?.children) {
- stack.push(...currentObject.children)
- }
}
return null
}
+export const findTutorialPath = (options: { mdPath?: string, id?: string }) =>
+ findMarkdownPath(store.getState().workbench.tutorials?.items, options)
+
const isGroupMode = (mode?: ResultsMode) => mode === ResultsMode.GroupMode
const isRawMode = (mode?: RunQueryMode) => mode === RunQueryMode.Raw
const isSilentMode = (mode?: ResultsMode) => mode === ResultsMode.Silent