Plugin name. It is recommended to use the folder name as the plugin name in the package.json.
+
+
+
main
+
Relative path to the core script of the plugin. Example: "./dist/index.js"
+
+
+
visualizations
+
+ Array of visualizations (objects) to visualize the results in the Workbench.
+
+ Required fields in visualizations:
+
+
id - visualization id
+
name - visualization name to display in the Workbench
+
activationMethod - name of the exported function to call when
+this visualization is selected in the Workbench
+
+ matchCommands - array of commands to use the visualization for. Supports regex string.
+ Example: ["CLIENT LIST", "FT.*"]
+
+
+
+
+
+
+You can specify the path to a css file in the `styles` field. If specified,
+this file will be included inside the iframe plugin.
+
+Simple example of the `package.json` file with required and optional fields:
+
+```json
+{
+ "author": {
+ "name": "Redis Ltd.",
+ "email": "support@redis.com",
+ "url": "https://redis.com/redis-enterprise/redis-insight"
+ },
+ "description": "Show client list as table",
+ "styles": "./dist/styles.css",
+ "main": "./dist/index.js",
+ "name": "client-list",
+ "version": "0.0.1",
+ "scripts": {},
+ "visualizations": [
+ {
+ "id": "clients-list",
+ "name": "Table",
+ "activationMethod": "renderClientsList",
+ "matchCommands": [
+ "CLIENT LIST"
+ ],
+ "description": "Example of client list plugin",
+ "default": true
+ }
+ ],
+ "devDependencies": {},
+ "dependencies": {}
+}
+```
+
+## Core script of the plugin
+
+This is the required script with defined visualization methods.
+The core script contains function and its export (functions - for multiple visualizations),
+which is run after the relevant visualization is selected in the Workbench.
+
+The following function receives props of the executed commands:
+```typescript
+interface Props {
+ command: string; // executed command
+ data: string; // result of the executed command
+ status: 'success' | 'fail'; // response status of the executed command
+}
+
+const renderVisualization = (props: Props) => {
+ // Do your magic
+}
+
+export default { renderVisualization }
+```
+
+Each plugin iframe has basic styles of RedisInsight application, including fonts and color schemes.
+
+It is recommended to use the React & [Elastic UI library](https://elastic.github.io/eui/#/) for
+consistency with plugin visualisations and the entire application.
+
+Find the example of the plugin here.
+
+* [Client List Plugin README](../../redisinsight/ui/src/packages/clients-list-example/README.md)
+* [Client List Plugin dir](../../redisinsight/ui/src/packages/clients-list-example/)
+
+### Available parameters
+
+Additional information provided to the plugin iframe is included in the `window.state`
+inside of the plugin script.
+
+```javascript
+const { config, modules } = window.state
+const { baseUrl } = config
+
+// modules - the list of modules of the current database
+// baseUrl - url for your plugin folder - can be used to include your assets
+```
+
+### Plugin rendering
+To render the plugin visualization, the iframe with basic html is generated which is
+then populated with relevant scripts and styles. To render the html data, use existing
+DOM Element `#app` or create your own DOM Elements.
+Rendered iframe also includes `theme_DARK` or `theme_LIGHT` className on `body` to indicate the application theme used.
+
+_Javascript Example:_
+```javascript
+const renderVisualization = (props) => {
+ const { command, data } = props;
+ document.getElementById('app')
+ .innerHTML = `
+
Executed command:
+
${command}
+
Result of the command
+
${data}
+ `
+}
+
+export default { renderVisualization }
+```
+
+_React Example:_
+```javascript
+import { render } from 'react-dom'
+import App from './App'
+
+const renderVisualization = (props) => {
+ const { command, status, data = '' } = props
+ render(
+ ,
+ document.getElementById('app')
+ )
+}
+
+// This is a required action - export the main function for execution of the visualization
+export default { renderVisualization }
+```
+
+
+## Plugins communication
+> **_Future updates:_**
+Support of communication with the main application via a third-party library - _redisinsight-plugin-sdk_.
diff --git a/docs/plugins/installation.md b/docs/plugins/installation.md
new file mode 100644
index 0000000000..cff18847f4
--- /dev/null
+++ b/docs/plugins/installation.md
@@ -0,0 +1,30 @@
+# Plugin installation & Usage
+
+This document describes the guides to add `plugins` for the Workbench to RedisInsight.
+
+## Installation guide
+
+**Note**: While adding new plugins for Workbench, use files only from trusted
+authors to avoid automatic execution of malicious code.
+
+1. Download the plugin for the Workbench.
+2. Open the `plugins` folder with the following path
+ * For MacOs: `/.redisinsight-v2.0/plugins`
+ * For Windows: `C:\Users\{Username}\.redisinsight-v2.0\plugins`
+ * For Linux: `/.redisinsight-v2.0/plugins`
+3. Add the folder with plugin to the `plugins` folder
+
+To see the uploaded plugin visualizations in the command results, reload the Workbench
+page and run Redis command relevant for this visualization.
+
+
+## Usage
+
+The plugin may contain different visualizations for any Redis commands.
+Below you can find a guide to see command results in the uploaded plugin visualization:
+
+1. Open RedisInsight
+2. Open a database added
+3. Open the Workbench
+4. Run the Redis command relevant for the plugin visualization
+5. Select the plugin visualization to display results in (if this visualization has not been set by default)
diff --git a/docs/plugins/introduction.md b/docs/plugins/introduction.md
new file mode 100644
index 0000000000..d585af2ab1
--- /dev/null
+++ b/docs/plugins/introduction.md
@@ -0,0 +1,9 @@
+# Introduction to plugins for the Workbench
+
+Plugins allow the customization of visualizations for Redis commands executed
+in the Workbench inside the RedisInsight.
+
+## Wiki
+
+* [Installation and Usage](installation.md)
+* [Plugin Development](development.md)
diff --git a/electron-builder.json b/electron-builder.json
index b7b893e969..9c046951c8 100644
--- a/electron-builder.json
+++ b/electron-builder.json
@@ -6,6 +6,7 @@
"dist/",
"node_modules/",
"index.html",
+ "splash.html",
"main.prod.js",
"main.prod.js.map",
"package.json"
diff --git a/redisinsight/api/README.md b/redisinsight/api/README.md
new file mode 100644
index 0000000000..e3e09c1b52
--- /dev/null
+++ b/redisinsight/api/README.md
@@ -0,0 +1,63 @@
+# RedisInsight API
+
+## Description
+RedisInsight provides an intuitive and efficient GUI for Redis, allowing you to interact with your databases and manage your data—with built-in support for most popular Redis modules. It provides tools to analyze the memory, profile the performance of your database usage, and guide you toward better Redis usage.
+
+## Prerequisites
+
+Make sure you have installed following packages:
+* [Node](https://nodejs.org/en/download/) >= 8.0
+* [npm](https://www.npmjs.com/get-npm) >= 5
+
+## Dependencies used
+* [NestJS](https://nestjs.com/)
+
+## Getting started
+
+### Installation
+
+```bash
+$ yarn install
+```
+
+### Running the app
+
+```bash
+# development
+$ yarn start
+
+# watch mode
+$ yarn start:dev
+
+# production mode
+$ yarn start:prod
+```
+
+### Formatting
+
+Formatting required before submitting pull request.
+
+Prints the filenames of files that are different from Prettier formatting
+```bash
+$ yarn format
+```
+### Swagger OpenApi
+
+The [OpenAPI](https://swagger.io/specification/) specification is a language-agnostic definition format used
+to describe RESTful APIs.
+
+While the application is running, open your browser and navigate to `http://localhost[:]/api/docs`.
+You should see the Swagger UI.
+
+### Test
+
+```bash
+# unit tests
+$ yarn test
+
+# e2e tests
+$ yarn test:e2e
+
+# test coverage
+$ yarn test:cov
+```
diff --git a/redisinsight/api/src/exceptions/global-exception.filter.ts b/redisinsight/api/src/exceptions/global-exception.filter.ts
new file mode 100644
index 0000000000..d43974372b
--- /dev/null
+++ b/redisinsight/api/src/exceptions/global-exception.filter.ts
@@ -0,0 +1,27 @@
+import { BaseExceptionFilter } from '@nestjs/core';
+import { ArgumentsHost, Logger } from '@nestjs/common';
+import { Request, Response } from 'express';
+
+export class GlobalExceptionFilter extends BaseExceptionFilter {
+ private staticServerLogger = new Logger('StaticServerLogger');
+
+ catch(exception: Error, host: ArgumentsHost) {
+ const ctx = host.switchToHttp();
+ const request = ctx.getRequest();
+
+ if (/^\/(?:plugins|static)\//i.test(request.url)) {
+ const response = ctx.getResponse();
+ const statusCode = exception['statusCode'] || 500;
+ const message = `Error when trying to fetch ${request.url}`;
+
+ this.staticServerLogger.error(message, { ...exception } as any);
+ return response.status(statusCode)
+ .json({
+ statusCode,
+ message,
+ });
+ }
+
+ return super.catch(exception, host);
+ }
+}
diff --git a/redisinsight/api/src/main.ts b/redisinsight/api/src/main.ts
index ce34af83e2..13a9fa7893 100644
--- a/redisinsight/api/src/main.ts
+++ b/redisinsight/api/src/main.ts
@@ -3,6 +3,7 @@ import { SwaggerModule } from '@nestjs/swagger';
import { NestApplicationOptions } from '@nestjs/common';
import * as bodyParser from 'body-parser';
import { WinstonModule } from 'nest-winston';
+import { GlobalExceptionFilter } from 'src/exceptions/global-exception.filter';
import { AppModule } from './app.module';
import SWAGGER_CONFIG from '../config/swagger';
import LOGGER_CONFIG from '../config/logger';
@@ -22,7 +23,7 @@ export default async function bootstrap() {
}
const app = await NestFactory.create(AppModule, options);
-
+ app.useGlobalFilters(new GlobalExceptionFilter(app.getHttpAdapter()));
app.use(bodyParser.json({ limit: '512mb' }));
app.use(bodyParser.urlencoded({ limit: '512mb', extended: true }));
app.enableCors();
diff --git a/redisinsight/main.dev.ts b/redisinsight/main.dev.ts
index 96cc4c6103..108625e1a5 100644
--- a/redisinsight/main.dev.ts
+++ b/redisinsight/main.dev.ts
@@ -94,7 +94,7 @@ export const getDisplayAppInTrayValue = (): boolean => {
/**
* Backend part...
*/
-const port = 5000;
+const port = 5001;
const launchApiServer = async () => {
try {
const detectPortConst = await detectPort(port);
@@ -134,19 +134,35 @@ const bootstrap = async () => {
export const windows = new Set();
-export const createWindow = async () => {
+const titleSplash = 'splash';
+export const createSplashScreen = async () => {
+ const splash = new BrowserWindow({
+ width: 500,
+ height: 200,
+ transparent: true,
+ frame: false,
+ resizable: false,
+ alwaysOnTop: true,
+ title: titleSplash,
+ });
+
+ splash.loadURL(`file://${__dirname}/splash.html`);
+
+ return splash;
+};
+
+export const createWindow = async (splash: BrowserWindow | null) => {
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'resources')
: path.join(__dirname, '../resources');
- const getAssetPath = (...paths: string[]): string => {
- return path.join(RESOURCES_PATH, ...paths);
- };
+ const getAssetPath = (...paths: string[]): string => path.join(RESOURCES_PATH, ...paths);
let x;
let y;
const currentWindow = BrowserWindow.getFocusedWindow();
- if (currentWindow) {
+
+ if (currentWindow && currentWindow?.getTitle() !== titleSplash) {
const [currentWindowX, currentWindowY] = currentWindow.getPosition();
x = currentWindowX + 24;
y = currentWindowY + 24;
@@ -188,8 +204,9 @@ export const createWindow = async () => {
if (process.env.START_MINIMIZED) {
newWindow.minimize();
} else {
- newWindow.show();
- newWindow.focus();
+ newWindow?.show();
+ newWindow?.focus();
+ splash?.close();
}
});
@@ -293,7 +310,11 @@ app.on('continue-activity-error', (event, type, error) => {
}
});
-app.whenReady().then(bootstrap).then(createWindow).catch(console.log);
+app.whenReady()
+ .then(bootstrap)
+ .then(createSplashScreen)
+ .then(createWindow)
+ .catch(console.log);
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
diff --git a/redisinsight/splash.html b/redisinsight/splash.html
new file mode 100644
index 0000000000..5763e7345a
--- /dev/null
+++ b/redisinsight/splash.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts b/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
index 46e177974b..25dd61a1e3 100644
--- a/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
+++ b/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
@@ -69,4 +69,16 @@ export const FILTER_GROUP_TYPE_OPTIONS = [
text: 'JSON',
value: CommandGroup.JSON,
},
+ {
+ text: 'TimeSeries',
+ value: CommandGroup.TimeSeries,
+ },
+ {
+ text: 'Graph',
+ value: CommandGroup.Graph,
+ },
+ {
+ text: 'AI',
+ value: CommandGroup.AI,
+ },
]
diff --git a/redisinsight/ui/src/constants/commands.ts b/redisinsight/ui/src/constants/commands.ts
index 531cf7aee9..b67dfd9c6b 100644
--- a/redisinsight/ui/src/constants/commands.ts
+++ b/redisinsight/ui/src/constants/commands.ts
@@ -56,6 +56,9 @@ export enum CommandGroup {
String = 'string',
Search = 'search',
JSON = 'json',
+ TimeSeries = 'timeseries',
+ Graph = 'graph',
+ AI = 'ai'
}
export enum CommandRediSearch {
diff --git a/redisinsight/ui/src/packages/clients-list-example/README.md b/redisinsight/ui/src/packages/clients-list-example/README.md
new file mode 100644
index 0000000000..40443ad0a0
--- /dev/null
+++ b/redisinsight/ui/src/packages/clients-list-example/README.md
@@ -0,0 +1,34 @@
+# Example of the plugin for the “Client List” command
+
+The example has been created using React, TypeScript, and [Elastic UI](https://elastic.github.io/eui/#/).
+[Parcel](https://parceljs.org/) is used to build the plugin.
+
+## Running locally
+
+The following commands will install dependencies and start the server to run the plugin locally:
+```
+yarn
+yarn start
+```
+These commands will install dependencies and start the server.
+
+_Note_: Base styles are included to `index.html` from the repository.
+
+This command will generate the `vendor` folder with styles and fonts of the core app. Add this folder
+inside the folder for your plugin and include appropriate styles to the `index.html` file.
+
+```
+yarn build:statics - for Linux or MacOs
+yarn build:statics:win - for Windows
+```
+
+## Build plugin
+
+The following commands will build plugins to be used in RedisInsight:
+```
+yarn
+yarn build
+```
+
+[Add](../../../../../docs/plugins/installation.md) the package.json file and the
+`dist` folder to the folder with your plugin, which should be located in the `plugins` folder.
diff --git a/redisinsight/ui/src/packages/clients-list-example/src/main.tsx b/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
index ff97fb6f3e..51359287e9 100644
--- a/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
+++ b/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
@@ -20,4 +20,5 @@ if (process.env.NODE_ENV === 'development') {
renderClientsList({ command: '', data: response, status: 'success' })
}
+// This is a required action - export the main function for execution of the visualization
export default { renderClientsList }
diff --git a/redisinsight/ui/src/packages/enablement-area/enablement-area.json b/redisinsight/ui/src/packages/enablement-area/enablement-area.json
index 2c00feb4e3..c4582ef82e 100644
--- a/redisinsight/ui/src/packages/enablement-area/enablement-area.json
+++ b/redisinsight/ui/src/packages/enablement-area/enablement-area.json
@@ -33,6 +33,24 @@
"backTitle": "Document Capabilities",
"path": "/static/workbench/guides/document-capabilities/working-with-hashes.html"
}
+ },
+ {
+ "type": "internal-link",
+ "id": "working-with-json",
+ "label": "Working with JSON",
+ "args": {
+ "backTitle": "Document Capabilities",
+ "path": "/static/workbench/guides/document-capabilities/working-with-json.html"
+ }
+ },
+ {
+ "type": "internal-link",
+ "id": "learn-more",
+ "label": "Learn More",
+ "args": {
+ "backTitle": "Document Capabilities",
+ "path": "/static/workbench/guides/document-capabilities/learn-more.html"
+ }
}
]
}
diff --git a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
index 5f58e7011d..e573784324 100644
--- a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
+++ b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
@@ -3,8 +3,8 @@
Full-text search and querying is supported for both Hashes and JSON via a secondary index.
+
Full-text search and querying is supported for both Hashes and JSON via a secondary index.
A number of data types are available for indexing:
@@ -32,7 +32,7 @@
Numeric range index
Tag index supporting multiple values
Geo index
-
Vector index
+
Vector index (upcoming)
@@ -58,10 +58,10 @@
PRE-REQUISITES
Follow these instructions to set up the RedisJSON and RediSearch modules on Redis OSS.
- For working with Hashes you will need Redis >=6, RediSearch >=2.0.
+ For working with Hashes you will need Redis >=6, RediSearch >=2.0.
- For working with JSON you will need Redis >=6, RediSearch >=2.2 and RedisJSON >=2.0.
+ For working with JSON you will need Redis >=6, RediSearch >=2.2 and RedisJSON >=2.0.
You could also create a free and ready to use instance on Redis Cloud.
diff --git a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html
new file mode 100644
index 0000000000..3f527f58da
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html
@@ -0,0 +1,56 @@
+
+
! Click on the button, see the command and the comments in the Workbench editor, and then run it.
+
Click on the button, see the command and the comments in the Workbench editor, and then run it.
diff --git a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/working-with-json.html b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/working-with-json.html
new file mode 100644
index 0000000000..3d23498dbc
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/working-with-json.html
@@ -0,0 +1,169 @@
+
+
+
Click on the button, see the command and the comments in the Workbench editor, and then run it.
+
+
+
+ CRUD operations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Secondary Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search and Querying Basics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-hashes/multiple-tags-or-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-hashes/multiple-tags-or-search.txt
index 942c0a627a..4644cc619f 100644
--- a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-hashes/multiple-tags-or-search.txt
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-hashes/multiple-tags-or-search.txt
@@ -1,4 +1,4 @@
-// Perform a search for documents that have one of multiple tags (OR condition)
+// Perform a search for documents that have one of multiple tags (OR condition)
FT.SEARCH "permits" "@work_type:{construction|design}"
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-and.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-and.txt
new file mode 100644
index 0000000000..e72baa6c0e
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-and.txt
@@ -0,0 +1,19 @@
+// Perform a combined search on two fields (AND): query for intersection of both search terms, a text search and a tag match
+
+FT.SEARCH "schools" "@description:girls @status:{closed}"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-geo-filter.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-geo-filter.txt
new file mode 100644
index 0000000000..83ec2b9109
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-geo-filter.txt
@@ -0,0 +1,19 @@
+// Perform a fuzzy text search and filter on location in a radius distance of 10 miles
+
+FT.SEARCH "schools" "%%gill%%" GEOFILTER location 51.11 0.45 10 mi
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-or.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-or.txt
new file mode 100644
index 0000000000..fa28f448e0
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-or.txt
@@ -0,0 +1,19 @@
+// Perform a combined search on two fields (OR): query for union of both search terms. The brackets are important.
+
+FT.SEARCH "schools" "(@city:{Oxford})|(@description:girls)"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/create-json-index.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/create-json-index.txt
new file mode 100644
index 0000000000..aa4972fce4
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/create-json-index.txt
@@ -0,0 +1,24 @@
+// It is possible to index either every hash or every JSON document in the keyspace or configure indexing only for a subset of the same data type documents described by a prefix.
+
+// RedisJSON supports JSONPath, so we can easily access and index nested properties and array elements.
+// Note that you cannot index values that contain JSON objects or JSON arrays. To be indexed, a JSONPath expression must return a single scalar value (string or number). If the JSONPath expression returns an object or an array, it will be ignored.
+
+// JSON Strings can only be indexed as TEXT, TAG and GEO (using the right syntax).
+// JSON numbers can only be indexed as NUMERIC.
+// Boolean and NULL values are ignored.
+
+// Command to create an index on JSON keys that are prefixed with "school:"
+
+FT.CREATE schools // Index name
+ on JSON // Indicates the type of data to index
+ PREFIX 1 "school:" // Tells the index which keys it should index
+ SCHEMA
+ $.name AS name TEXT NOSTEM SORTABLE // Will be indexed as a TEXT field. Will permit sorting during query. Stemming is disabled - which is ideal for proper names.
+ $.description AS description TEXT
+ $.school_type AS school_type TAG SEPARATOR ";" // For tag fields, a separator indicates how the text contained in the field is to be split into individual tags
+ $.class AS class TAG // Will be indexed as a tag. Will allow exact-match queries.
+ $.address.street AS address TEXT NOSTEM // '$.address.street' field will be indexed as TEXT and can be referred as 'street' due to the '... AS fieldname ...' construct.
+ $.address.city AS city TAG
+ $.pupils AS pupils NUMERIC SORTABLE // Will be indexed as a numeric field. Will permit sorting during query
+ $.location AS location GEO // Will be indexed as GEO. Will allow geographic range queries
+ $.status_log.[-1] as status TAG // Will index the last element of the array as "status"
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-create.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-create.txt
new file mode 100644
index 0000000000..5904384541
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-create.txt
@@ -0,0 +1,11 @@
+// Let's add four documents as JSON to the index. Note the format of the key names.
+// Each document represents a school.
+
+JSON.SET school:1 . '{"name":"Hall School", "description":"Independent primary school for boys aged 5 to 11","school_type":"single;boys","class":"independent", "address":{"city":"London", "street":"Manor Street"}, "pupils":342, "location":"51.445417, -0.258352", "status_log":["new", "operating"]}'
+
+JSON.SET school:2 . '{"name":"Garden School", "description":"State school for boys and girls aged 5 to 18","school_type":"mixed;boys;girls","class":"state", "address":{"city":"London", "street":"Gordon Street"}, "pupils":1452, "location":"51.402926, -0.321523", "status_log":["new", "operating"]}'
+
+JSON.SET school:3 . '{"name":"Gillford School", "description":"Independent school for girls aged 5 to 18","school_type":"single;girls","class":"private", "address":{"city":"Goudhurst", "street":"Goudhurst"}, "pupils":721, "location":"51.112685, 0.451076", "status_log":["new", "operating", "closed"]}'
+
+JSON.SET school:4 . '{"name":"Old Boys School", "description":"Independent school for boys aged 5 to 18","school_type":"single;boys","class":"independent", "address":{"city":"Oxford", "street":"Trident Street"}, "pupils":1200, "location":"51.781756, -1.123196", "status_log":["new", "operating"]}'
+
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-delete.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-delete.txt
new file mode 100644
index 0000000000..68970feb23
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-delete.txt
@@ -0,0 +1,9 @@
+JSON.GET school:1 $.pupils // Read the pupils field before deletion
+
+JSON.DEL school:1 $.pupils // Delete only the pupils field from the document
+
+JSON.GET school:1 // Read the whole document to confirm the construction_value field has been deleted
+
+JSON.DEL school:1 // Delete the entire document
+
+JSON.GET school:1 // Confirm the entire document has been deleted
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-read.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-read.txt
new file mode 100644
index 0000000000..9af0845a6c
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-read.txt
@@ -0,0 +1,5 @@
+JSON.GET school:1 // Read the whole document
+
+// RedisJSON supports JSONPath, so we can easily access nested properties using $. construct
+
+JSON.GET school:1 $.description // Read only the field description
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-update.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-update.txt
new file mode 100644
index 0000000000..b9cb1e0f19
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-update.txt
@@ -0,0 +1,5 @@
+JSON.GET school:1 $.pupils // Read the pupils field before the update
+
+JSON.SET school:1 $.pupils 430 // Update the pupils field
+
+JSON.GET school:1 $.pupils // Read the pupils field after the update
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/exact-text-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/exact-text-search.txt
new file mode 100644
index 0000000000..64d41fabeb
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/exact-text-search.txt
@@ -0,0 +1,19 @@
+// Perform a text search on all text fields: query for documents inside which the word 'girls' occurs
+
+FT.SEARCH "schools" "girls"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/field-specific-text-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/field-specific-text-search.txt
new file mode 100644
index 0000000000..a30dae9d82
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/field-specific-text-search.txt
@@ -0,0 +1,20 @@
+// Perform a text search on a specific field: query for documents which have a field 'name' inside which the word 'old' occurs
+// To reference a field, use @ construct
+
+FT.SEARCH "schools" "@name:old"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/fuzzy-text-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/fuzzy-text-search.txt
new file mode 100644
index 0000000000..5b3b140140
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/fuzzy-text-search.txt
@@ -0,0 +1,19 @@
+// Perform a Fuzzy text search on all text fields: query for documents with words similar to 'gill'. The number of % indicates the allowed Levenshtein distance. So the query would also match on 'girl' because 'gill' and 'girl' have a distance of two.
+
+FT.SEARCH "schools" "%%gill%%"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/group-and-sort-by-aggregation.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/group-and-sort-by-aggregation.txt
new file mode 100644
index 0000000000..80cbfa4f90
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/group-and-sort-by-aggregation.txt
@@ -0,0 +1,25 @@
+// Aggregations are a way to process the results of a search query, group, sort and transform them - and extract analytic insights from them.
+// Aggregations are represented as the following data processing pipeline:
+// Filter -> Group (Reduce) -> Apply -> Sort -> Apply
+
+// Perform a Group By & Sort By aggregation of your documents: display the number of permits by city and then sort the city alphabetically
+
+FT.AGGREGATE "schools" "*"
+ GROUPBY 1 @city REDUCE COUNT 0 AS nb_of_schools
+ SORTBY 2 @city Asc
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/index-info.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/index-info.txt
new file mode 100644
index 0000000000..40ab37462a
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/index-info.txt
@@ -0,0 +1,5 @@
+// Command to display information about a particular index.
+// In this case display the information about the newly created "schools" index
+
+FT.INFO "schools"
+
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/list-all-indexes.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/list-all-indexes.txt
new file mode 100644
index 0000000000..01a7b83a5b
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/list-all-indexes.txt
@@ -0,0 +1,3 @@
+// Command to return the list of all existing indexes
+
+FT._LIST
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-and-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-and-search.txt
new file mode 100644
index 0000000000..f95fbbb128
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-and-search.txt
@@ -0,0 +1,19 @@
+// Perform a search for documents that all of the tags (AND condition)
+
+FT.SEARCH "schools" "@school_type:{single} @school_type:{girls}"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-or-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-or-search.txt
new file mode 100644
index 0000000000..2713ed5863
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-or-search.txt
@@ -0,0 +1,19 @@
+// Perform a search for documents that have one of multiple tags (OR condition)
+
+FT.SEARCH "schools" "@school_type:{single|girls}"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/numeric-range-query.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/numeric-range-query.txt
new file mode 100644
index 0000000000..91dfb9725d
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/numeric-range-query.txt
@@ -0,0 +1,21 @@
+// Perform a numeric range query: query for every document that has a 'pupils' value between 0 and 1000
+// For numerical ranges, square brackets are inclusive of the listed values
+
+FT.SEARCH "schools" "@pupils:[0,1000]"
+
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+// $.status_log.[-1] as status TAG
diff --git a/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/tag-search.txt b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/tag-search.txt
new file mode 100644
index 0000000000..bb1abaf392
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/tag-search.txt
@@ -0,0 +1,19 @@
+// Perform a tag search: query for documents which have the city field set to "London". Note that we use curly braces around the tag.
+
+FT.SEARCH "schools" "@city:{Oxford}"
+
+// See the "schools" index schema for reference
+
+// FT.CREATE schools
+// on JSON
+// PREFIX 1 "school:"
+// SCHEMA
+// $.name AS name TEXT NOSTEM SORTABLE
+// $.description AS description TEXT
+// $.school_type AS school_type TAG SEPARATOR ";"
+// $.class AS class TAG
+// $.address.street AS address TEXT NOSTEM
+// $.address.city AS city TAG
+// $.pupils AS pupils NUMERIC SORTABLE
+// $.location AS location GEO
+//
diff --git a/redisinsight/ui/src/packages/redisearch/src/components/TableInfoResult/TableInfoResult.tsx b/redisinsight/ui/src/packages/redisearch/src/components/TableInfoResult/TableInfoResult.tsx
index 42a9086bd0..57d956852d 100644
--- a/redisinsight/ui/src/packages/redisearch/src/components/TableInfoResult/TableInfoResult.tsx
+++ b/redisinsight/ui/src/packages/redisearch/src/components/TableInfoResult/TableInfoResult.tsx
@@ -120,6 +120,7 @@ const TableInfoResult = React.memo((props: Props) => {
className={cx('inMemoryTableDefault', 'tableInfo', {
tableWithPagination: result?.length > 10,
})}
+ responsive={false}
data-testid={`query-table-result-${query}`}
/>
{Footer()}
diff --git a/redisinsight/ui/src/packages/redisearch/src/components/TableResult/TableResult.tsx b/redisinsight/ui/src/packages/redisearch/src/components/TableResult/TableResult.tsx
index b497a0adfa..1d115634d0 100644
--- a/redisinsight/ui/src/packages/redisearch/src/components/TableResult/TableResult.tsx
+++ b/redisinsight/ui/src/packages/redisearch/src/components/TableResult/TableResult.tsx
@@ -117,6 +117,7 @@ const TableResult = React.memo((props: Props) => {
tableWithPagination: result?.length > 10,
}
)}
+ responsive={false}
data-testid={`query-table-result-${query}`}
/>
)}
diff --git a/redisinsight/ui/src/pages/browser/components/list-details/ListDetails.tsx b/redisinsight/ui/src/pages/browser/components/list-details/ListDetails.tsx
index e6a4ab0c01..7f216c5cc2 100644
--- a/redisinsight/ui/src/pages/browser/components/list-details/ListDetails.tsx
+++ b/redisinsight/ui/src/pages/browser/components/list-details/ListDetails.tsx
@@ -2,7 +2,7 @@ import { EuiButtonIcon, EuiText, EuiToolTip } from '@elastic/eui'
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import cx from 'classnames'
-import { isNull } from 'lodash'
+import { isEqual, isNull } from 'lodash'
import { SCAN_COUNT_DEFAULT } from 'uiSrc/constants/api'
import {
@@ -66,10 +66,16 @@ const ListDetails = (props: Props) => {
}, [loadedElements])
const handleEditElement = (index = 0, editing: boolean) => {
- const elems = [...elements]
- elems[index].editing = editing
-
- setElements(elems)
+ const newElemsState = elements.map((item) => {
+ if (item.index === index) {
+ return { ...item, editing }
+ }
+ return item
+ })
+
+ if (!isEqual(elements, newElemsState)) {
+ setElements(newElemsState)
+ }
}
const handleApplyEditElement = (index = 0, element: string) => {
diff --git a/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/Group/styles.scss b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/Group/styles.scss
index 1172ecc8c5..466d660140 100644
--- a/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/Group/styles.scss
+++ b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/Group/styles.scss
@@ -34,6 +34,10 @@
.euiListGroupItem {
button {
padding: 3px 8px;
+ line-height: 24px;
+ }
+ .euiListGroupItem__label {
+ line-height: 20px;
}
}
}
diff --git a/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/InternalLink.tsx b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/InternalLink.tsx
index 06f32ca0dd..328c24dad4 100644
--- a/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/InternalLink.tsx
+++ b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/InternalLink.tsx
@@ -4,6 +4,7 @@ import cx from 'classnames'
import EnablementAreaContext from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
import styles from './styles.module.scss'
+import './styles.scss'
export interface Props {
testId: string,
diff --git a/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/styles.scss b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/styles.scss
new file mode 100644
index 0000000000..f1b7d39490
--- /dev/null
+++ b/redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/styles.scss
@@ -0,0 +1,3 @@
+.euiListGroupItem--xSmall .euiListGroupItem__label {
+ line-height: 12px;
+}
diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx
index b70b04bc16..504d61728c 100644
--- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx
+++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx
@@ -79,7 +79,7 @@ const WBView = (props: Props) => {
{ isCollapsed.current = !isCollapsed.current }}
@@ -92,11 +92,12 @@ const WBView = (props: Props) => {
data-test-subj="resize-btn-preselects-area"
/>
{(EuiResizablePanel, EuiResizableButton) => (
@@ -106,6 +107,7 @@ const WBView = (props: Props) => {
minSize="140px"
paddingSize="none"
scrollable={false}
+ className={styles.queryPanel}
initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20}
style={{ minHeight: '140px' }}
>
@@ -129,7 +131,9 @@ const WBView = (props: Props) => {
paddingSize="none"
scrollable={false}
initialSize={vertical[verticalPanelIds.secondPanelId] ?? 80}
- className={styles.queryResults}
+ className={cx(styles.queryResults, styles.queryResultsPanel)}
+ // Fix scroll on low height - 140px (queryPanel)
+ style={{ maxHeight: 'calc(100% - 140px)' }}
>
{
- state.data.elements[payload.index] = payload.element
+ state.data.elements[state.data.elements.length === 1 ? 0 : payload.index] = payload.element
},
insertListElements: (state) => {
state.loading = true
diff --git a/redisinsight/ui/src/utils/commands.ts b/redisinsight/ui/src/utils/commands.ts
index 1053257a98..0a9006af89 100644
--- a/redisinsight/ui/src/utils/commands.ts
+++ b/redisinsight/ui/src/utils/commands.ts
@@ -49,26 +49,30 @@ export const generateArgsNames = (
isEmpty
)
+const getExternalCommandFormat = (commandName = '') =>
+ commandName
+ .replace(/\s+/g, '_')
+ .replace(/[.]+/g, '')
+ .toLowerCase()
+
export const getDocUrlForCommand = (
commandName: string,
commandGroup: CommandGroup | string = CommandGroup.Generic
): string => {
- let commandPage = ''
+ let command = getExternalCommandFormat(commandName)
switch (commandGroup) {
case CommandGroup.Search:
- commandPage = commandName
- .replace(/\s+/g, '_')
- .replace(/[.]+/g, '')
- .toLowerCase()
- return `https://oss.redis.com/redisearch/Commands/#${commandPage}`
+ return `https://oss.redis.com/redisearch/Commands/#${command}`
case CommandGroup.JSON:
- commandPage = commandName
- .replace(/\s+/g, '_')
- .replace(/[.]+/g, '')
- .toLowerCase()
- return `https://oss.redis.com/redisjson/commands/#${commandPage}`
+ return `https://oss.redis.com/redisjson/commands/#${command}`
+ case CommandGroup.TimeSeries:
+ return `https://oss.redis.com/redistimeseries/commands/#${command}`
+ case CommandGroup.Graph:
+ return `https://oss.redis.com/redisgraph/commands/#${command}`
+ case CommandGroup.AI:
+ return `https://oss.redis.com/redisai/commands/#${command}`
default:
- commandPage = commandName.replace(/\s+/g, '-').toLowerCase()
- return `https://redis.io/commands/${commandPage}`
+ command = commandName.replace(/\s+/g, '-').toLowerCase()
+ return `https://redis.io/commands/${command}`
}
}
diff --git a/redisinsight/ui/src/utils/tests/commands.spec.ts b/redisinsight/ui/src/utils/tests/commands.spec.ts
index 06671e18f4..4ae9286224 100644
--- a/redisinsight/ui/src/utils/tests/commands.spec.ts
+++ b/redisinsight/ui/src/utils/tests/commands.spec.ts
@@ -192,6 +192,12 @@ const getDocUrlForCommandTests: any[] = [
['JSON.GET', CommandGroup.JSON, 'https://oss.redis.com/redisjson/commands/#jsonget'],
['FT.CREATE', CommandGroup.Search, 'https://oss.redis.com/redisearch/Commands/#ftcreate'],
['FT.ALTER SCHEMA ADD', CommandGroup.Search, 'https://oss.redis.com/redisearch/Commands/#ftalter_schema_add'],
+ ['TS.ADD', CommandGroup.TimeSeries, 'https://oss.redis.com/redistimeseries/commands/#tsadd'],
+ ['TS.CREATE', CommandGroup.TimeSeries, 'https://oss.redis.com/redistimeseries/commands/#tscreate'],
+ ['GRAPH.EXPLAIN', CommandGroup.Graph, 'https://oss.redis.com/redisgraph/commands/#graphexplain'],
+ ['GRAPH.QUERY', CommandGroup.Graph, 'https://oss.redis.com/redisgraph/commands/#graphquery'],
+ ['AI.MODELRUN', CommandGroup.AI, 'https://oss.redis.com/redisai/commands/#aimodelrun'],
+ ['AI.SCRIPTDEL', CommandGroup.AI, 'https://oss.redis.com/redisai/commands/#aiscriptdel'],
['NON EXIST COMMAND', 'non-exist', 'https://redis.io/commands/non-exist-command'],
]
diff --git a/tests/e2e/package.json b/tests/e2e/package.json
index 6cba7ae7d5..b8ab6b5e88 100644
--- a/tests/e2e/package.json
+++ b/tests/e2e/package.json
@@ -7,6 +7,8 @@
"test:live": "testcafe --live chrome ",
"start:api": "cross-env SERVER_STATIC_CONTENT=true yarn --cwd ../../redisinsight/api start:prod",
"build:api": "yarn --cwd ../../redisinsight/api build:prod",
+ "build:statics": "yarn --cwd ../../ build:statics",
+ "build:statics:win": "yarn --cwd ../../ build:statics:win",
"build:web": "yarn --cwd ../../ build:web",
"redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod",
"start:app": "cross-env SERVER_STATIC_CONTENT=true yarn start:api",
From 134817fb94d504ca6b0946ddd94e4fdee8c81876 Mon Sep 17 00:00:00 2001
From: Zalenski Egor <63463140+zalenskiSofteq@users.noreply.github.com>
Date: Wed, 17 Nov 2021 20:38:50 +0300
Subject: [PATCH 2/4] updates
---
README.md | 7 +
docs/plugins/development.md | 182 ++++++++++++++++++
docs/plugins/installation.md | 30 +++
docs/plugins/introduction.md | 9 +
electron-builder.json | 1 +
.../src/exceptions/global-exception.filter.ts | 27 +++
redisinsight/api/src/main.ts | 3 +-
redisinsight/main.dev.ts | 39 +++-
redisinsight/splash.html | 106 ++++++++++
.../cli-search/CliSearchFilter/constants.ts | 12 ++
redisinsight/ui/src/constants/commands.ts | 3 +
.../packages/clients-list-example/README.md | 34 ++++
.../clients-list-example/src/main.tsx | 1 +
.../enablement-area/enablement-area.json | 18 ++
.../document-capabilities/introduction.html | 12 +-
.../document-capabilities/learn-more.html | 56 ++++++
.../working-with-hashes.html | 2 +-
.../working-with-json.html | 169 ++++++++++++++++
.../multiple-tags-or-search.txt | 2 +-
.../combined-search-with-and.txt | 19 ++
.../combined-search-with-geo-filter.txt | 19 ++
.../combined-search-with-or.txt | 19 ++
.../working-with-json/create-json-index.txt | 24 +++
.../working-with-json/crud-create.txt | 11 ++
.../working-with-json/crud-delete.txt | 9 +
.../working-with-json/crud-read.txt | 5 +
.../working-with-json/crud-update.txt | 5 +
.../working-with-json/exact-text-search.txt | 19 ++
.../field-specific-text-search.txt | 20 ++
.../working-with-json/fuzzy-text-search.txt | 19 ++
.../group-and-sort-by-aggregation.txt | 25 +++
.../working-with-json/index-info.txt | 5 +
.../working-with-json/list-all-indexes.txt | 3 +
.../multiple-tags-and-search.txt | 19 ++
.../multiple-tags-or-search.txt | 19 ++
.../working-with-json/numeric-range-query.txt | 21 ++
.../working-with-json/tag-search.txt | 19 ++
.../TableInfoResult/TableInfoResult.tsx | 1 +
.../components/TableResult/TableResult.tsx | 1 +
.../components/list-details/ListDetails.tsx | 16 +-
.../components/Group/styles.scss | 4 +
.../components/InternalLink/InternalLink.tsx | 1 +
.../components/InternalLink/styles.scss | 3 +
.../components/wb-view/WBView/WBView.tsx | 10 +-
.../wb-view/WBView/styles.module.scss | 17 +-
redisinsight/ui/src/slices/keys.ts | 8 +-
redisinsight/ui/src/slices/list.ts | 2 +-
redisinsight/ui/src/utils/commands.ts | 30 +--
.../ui/src/utils/tests/commands.spec.ts | 6 +
tests/e2e/package.json | 2 +
50 files changed, 1050 insertions(+), 44 deletions(-)
create mode 100644 docs/plugins/development.md
create mode 100644 docs/plugins/installation.md
create mode 100644 docs/plugins/introduction.md
create mode 100644 redisinsight/api/src/exceptions/global-exception.filter.ts
create mode 100644 redisinsight/splash.html
create mode 100644 redisinsight/ui/src/packages/clients-list-example/README.md
create mode 100644 redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html
create mode 100644 redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/working-with-json.html
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-and.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-geo-filter.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/combined-search-with-or.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/create-json-index.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-create.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-delete.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-read.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/crud-update.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/exact-text-search.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/field-specific-text-search.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/fuzzy-text-search.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/group-and-sort-by-aggregation.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/index-info.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/list-all-indexes.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-and-search.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/multiple-tags-or-search.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/numeric-range-query.txt
create mode 100644 redisinsight/ui/src/packages/enablement-area/scripts/document-capabilities/working-with-json/tag-search.txt
create mode 100644 redisinsight/ui/src/pages/workbench/components/enablament-area/EnablementArea/components/InternalLink/styles.scss
diff --git a/README.md b/README.md
index e29400c3ee..96d99a6d4b 100644
--- a/README.md
+++ b/README.md
@@ -8,10 +8,17 @@ Awesome Redis GUI written in Electron, NodeJS and React
- `redisinsight/ui` - Contains the frontend code
- `redisinsight/api` - Contains the backend code
+- `docs` - Contains the documentation
- `scripts` - Build scripts and other build-related files
- `configs` - Webpack configuration files and other build-related files
- `tests` - Contains the e2e
+## Plugins documentation
+
+* [Introduction](docs/plugins/introduction.md)
+* [Installation and Usage](docs/plugins/installation.md)
+* [Plugin Development](docs/plugins/development.md)
+
## Prerequisites
Make sure you have installed following packages:
diff --git a/docs/plugins/development.md b/docs/plugins/development.md
new file mode 100644
index 0000000000..dcb6024e33
--- /dev/null
+++ b/docs/plugins/development.md
@@ -0,0 +1,182 @@
+# Plugin development
+
+This document describes the guides to develop your own plugin for the RedisInsight Workbench.
+
+## How it works
+
+Plugin visualization in the Workbench is rendered using Iframe to encapsulate plugin scripts and styles, described in
+the main plugin script and the stylesheet (if it has been specified in the `package.json`),
+iframe includes basic styles as well.
+
+## Plugin structure
+
+Each plugin should have a unique name with all its files [loaded](installation.md) to
+a separate folder inside the default `plugins` folder.
+
+> Default plugins are located inside the application.
+
+### Files
+`package.json` should be located in the root folder of your plugins, all other files can be included into a subfolder.
+
+* **pluginName/package.json** *(required)* - Manifest of the plugin
+* **pluginName/{anyName}.js** *(required)* - Core script of the plugin
+* **pluginName/{anyName}.css** *(optional)* - File with styles for the plugin visualizations
+* **pluginName/{anyFileOrFolder}** *(optional)* - Specify any other file or folder inside the plugin folder
+to use by the core module script. *For example*: pluginName/images/image.png.
+
+## `package.json` structure
+
+This is the required manifest to use the plugin. `package.json` file should include
+the following **required** fields:
+
+
+
+
name
+
Plugin name. It is recommended to use the folder name as the plugin name in the package.json.
+
+
+
main
+
Relative path to the core script of the plugin. Example: "./dist/index.js"
+
+
+
visualizations
+
+ Array of visualizations (objects) to visualize the results in the Workbench.
+
+ Required fields in visualizations:
+
+
id - visualization id
+
name - visualization name to display in the Workbench
+
activationMethod - name of the exported function to call when
+this visualization is selected in the Workbench
+
+ matchCommands - array of commands to use the visualization for. Supports regex string.
+ Example: ["CLIENT LIST", "FT.*"]
+
+
+
+
+
+
+You can specify the path to a css file in the `styles` field. If specified,
+this file will be included inside the iframe plugin.
+
+Simple example of the `package.json` file with required and optional fields:
+
+```json
+{
+ "author": {
+ "name": "Redis Ltd.",
+ "email": "support@redis.com",
+ "url": "https://redis.com/redis-enterprise/redis-insight"
+ },
+ "description": "Show client list as table",
+ "styles": "./dist/styles.css",
+ "main": "./dist/index.js",
+ "name": "client-list",
+ "version": "0.0.1",
+ "scripts": {},
+ "visualizations": [
+ {
+ "id": "clients-list",
+ "name": "Table",
+ "activationMethod": "renderClientsList",
+ "matchCommands": [
+ "CLIENT LIST"
+ ],
+ "description": "Example of client list plugin",
+ "default": true
+ }
+ ],
+ "devDependencies": {},
+ "dependencies": {}
+}
+```
+
+## Core script of the plugin
+
+This is the required script with defined visualization methods.
+The core script contains function and its export (functions - for multiple visualizations),
+which is run after the relevant visualization is selected in the Workbench.
+
+The following function receives props of the executed commands:
+```typescript
+interface Props {
+ command: string; // executed command
+ data: string; // result of the executed command
+ status: 'success' | 'fail'; // response status of the executed command
+}
+
+const renderVisualization = (props: Props) => {
+ // Do your magic
+}
+
+export default { renderVisualization }
+```
+
+Each plugin iframe has basic styles of RedisInsight application, including fonts and color schemes.
+
+It is recommended to use the React & [Elastic UI library](https://elastic.github.io/eui/#/) for
+consistency with plugin visualisations and the entire application.
+
+Find the example of the plugin here.
+
+* [Client List Plugin README](../../redisinsight/ui/src/packages/clients-list-example/README.md)
+* [Client List Plugin dir](../../redisinsight/ui/src/packages/clients-list-example/)
+
+### Available parameters
+
+Additional information provided to the plugin iframe is included in the `window.state`
+inside of the plugin script.
+
+```javascript
+const { config, modules } = window.state
+const { baseUrl } = config
+
+// modules - the list of modules of the current database
+// baseUrl - url for your plugin folder - can be used to include your assets
+```
+
+### Plugin rendering
+To render the plugin visualization, the iframe with basic html is generated which is
+then populated with relevant scripts and styles. To render the html data, use existing
+DOM Element `#app` or create your own DOM Elements.
+Rendered iframe also includes `theme_DARK` or `theme_LIGHT` className on `body` to indicate the application theme used.
+
+_Javascript Example:_
+```javascript
+const renderVisualization = (props) => {
+ const { command, data } = props;
+ document.getElementById('app')
+ .innerHTML = `
+
Executed command:
+
${command}
+
Result of the command
+
${data}
+ `
+}
+
+export default { renderVisualization }
+```
+
+_React Example:_
+```javascript
+import { render } from 'react-dom'
+import App from './App'
+
+const renderVisualization = (props) => {
+ const { command, status, data = '' } = props
+ render(
+ ,
+ document.getElementById('app')
+ )
+}
+
+// This is a required action - export the main function for execution of the visualization
+export default { renderVisualization }
+```
+
+
+## Plugins communication
+> **_Future updates:_**
+Support of communication with the main application via a third-party library - _redisinsight-plugin-sdk_.
diff --git a/docs/plugins/installation.md b/docs/plugins/installation.md
new file mode 100644
index 0000000000..cff18847f4
--- /dev/null
+++ b/docs/plugins/installation.md
@@ -0,0 +1,30 @@
+# Plugin installation & Usage
+
+This document describes the guides to add `plugins` for the Workbench to RedisInsight.
+
+## Installation guide
+
+**Note**: While adding new plugins for Workbench, use files only from trusted
+authors to avoid automatic execution of malicious code.
+
+1. Download the plugin for the Workbench.
+2. Open the `plugins` folder with the following path
+ * For MacOs: `/.redisinsight-v2.0/plugins`
+ * For Windows: `C:\Users\{Username}\.redisinsight-v2.0\plugins`
+ * For Linux: `/.redisinsight-v2.0/plugins`
+3. Add the folder with plugin to the `plugins` folder
+
+To see the uploaded plugin visualizations in the command results, reload the Workbench
+page and run Redis command relevant for this visualization.
+
+
+## Usage
+
+The plugin may contain different visualizations for any Redis commands.
+Below you can find a guide to see command results in the uploaded plugin visualization:
+
+1. Open RedisInsight
+2. Open a database added
+3. Open the Workbench
+4. Run the Redis command relevant for the plugin visualization
+5. Select the plugin visualization to display results in (if this visualization has not been set by default)
diff --git a/docs/plugins/introduction.md b/docs/plugins/introduction.md
new file mode 100644
index 0000000000..d585af2ab1
--- /dev/null
+++ b/docs/plugins/introduction.md
@@ -0,0 +1,9 @@
+# Introduction to plugins for the Workbench
+
+Plugins allow the customization of visualizations for Redis commands executed
+in the Workbench inside the RedisInsight.
+
+## Wiki
+
+* [Installation and Usage](installation.md)
+* [Plugin Development](development.md)
diff --git a/electron-builder.json b/electron-builder.json
index b7b893e969..9c046951c8 100644
--- a/electron-builder.json
+++ b/electron-builder.json
@@ -6,6 +6,7 @@
"dist/",
"node_modules/",
"index.html",
+ "splash.html",
"main.prod.js",
"main.prod.js.map",
"package.json"
diff --git a/redisinsight/api/src/exceptions/global-exception.filter.ts b/redisinsight/api/src/exceptions/global-exception.filter.ts
new file mode 100644
index 0000000000..d43974372b
--- /dev/null
+++ b/redisinsight/api/src/exceptions/global-exception.filter.ts
@@ -0,0 +1,27 @@
+import { BaseExceptionFilter } from '@nestjs/core';
+import { ArgumentsHost, Logger } from '@nestjs/common';
+import { Request, Response } from 'express';
+
+export class GlobalExceptionFilter extends BaseExceptionFilter {
+ private staticServerLogger = new Logger('StaticServerLogger');
+
+ catch(exception: Error, host: ArgumentsHost) {
+ const ctx = host.switchToHttp();
+ const request = ctx.getRequest();
+
+ if (/^\/(?:plugins|static)\//i.test(request.url)) {
+ const response = ctx.getResponse();
+ const statusCode = exception['statusCode'] || 500;
+ const message = `Error when trying to fetch ${request.url}`;
+
+ this.staticServerLogger.error(message, { ...exception } as any);
+ return response.status(statusCode)
+ .json({
+ statusCode,
+ message,
+ });
+ }
+
+ return super.catch(exception, host);
+ }
+}
diff --git a/redisinsight/api/src/main.ts b/redisinsight/api/src/main.ts
index ce34af83e2..13a9fa7893 100644
--- a/redisinsight/api/src/main.ts
+++ b/redisinsight/api/src/main.ts
@@ -3,6 +3,7 @@ import { SwaggerModule } from '@nestjs/swagger';
import { NestApplicationOptions } from '@nestjs/common';
import * as bodyParser from 'body-parser';
import { WinstonModule } from 'nest-winston';
+import { GlobalExceptionFilter } from 'src/exceptions/global-exception.filter';
import { AppModule } from './app.module';
import SWAGGER_CONFIG from '../config/swagger';
import LOGGER_CONFIG from '../config/logger';
@@ -22,7 +23,7 @@ export default async function bootstrap() {
}
const app = await NestFactory.create(AppModule, options);
-
+ app.useGlobalFilters(new GlobalExceptionFilter(app.getHttpAdapter()));
app.use(bodyParser.json({ limit: '512mb' }));
app.use(bodyParser.urlencoded({ limit: '512mb', extended: true }));
app.enableCors();
diff --git a/redisinsight/main.dev.ts b/redisinsight/main.dev.ts
index 96cc4c6103..108625e1a5 100644
--- a/redisinsight/main.dev.ts
+++ b/redisinsight/main.dev.ts
@@ -94,7 +94,7 @@ export const getDisplayAppInTrayValue = (): boolean => {
/**
* Backend part...
*/
-const port = 5000;
+const port = 5001;
const launchApiServer = async () => {
try {
const detectPortConst = await detectPort(port);
@@ -134,19 +134,35 @@ const bootstrap = async () => {
export const windows = new Set();
-export const createWindow = async () => {
+const titleSplash = 'splash';
+export const createSplashScreen = async () => {
+ const splash = new BrowserWindow({
+ width: 500,
+ height: 200,
+ transparent: true,
+ frame: false,
+ resizable: false,
+ alwaysOnTop: true,
+ title: titleSplash,
+ });
+
+ splash.loadURL(`file://${__dirname}/splash.html`);
+
+ return splash;
+};
+
+export const createWindow = async (splash: BrowserWindow | null) => {
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'resources')
: path.join(__dirname, '../resources');
- const getAssetPath = (...paths: string[]): string => {
- return path.join(RESOURCES_PATH, ...paths);
- };
+ const getAssetPath = (...paths: string[]): string => path.join(RESOURCES_PATH, ...paths);
let x;
let y;
const currentWindow = BrowserWindow.getFocusedWindow();
- if (currentWindow) {
+
+ if (currentWindow && currentWindow?.getTitle() !== titleSplash) {
const [currentWindowX, currentWindowY] = currentWindow.getPosition();
x = currentWindowX + 24;
y = currentWindowY + 24;
@@ -188,8 +204,9 @@ export const createWindow = async () => {
if (process.env.START_MINIMIZED) {
newWindow.minimize();
} else {
- newWindow.show();
- newWindow.focus();
+ newWindow?.show();
+ newWindow?.focus();
+ splash?.close();
}
});
@@ -293,7 +310,11 @@ app.on('continue-activity-error', (event, type, error) => {
}
});
-app.whenReady().then(bootstrap).then(createWindow).catch(console.log);
+app.whenReady()
+ .then(bootstrap)
+ .then(createSplashScreen)
+ .then(createWindow)
+ .catch(console.log);
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
diff --git a/redisinsight/splash.html b/redisinsight/splash.html
new file mode 100644
index 0000000000..5763e7345a
--- /dev/null
+++ b/redisinsight/splash.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts b/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
index 46e177974b..25dd61a1e3 100644
--- a/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
+++ b/redisinsight/ui/src/components/cli/components/cli-search/CliSearchFilter/constants.ts
@@ -69,4 +69,16 @@ export const FILTER_GROUP_TYPE_OPTIONS = [
text: 'JSON',
value: CommandGroup.JSON,
},
+ {
+ text: 'TimeSeries',
+ value: CommandGroup.TimeSeries,
+ },
+ {
+ text: 'Graph',
+ value: CommandGroup.Graph,
+ },
+ {
+ text: 'AI',
+ value: CommandGroup.AI,
+ },
]
diff --git a/redisinsight/ui/src/constants/commands.ts b/redisinsight/ui/src/constants/commands.ts
index 531cf7aee9..b67dfd9c6b 100644
--- a/redisinsight/ui/src/constants/commands.ts
+++ b/redisinsight/ui/src/constants/commands.ts
@@ -56,6 +56,9 @@ export enum CommandGroup {
String = 'string',
Search = 'search',
JSON = 'json',
+ TimeSeries = 'timeseries',
+ Graph = 'graph',
+ AI = 'ai'
}
export enum CommandRediSearch {
diff --git a/redisinsight/ui/src/packages/clients-list-example/README.md b/redisinsight/ui/src/packages/clients-list-example/README.md
new file mode 100644
index 0000000000..40443ad0a0
--- /dev/null
+++ b/redisinsight/ui/src/packages/clients-list-example/README.md
@@ -0,0 +1,34 @@
+# Example of the plugin for the “Client List” command
+
+The example has been created using React, TypeScript, and [Elastic UI](https://elastic.github.io/eui/#/).
+[Parcel](https://parceljs.org/) is used to build the plugin.
+
+## Running locally
+
+The following commands will install dependencies and start the server to run the plugin locally:
+```
+yarn
+yarn start
+```
+These commands will install dependencies and start the server.
+
+_Note_: Base styles are included to `index.html` from the repository.
+
+This command will generate the `vendor` folder with styles and fonts of the core app. Add this folder
+inside the folder for your plugin and include appropriate styles to the `index.html` file.
+
+```
+yarn build:statics - for Linux or MacOs
+yarn build:statics:win - for Windows
+```
+
+## Build plugin
+
+The following commands will build plugins to be used in RedisInsight:
+```
+yarn
+yarn build
+```
+
+[Add](../../../../../docs/plugins/installation.md) the package.json file and the
+`dist` folder to the folder with your plugin, which should be located in the `plugins` folder.
diff --git a/redisinsight/ui/src/packages/clients-list-example/src/main.tsx b/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
index ff97fb6f3e..51359287e9 100644
--- a/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
+++ b/redisinsight/ui/src/packages/clients-list-example/src/main.tsx
@@ -20,4 +20,5 @@ if (process.env.NODE_ENV === 'development') {
renderClientsList({ command: '', data: response, status: 'success' })
}
+// This is a required action - export the main function for execution of the visualization
export default { renderClientsList }
diff --git a/redisinsight/ui/src/packages/enablement-area/enablement-area.json b/redisinsight/ui/src/packages/enablement-area/enablement-area.json
index 2c00feb4e3..c4582ef82e 100644
--- a/redisinsight/ui/src/packages/enablement-area/enablement-area.json
+++ b/redisinsight/ui/src/packages/enablement-area/enablement-area.json
@@ -33,6 +33,24 @@
"backTitle": "Document Capabilities",
"path": "/static/workbench/guides/document-capabilities/working-with-hashes.html"
}
+ },
+ {
+ "type": "internal-link",
+ "id": "working-with-json",
+ "label": "Working with JSON",
+ "args": {
+ "backTitle": "Document Capabilities",
+ "path": "/static/workbench/guides/document-capabilities/working-with-json.html"
+ }
+ },
+ {
+ "type": "internal-link",
+ "id": "learn-more",
+ "label": "Learn More",
+ "args": {
+ "backTitle": "Document Capabilities",
+ "path": "/static/workbench/guides/document-capabilities/learn-more.html"
+ }
}
]
}
diff --git a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
index 5f58e7011d..e573784324 100644
--- a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
+++ b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/introduction.html
@@ -3,8 +3,8 @@
Full-text search and querying is supported for both Hashes and JSON via a secondary index.
+
Full-text search and querying is supported for both Hashes and JSON via a secondary index.
A number of data types are available for indexing:
@@ -32,7 +32,7 @@
Numeric range index
Tag index supporting multiple values
Geo index
-
Vector index
+
Vector index (upcoming)
@@ -58,10 +58,10 @@
PRE-REQUISITES
Follow these instructions to set up the RedisJSON and RediSearch modules on Redis OSS.
- For working with Hashes you will need Redis >=6, RediSearch >=2.0.
+ For working with Hashes you will need Redis >=6, RediSearch >=2.0.
- For working with JSON you will need Redis >=6, RediSearch >=2.2 and RedisJSON >=2.0.
+ For working with JSON you will need Redis >=6, RediSearch >=2.2 and RedisJSON >=2.0.
You could also create a free and ready to use instance on Redis Cloud.
diff --git a/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html
new file mode 100644
index 0000000000..3f527f58da
--- /dev/null
+++ b/redisinsight/ui/src/packages/enablement-area/guides/document-capabilities/learn-more.html
@@ -0,0 +1,56 @@
+
+