Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
9045d09
Add draft implementation of FT.EXPLAIN/FT.EXPLAINCLI vizualization.
GnaneshKunal Dec 28, 2022
2878b55
Add support for ft.profile (plain version) and scrollbar functionality
GnaneshKunal Dec 29, 2022
3c92f20
Add support for ft.profile (non-clustered version) visualization
GnaneshKunal Dec 30, 2022
57604ef
Remove semicolons
GnaneshKunal Dec 30, 2022
843df8a
Center profile info
GnaneshKunal Dec 30, 2022
96f48c9
Merge branch 'main' into ri-explain-plugin
egor-zalenski Jan 5, 2023
26f7264
#RI-3726 - Prepare for vizualizations for Graph and FT profile and ex…
egor-zalenski Jan 5, 2023
9e47c5c
#RI-3726 - Prepare for vizualizations for Graph and FT profile and ex…
egor-zalenski Jan 5, 2023
3ea6c44
Merge pull request #1560 from RedisInsight/main
egor-zalenski Jan 5, 2023
4cf3ede
Merge remote-tracking branch 'origin/ri-explain-plugin' into build/ri…
egor-zalenski Jan 5, 2023
154ac45
Merge pull request #1561 from RedisInsight/build/ri-explain-plugin
egor-zalenski Jan 6, 2023
405ac84
Add support for redisearch cluster profile.
GnaneshKunal Jan 7, 2023
398e6e8
Add support for GRAPH.EXPLAIN and GRAPH.PROFILE
GnaneshKunal Jan 8, 2023
e135c33
Dump regex for simple parsing of size and time
GnaneshKunal Jan 8, 2023
9d7d921
Remove semicolons and fix ternary operator lint
GnaneshKunal Jan 9, 2023
fd4e151
Add support for hovering for search queries
GnaneshKunal Jan 11, 2023
7085375
Add proper recursive redisgraph PROFILE/EXPLAIN level parser
GnaneshKunal Jan 14, 2023
7569daf
- Suffix time with 'ms'
GnaneshKunal Jan 14, 2023
5b2b181
- Edge width should depend on record size.
GnaneshKunal Jan 14, 2023
7c38d91
Highlight ancestors on child node hover
GnaneshKunal Jan 15, 2023
4732c09
Calculate total execution time for redisgraph profile
GnaneshKunal Jan 15, 2023
d8b3889
Parse tags and display them in snippet region if available
GnaneshKunal Jan 17, 2023
5d54e87
- Calculate edge size using log.
GnaneshKunal Jan 21, 2023
fae5e99
Merge branch 'main' into ri-explain-plugin
GnaneshKunal Jan 21, 2023
3e20c4f
Add ability to run a profile/explain right from the query card tab of
GnaneshKunal Jan 22, 2023
fc31b41
Fix comments - https://github.com/RedisInsight/RedisInsight/pull/1537…
GnaneshKunal Jan 23, 2023
f770a43
- Move queryProfile to parent and create a new telement event on the …
GnaneshKunal Jan 23, 2023
9d2e65c
- Add null checks for generate profile command functions
GnaneshKunal Jan 23, 2023
3904a0e
Merge remote-tracking branch 'origin/main' into ri-explain-plugin
GnaneshKunal Jan 24, 2023
c05bdde
Switch back to compactBox layout
GnaneshKunal Jan 25, 2023
eb75d62
Wrap info data for large texts
GnaneshKunal Jan 25, 2023
6355f4c
Merge pull request #1537 from RedisInsight/ri-explain-plugin
GnaneshKunal Jan 25, 2023
752657a
#RI-4021 - Update telemetry WORKBENCH_COMMAND_COPY event
egor-zalenski Jan 26, 2023
d3dbcb4
#RI-4104 - update recommendation link
AmirAllayarovSofteq Jan 27, 2023
df6c227
Merge pull request #1633 from RedisInsight/fe/feature/RI-4021_Telemetry
vlad-dargel Jan 27, 2023
2cd4cb3
Revert "#RI-4021 - Update telemetry WORKBENCH_COMMAND_COPY event"
vlad-dargel Jan 27, 2023
2b54301
Merge pull request #1645 from RedisInsight/bugfix/RI-4104_recommendat…
vlad-dargel Jan 27, 2023
e42e71e
Merge pull request #1647 from RedisInsight/revert-1633-fe/feature/RI-…
vlad-dargel Jan 27, 2023
05428a9
#RI-4110 - remove dangerous commands recommendation
AmirAllayarovSofteq Jan 27, 2023
735947a
#RI-4109 - update ssh private key placeholder
AmirAllayarovSofteq Jan 30, 2023
245368b
Merge pull request #1651 from RedisInsight/feature/RI-4110_remove_dan…
vlad-dargel Jan 30, 2023
d6d131a
Merge pull request #1652 from RedisInsight/feature/RI-4109-ssh-privat…
vlad-dargel Jan 30, 2023
c1a9ac1
#RI-4122 - fix redisearch module property loaded for telemetry
rsergeenko Jan 31, 2023
3ec7047
#RI-4122 - remove import
rsergeenko Jan 31, 2023
6e07f3f
Merge pull request #1654 from RedisInsight/fe/bugfix/RI-4122
vlad-dargel Jan 31, 2023
47913b1
Revert "- Add null checks for generate profile command functions"
GnaneshKunal Jan 31, 2023
efaa720
Revert "- Move queryProfile to parent and create a new telement event…
GnaneshKunal Jan 31, 2023
58a0ccc
Revert "Fix comments - https://github.com/RedisInsight/RedisInsight/p…
GnaneshKunal Jan 31, 2023
dee1683
Revert "Add ability to run a profile/explain right from the query car…
GnaneshKunal Jan 31, 2023
34e429a
Merge pull request #1655 from RedisInsight/fe/bugfix-RI-3726-remove-w…
nmammadli Jan 31, 2023
559b589
Merge pull request #1629 from RedisInsight/feature/RI-3726_profile_ex…
vlad-dargel Jan 31, 2023
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
2 changes: 0 additions & 2 deletions redisinsight/api/src/constants/recommendations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ export const RECOMMENDATION_NAMES = Object.freeze({
REDIS_VERSION: 'redisVersion',
REDIS_SEARCH: 'redisSearch',
SEARCH_INDEXES: 'searchIndexes',
DANGEROUS_COMMANDS: 'dangerousCommands',
});

export const ONE_NODE_RECOMMENDATIONS = [
RECOMMENDATION_NAMES.LUA_SCRIPT,
RECOMMENDATION_NAMES.DANGEROUS_COMMANDS,
RECOMMENDATION_NAMES.AVOID_LOGICAL_DATABASES,
RECOMMENDATION_NAMES.RTS,
RECOMMENDATION_NAMES.REDIS_VERSION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,18 +651,4 @@ describe('RecommendationProvider', () => {
expect(redisVersionRecommendation).toEqual(null);
});
});

describe('determineDangerousCommandsRecommendation', () => {
it('should not return dangerous commands recommendation when "command" command executed with error',
async () => {
resetAllWhenMocks();
when(nodeClient.sendCommand)
.calledWith(jasmine.objectContaining({ name: 'command' }))
.mockRejectedValue('some error');

const dangerousCommandsRecommendation = await service
.determineDangerousCommandsRecommendation(nodeClient);
expect(dangerousCommandsRecommendation).toEqual(null);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -438,39 +438,6 @@ export class RecommendationProvider {
}
}

/*
* Check dangerous commands recommendation
* @param redisClient
*/

async determineDangerousCommandsRecommendation(
redisClient: Redis | Cluster,
): Promise<Recommendation> {
try {
const dangerousCommands = await redisClient.sendCommand(
new Command('ACL', ['CAT', 'dangerous'], { replyEncoding: 'utf8' }),
) as string[];

const filteredDangerousCommands = dangerousCommands.filter((command) => {
const commandName = command.split('|')[0];
return !redisInsightCommands.includes(commandName);
});

const activeDangerousCommands = await Promise.all(
filteredDangerousCommands.map(async (command) => await this.checkCommandInfo(redisClient, command)),
);
const commands = activeDangerousCommands
.filter((command) => !isNull(command))
.join('\r\n').toUpperCase();
return activeDangerousCommands.length
? { name: RECOMMENDATION_NAMES.DANGEROUS_COMMANDS, params: { commands } }
: null;
} catch (err) {
this.logger.error('Can not determine dangerous commands recommendation', err);
return null;
}
}

private async checkAuth(redisClient: Redis | Cluster): Promise<boolean> {
try {
await redisClient.sendCommand(
Expand All @@ -484,20 +451,6 @@ export class RecommendationProvider {
return false;
}

private async checkCommandInfo(redisClient: Redis | Cluster, command: string): Promise<string> {
try {
const result = await redisClient.sendCommand(
new Command('command', ['info', command]),
);
if (isNull(result[0])) {
return null;
}
} catch (err) {
return null;
}
return command;
}

private checkTimestamp(value: string): boolean {
try {
if (!IS_NUMBER_REGEX.test(value) && isValid(new Date(value))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ export class RecommendationService {
RECOMMENDATION_NAMES.SEARCH_INDEXES,
async () => await this.recommendationProvider.determineSearchIndexesRecommendation(client, keys, globalClient),
],
[
RECOMMENDATION_NAMES.DANGEROUS_COMMANDS,
async () => await this.recommendationProvider.determineDangerousCommandsRecommendation(client),
],
[
RECOMMENDATION_NAMES.SET_PASSWORD,
async () => await this.recommendationProvider.determineSetPasswordRecommendation(client),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const QueryCardHeader = (props: Props) => {
setSelectedValue,
onQueryDelete,
onQueryReRun,
onQueryProfile,
db,
} = props

Expand Down
31 changes: 0 additions & 31 deletions redisinsight/ui/src/constants/dbAnalysisRecommendations.json
Original file line number Diff line number Diff line change
Expand Up @@ -687,36 +687,5 @@
}
],
"badges": ["upgrade"]
},
"dangerousCommands": {
"id": "dangerousCommands",
"title": "Rename or disable dangerous commands",
"content": [
{
"id": "1",
"type": "paragraph",
"value": "The following commands are currently not renamed or disabled for your Instance. These commands are powerful and dangerous if not managed properly. Rename or disable them, especially for the production environment"
},
{
"id": "2",
"type": "pre",
"parameter": ["commands"],
"value": "${0} "
},
{
"id": "3",
"type": "spacer",
"value": "s"
},
{
"id": "4",
"type": "link",
"value": {
"href": "https://redis.io/download/",
"name": "Read more"
}
}
],
"badges": ["code_changes"]
}
}
1 change: 1 addition & 0 deletions redisinsight/ui/src/packages/ri-explain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# RI-Explain plugin
71 changes: 71 additions & 0 deletions redisinsight/ui/src/packages/ri-explain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"author": {
"name": "Redis Ltd.",
"email": "support@redis.com",
"url": "https://redis.com/redis-enterprise/redis-insight"
},
"bugs": {
"url": "https://github.com/"
},
"description": "Show Profile/Explain Visualization",
"source": "./src/main.tsx",
"styles": "./dist/styles.css",
"main": "./dist/index.js",
"name": "explain-plugin",
"version": "0.0.1",
"scripts": {
"start": "cross-env NODE_ENV=development parcel serve src/index.html",
"build": "rimraf dist && cross-env NODE_ENV=production concurrently \"yarn build:js && yarn minify:js\" \"yarn build:css\" \"yarn build:assets\"",
"build-lite": "rm dist/*.js && cross-env NODE_ENV=production concurrently \"yarn build:js && yarn minify:js\"",
"build:js": "parcel build src/main.tsx --dist-dir dist",
"build:css": "parcel build src/styles/styles.less --dist-dir dist",
"build:assets": "parcel build src/assets/**/* --dist-dir dist",
"minify:js": "terser -- dist/main.js > dist/index.js && rimraf dist/main.js"
},
"targets": {
"main": false,
"module": {
"includeNodeModules": true
}
},
"visualizations": [
{
"id": "profile-explain-viz",
"name": "Visualization",
"activationMethod": "renderCore",
"matchCommands": [
"FT.EXPLAIN",
"FT.EXPLAINCLI",
"FT.PROFILE",
"GRAPH.EXPLAIN",
"GRAPH.PROFILE"
],
"iconDark": "./dist/profile_icon_dark.svg",
"iconLight": "./dist/profile_icon_light.svg",
"description": "Profile/Explain plugin Visualization",
"default": true
}
],
"devDependencies": {
"@parcel/compressor-brotli": "^2.0.0",
"@parcel/compressor-gzip": "^2.0.0",
"@parcel/transformer-less": "^2.3.2",
"concurrently": "^6.3.0",
"cross-env": "^7.0.3",
"parcel": "^2.0.0",
"rimraf": "^3.0.2",
"terser": "^5.9.0"
},
"dependencies": {
"@antv/hierarchy": "^0.6.8",
"@antv/x6": "^2.1.3",
"@antv/x6-react-shape": "^2.1.0",
"@elastic/eui": "34.6.0",
"@emotion/react": "^11.7.1",
"classnames": "^2.3.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"uuid": "^9.0.0"
}
}
27 changes: 27 additions & 0 deletions redisinsight/ui/src/packages/ri-explain/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import Explain from './Explain'

const isDarkTheme = document.body.classList.contains('theme_DARK')

export function App(props: { command?: string, data: any }) {

const ErrorResponse = HandleError(props)

if (ErrorResponse !== null) return ErrorResponse

return (
<div id="mainApp" style={{ height: "100%", width: '100%', overflowX: 'auto' }}>
<Explain command={props.command || ''} data={props.data}/>
</div>
)
}

function HandleError(props: { command?: string, data: any }): JSX.Element | null {
const { data: [{ response = '', status = '' } = {}] = [] } = props

if (status === 'fail') {
return <div className="responseFail">{JSON.stringify(response)}</div>
}

return null
}
Loading