From b8fb6a3d879eac1db9be4024b1c4cf1c4a759ed7 Mon Sep 17 00:00:00 2001 From: liugq Date: Fri, 15 Oct 2021 11:41:38 +0800 Subject: [PATCH] console tab v0.1 --- api/index_management/document.go | 41 ++- api/index_management/indices.go | 6 + api/index_management/rebuild.go | 1 - api/init.go | 1 + web/config/router.config.js | 309 +++++++++--------- .../kibana/console/components/Console.tsx | 90 +++-- .../console/components/ConsoleInput.tsx | 30 +- .../console/components/ConsoleOutput.tsx | 2 +- .../editor_context/editor_registry.ts | 27 ++ .../kibana/console/entities/sense_editor.ts | 4 + .../modules/autocomplete/autocomplete.ts | 48 +-- .../legacy_core_editor/legacy_core_editor.ts | 44 +-- .../console/modules/mappings/mappings.js | 90 ++--- .../components/discover_table/table.tsx | 2 +- .../discover_table/table_row/detail.tsx | 9 +- .../public/context.ts | 2 +- web/src/lib/hooks/storage.js | 40 +++ web/src/pages/DataManagement/Discover.jsx | 26 +- web/src/pages/DataManagement/Index.js | 34 +- web/src/pages/DataManagement/models/index.js | 15 +- web/src/pages/DevTool/Console.tsx | 188 ++++++++++- 21 files changed, 691 insertions(+), 318 deletions(-) create mode 100644 web/src/lib/hooks/storage.js diff --git a/api/index_management/document.go b/api/index_management/document.go index 9d938a5c..ba9b7633 100644 --- a/api/index_management/document.go +++ b/api/index_management/document.go @@ -61,13 +61,28 @@ func (handler APIHandler) HandleUpdateDocumentAction(w http.ResponseWriter, req err := handler.DecodeJSON(req, &reqBody) if err != nil { - resBody["error"] = err + resBody["error"] = err.Error() handler.WriteJSON(w, resBody, http.StatusOK) return } indexName := ps.ByName("index") docID := ps.ByName("docId") typ := handler.GetParameter(req, "_type") + isNew := handler.GetParameter(req, "is_new") + if isNew == "1" { + getRes, err := client.Get(indexName, typ, docID) + if err != nil { + resBody["error"] = err.Error() + handler.WriteJSON(w, resBody, http.StatusOK) + return + } + if getRes.Found { + resBody["error"] = "doc id already exists" + handler.WriteJSON(w, resBody, http.StatusOK) + return + } + } + insertRes, err := client.Index(indexName, typ, docID, reqBody) if err != nil { resBody["error"] = err.Error() @@ -156,6 +171,30 @@ func (handler APIHandler) HandleSearchDocumentAction(w http.ResponseWriter, req handler.WriteJSON(w, resResult, http.StatusOK) } +func (handler APIHandler) ValidateDocIDAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + targetClusterID := ps.ByName("id") + client := elastic.GetClient(targetClusterID) + resBody := util.MapStr{} + if client != nil { + resBody["error"] = "cluster not found" + handler.WriteJSON(w, resBody, http.StatusOK) + return + } + var ( + index = handler.GetParameter(req, "index") + docID = handler.GetParameter(req, "doc_id") + typ = handler.GetParameter(req, "type") + ) + getRes, err := client.Get(index, typ, docID) + if err != nil { + resBody["error"] = err + handler.WriteJSON(w, resBody, http.StatusOK) + return + } + resBody["found"] = getRes.Found + handler.WriteJSON(w, resBody, http.StatusOK) +} + func formatESSearchResult(esResp *elastic.SearchResponse) map[string]interface{} { total := esResp.Hits.Total if len(esResp.Hits.Hits) == 0 { diff --git a/api/index_management/indices.go b/api/index_management/indices.go index 8b21459c..8d764db4 100644 --- a/api/index_management/indices.go +++ b/api/index_management/indices.go @@ -5,6 +5,7 @@ import ( "infini.sh/framework/core/elastic" "infini.sh/framework/core/util" "net/http" + "runtime/debug" ) func (handler APIHandler) HandleGetMappingsAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { @@ -62,6 +63,11 @@ func (handler APIHandler) HandleGetSettingsAction(w http.ResponseWriter, req *ht } func (handler APIHandler) HandleUpdateSettingsAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + defer func() { + if err := recover(); err != nil { + debug.PrintStack() + } + }() targetClusterID := ps.ByName("id") client := elastic.GetClient(targetClusterID) indexName := ps.ByName("index") diff --git a/api/index_management/rebuild.go b/api/index_management/rebuild.go index e7463f83..d6bf025f 100644 --- a/api/index_management/rebuild.go +++ b/api/index_management/rebuild.go @@ -86,7 +86,6 @@ func reindex(esName string, body *model.Reindex, typ string) (string, error) { func newResponseBody() map[string]interface{} { return map[string]interface{}{ - "status": true, } } diff --git a/api/init.go b/api/init.go index 47b38f57..7e6ae2fa 100644 --- a/api/init.go +++ b/api/init.go @@ -29,6 +29,7 @@ func Init(cfg *config.AppConfig) { ui.HandleUIMethod(api.POST, path.Join(esPrefix, "doc/:index"), handler.HandleAddDocumentAction) ui.HandleUIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleUpdateDocumentAction) ui.HandleUIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleDeleteDocumentAction) + ui.HandleUIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) ui.HandleUIMethod(api.POST, path.Join(pathPrefix, "rebuild/*id"), handler.HandleReindexAction) ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction) diff --git a/web/config/router.config.js b/web/config/router.config.js index 2f5afcd2..d3b4271c 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -162,7 +162,8 @@ export default [ // routes:[ // { path: '/', redirect: '/' }, // ], - // }, { + // }, + // { // path: '/data/template', // name: 'template', // component: './DataManagement/IndexTemplate', @@ -200,157 +201,161 @@ export default [ //search - // { - // path: '/search', - // name: 'search', - // icon: 'search', - // routes: [ - // { - // path: '/search/overview', - // name: 'overview', - // component: './SearchManage/template/Template', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/template', - // name: 'template', - // component: './SearchManage/template/Template', - // routes: [ - // { - // path: '/search/template', - // redirect: '/search/template/template', - // }, - // { - // path: '/search/template/template', - // component: './SearchManage/template/SearchTemplate', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/template/:cluster_id', - // component: './SearchManage/template/SearchTemplate', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/template/history', - // component: './SearchManage/template/History', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // ] - // }, { - // path: '/search/alias', - // name: 'alias', - // component: './SearchManage/alias/Alias', - // routes: [ - // { - // path: '/search/alias', - // redirect: '/search/alias/index', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // }, - // { - // path: '/search/alias/index', - // component: './SearchManage/alias/AliasManage', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/alias/rule', - // component: './SearchManage/alias/Rule', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // } - // ] - // }, { - // path: '/search/dict', - // name: 'dict', - // component: './SearchManage/dict/Dict', - // routes: [ - // { - // path: '/search/dict', - // redirect: '/search/dict/professional', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // }, - // { - // path: '/search/dict/professional', - // component: './SearchManage/dict/Pro', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/dict/common', - // component: './SearchManage/dict/Common', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // } - // ] - // }, { - // path: '/search/analyzer', - // name: 'analyzer', - // component: './SearchManage/analyzer/Analyzer', - // routes: [ - // { - // path: '/search/analyzer', - // redirect: '/search/analyzer/manage', - // }, - // { - // path: '/search/analyzer/manage', - // component: './SearchManage/analyzer/Manage', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/search/analyzer/test', - // component: './SearchManage/analyzer/AnalyzerTest', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // } - // ] - // }//, { - // // path: '/search/nlp', - // // name: 'nlp', - // // component: './SearchManage/nlp/NLP', - // // routes: [ - // // { - // // path: '/search/nlp', - // // redirect: '/search/nlp/query', - // // }, - // // { - // // path: '/search/nlp/query', - // // component: './SearchManage/nlp/Query', - // // }, - // // { - // // path: '/search/nlp/intention', - // // component: './SearchManage/nlp/Intention', - // // }, - // // { - // // path: '/search/nlp/knowledge', - // // component: './SearchManage/nlp/Knowledge', - // // }, - // // { - // // path: '/search/nlp/text', - // // component: './SearchManage/nlp/Text', - // // } - // //] - // //}, - // ] - // }, + { + path: '/search', + name: 'search', + icon: 'search', + routes: [ + // { + // path: '/search/overview', + // name: 'overview', + // component: './SearchManage/template/Template', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/search/template', + // name: 'template', + // component: './SearchManage/template/Template', + // routes: [ + // { + // path: '/search/template', + // redirect: '/search/template/template', + // }, + // { + // path: '/search/template/template', + // component: './SearchManage/template/SearchTemplate', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/search/template/:cluster_id', + // component: './SearchManage/template/SearchTemplate', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/search/template/history', + // component: './SearchManage/template/History', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // ] + // }, + { + path: '/search/alias', + name: 'alias', + component: './SearchManage/alias/Alias', + routes: [ + { + path: '/search/alias', + redirect: '/search/alias/index', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + }, + { + path: '/search/alias/index', + component: './SearchManage/alias/AliasManage', + routes:[ + { path: '/', redirect: '/' }, + ], + }, + { + path: '/search/alias/rule', + component: './SearchManage/alias/Rule', + routes:[ + { path: '/', redirect: '/' }, + ], + } + ] + }, + // { + // path: '/search/dict', + // name: 'dict', + // component: './SearchManage/dict/Dict', + // routes: [ + // { + // path: '/search/dict', + // redirect: '/search/dict/professional', + // // routes:[ + // // { path: '/', redirect: '/' }, + // // ], + // }, + // { + // path: '/search/dict/professional', + // component: './SearchManage/dict/Pro', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/search/dict/common', + // component: './SearchManage/dict/Common', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // } + // ] + // }, + // { + // path: '/search/analyzer', + // name: 'analyzer', + // component: './SearchManage/analyzer/Analyzer', + // routes: [ + // { + // path: '/search/analyzer', + // redirect: '/search/analyzer/manage', + // }, + // { + // path: '/search/analyzer/manage', + // component: './SearchManage/analyzer/Manage', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/search/analyzer/test', + // component: './SearchManage/analyzer/AnalyzerTest', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // } + // ] + // } + //, { + // path: '/search/nlp', + // name: 'nlp', + // component: './SearchManage/nlp/NLP', + // routes: [ + // { + // path: '/search/nlp', + // redirect: '/search/nlp/query', + // }, + // { + // path: '/search/nlp/query', + // component: './SearchManage/nlp/Query', + // }, + // { + // path: '/search/nlp/intention', + // component: './SearchManage/nlp/Intention', + // }, + // { + // path: '/search/nlp/knowledge', + // component: './SearchManage/nlp/Knowledge', + // }, + // { + // path: '/search/nlp/text', + // component: './SearchManage/nlp/Text', + // } + //] + //}, + ] + }, // // //sync // { diff --git a/web/src/components/kibana/console/components/Console.tsx b/web/src/components/kibana/console/components/Console.tsx index de431164..46c24bee 100644 --- a/web/src/components/kibana/console/components/Console.tsx +++ b/web/src/components/kibana/console/components/Console.tsx @@ -1,5 +1,5 @@ // @ts-ignore -import React, { useRef, useMemo } from 'react'; +import React, { useRef, useMemo,useEffect } from 'react'; import ConsoleInput from './ConsoleInput'; import ConsoleOutput from './ConsoleOutput'; import { Panel } from './Panel'; @@ -17,13 +17,19 @@ import {RequestStatusBar} from './request_status_bar'; interface props { selectedCluster: any; + saveEditorContent: (content: string)=>void; + initialText: string; + paneKey: string; } const INITIAL_PANEL_WIDTH = 50; const PANEL_MIN_WIDTH = '300px'; const ConsoleWrapper = ({ - selectedCluster + selectedCluster, + saveEditorContent, + initialText, + paneKey, }:props) => { const { @@ -32,42 +38,74 @@ const ConsoleWrapper = ({ } = useRequestReadContext(); const lastDatum = requestData?.[requestData.length - 1] ?? requestError; + const getElementTop = (elem: any)=>{ +   var elemTop=elem.offsetTop; +   elem=elem.offsetParent; + +   while(elem!=null){ +     elemTop+=elem.offsetTop; +     elem=elem.offsetParent; +   } + +   return elemTop; + + } + const statusBarRef = useRef(null); + const consoleRef = useRef(null); + + useEffect(()=>{ + statusBarRef.current && consoleRef.current && (statusBarRef.current.style.width=consoleRef.current.offsetWidth+'px'); + const winScroll = ()=>{ + const wsTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; + if(wsTop>getElementTop(consoleRef.current)) { + statusBarRef.current && (statusBarRef.current.style.position='relative'); + }else{ + statusBarRef.current && (statusBarRef.current.style.position='fixed'); + } + } + window.addEventListener('scroll', winScroll) + return ()=>{ + window.removeEventListener('scroll', winScroll) + } + },[]) return (
- - - - - -
+
- +
+
+ + + + + +
); }; diff --git a/web/src/components/kibana/console/components/ConsoleInput.tsx b/web/src/components/kibana/console/components/ConsoleInput.tsx index 663a70bc..d5f6f11b 100644 --- a/web/src/components/kibana/console/components/ConsoleInput.tsx +++ b/web/src/components/kibana/console/components/ConsoleInput.tsx @@ -11,7 +11,7 @@ import './ConsoleInput.scss'; import { useSendCurrentRequestToES } from '../hooks/use_send_current_request_to_es'; import { useSetInputEditor } from '../hooks/use_set_input_editor'; import '@elastic/eui/dist/eui_theme_light.css'; -import { instance as registry } from '../contexts/editor_context/editor_registry'; +import { instance as registry, editorList } from '../contexts/editor_context/editor_registry'; import 'antd/dist/antd.css'; import {retrieveAutoCompleteInfo} from '../modules/mappings/mappings'; import {useSaveCurrentTextObject} from '../hooks/use_save_current_text_object'; @@ -66,6 +66,8 @@ const SendRequestButton = (props: any) => { interface ConsoleInputProps { clusterID: string, initialText: string | undefined, + saveEditorContent: (content: string)=>void, + paneKey: string, } const DEFAULT_INPUT_VALUE = `GET _search @@ -75,7 +77,8 @@ const DEFAULT_INPUT_VALUE = `GET _search } }`; -const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { + +const ConsoleInputUI = ({clusterID, initialText, saveEditorContent, paneKey}:ConsoleInputProps) => { const editorRef = useRef(null); const editorActionsRef = useRef(null); const editorInstanceRef = useRef(null); @@ -105,8 +108,10 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { // senseEditor.highlightCurrentRequestsAndUpdateActionBar(); editorInstanceRef.current = senseEditor; setInputEditor(senseEditor); + senseEditor.paneKey = paneKey; + editorList.addInputEditor(senseEditor); senseEditor.update(initialText || DEFAULT_INPUT_VALUE); - // applyCurrentSettings(senseEditor!.getCoreEditor(), {fontSize:14, wrapMode: true,}); + applyCurrentSettings(senseEditor!.getCoreEditor(), {fontSize:12, wrapMode: true,}); function setupAutosave() { let timer: number; @@ -123,7 +128,8 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { function saveCurrentState() { try { const content = senseEditor.getCoreEditor().getValue(); - saveCurrentTextObjectRef.current(content); + // saveCurrentTextObjectRef.current(content); + saveEditorContent(content) } catch (e) { console.log(e) // Ignoring saving error @@ -142,6 +148,7 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { }, []); useEffect(()=>{ retrieveAutoCompleteInfo(settings, settings.getAutocomplete(), clusterID); + aceEditorRef.current && (aceEditorRef.current['clusterID'] = clusterID); },[clusterID]) const handleSaveAsCommonCommand = async () => { @@ -188,7 +195,7 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
{consoleMenuRef.current?.closePopover(); aceEditorRef.current?.focus()}} @@ -198,13 +205,14 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { ); }; -const ConsoleInput = ({clusterID}:{clusterID:string})=>{ - const { done, error, retry } = useDataInit(); - const { currentTextObject } = useEditorReadContext(); - return done ? : <> -} +// const ConsoleInput = ({clusterID}:{clusterID:string})=>{ +// const { done, error, retry } = useDataInit(); +// const { currentTextObject } = useEditorReadContext(); +// return done ? : <> +// } -export default ConsoleInput; +// export default ConsoleInput; +export default ConsoleInputUI; diff --git a/web/src/components/kibana/console/components/ConsoleOutput.tsx b/web/src/components/kibana/console/components/ConsoleOutput.tsx index 178619db..a959ff9c 100644 --- a/web/src/components/kibana/console/components/ConsoleOutput.tsx +++ b/web/src/components/kibana/console/components/ConsoleOutput.tsx @@ -46,7 +46,7 @@ function ConsoleOutput({clusterID}: props) { const textarea = editorRef.current!.querySelector('textarea')!; textarea.setAttribute('id', inputId); textarea.setAttribute('readonly', 'true'); - // applyCurrentSettings(editorInstanceRef.current!, {fontSize:14, wrapMode: true,}) + applyCurrentSettings(editorInstanceRef.current!, {fontSize:12, wrapMode: true,}) const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editorInstanceRef.current!); return () => { diff --git a/web/src/components/kibana/console/contexts/editor_context/editor_registry.ts b/web/src/components/kibana/console/contexts/editor_context/editor_registry.ts index 46dd12d3..b063cdeb 100644 --- a/web/src/components/kibana/console/contexts/editor_context/editor_registry.ts +++ b/web/src/components/kibana/console/contexts/editor_context/editor_registry.ts @@ -37,6 +37,7 @@ export class EditorRegistry { setInputEditor(inputEditor: SenseEditor) { this.inputEditor = inputEditor; + inputEditor.setAutocompleter(); } getInputEditor() { @@ -46,3 +47,29 @@ export class EditorRegistry { // Create a single instance of this and use as private state. export const instance = new EditorRegistry(); + +export class EditorList { + private inputEditors: SenseEditor[]; + constructor(){ + this.inputEditors = []; + } + addInputEditor(inputEditor: SenseEditor) { + this.inputEditors.push(inputEditor); + } + + removeInputEditor(inputEditor: SenseEditor){ + const idx = this.inputEditors.findIndex(editor=> editor==inputEditor); + if(idx > -1) this.inputEditors = this.inputEditors.splice(idx,1); + } + + setActiveEditor(key: string){ + for(let i=0; i{ + this.coreEditor.registerAutocompleter(this.autocomplete.getCompletions); + } + prevRequestStart = (rowOrPos?: number | Position): Position => { let curRow: number; diff --git a/web/src/components/kibana/console/modules/autocomplete/autocomplete.ts b/web/src/components/kibana/console/modules/autocomplete/autocomplete.ts index 20e7054c..6d7d4595 100644 --- a/web/src/components/kibana/console/modules/autocomplete/autocomplete.ts +++ b/web/src/components/kibana/console/modules/autocomplete/autocomplete.ts @@ -333,6 +333,30 @@ export function getCurrentMethodAndTokenPaths( return ret; } +function isUrlPathToken(token: Token | null) { + switch ((token || ({} as Token)).type) { + case 'url.slash': + case 'url.comma': + case 'url.part': + return true; + default: + return false; + } +} + +function addMetaToTermsList( + list: unknown[], + meta: unknown, + template?: string +): Array<{ meta: unknown; template: unknown; name?: string }> { + return _.map(list, function (t) { + if (typeof t !== 'object') { + t = { name: t }; + } + return _.defaults(t, { meta, template }); + }); +} + // eslint-disable-next-line export default function ({ coreEditor: editor, @@ -341,29 +365,7 @@ export default function ({ coreEditor: CoreEditor; parser: RowParser; }) { - function isUrlPathToken(token: Token | null) { - switch ((token || ({} as Token)).type) { - case 'url.slash': - case 'url.comma': - case 'url.part': - return true; - default: - return false; - } - } - - function addMetaToTermsList( - list: unknown[], - meta: unknown, - template?: string - ): Array<{ meta: unknown; template: unknown; name?: string }> { - return _.map(list, function (t) { - if (typeof t !== 'object') { - t = { name: t }; - } - return _.defaults(t, { meta, template }); - }); - } + function applyTerm(term: { value?: string; diff --git a/web/src/components/kibana/console/modules/legacy_core_editor/legacy_core_editor.ts b/web/src/components/kibana/console/modules/legacy_core_editor/legacy_core_editor.ts index 4fa278a9..16a7967f 100644 --- a/web/src/components/kibana/console/modules/legacy_core_editor/legacy_core_editor.ts +++ b/web/src/components/kibana/console/modules/legacy_core_editor/legacy_core_editor.ts @@ -10,6 +10,28 @@ import { EditorEvent, AutoCompleterFunction } from '../../entities/core_editor'; import { AceTokensProvider } from '../../entities/ace_tokens_providers'; import * as curl from './curl'; import smartResize from './smart_resize'; +ace.define( + 'ace/autocomplete/text_completer', + ['require', 'exports', 'module'], + function ( + require: unknown, + exports: { + getCompletions: ( + innerEditor: unknown, + session: unknown, + pos: unknown, + prefix: unknown, + callback: (e: null | Error, values: string[]) => void + ) => void; + } + ) { + exports.getCompletions = function (innerEditor, session, pos, prefix, callback) { + callback(null, []); + }; + } +); + +const langTools = ace.acequire('ace/ext/language_tools'); // @ts-ignore import * as InputMode from './mode/input'; @@ -351,28 +373,6 @@ export class LegacyCoreEditor implements CoreEditor { // disable standard context based autocompletion. // @ts-ignore - ace.define( - 'ace/autocomplete/text_completer', - ['require', 'exports', 'module'], - function ( - require: unknown, - exports: { - getCompletions: ( - innerEditor: unknown, - session: unknown, - pos: unknown, - prefix: unknown, - callback: (e: null | Error, values: string[]) => void - ) => void; - } - ) { - exports.getCompletions = function (innerEditor, session, pos, prefix, callback) { - callback(null, []); - }; - } - ); - - const langTools = ace.acequire('ace/ext/language_tools'); langTools.setCompleters( //addCompleters [{ diff --git a/web/src/components/kibana/console/modules/mappings/mappings.js b/web/src/components/kibana/console/modules/mappings/mappings.js index 9e2a42f9..c4675e3a 100644 --- a/web/src/components/kibana/console/modules/mappings/mappings.js +++ b/web/src/components/kibana/console/modules/mappings/mappings.js @@ -40,14 +40,15 @@ const POLL_INTERVAL = 60000; let pollTimeoutId; let perIndexTypes = {}; -let perAliasIndexes = []; -let templates = []; +let perAliasIndexes = {}; +let templates = {}; //new add let commands = []; - const mappingObj = {}; +let clusterID = ''; -export function expandAliases(indicesOrAliases) { +export function expandAliases(indicesOrAliases, clusterID) { + const clusterPerAliasIndexes = perAliasIndexes[clusterID] || {}; // takes a list of indices or aliases or a string which may be either and returns a list of indices // returns a list for multiple values or a string for a single. @@ -59,8 +60,8 @@ export function expandAliases(indicesOrAliases) { indicesOrAliases = [indicesOrAliases]; } indicesOrAliases = $.map(indicesOrAliases, function (iOrA) { - if (perAliasIndexes[iOrA]) { - return perAliasIndexes[iOrA]; + if (clusterPerAliasIndexes[iOrA]) { + return clusterPerAliasIndexes[iOrA]; } return [iOrA]; }); @@ -75,17 +76,21 @@ export function expandAliases(indicesOrAliases) { return ret.length > 1 ? ret : ret[0]; } -export function getTemplates() { - return [...templates]; +export function getTemplates(key) { + key = key.editor.editor.clusterID || clusterID; + const clusterTemplates = templates[key] || []; + return [...clusterTemplates]; } -export function getFields(indices, types) { +export function getFields(indices, types, key) { + key = key || clusterID + const clusterPerIndexTypes = perIndexTypes[key] || {}; // get fields for indices and types. Both can be a list, a string or null (meaning all). let ret = []; - indices = expandAliases(indices); + indices = expandAliases(indices, key); if (typeof indices === 'string') { - const typeDict = perIndexTypes[indices]; + const typeDict = clusterPerIndexTypes[indices]; if (!typeDict) { return []; } @@ -105,9 +110,9 @@ export function getFields(indices, types) { } } else { // multi index mode. - $.each(perIndexTypes, function (index) { + $.each(clusterPerIndexTypes, function (index) { if (!indices || indices.length === 0 || $.inArray(index, indices) !== -1) { - ret.push(getFields(index, types)); + ret.push(getFields(index, types, key)); } }); ret = [].concat.apply([], ret); @@ -118,11 +123,12 @@ export function getFields(indices, types) { }); } -export function getTypes(indices) { +export function getTypes(indices, clusterID) { + const clusterPerIndexTypes = perIndexTypes[clusterID] || {}; let ret = []; - indices = expandAliases(indices); + indices = expandAliases(indices, clusterID); if (typeof indices === 'string') { - const typeDict = perIndexTypes[indices]; + const typeDict = clusterPerIndexTypes[indices]; if (!typeDict) { return []; } @@ -133,9 +139,9 @@ export function getTypes(indices) { }); } else { // multi index mode. - $.each(perIndexTypes, function (index) { + $.each(clusterPerIndexTypes, function (index) { if (!indices || $.inArray(index, indices) !== -1) { - ret.push(getTypes(index)); + ret.push(getTypes(index, clusterID)); } }); ret = [].concat.apply([], ret); @@ -144,13 +150,18 @@ export function getTypes(indices) { return _.uniq(ret); } -export function getIndices(includeAliases) { +export function getIndices(includeAliases, key) { + if(typeof key != 'string') { + key = key?.editor?.clusterID || clusterID + } + const clusterPerIndexTypes = perIndexTypes[key] || {}; + const clusterPerAliasIndexes = perAliasIndexes[key] || []; const ret = []; - $.each(perIndexTypes, function (index) { + $.each(clusterPerIndexTypes, function (index) { ret.push(index); }); if (typeof includeAliases === 'undefined' ? true : includeAliases) { - $.each(perAliasIndexes, function (alias) { + $.each(clusterPerAliasIndexes, function (alias) { ret.push(alias); }); } @@ -211,12 +222,12 @@ function getFieldNamesFromProperties(properties = {}) { }); } -function loadTemplates(templatesObject = {}) { - templates = Object.keys(templatesObject); +function loadTemplates(templatesObject = {}, clusterID) { + templates[clusterID] = Object.keys(templatesObject); } -export function loadMappings(mappings) { - perIndexTypes = {}; +export function loadMappings(mappings, clusterID) { + let clusterPerIndexTypes = {}; $.each(mappings, function (index, indexMapping) { const normalizedIndexMappings = {}; @@ -234,31 +245,32 @@ export function loadMappings(mappings) { normalizedIndexMappings[typeName] = []; } }); - - perIndexTypes[index] = normalizedIndexMappings; + clusterPerIndexTypes[index] = normalizedIndexMappings; }); + perIndexTypes[clusterID] = clusterPerIndexTypes; } -export function loadAliases(aliases) { - perAliasIndexes = {}; +export function loadAliases(aliases, clusterID) { + let clusterPerAliasIndexes = {}; $.each(aliases || {}, function (index, omdexAliases) { // verify we have an index defined. useful when mapping loading is disabled - perIndexTypes[index] = perIndexTypes[index] || {}; + // clusterPerAliasIndexes[index] = clusterPerAliasIndexes[index] || {}; $.each(omdexAliases.aliases || {}, function (alias) { if (alias === index) { return; } // alias which is identical to index means no index. - let curAliases = perAliasIndexes[alias]; + + let curAliases = clusterPerAliasIndexes[alias]; if (!curAliases) { curAliases = []; - perAliasIndexes[alias] = curAliases; + clusterPerAliasIndexes[alias] = curAliases; } curAliases.push(index); }); }); - - perAliasIndexes._all = getIndices(false); + clusterPerAliasIndexes._all = getIndices(false, clusterID); + perAliasIndexes[clusterID] = clusterPerAliasIndexes; } export function clear() { @@ -343,15 +355,15 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID } else { mappingsResponse = mappings[0]; } - loadMappings(getObject(mappingsResponse)); // + loadMappings(getObject(mappingsResponse), clusterID); // } if (aliases) { - loadAliases(getObject(aliases[0])); + loadAliases(getObject(aliases[0]), clusterID); } if (templates) { - loadTemplates(getObject(templates[0])); + loadTemplates(getObject(templates[0]), clusterID); } if (mappings && aliases) { @@ -410,4 +422,8 @@ export function getCommand(title) { return c._source['title'] == title; }) return command && command[0]; +} + +export function setClusterID(id) { + clusterID = id; } \ No newline at end of file diff --git a/web/src/components/kibana/discover/public/application/components/discover_table/table.tsx b/web/src/components/kibana/discover/public/application/components/discover_table/table.tsx index a39598c7..ab7b8270 100644 --- a/web/src/components/kibana/discover/public/application/components/discover_table/table.tsx +++ b/web/src/components/kibana/discover/public/application/components/discover_table/table.tsx @@ -63,7 +63,7 @@ const Table: React.FC = ({ columns, hits, sortOrder, indexPattern, o {hits.slice(0, scrollState.limit).map((row, idx)=>{ - return { diff --git a/web/src/components/kibana/index_pattern_management/public/context.ts b/web/src/components/kibana/index_pattern_management/public/context.ts index 99c54143..e12e6c6b 100644 --- a/web/src/components/kibana/index_pattern_management/public/context.ts +++ b/web/src/components/kibana/index_pattern_management/public/context.ts @@ -83,7 +83,7 @@ const indexPatternManagementStart = indexPatternManagementService.start() const indexPatternsApiClient = new IndexPatternsApiClient(http); const uiconfigs = { - ['metaFields']: ['_source', '_id', '_type', '_index', '_score'], + ['metaFields']: ['_source', '_id', '_type', '_index' ],//'_score' defaultIndex: '', }; const uiSettings = { diff --git a/web/src/lib/hooks/storage.js b/web/src/lib/hooks/storage.js new file mode 100644 index 00000000..ac9805dd --- /dev/null +++ b/web/src/lib/hooks/storage.js @@ -0,0 +1,40 @@ +import { useCallback, useState, useEffect } from "react" + +export function useLocalStorage(key, defaultValue, encryptor) { + return useStorage(key, defaultValue, window.localStorage, encryptor) +} + +export function useSessionStorage(key, defaultValue) { + return useStorage(key, defaultValue, window.sessionStorage) +} + +function useStorage(key, defaultValue, storageObject, encryptor) { + const [value, setValue] = useState(() => { + const storeValue = storageObject.getItem(key) + if (storeValue) { + if(encryptor && typeof encryptor.encode == 'function') return encryptor.decode(storeValue); + return storeValue + } + + if (typeof initialValue === "function") { + return defaultValue() + } else { + return defaultValue + } + }) + + useEffect(() => { + if (value === undefined) return storageObject.removeItem(key) + let toStoreValue = value; + if(encryptor && typeof encryptor.encode == 'function'){ + toStoreValue = encryptor.encode(toStoreValue) + } + storageObject.setItem(key, toStoreValue) + }, [key, value, storageObject]) + + const remove = useCallback(() => { + setValue(undefined) + }, []) + + return [value, setValue, remove] +} \ No newline at end of file diff --git a/web/src/pages/DataManagement/Discover.jsx b/web/src/pages/DataManagement/Discover.jsx index 1c910cc5..7e8ab807 100644 --- a/web/src/pages/DataManagement/Discover.jsx +++ b/web/src/pages/DataManagement/Discover.jsx @@ -93,7 +93,6 @@ const Discover = (props)=>{ columns: ['_source'], sort: [], }) - // updateQuery({indexPattern:IP}); } //const indexPatterns = [{"id":"1ccce5c0-bb9a-11eb-957b-939add21a246","type":"index-pattern","namespaces":["default"],"updated_at":"2021-05-23T07:40:14.747Z","version":"WzkxOTEsNDhd","attributes":{"title":"test-custom*","timeFieldName":"created_at","fields":"[{\"count\":0,\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_score\",\"type\":\"number\",\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"address\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"address.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"address\"}}},{\"count\":0,\"conflictDescriptions\":{\"text\":[\"test-custom1\"],\"long\":[\"test-custom\",\"test-custom8\",\"test-custom9\"]},\"name\":\"age\",\"type\":\"conflict\",\"esTypes\":[\"text\",\"long\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"age.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"age\"}}},{\"count\":0,\"name\":\"created_at\",\"type\":\"date\",\"esTypes\":[\"date\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"email\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"email.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"email\"}}},{\"count\":0,\"name\":\"hobbies\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"hobbies.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"hobbies\"}}},{\"count\":0,\"name\":\"id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"id\"}}},{\"count\":0,\"name\":\"name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"name\"}}}]"},"references":[],"migrationVersion":{"index-pattern":"7.6.0"}}]; @@ -113,9 +112,7 @@ const Discover = (props)=>{ const columns = state.columns; const updateQuery = useCallback( - async (_payload, isUpdate) => { - // if (isUpdate === false) { - // } + async (_payload) => { if(!indexPattern){ return } @@ -139,11 +136,9 @@ const Discover = (props)=>{ //console.log(JSON.stringify(params)); //console.log(getEsQuery(indexPattern)) }, - [props.indexPatternList, state.interval, state.sort] + [indexPattern, state.interval,] ); - - const onChangeInterval = useCallback( (interval) => { if (interval) { @@ -276,7 +271,7 @@ const Discover = (props)=>{ filterManager.addFilters(newFilters); updateQuery() }, - [indexPattern, indexPatterns] + [indexPattern] ); const timefilterUpdateHandler = useCallback( @@ -308,12 +303,13 @@ const Discover = (props)=>{ const resetQuery = ()=>{}; const showDatePicker = indexPattern.timeFieldName != ""; - const saveDocument = useCallback(async ({_index, _id, _type, _source})=>{ + const saveDocument = useCallback(async ({_index, _id, _type, _source, is_new})=>{ const {http} = getContext(); const res = await http.put(`/elasticsearch/${props.selectedCluster.id}/doc/${_index}/${_id}`, { prependBasePath: false, query: { _type, + is_new, }, body: JSON.stringify(_source), }); @@ -323,8 +319,8 @@ const Discover = (props)=>{ } message.success('saved successfully'); updateQuery() - return res - },[props.selectedCluster]) + return res; + },[props.selectedCluster, updateQuery]) const deleteDocument = useCallback(async ({_index, _id, _type})=>{ const {http} = getContext(); @@ -341,7 +337,7 @@ const Discover = (props)=>{ message.success('deleted successfully'); updateQuery() return res - },[props.selectedCluster]) + },[props.selectedCluster, updateQuery]) return ( @@ -589,9 +585,9 @@ const DiscoverUI = (props)=>{ } } initialFetch(); - return ()=>{ - queryStringManager.setQuery(''); - } + // return ()=>{ + // queryStringManager.setQuery(''); + // } },[props.selectedCluster]); function changeIndexPattern(indexPattern){ diff --git a/web/src/pages/DataManagement/Index.js b/web/src/pages/DataManagement/Index.js index 872ab80e..0e0f5f10 100644 --- a/web/src/pages/DataManagement/Index.js +++ b/web/src/pages/DataManagement/Index.js @@ -61,13 +61,18 @@ class JSONWrapper extends PureComponent { class CreateForm extends React.Component { okHandle = () => { const {handleAdd, form} = this.props; + const me = this; + form.validateFields((err, fieldsValue) => { if (err) return; - form.resetFields(); - fieldsValue['config'] = this.editorValueGetter(); + fieldsValue['config'] = me.editor.getValue(); handleAdd(fieldsValue); + form.resetFields(); }); }; + onEditorDidMount = (editor)=>{ + this.editor = editor; + } render() { const {modalVisible, form, handleModalVisible} = this.props; @@ -98,7 +103,7 @@ class CreateForm extends React.Component { tabSize: 2, wordBasedSuggestions: true, }} - editorDidMount={(valueGetter)=>{this.editorValueGetter=valueGetter}} + onMount={this.onEditorDidMount} />
@@ -162,8 +167,8 @@ class Index extends PureComponent { this.handleDeleteClick(record.index)}> 删除 - - 文档管理 + {/* + 文档管理 */} ), }, @@ -268,12 +273,12 @@ class Index extends PureComponent { }) } } - handleEditorDidMount = (editorName, _valueGetter)=>{ - this[editorName] = _valueGetter; + handleEditorDidMount = (editorName, editor)=>{ + this[editorName] = editor; } handleIndexSettingsSaveClick = (indexName)=>{ - let settings = this.indexSettingsGetter(); + let settings = this.indexSettingsEditor.getValue(); settings = JSON.parse(settings); const {dispatch,clusterID} = this.props; dispatch({ @@ -423,7 +428,7 @@ class Index extends PureComponent { tabSize: 2, wordBasedSuggestions: true, }} - editorDidMount={(valueGetter)=>this.handleEditorDidMount('indexSettingsGetter', valueGetter)} + onMount={(editor)=>this.handleEditorDidMount('indexSettingsEditor', editor)} />
@@ -432,10 +437,15 @@ class Index extends PureComponent { {}}> + - - Delete + { + this.handleDeleteClick(editingIndex.index); + this.setState({drawerVisible: false}) + }} title="sure to delete ?"> + + Delete + {/**/} {/* */} diff --git a/web/src/pages/DataManagement/models/index.js b/web/src/pages/DataManagement/models/index.js index 3f50f102..c98aea24 100644 --- a/web/src/pages/DataManagement/models/index.js +++ b/web/src/pages/DataManagement/models/index.js @@ -13,7 +13,7 @@ export default { *fetchIndices({payload}, {call, put}){ let resp = yield call(getIndices, payload) if(resp.error){ - message.warn("获取数据失败") + message.error("获取数据失败") return } yield put({ @@ -27,7 +27,7 @@ export default { *fetchMappings({payload}, {call, put}){ let resp = yield call(getMappings, payload); if(resp.error){ - message.warn("get mappings failed") + message.warn(resp.error) return } yield put({ @@ -40,7 +40,7 @@ export default { *fetchSettings({payload}, {call, put}){ let resp = yield call(getSettings, payload); if(resp.error){ - message.warn("get settings failed") + message.warn(resp.error) return } yield put({ @@ -53,9 +53,12 @@ export default { *saveSettings({payload}, {call, put, select}){ let resp = yield call(updateSettings, payload); if(resp.error){ - message.warn("save settings failed") + message.error(resp.error) return } + if(resp.result == 'updated'){ + message.success("save successfully") + } let {settings} = yield select(state=>state.index); settings[payload.index] = payload.settings; yield put({ @@ -68,7 +71,7 @@ export default { *removeIndex({payload}, {call, put, select}){ let resp = yield call(deleteIndex, payload); if(resp.error){ - message.warn("get mappings failed") + message.error(resp.error) return } let {clusterIndices} = yield select(state=>state.index); @@ -83,7 +86,7 @@ export default { *addIndex({payload}, {call, put, select}){ let resp = yield call(createIndex, payload); if(resp.error){ - message.warn("create index failed") + message.error(resp.error) return } yield put({ diff --git a/web/src/pages/DevTool/Console.tsx b/web/src/pages/DevTool/Console.tsx index 50058ea1..f687f58a 100644 --- a/web/src/pages/DevTool/Console.tsx +++ b/web/src/pages/DevTool/Console.tsx @@ -1,15 +1,191 @@ import Console from '../../components/kibana/console/components/Console'; import {connect} from 'dva'; +import {Tabs, Button, Icon, Menu, Dropdown} from 'antd'; +import {useState, useReducer, useCallback, useEffect, useMemo} from 'react'; +import {useLocalStorage} from '@/lib/hooks/storage'; +import {setClusterID} from '../../components/kibana/console/modules/mappings/mappings'; +import {editorList} from '@/components/kibana/console/contexts/editor_context/editor_registry'; -// export default ()=>{ -// return ( -// -// ) -// } +const { TabPane } = Tabs; +const TabConsole = (props:any)=>{ + return ( + + ) +} + + +// export default connect(({ +// global +// })=>({ +// selectedCluster: global.selectedCluster, +// }))(Console); + +const addTab = (state: any, action: any) => { + const { panes } = state; + const {cluster} = action.payload; + const activeKey = `${cluster.id}:${new Date().valueOf()}`; + panes.push({ key: activeKey, cluster_id: cluster.id}); + return { + ...state, + panes, + activeKey, + } +} +const removeTab = (state: any, action: any) =>{ + const { activeKey, panes } = state; + const {targetKey} = action.payload; + const newPanes = panes.filter(pane => pane.key !== targetKey); + return { + ...state, + panes: newPanes, + activeKey: panes[0]?.key, + } +} + +const consoleTabReducer = (state: any, action: any) => { + const {type, payload} = action; + let newState = state; + switch(type){ + case 'add': + newState = addTab(state, action); + break; + case 'remove': + newState = removeTab(state, action); + break; + case 'change': + newState = { + ...state, + activeKey: payload.activeKey, + } + editorList.setActiveEditor(payload.activeKey); + break; + case 'saveContent': + const panes = state.panes.map((pane)=>{ + if(pane.key == state.activeKey){ + return { + ...pane, + content: action.payload.content, + } + } + return pane; + }); + newState = ({ + ...state, + panes, + }); + break; + default: + } + // setLocalState(newState); + return newState; +} + +const ConsoleUI = ({clusterList}: any)=>{ + const clusterMap = useMemo(()=>{ + let cm = {}; + (clusterList || []).map((cluster: any)=>{ + cm[cluster.id] = cluster; + }); + return cm; + }, [clusterList]) + const [localState, setLocalState, removeLocalState] = useLocalStorage("console:state", { + panes: [], + activeKey: '', + },{ + encode: JSON.stringify, + decode: JSON.parse, + }) + const [tabState, dispatch] = useReducer(consoleTabReducer, localState) + + useEffect(()=>{ + setLocalState(tabState) + }, [tabState]) + + const saveEditorContent = useCallback((content)=>{ + dispatch({ + type: 'saveContent', + payload: { + content + } + }) + }, [dispatch]) + + const onChange = (activeKey:string) => { + dispatch({ + type: 'change', + payload: { + activeKey + } + }) + }; + + const onEdit = (targetKey: string | React.MouseEvent, action:string) => { + dispatch({ + type: action, + payload: { + targetKey, + } + }) + }; + + const newTabClick = useCallback((param: any)=>{ + const cluster = clusterList.find(item=>item.id == param.key); + if(!cluster){ + console.log('cluster not found') + return; + } + dispatch({ + type:'add', + payload: { + cluster, + } + }) + },[clusterList]) + + const menu = ( + + {(clusterList||[]).map((cluster:any)=>{ + return {cluster.name} + })} + + ); + + const tabBarExtra =( + + ); + + setClusterID(tabState.activeKey?.split(':')[0]); + const panes = tabState.panes.filter((pane: any)=>{ + return typeof clusterMap[pane.cluster_id] != 'undefined'; + }) + + return ( +
+ + {panes.map(pane => ( + + + {/* {pane.content} */} + + ))} + +
+ ); +} export default connect(({ global })=>({ selectedCluster: global.selectedCluster, -}))(Console); \ No newline at end of file + clusterList: global.clusterList, +}))(ConsoleUI); \ No newline at end of file