console tab v0.1

This commit is contained in:
liugq 2021-10-15 11:41:38 +08:00
parent e1cd6d0cf7
commit b8fb6a3d87
21 changed files with 691 additions and 318 deletions

View File

@ -61,13 +61,28 @@ func (handler APIHandler) HandleUpdateDocumentAction(w http.ResponseWriter, req
err := handler.DecodeJSON(req, &reqBody) err := handler.DecodeJSON(req, &reqBody)
if err != nil { if err != nil {
resBody["error"] = err resBody["error"] = err.Error()
handler.WriteJSON(w, resBody, http.StatusOK) handler.WriteJSON(w, resBody, http.StatusOK)
return return
} }
indexName := ps.ByName("index") indexName := ps.ByName("index")
docID := ps.ByName("docId") docID := ps.ByName("docId")
typ := handler.GetParameter(req, "_type") 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) insertRes, err := client.Index(indexName, typ, docID, reqBody)
if err != nil { if err != nil {
resBody["error"] = err.Error() resBody["error"] = err.Error()
@ -156,6 +171,30 @@ func (handler APIHandler) HandleSearchDocumentAction(w http.ResponseWriter, req
handler.WriteJSON(w, resResult, http.StatusOK) 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{} { func formatESSearchResult(esResp *elastic.SearchResponse) map[string]interface{} {
total := esResp.Hits.Total total := esResp.Hits.Total
if len(esResp.Hits.Hits) == 0 { if len(esResp.Hits.Hits) == 0 {

View File

@ -5,6 +5,7 @@ import (
"infini.sh/framework/core/elastic" "infini.sh/framework/core/elastic"
"infini.sh/framework/core/util" "infini.sh/framework/core/util"
"net/http" "net/http"
"runtime/debug"
) )
func (handler APIHandler) HandleGetMappingsAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { 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) { 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") targetClusterID := ps.ByName("id")
client := elastic.GetClient(targetClusterID) client := elastic.GetClient(targetClusterID)
indexName := ps.ByName("index") indexName := ps.ByName("index")

View File

@ -86,7 +86,6 @@ func reindex(esName string, body *model.Reindex, typ string) (string, error) {
func newResponseBody() map[string]interface{} { func newResponseBody() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"status": true,
} }
} }

View File

@ -29,6 +29,7 @@ func Init(cfg *config.AppConfig) {
ui.HandleUIMethod(api.POST, path.Join(esPrefix, "doc/:index"), handler.HandleAddDocumentAction) 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.PUT, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleUpdateDocumentAction)
ui.HandleUIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleDeleteDocumentAction) 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.POST, path.Join(pathPrefix, "rebuild/*id"), handler.HandleReindexAction)
ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction) ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction)

View File

@ -162,7 +162,8 @@ export default [
// routes:[ // routes:[
// { path: '/', redirect: '/' }, // { path: '/', redirect: '/' },
// ], // ],
// }, { // },
// {
// path: '/data/template', // path: '/data/template',
// name: 'template', // name: 'template',
// component: './DataManagement/IndexTemplate', // component: './DataManagement/IndexTemplate',
@ -200,11 +201,11 @@ export default [
//search //search
// { {
// path: '/search', path: '/search',
// name: 'search', name: 'search',
// icon: 'search', icon: 'search',
// routes: [ routes: [
// { // {
// path: '/search/overview', // path: '/search/overview',
// name: 'overview', // name: 'overview',
@ -244,34 +245,36 @@ export default [
// ], // ],
// }, // },
// ] // ]
// }, {
// path: '/search/alias',
// name: 'alias',
// component: './SearchManage/alias/Alias',
// routes: [
// {
// path: '/search/alias',
// redirect: '/search/alias/index',
// // routes:[
// // { path: '/', redirect: '/' },
// // ],
// }, // },
// { {
// path: '/search/alias/index', path: '/search/alias',
// component: './SearchManage/alias/AliasManage', name: 'alias',
component: './SearchManage/alias/Alias',
routes: [
{
path: '/search/alias',
redirect: '/search/alias/index',
// routes:[ // routes:[
// { path: '/', redirect: '/' }, // { 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/alias/rule',
// component: './SearchManage/alias/Rule',
// routes:[
// { path: '/', redirect: '/' },
// ],
// }
// ]
// }, {
// path: '/search/dict', // path: '/search/dict',
// name: 'dict', // name: 'dict',
// component: './SearchManage/dict/Dict', // component: './SearchManage/dict/Dict',
@ -298,7 +301,8 @@ export default [
// ], // ],
// } // }
// ] // ]
// }, { // },
// {
// path: '/search/analyzer', // path: '/search/analyzer',
// name: 'analyzer', // name: 'analyzer',
// component: './SearchManage/analyzer/Analyzer', // component: './SearchManage/analyzer/Analyzer',
@ -322,35 +326,36 @@ export default [
// ], // ],
// } // }
// ] // ]
// }//, { // }
// // path: '/search/nlp', //, {
// // name: 'nlp', // path: '/search/nlp',
// // component: './SearchManage/nlp/NLP', // name: 'nlp',
// // routes: [ // component: './SearchManage/nlp/NLP',
// // { // routes: [
// // path: '/search/nlp', // {
// // redirect: '/search/nlp/query', // path: '/search/nlp',
// // }, // redirect: '/search/nlp/query',
// // { // },
// // path: '/search/nlp/query', // {
// // component: './SearchManage/nlp/Query', // path: '/search/nlp/query',
// // }, // component: './SearchManage/nlp/Query',
// // { // },
// // path: '/search/nlp/intention', // {
// // component: './SearchManage/nlp/Intention', // path: '/search/nlp/intention',
// // }, // component: './SearchManage/nlp/Intention',
// // { // },
// // path: '/search/nlp/knowledge', // {
// // component: './SearchManage/nlp/Knowledge', // path: '/search/nlp/knowledge',
// // }, // component: './SearchManage/nlp/Knowledge',
// // { // },
// // path: '/search/nlp/text', // {
// // component: './SearchManage/nlp/Text', // path: '/search/nlp/text',
// // } // component: './SearchManage/nlp/Text',
// //] // }
// //},
//] //]
//}, //},
]
},
// //
// //sync // //sync
// { // {

View File

@ -1,5 +1,5 @@
// @ts-ignore // @ts-ignore
import React, { useRef, useMemo } from 'react'; import React, { useRef, useMemo,useEffect } from 'react';
import ConsoleInput from './ConsoleInput'; import ConsoleInput from './ConsoleInput';
import ConsoleOutput from './ConsoleOutput'; import ConsoleOutput from './ConsoleOutput';
import { Panel } from './Panel'; import { Panel } from './Panel';
@ -17,13 +17,19 @@ import {RequestStatusBar} from './request_status_bar';
interface props { interface props {
selectedCluster: any; selectedCluster: any;
saveEditorContent: (content: string)=>void;
initialText: string;
paneKey: string;
} }
const INITIAL_PANEL_WIDTH = 50; const INITIAL_PANEL_WIDTH = 50;
const PANEL_MIN_WIDTH = '300px'; const PANEL_MIN_WIDTH = '300px';
const ConsoleWrapper = ({ const ConsoleWrapper = ({
selectedCluster selectedCluster,
saveEditorContent,
initialText,
paneKey,
}:props) => { }:props) => {
const { const {
@ -32,10 +38,51 @@ const ConsoleWrapper = ({
} = useRequestReadContext(); } = useRequestReadContext();
const lastDatum = requestData?.[requestData.length - 1] ?? requestError; 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<HTMLDivElement>(null);
const consoleRef = useRef<HTMLDivElement>(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 ( return (
<div> <div>
<div ref={consoleRef} className="Console">
<PanelsContainer resizerClassName="resizer">
<Panel style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }} initialWidth={INITIAL_PANEL_WIDTH}>
<ConsoleInput clusterID={selectedCluster.id} saveEditorContent={saveEditorContent} initialText={initialText} paneKey={paneKey} />
</Panel>
<Panel style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }} initialWidth={INITIAL_PANEL_WIDTH}>
<ConsoleOutput clusterID={selectedCluster.id} />
</Panel>
</PanelsContainer>
</div>
<div ref={statusBarRef} style={{ position:'fixed', bottom:0, borderTop: '1px solid #eee', zIndex:5000}}>
<EuiFlexGroup className="consoleContainer" <EuiFlexGroup className="consoleContainer"
style={{height:30, background:'#fff'}} style={{height:30, background:'#fff'}}
gutterSize="none" gutterSize="none"
@ -58,15 +105,6 @@ const ConsoleWrapper = ({
/> />
</EuiFlexItem> </EuiFlexItem>
</EuiFlexGroup> </EuiFlexGroup>
<div className="Console">
<PanelsContainer resizerClassName="resizer">
<Panel style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }} initialWidth={INITIAL_PANEL_WIDTH}>
<ConsoleInput clusterID={selectedCluster.id} />
</Panel>
<Panel style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }} initialWidth={INITIAL_PANEL_WIDTH}>
<ConsoleOutput clusterID={selectedCluster.id} />
</Panel>
</PanelsContainer>
</div> </div>
</div> </div>
); );

View File

@ -11,7 +11,7 @@ import './ConsoleInput.scss';
import { useSendCurrentRequestToES } from '../hooks/use_send_current_request_to_es'; import { useSendCurrentRequestToES } from '../hooks/use_send_current_request_to_es';
import { useSetInputEditor } from '../hooks/use_set_input_editor'; import { useSetInputEditor } from '../hooks/use_set_input_editor';
import '@elastic/eui/dist/eui_theme_light.css'; 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 'antd/dist/antd.css';
import {retrieveAutoCompleteInfo} from '../modules/mappings/mappings'; import {retrieveAutoCompleteInfo} from '../modules/mappings/mappings';
import {useSaveCurrentTextObject} from '../hooks/use_save_current_text_object'; import {useSaveCurrentTextObject} from '../hooks/use_save_current_text_object';
@ -66,6 +66,8 @@ const SendRequestButton = (props: any) => {
interface ConsoleInputProps { interface ConsoleInputProps {
clusterID: string, clusterID: string,
initialText: string | undefined, initialText: string | undefined,
saveEditorContent: (content: string)=>void,
paneKey: string,
} }
const DEFAULT_INPUT_VALUE = `GET _search 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<HTMLDivElement | null>(null); const editorRef = useRef<HTMLDivElement | null>(null);
const editorActionsRef = useRef<HTMLDivElement | null>(null); const editorActionsRef = useRef<HTMLDivElement | null>(null);
const editorInstanceRef = useRef<SenseEditor | null>(null); const editorInstanceRef = useRef<SenseEditor | null>(null);
@ -105,8 +108,10 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
// senseEditor.highlightCurrentRequestsAndUpdateActionBar(); // senseEditor.highlightCurrentRequestsAndUpdateActionBar();
editorInstanceRef.current = senseEditor; editorInstanceRef.current = senseEditor;
setInputEditor(senseEditor); setInputEditor(senseEditor);
senseEditor.paneKey = paneKey;
editorList.addInputEditor(senseEditor);
senseEditor.update(initialText || DEFAULT_INPUT_VALUE); senseEditor.update(initialText || DEFAULT_INPUT_VALUE);
// applyCurrentSettings(senseEditor!.getCoreEditor(), {fontSize:14, wrapMode: true,}); applyCurrentSettings(senseEditor!.getCoreEditor(), {fontSize:12, wrapMode: true,});
function setupAutosave() { function setupAutosave() {
let timer: number; let timer: number;
@ -123,7 +128,8 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
function saveCurrentState() { function saveCurrentState() {
try { try {
const content = senseEditor.getCoreEditor().getValue(); const content = senseEditor.getCoreEditor().getValue();
saveCurrentTextObjectRef.current(content); // saveCurrentTextObjectRef.current(content);
saveEditorContent(content)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
// Ignoring saving error // Ignoring saving error
@ -142,6 +148,7 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
}, []); }, []);
useEffect(()=>{ useEffect(()=>{
retrieveAutoCompleteInfo(settings, settings.getAutocomplete(), clusterID); retrieveAutoCompleteInfo(settings, settings.getAutocomplete(), clusterID);
aceEditorRef.current && (aceEditorRef.current['clusterID'] = clusterID);
},[clusterID]) },[clusterID])
const handleSaveAsCommonCommand = async () => { const handleSaveAsCommonCommand = async () => {
@ -188,7 +195,7 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
</EuiFlexGroup> </EuiFlexGroup>
<div <div
ref={editorRef} ref={editorRef}
id="ConAppEditor" id={`Editor_${editorInstanceRef.current?.paneKey}`}
className="conApp__editorContent" className="conApp__editorContent"
data-test-subj="request-editor" data-test-subj="request-editor"
onClick={()=>{consoleMenuRef.current?.closePopover(); aceEditorRef.current?.focus()}} onClick={()=>{consoleMenuRef.current?.closePopover(); aceEditorRef.current?.focus()}}
@ -198,13 +205,14 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
); );
}; };
const ConsoleInput = ({clusterID}:{clusterID:string})=>{ // const ConsoleInput = ({clusterID}:{clusterID:string})=>{
const { done, error, retry } = useDataInit(); // const { done, error, retry } = useDataInit();
const { currentTextObject } = useEditorReadContext(); // const { currentTextObject } = useEditorReadContext();
return done ? <ConsoleInputUI clusterID={clusterID} initialText={currentTextObject?.text}/>: <></> // return done ? <ConsoleInputUI clusterID={clusterID} initialText={currentTextObject?.text}/>: <></>
} // }
export default ConsoleInput; // export default ConsoleInput;
export default ConsoleInputUI;

View File

@ -46,7 +46,7 @@ function ConsoleOutput({clusterID}: props) {
const textarea = editorRef.current!.querySelector('textarea')!; const textarea = editorRef.current!.querySelector('textarea')!;
textarea.setAttribute('id', inputId); textarea.setAttribute('id', inputId);
textarea.setAttribute('readonly', 'true'); 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!); const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editorInstanceRef.current!);
return () => { return () => {

View File

@ -37,6 +37,7 @@ export class EditorRegistry {
setInputEditor(inputEditor: SenseEditor) { setInputEditor(inputEditor: SenseEditor) {
this.inputEditor = inputEditor; this.inputEditor = inputEditor;
inputEditor.setAutocompleter();
} }
getInputEditor() { getInputEditor() {
@ -46,3 +47,29 @@ export class EditorRegistry {
// Create a single instance of this and use as private state. // Create a single instance of this and use as private state.
export const instance = new EditorRegistry(); 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.inputEditors.length; i++){
const editor = this.inputEditors[i];
if(key == editor.paneKey) {
instance.setInputEditor(editor);
break;
}
}
}
}
export const editorList = new EditorList();

View File

@ -30,6 +30,10 @@ export class SenseEditor {
this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this)); this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this));
} }
setAutocompleter = ()=>{
this.coreEditor.registerAutocompleter(this.autocomplete.getCompletions);
}
prevRequestStart = (rowOrPos?: number | Position): Position => { prevRequestStart = (rowOrPos?: number | Position): Position => {
let curRow: number; let curRow: number;

View File

@ -333,14 +333,6 @@ export function getCurrentMethodAndTokenPaths(
return ret; return ret;
} }
// eslint-disable-next-line
export default function ({
coreEditor: editor,
parser,
}: {
coreEditor: CoreEditor;
parser: RowParser;
}) {
function isUrlPathToken(token: Token | null) { function isUrlPathToken(token: Token | null) {
switch ((token || ({} as Token)).type) { switch ((token || ({} as Token)).type) {
case 'url.slash': case 'url.slash':
@ -365,6 +357,16 @@ export default function ({
}); });
} }
// eslint-disable-next-line
export default function ({
coreEditor: editor,
parser,
}: {
coreEditor: CoreEditor;
parser: RowParser;
}) {
function applyTerm(term: { function applyTerm(term: {
value?: string; value?: string;
context?: AutoCompleteContext; context?: AutoCompleteContext;

View File

@ -10,6 +10,28 @@ import { EditorEvent, AutoCompleterFunction } from '../../entities/core_editor';
import { AceTokensProvider } from '../../entities/ace_tokens_providers'; import { AceTokensProvider } from '../../entities/ace_tokens_providers';
import * as curl from './curl'; import * as curl from './curl';
import smartResize from './smart_resize'; 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 // @ts-ignore
import * as InputMode from './mode/input'; import * as InputMode from './mode/input';
@ -351,28 +373,6 @@ export class LegacyCoreEditor implements CoreEditor {
// disable standard context based autocompletion. // disable standard context based autocompletion.
// @ts-ignore // @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 langTools.setCompleters( //addCompleters
[{ [{

View File

@ -40,14 +40,15 @@ const POLL_INTERVAL = 60000;
let pollTimeoutId; let pollTimeoutId;
let perIndexTypes = {}; let perIndexTypes = {};
let perAliasIndexes = []; let perAliasIndexes = {};
let templates = []; let templates = {};
//new add //new add
let commands = []; let commands = [];
const mappingObj = {}; 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 // 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. // returns a list for multiple values or a string for a single.
@ -59,8 +60,8 @@ export function expandAliases(indicesOrAliases) {
indicesOrAliases = [indicesOrAliases]; indicesOrAliases = [indicesOrAliases];
} }
indicesOrAliases = $.map(indicesOrAliases, function (iOrA) { indicesOrAliases = $.map(indicesOrAliases, function (iOrA) {
if (perAliasIndexes[iOrA]) { if (clusterPerAliasIndexes[iOrA]) {
return perAliasIndexes[iOrA]; return clusterPerAliasIndexes[iOrA];
} }
return [iOrA]; return [iOrA];
}); });
@ -75,17 +76,21 @@ export function expandAliases(indicesOrAliases) {
return ret.length > 1 ? ret : ret[0]; return ret.length > 1 ? ret : ret[0];
} }
export function getTemplates() { export function getTemplates(key) {
return [...templates]; 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). // get fields for indices and types. Both can be a list, a string or null (meaning all).
let ret = []; let ret = [];
indices = expandAliases(indices); indices = expandAliases(indices, key);
if (typeof indices === 'string') { if (typeof indices === 'string') {
const typeDict = perIndexTypes[indices]; const typeDict = clusterPerIndexTypes[indices];
if (!typeDict) { if (!typeDict) {
return []; return [];
} }
@ -105,9 +110,9 @@ export function getFields(indices, types) {
} }
} else { } else {
// multi index mode. // multi index mode.
$.each(perIndexTypes, function (index) { $.each(clusterPerIndexTypes, function (index) {
if (!indices || indices.length === 0 || $.inArray(index, indices) !== -1) { if (!indices || indices.length === 0 || $.inArray(index, indices) !== -1) {
ret.push(getFields(index, types)); ret.push(getFields(index, types, key));
} }
}); });
ret = [].concat.apply([], ret); 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 = []; let ret = [];
indices = expandAliases(indices); indices = expandAliases(indices, clusterID);
if (typeof indices === 'string') { if (typeof indices === 'string') {
const typeDict = perIndexTypes[indices]; const typeDict = clusterPerIndexTypes[indices];
if (!typeDict) { if (!typeDict) {
return []; return [];
} }
@ -133,9 +139,9 @@ export function getTypes(indices) {
}); });
} else { } else {
// multi index mode. // multi index mode.
$.each(perIndexTypes, function (index) { $.each(clusterPerIndexTypes, function (index) {
if (!indices || $.inArray(index, indices) !== -1) { if (!indices || $.inArray(index, indices) !== -1) {
ret.push(getTypes(index)); ret.push(getTypes(index, clusterID));
} }
}); });
ret = [].concat.apply([], ret); ret = [].concat.apply([], ret);
@ -144,13 +150,18 @@ export function getTypes(indices) {
return _.uniq(ret); 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 = []; const ret = [];
$.each(perIndexTypes, function (index) { $.each(clusterPerIndexTypes, function (index) {
ret.push(index); ret.push(index);
}); });
if (typeof includeAliases === 'undefined' ? true : includeAliases) { if (typeof includeAliases === 'undefined' ? true : includeAliases) {
$.each(perAliasIndexes, function (alias) { $.each(clusterPerAliasIndexes, function (alias) {
ret.push(alias); ret.push(alias);
}); });
} }
@ -211,12 +222,12 @@ function getFieldNamesFromProperties(properties = {}) {
}); });
} }
function loadTemplates(templatesObject = {}) { function loadTemplates(templatesObject = {}, clusterID) {
templates = Object.keys(templatesObject); templates[clusterID] = Object.keys(templatesObject);
} }
export function loadMappings(mappings) { export function loadMappings(mappings, clusterID) {
perIndexTypes = {}; let clusterPerIndexTypes = {};
$.each(mappings, function (index, indexMapping) { $.each(mappings, function (index, indexMapping) {
const normalizedIndexMappings = {}; const normalizedIndexMappings = {};
@ -234,31 +245,32 @@ export function loadMappings(mappings) {
normalizedIndexMappings[typeName] = []; normalizedIndexMappings[typeName] = [];
} }
}); });
clusterPerIndexTypes[index] = normalizedIndexMappings;
perIndexTypes[index] = normalizedIndexMappings;
}); });
perIndexTypes[clusterID] = clusterPerIndexTypes;
} }
export function loadAliases(aliases) { export function loadAliases(aliases, clusterID) {
perAliasIndexes = {}; let clusterPerAliasIndexes = {};
$.each(aliases || {}, function (index, omdexAliases) { $.each(aliases || {}, function (index, omdexAliases) {
// verify we have an index defined. useful when mapping loading is disabled // 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) { $.each(omdexAliases.aliases || {}, function (alias) {
if (alias === index) { if (alias === index) {
return; return;
} // alias which is identical to index means no index. } // alias which is identical to index means no index.
let curAliases = perAliasIndexes[alias];
let curAliases = clusterPerAliasIndexes[alias];
if (!curAliases) { if (!curAliases) {
curAliases = []; curAliases = [];
perAliasIndexes[alias] = curAliases; clusterPerAliasIndexes[alias] = curAliases;
} }
curAliases.push(index); curAliases.push(index);
}); });
}); });
clusterPerAliasIndexes._all = getIndices(false, clusterID);
perAliasIndexes._all = getIndices(false); perAliasIndexes[clusterID] = clusterPerAliasIndexes;
} }
export function clear() { export function clear() {
@ -343,15 +355,15 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID
} else { } else {
mappingsResponse = mappings[0]; mappingsResponse = mappings[0];
} }
loadMappings(getObject(mappingsResponse)); // loadMappings(getObject(mappingsResponse), clusterID); //
} }
if (aliases) { if (aliases) {
loadAliases(getObject(aliases[0])); loadAliases(getObject(aliases[0]), clusterID);
} }
if (templates) { if (templates) {
loadTemplates(getObject(templates[0])); loadTemplates(getObject(templates[0]), clusterID);
} }
if (mappings && aliases) { if (mappings && aliases) {
@ -411,3 +423,7 @@ export function getCommand(title) {
}) })
return command && command[0]; return command && command[0];
} }
export function setClusterID(id) {
clusterID = id;
}

View File

@ -63,7 +63,7 @@ const Table: React.FC<TableProps> = ({ columns, hits, sortOrder, indexPattern, o
<tbody> <tbody>
{hits.slice(0, scrollState.limit).map((row, idx)=>{ {hits.slice(0, scrollState.limit).map((row, idx)=>{
return <TableRow key={'discover-table-row'+idx} onFilter={onFilter} return <TableRow key={'discover-table-row'+row._id} onFilter={onFilter}
columns={columns} columns={columns}
hideTimeColumn={false} hideTimeColumn={false}
indexPattern={indexPattern} indexPattern={indexPattern}

View File

@ -51,12 +51,15 @@ export function Detail({
message.error('wrong json format') message.error('wrong json format')
return return
} }
const res = await document.saveDocument({ let params = {
_index: row._index, _index: row._index,
_id: docID || row._id, _id: docID || row._id,
_type: row._type, _type: row._type,
_source: source _source: source,
}) };
docID && (params['is_new'] = '1')
const res = await document.saveDocument(params)
if(!res.error) setEditorVisble(false) if(!res.error) setEditorVisble(false)
} }
const deleteDocumentClick = ()=>{ const deleteDocumentClick = ()=>{

View File

@ -83,7 +83,7 @@ const indexPatternManagementStart = indexPatternManagementService.start()
const indexPatternsApiClient = new IndexPatternsApiClient(http); const indexPatternsApiClient = new IndexPatternsApiClient(http);
const uiconfigs = { const uiconfigs = {
['metaFields']: ['_source', '_id', '_type', '_index', '_score'], ['metaFields']: ['_source', '_id', '_type', '_index' ],//'_score'
defaultIndex: '', defaultIndex: '',
}; };
const uiSettings = { const uiSettings = {

View File

@ -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]
}

View File

@ -93,7 +93,6 @@ const Discover = (props)=>{
columns: ['_source'], columns: ['_source'],
sort: [], 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"}}]; //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 columns = state.columns;
const updateQuery = useCallback( const updateQuery = useCallback(
async (_payload, isUpdate) => { async (_payload) => {
// if (isUpdate === false) {
// }
if(!indexPattern){ if(!indexPattern){
return return
} }
@ -139,11 +136,9 @@ const Discover = (props)=>{
//console.log(JSON.stringify(params)); //console.log(JSON.stringify(params));
//console.log(getEsQuery(indexPattern)) //console.log(getEsQuery(indexPattern))
}, },
[props.indexPatternList, state.interval, state.sort] [indexPattern, state.interval,]
); );
const onChangeInterval = useCallback( const onChangeInterval = useCallback(
(interval) => { (interval) => {
if (interval) { if (interval) {
@ -276,7 +271,7 @@ const Discover = (props)=>{
filterManager.addFilters(newFilters); filterManager.addFilters(newFilters);
updateQuery() updateQuery()
}, },
[indexPattern, indexPatterns] [indexPattern]
); );
const timefilterUpdateHandler = useCallback( const timefilterUpdateHandler = useCallback(
@ -308,12 +303,13 @@ const Discover = (props)=>{
const resetQuery = ()=>{}; const resetQuery = ()=>{};
const showDatePicker = indexPattern.timeFieldName != ""; 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 {http} = getContext();
const res = await http.put(`/elasticsearch/${props.selectedCluster.id}/doc/${_index}/${_id}`, { const res = await http.put(`/elasticsearch/${props.selectedCluster.id}/doc/${_index}/${_id}`, {
prependBasePath: false, prependBasePath: false,
query: { query: {
_type, _type,
is_new,
}, },
body: JSON.stringify(_source), body: JSON.stringify(_source),
}); });
@ -323,8 +319,8 @@ const Discover = (props)=>{
} }
message.success('saved successfully'); message.success('saved successfully');
updateQuery() updateQuery()
return res return res;
},[props.selectedCluster]) },[props.selectedCluster, updateQuery])
const deleteDocument = useCallback(async ({_index, _id, _type})=>{ const deleteDocument = useCallback(async ({_index, _id, _type})=>{
const {http} = getContext(); const {http} = getContext();
@ -341,7 +337,7 @@ const Discover = (props)=>{
message.success('deleted successfully'); message.success('deleted successfully');
updateQuery() updateQuery()
return res return res
},[props.selectedCluster]) },[props.selectedCluster, updateQuery])
return ( return (
<Card bordered={false}> <Card bordered={false}>
@ -589,9 +585,9 @@ const DiscoverUI = (props)=>{
} }
} }
initialFetch(); initialFetch();
return ()=>{ // return ()=>{
queryStringManager.setQuery(''); // queryStringManager.setQuery('');
} // }
},[props.selectedCluster]); },[props.selectedCluster]);
function changeIndexPattern(indexPattern){ function changeIndexPattern(indexPattern){

View File

@ -61,13 +61,18 @@ class JSONWrapper extends PureComponent {
class CreateForm extends React.Component { class CreateForm extends React.Component {
okHandle = () => { okHandle = () => {
const {handleAdd, form} = this.props; const {handleAdd, form} = this.props;
const me = this;
form.validateFields((err, fieldsValue) => { form.validateFields((err, fieldsValue) => {
if (err) return; if (err) return;
form.resetFields(); fieldsValue['config'] = me.editor.getValue();
fieldsValue['config'] = this.editorValueGetter();
handleAdd(fieldsValue); handleAdd(fieldsValue);
form.resetFields();
}); });
}; };
onEditorDidMount = (editor)=>{
this.editor = editor;
}
render() { render() {
const {modalVisible, form, handleModalVisible} = this.props; const {modalVisible, form, handleModalVisible} = this.props;
@ -98,7 +103,7 @@ class CreateForm extends React.Component {
tabSize: 2, tabSize: 2,
wordBasedSuggestions: true, wordBasedSuggestions: true,
}} }}
editorDidMount={(valueGetter)=>{this.editorValueGetter=valueGetter}} onMount={this.onEditorDidMount}
/> />
</div> </div>
</FormItem> </FormItem>
@ -162,8 +167,8 @@ class Index extends PureComponent {
<Popconfirm title="Sure to delete?" onConfirm={() => this.handleDeleteClick(record.index)}> <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDeleteClick(record.index)}>
<a>删除</a> <a>删除</a>
</Popconfirm> </Popconfirm>
<Divider type="vertical" /> {/* <Divider type="vertical" />
<Link to={"/data/document?index=" + record.index}>文档管理</Link> <Link to={"/data/document?index=" + record.index}>文档管理</Link> */}
</Fragment> </Fragment>
), ),
}, },
@ -268,12 +273,12 @@ class Index extends PureComponent {
}) })
} }
} }
handleEditorDidMount = (editorName, _valueGetter)=>{ handleEditorDidMount = (editorName, editor)=>{
this[editorName] = _valueGetter; this[editorName] = editor;
} }
handleIndexSettingsSaveClick = (indexName)=>{ handleIndexSettingsSaveClick = (indexName)=>{
let settings = this.indexSettingsGetter(); let settings = this.indexSettingsEditor.getValue();
settings = JSON.parse(settings); settings = JSON.parse(settings);
const {dispatch,clusterID} = this.props; const {dispatch,clusterID} = this.props;
dispatch({ dispatch({
@ -423,7 +428,7 @@ class Index extends PureComponent {
tabSize: 2, tabSize: 2,
wordBasedSuggestions: true, wordBasedSuggestions: true,
}} }}
editorDidMount={(valueGetter)=>this.handleEditorDidMount('indexSettingsGetter', valueGetter)} onMount={(editor)=>this.handleEditorDidMount('indexSettingsEditor', editor)}
/> />
</div> </div>
</TabPane> </TabPane>
@ -432,10 +437,15 @@ class Index extends PureComponent {
<Dropdown <Dropdown
placement="topLeft" placement="topLeft"
overlay={( overlay={(
<Menu onClick={()=>{}}> <Menu>
<Menu.Item key="1"> <Menu.Item key="1">
<Popconfirm onConfirm={()=>{
this.handleDeleteClick(editingIndex.index);
this.setState({drawerVisible: false})
}} title="sure to delete ?">
<Icon type="delete" /> <Icon type="delete" />
Delete Delete
</Popconfirm>
</Menu.Item> </Menu.Item>
{/*<Menu.Item key="2">*/} {/*<Menu.Item key="2">*/}
{/* <Icon type="edit" />*/} {/* <Icon type="edit" />*/}

View File

@ -13,7 +13,7 @@ export default {
*fetchIndices({payload}, {call, put}){ *fetchIndices({payload}, {call, put}){
let resp = yield call(getIndices, payload) let resp = yield call(getIndices, payload)
if(resp.error){ if(resp.error){
message.warn("获取数据失败") message.error("获取数据失败")
return return
} }
yield put({ yield put({
@ -27,7 +27,7 @@ export default {
*fetchMappings({payload}, {call, put}){ *fetchMappings({payload}, {call, put}){
let resp = yield call(getMappings, payload); let resp = yield call(getMappings, payload);
if(resp.error){ if(resp.error){
message.warn("get mappings failed") message.warn(resp.error)
return return
} }
yield put({ yield put({
@ -40,7 +40,7 @@ export default {
*fetchSettings({payload}, {call, put}){ *fetchSettings({payload}, {call, put}){
let resp = yield call(getSettings, payload); let resp = yield call(getSettings, payload);
if(resp.error){ if(resp.error){
message.warn("get settings failed") message.warn(resp.error)
return return
} }
yield put({ yield put({
@ -53,9 +53,12 @@ export default {
*saveSettings({payload}, {call, put, select}){ *saveSettings({payload}, {call, put, select}){
let resp = yield call(updateSettings, payload); let resp = yield call(updateSettings, payload);
if(resp.error){ if(resp.error){
message.warn("save settings failed") message.error(resp.error)
return return
} }
if(resp.result == 'updated'){
message.success("save successfully")
}
let {settings} = yield select(state=>state.index); let {settings} = yield select(state=>state.index);
settings[payload.index] = payload.settings; settings[payload.index] = payload.settings;
yield put({ yield put({
@ -68,7 +71,7 @@ export default {
*removeIndex({payload}, {call, put, select}){ *removeIndex({payload}, {call, put, select}){
let resp = yield call(deleteIndex, payload); let resp = yield call(deleteIndex, payload);
if(resp.error){ if(resp.error){
message.warn("get mappings failed") message.error(resp.error)
return return
} }
let {clusterIndices} = yield select(state=>state.index); let {clusterIndices} = yield select(state=>state.index);
@ -83,7 +86,7 @@ export default {
*addIndex({payload}, {call, put, select}){ *addIndex({payload}, {call, put, select}){
let resp = yield call(createIndex, payload); let resp = yield call(createIndex, payload);
if(resp.error){ if(resp.error){
message.warn("create index failed") message.error(resp.error)
return return
} }
yield put({ yield put({

View File

@ -1,15 +1,191 @@
import Console from '../../components/kibana/console/components/Console'; import Console from '../../components/kibana/console/components/Console';
import {connect} from 'dva'; 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 ()=>{ const { TabPane } = Tabs;
// return (
// <Console />
// )
// }
const TabConsole = (props:any)=>{
return (
<Console {...props}/>
)
}
// 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<HTMLElement, 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 = (
<Menu onClick={newTabClick}>
{(clusterList||[]).map((cluster:any)=>{
return <Menu.Item key={cluster.id}>{cluster.name}</Menu.Item>
})}
</Menu>
);
const tabBarExtra =(<Dropdown overlay={menu}>
<Button size="small">
<Icon type="plus"/>
</Button>
</Dropdown>);
setClusterID(tabState.activeKey?.split(':')[0]);
const panes = tabState.panes.filter((pane: any)=>{
return typeof clusterMap[pane.cluster_id] != 'undefined';
})
return (
<div style={{background:'#fff'}}>
<Tabs
onChange={onChange}
activeKey={tabState.activeKey}
type="editable-card"
onEdit={onEdit}
hideAdd
tabBarExtraContent={tabBarExtra}
>
{panes.map(pane => (
<TabPane tab={clusterMap[pane.cluster_id].name} key={pane.key} closable={pane.closable}>
<TabConsole selectedCluster={clusterMap[pane.cluster_id]} paneKey={pane.key} saveEditorContent={saveEditorContent} initialText={pane.content} />
{/* {pane.content} */}
</TabPane>
))}
</Tabs>
</div>
);
}
export default connect(({ export default connect(({
global global
})=>({ })=>({
selectedCluster: global.selectedCluster, selectedCluster: global.selectedCluster,
}))(Console); clusterList: global.clusterList,
}))(ConsoleUI);