add discover and console module
This commit is contained in:
parent
7f4ef3e399
commit
77fc87c3dc
|
@ -71,7 +71,7 @@ pipeline {
|
|||
|
||||
stage('Start Backend Docker') {
|
||||
steps {
|
||||
sh 'cd /home/deploy/search-center/docker && docker-compose -f docker-compose.dev.yml up -d'
|
||||
sh 'cd /home/deploy/search-center/docker && docker-compose -f docker-compose.dev.yml up --remove-orphans -d'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,233 +1,247 @@
|
|||
SHELL=/bin/bash
|
||||
|
||||
# APP info
|
||||
APP_NAME := search-center
|
||||
APP_VERSION := 1.0.0_SNAPSHOT
|
||||
APP_CONFIG := $(APP_NAME).yml
|
||||
APP_EOLDate := "2021-12-31 10:10:10"
|
||||
APP_STATIC_FOLDER := .public
|
||||
APP_STATIC_PACKAGE := public
|
||||
APP_UI_FOLDER := ui
|
||||
APP_PLUGIN_FOLDER := plugin
|
||||
|
||||
# Get release version from environment
|
||||
ifneq "$(VERSION)" ""
|
||||
APP_VERSION := $(VERSION)
|
||||
endif
|
||||
|
||||
ifneq "$(EOL)" ""
|
||||
APP_EOLDate := $(EOL)
|
||||
endif
|
||||
|
||||
# Ensure GOPATH is set before running build process.
|
||||
ifeq "$(GOPATH)" ""
|
||||
GOPATH := ~/go
|
||||
#$(error Please set the environment variable GOPATH before running `make`)
|
||||
endif
|
||||
|
||||
|
||||
PATH := $(PATH):$(GOPATH)/bin
|
||||
|
||||
# Go environment
|
||||
CURDIR := $(shell pwd)
|
||||
OLDGOPATH:= $(GOPATH)
|
||||
|
||||
CMD_DIR := $(CURDIR)/cmd
|
||||
OUTPUT_DIR := $(CURDIR)/bin
|
||||
|
||||
|
||||
# INFINI framework
|
||||
INFINI_BASE_FOLDER := $(OLDGOPATH)/src/infini.sh/
|
||||
FRAMEWORK_FOLDER := $(INFINI_BASE_FOLDER)/framework/
|
||||
FRAMEWORK_REPO := ssh://git@git.infini.ltd:64221/infini/framework.git
|
||||
FRAMEWORK_BRANCH := master
|
||||
FRAMEWORK_VENDOR_FOLDER := $(CURDIR)/../vendor/
|
||||
FRAMEWORK_VENDOR_REPO := ssh://git@git.infini.ltd:64221/infini/framework-vendor.git
|
||||
FRAMEWORK_VENDOR_BRANCH := master
|
||||
|
||||
|
||||
NEWGOPATH:= $(CURDIR):$(FRAMEWORK_VENDOR_FOLDER):$(GOPATH)
|
||||
|
||||
GO := GO15VENDOREXPERIMENT="1" GO111MODULE=off go
|
||||
GOBUILD := GOPATH=$(NEWGOPATH) CGO_ENABLED=0 GRPC_GO_REQUIRE_HANDSHAKE=off $(GO) build -ldflags='-s -w' -gcflags "-m" --work
|
||||
GOBUILDNCGO := GOPATH=$(NEWGOPATH) CGO_ENABLED=1 $(GO) build -ldflags -s
|
||||
GOTEST := GOPATH=$(NEWGOPATH) CGO_ENABLED=1 $(GO) test -ldflags -s
|
||||
|
||||
ARCH := "`uname -s`"
|
||||
LINUX := "Linux"
|
||||
MAC := "Darwin"
|
||||
GO_FILES=$(find . -iname '*.go' | grep -v /vendor/)
|
||||
PKGS=$(go list ./... | grep -v /vendor/)
|
||||
|
||||
FRAMEWORK_OFFLINE_BUILD := ""
|
||||
ifneq "$(OFFLINE_BUILD)" ""
|
||||
FRAMEWORK_OFFLINE_BUILD := $(OFFLINE_BUILD)
|
||||
endif
|
||||
|
||||
.PHONY: all build update test clean
|
||||
|
||||
default: build
|
||||
|
||||
env:
|
||||
@echo OLDGOPATH:$(OLDGOPATH)
|
||||
@echo GOPATH:$(GOPATH)
|
||||
@echo NEWGOPATH:$(NEWGOPATH)
|
||||
@echo INFINI_BASE_FOLDER:$(INFINI_BASE_FOLDER)
|
||||
@echo FRAMEWORK_FOLDER:$(FRAMEWORK_FOLDER)
|
||||
@echo FRAMEWORK_VENDOR_FOLDER:$(FRAMEWORK_VENDOR_FOLDER)
|
||||
|
||||
build: config
|
||||
$(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-cmd: config
|
||||
@$(MAKE) restore-generated-file
|
||||
@for f in $(shell ls ${CMD_DIR}); do (cd $(CMD_DIR)/$${f} && $(GOBUILD) -o $(OUTPUT_DIR)/$${f}); done
|
||||
|
||||
|
||||
# used to build the binary for gdb debugging
|
||||
build-race: clean config update-vfs
|
||||
$(GOBUILD) -gcflags "-m -N -l" -race -o $(OUTPUT_DIR)/$(APP_NAME)
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
tar: build
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/$(APP_NAME).tar.gz $(APP_NAME) $(APP_CONFIG)
|
||||
|
||||
cross-build: clean config update-vfs
|
||||
$(GO) test
|
||||
GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows64.exe
|
||||
GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-darwin64
|
||||
GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux64
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
|
||||
build-win:
|
||||
CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows64.exe
|
||||
CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOOS=windows GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows32.exe
|
||||
|
||||
build-linux:
|
||||
GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux64
|
||||
GOOS=linux GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux32
|
||||
|
||||
build-arm:
|
||||
GOOS=linux GOARCH=arm64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-arm64
|
||||
GOOS=linux GOARCH=arm GOARM=5 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-armv5
|
||||
GOOS=linux GOARCH=arm GOARM=6 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-armv6
|
||||
GOOS=linux GOARCH=arm GOARM=7 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-armv7
|
||||
|
||||
build-darwin:
|
||||
GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-darwin64
|
||||
#GOOS=darwin GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-darwin32
|
||||
|
||||
build-bsd:
|
||||
GOOS=freebsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-freebsd64
|
||||
GOOS=freebsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-freebsd32
|
||||
GOOS=netbsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-netbsd64
|
||||
GOOS=netbsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-netbsd32
|
||||
GOOS=openbsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-openbsd64
|
||||
GOOS=openbsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-openbsd32
|
||||
|
||||
all: clean config update-vfs cross-build restore-generated-file
|
||||
|
||||
all-platform: clean config update-vfs cross-build-all-platform restore-generated-file
|
||||
|
||||
cross-build-all-platform: clean config build-bsd build-linux build-darwin build-win restore-generated-file
|
||||
|
||||
format:
|
||||
go fmt $$(go list ./... | grep -v /vendor/)
|
||||
|
||||
clean_data:
|
||||
rm -rif dist
|
||||
rm -rif data
|
||||
rm -rif log
|
||||
|
||||
clean: clean_data
|
||||
rm -rif $(OUTPUT_DIR)
|
||||
mkdir $(OUTPUT_DIR)
|
||||
|
||||
init:
|
||||
@echo building $(APP_NAME) $(APP_VERSION)
|
||||
@echo $(CURDIR)
|
||||
@mkdir -p $(INFINI_BASE_FOLDER)
|
||||
@echo "framework path: " $(FRAMEWORK_FOLDER)
|
||||
@if [ ! -d $(FRAMEWORK_FOLDER) ]; then echo "framework does not exist";(cd $(INFINI_BASE_FOLDER)&&git clone -b $(FRAMEWORK_BRANCH) $(FRAMEWORK_REPO) framework ) fi
|
||||
@if [ ! -d $(FRAMEWORK_VENDOR_FOLDER) ]; then echo "framework vendor does not exist";(cd $(INFINI_BASE_FOLDER)&&git clone -b $(FRAMEWORK_VENDOR_BRANCH) $(FRAMEWORK_VENDOR_REPO) vendor) fi
|
||||
@if [ "" == $(FRAMEWORK_OFFLINE_BUILD) ]; then (cd $(FRAMEWORK_FOLDER) && git pull origin $(FRAMEWORK_BRANCH)); fi;
|
||||
@if [ "" == $(FRAMEWORK_OFFLINE_BUILD) ]; then (cd $(FRAMEWORK_VENDOR_FOLDER) && git pull origin $(FRAMEWORK_VENDOR_BRANCH)); fi;
|
||||
|
||||
update-generated-file:
|
||||
@echo "update generated info"
|
||||
@echo -e "package config\n\nconst LastCommitLog = \""`git log -1 --pretty=format:"%h, %ad, %an, %s"` "\"\nconst BuildDate = \"`date "+%Y-%m-%d %H:%M:%S"`\"" > config/generated.go
|
||||
@echo -e "\nconst EOLDate = \"$(APP_EOLDate)\"" >> config/generated.go
|
||||
@echo -e "\nconst Version = \"$(APP_VERSION)\"" >> config/generated.go
|
||||
|
||||
|
||||
restore-generated-file:
|
||||
@echo "restore generated info"
|
||||
@echo -e "package config\n\nconst LastCommitLog = \"N/A\"\nconst BuildDate = \"N/A\"" > config/generated.go
|
||||
@echo -e "\nconst EOLDate = \"N/A\"" >> config/generated.go
|
||||
@echo -e "\nconst Version = \"0.0.1-SNAPSHOT\"" >> config/generated.go
|
||||
|
||||
|
||||
update-vfs:
|
||||
cd $(FRAMEWORK_FOLDER) && cd cmd/vfs && $(GO) build && cp vfs ~/
|
||||
@if [ -d $(APP_STATIC_FOLDER) ]; then echo "generate static files";(cd $(APP_STATIC_FOLDER) && ~/vfs -ignore="static.go|.DS_Store" -o static.go -pkg $(APP_STATIC_PACKAGE) . ) fi
|
||||
|
||||
config: init update-vfs update-generated-file
|
||||
@echo "update configs"
|
||||
@# $(GO) env
|
||||
@mkdir -p $(OUTPUT_DIR)
|
||||
@cp $(APP_CONFIG) $(OUTPUT_DIR)/$(APP_CONFIG)
|
||||
|
||||
|
||||
dist: cross-build package
|
||||
|
||||
dist-major-platform: all package
|
||||
|
||||
dist-all-platform: all-platform package-all-platform
|
||||
|
||||
package:
|
||||
@echo "Packaging"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/darwin64.tar.gz darwin64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux64.tar.gz linux64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows64.tar.gz windows64 $(APP_CONFIG)
|
||||
|
||||
package-all-platform: package-darwin-platform package-linux-platform package-windows-platform
|
||||
@echo "Packaging all"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/freebsd64.tar.gz $(APP_NAME)-freebsd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/freebsd32.tar.gz $(APP_NAME)-freebsd32 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/netbsd64.tar.gz $(APP_NAME)-netbsd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/netbsd32.tar.gz $(APP_NAME)-netbsd32 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/openbsd64.tar.gz $(APP_NAME)-openbsd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/openbsd32.tar.gz $(APP_NAME)-openbsd32 $(APP_CONFIG)
|
||||
|
||||
|
||||
package-darwin-platform:
|
||||
@echo "Packaging Darwin"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/darwin64.tar.gz $(APP_NAME)-darwin64 $(APP_CONFIG)
|
||||
#cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/darwin32.tar.gz $(APP_NAME)-darwin32 $(APP_CONFIG)
|
||||
|
||||
package-linux-platform:
|
||||
@echo "Packaging Linux"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux64.tar.gz $(APP_NAME)-linux64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux32.tar.gz $(APP_NAME)-linux32 $(APP_CONFIG)
|
||||
|
||||
package-linux-arm-platform:
|
||||
@echo "Packaging Linux (ARM)"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/arm64.tar.gz $(APP_NAME)-arm64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/armv5.tar.gz $(APP_NAME)-armv5 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/armv6.tar.gz $(APP_NAME)-armv6 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/armv7.tar.gz $(APP_NAME)-armv7 $(APP_CONFIG)
|
||||
|
||||
package-windows-platform:
|
||||
@echo "Packaging Windows"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows64.tar.gz $(APP_NAME)-windows64.exe $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows32.tar.gz $(APP_NAME)-windows32.exe $(APP_CONFIG)
|
||||
|
||||
test:
|
||||
go get -u github.com/kardianos/govendor
|
||||
go get github.com/stretchr/testify/assert
|
||||
govendor test +local
|
||||
go test -timeout 60s ./...
|
||||
#GORACE="halt_on_error=1" go test ./... -race -timeout 120s --ignore ./vendor
|
||||
#go test -bench=. -benchmem
|
||||
SHELL=/bin/bash
|
||||
|
||||
# APP info
|
||||
APP_NAME := search-center
|
||||
APP_VERSION := 1.0.0_SNAPSHOT
|
||||
APP_CONFIG := $(APP_NAME).yml
|
||||
APP_EOLDate := "2021-12-31 10:10:10"
|
||||
APP_STATIC_FOLDER := .public
|
||||
APP_STATIC_PACKAGE := public
|
||||
APP_UI_FOLDER := ui
|
||||
APP_PLUGIN_FOLDER := plugin
|
||||
|
||||
# Get release version from environment
|
||||
ifneq "$(VERSION)" ""
|
||||
APP_VERSION := $(VERSION)
|
||||
endif
|
||||
|
||||
ifneq "$(EOL)" ""
|
||||
APP_EOLDate := $(EOL)
|
||||
endif
|
||||
|
||||
# Ensure GOPATH is set before running build process.
|
||||
ifeq "$(GOPATH)" ""
|
||||
GOPATH := ~/go
|
||||
#$(error Please set the environment variable GOPATH before running `make`)
|
||||
endif
|
||||
|
||||
|
||||
PATH := $(PATH):$(GOPATH)/bin
|
||||
|
||||
# Go environment
|
||||
CURDIR := $(shell pwd)
|
||||
OLDGOPATH:= $(GOPATH)
|
||||
|
||||
CMD_DIR := $(CURDIR)/cmd
|
||||
OUTPUT_DIR := $(CURDIR)/bin
|
||||
|
||||
|
||||
# INFINI framework
|
||||
INFINI_BASE_FOLDER := $(OLDGOPATH)/src/infini.sh/
|
||||
FRAMEWORK_FOLDER := $(INFINI_BASE_FOLDER)/framework/
|
||||
FRAMEWORK_REPO := ssh://git@git.infini.ltd:64221/infini/framework.git
|
||||
FRAMEWORK_BRANCH := master
|
||||
FRAMEWORK_VENDOR_FOLDER := $(CURDIR)/../vendor/
|
||||
FRAMEWORK_VENDOR_REPO := ssh://git@git.infini.ltd:64221/infini/framework-vendor.git
|
||||
FRAMEWORK_VENDOR_BRANCH := master
|
||||
|
||||
|
||||
NEWGOPATH:= $(CURDIR):$(FRAMEWORK_VENDOR_FOLDER):$(GOPATH)
|
||||
|
||||
GO := GO15VENDOREXPERIMENT="1" GO111MODULE=off go
|
||||
GOBUILD := GOPATH=$(NEWGOPATH) CGO_ENABLED=0 GRPC_GO_REQUIRE_HANDSHAKE=off $(GO) build -ldflags='-s -w' -gcflags "-m" --work
|
||||
GOBUILDNCGO := GOPATH=$(NEWGOPATH) CGO_ENABLED=1 $(GO) build -ldflags -s
|
||||
GOTEST := GOPATH=$(NEWGOPATH) CGO_ENABLED=1 $(GO) test -ldflags -s
|
||||
|
||||
ARCH := "`uname -s`"
|
||||
LINUX := "Linux"
|
||||
MAC := "Darwin"
|
||||
GO_FILES=$(find . -iname '*.go' | grep -v /vendor/)
|
||||
PKGS=$(go list ./... | grep -v /vendor/)
|
||||
|
||||
FRAMEWORK_OFFLINE_BUILD := ""
|
||||
ifneq "$(OFFLINE_BUILD)" ""
|
||||
FRAMEWORK_OFFLINE_BUILD := $(OFFLINE_BUILD)
|
||||
endif
|
||||
|
||||
.PHONY: all build update test clean
|
||||
|
||||
default: build-race
|
||||
|
||||
env:
|
||||
@echo OLDGOPATH:$(OLDGOPATH)
|
||||
@echo GOPATH:$(GOPATH)
|
||||
@echo NEWGOPATH:$(NEWGOPATH)
|
||||
@echo INFINI_BASE_FOLDER:$(INFINI_BASE_FOLDER)
|
||||
@echo FRAMEWORK_FOLDER:$(FRAMEWORK_FOLDER)
|
||||
@echo FRAMEWORK_VENDOR_FOLDER:$(FRAMEWORK_VENDOR_FOLDER)
|
||||
|
||||
build: config
|
||||
$(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-cmd: config
|
||||
@for f in $(shell ls ${CMD_DIR}); do (cd $(CMD_DIR)/$${f} && $(GOBUILD) -o $(OUTPUT_DIR)/$${f}); done
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
|
||||
# used to build the binary for gdb debugging
|
||||
build-race: clean config update-vfs
|
||||
$(GOBUILDNCGO) -gcflags "-m -N -l" -race -o $(OUTPUT_DIR)/$(APP_NAME)
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
tar: build
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/$(APP_NAME).tar.gz $(APP_NAME) $(APP_CONFIG)
|
||||
|
||||
cross-build: clean config update-vfs
|
||||
$(GO) test
|
||||
GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows-amd64.exe
|
||||
GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-mac-amd64
|
||||
GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-amd64
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
|
||||
build-win: config
|
||||
CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows-amd64.exe
|
||||
CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOOS=windows GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-windows-386.exe
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-linux: config
|
||||
GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-amd64
|
||||
GOOS=linux GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-386
|
||||
GOOS=linux GOARCH=mips $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-mips
|
||||
GOOS=linux GOARCH=mipsle $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-mipsle
|
||||
GOOS=linux GOARCH=mips64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-mips64
|
||||
GOOS=linux GOARCH=mips64le $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-mips64le
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-arm: config
|
||||
GOOS=linux GOARCH=arm64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-arm64
|
||||
GOOS=linux GOARCH=arm GOARM=5 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-armv5
|
||||
GOOS=linux GOARCH=arm GOARM=6 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-armv6
|
||||
GOOS=linux GOARCH=arm GOARM=7 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-linux-armv7
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-darwin: config
|
||||
GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-mac-amd64
|
||||
# GOOS=darwin GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-mac-386
|
||||
# GOOS=darwin GOARCH=arm64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-mac-arm64
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
build-bsd: config
|
||||
GOOS=freebsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-freebsd-amd64
|
||||
GOOS=freebsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-freebsd-386
|
||||
GOOS=netbsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-netbsd-amd64
|
||||
GOOS=netbsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-netbsd-386
|
||||
GOOS=openbsd GOARCH=amd64 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-openbsd-amd64
|
||||
GOOS=openbsd GOARCH=386 $(GOBUILD) -o $(OUTPUT_DIR)/$(APP_NAME)-openbsd-386
|
||||
@$(MAKE) restore-generated-file
|
||||
|
||||
all: clean config update-vfs cross-build restore-generated-file
|
||||
|
||||
all-platform: clean config update-vfs cross-build-all-platform restore-generated-file
|
||||
|
||||
cross-build-all-platform: clean config build-bsd build-linux build-darwin build-win restore-generated-file
|
||||
|
||||
format:
|
||||
go fmt $$(go list ./... | grep -v /vendor/)
|
||||
|
||||
clean_data:
|
||||
rm -rif dist
|
||||
rm -rif data
|
||||
rm -rif log
|
||||
|
||||
clean: clean_data
|
||||
rm -rif $(OUTPUT_DIR)
|
||||
mkdir $(OUTPUT_DIR)
|
||||
|
||||
init:
|
||||
@echo building $(APP_NAME) $(APP_VERSION)
|
||||
@echo $(CURDIR)
|
||||
@mkdir -p $(INFINI_BASE_FOLDER)
|
||||
@echo "framework path: " $(FRAMEWORK_FOLDER)
|
||||
@if [ ! -d $(FRAMEWORK_FOLDER) ]; then echo "framework does not exist";(cd $(INFINI_BASE_FOLDER)&&git clone -b $(FRAMEWORK_BRANCH) $(FRAMEWORK_REPO) framework ) fi
|
||||
@if [ ! -d $(FRAMEWORK_VENDOR_FOLDER) ]; then echo "framework vendor does not exist";(cd $(INFINI_BASE_FOLDER)&&git clone -b $(FRAMEWORK_VENDOR_BRANCH) $(FRAMEWORK_VENDOR_REPO) vendor) fi
|
||||
@if [ "" == $(FRAMEWORK_OFFLINE_BUILD) ]; then (cd $(FRAMEWORK_FOLDER) && git pull origin $(FRAMEWORK_BRANCH)); fi;
|
||||
@if [ "" == $(FRAMEWORK_OFFLINE_BUILD) ]; then (cd $(FRAMEWORK_VENDOR_FOLDER) && git pull origin $(FRAMEWORK_VENDOR_BRANCH)); fi;
|
||||
|
||||
update-generated-file:
|
||||
@echo "update generated info"
|
||||
@echo -e "package config\n\nconst LastCommitLog = \""`git log -1 --pretty=format:"%h, %ad, %an, %s"` "\"\nconst BuildDate = \"`date "+%Y-%m-%d %H:%M:%S"`\"" > config/generated.go
|
||||
@echo -e "\nconst EOLDate = \"$(APP_EOLDate)\"" >> config/generated.go
|
||||
@echo -e "\nconst Version = \"$(APP_VERSION)\"" >> config/generated.go
|
||||
|
||||
|
||||
restore-generated-file:
|
||||
@echo "restore generated info"
|
||||
@echo -e "package config\n\nconst LastCommitLog = \"N/A\"\nconst BuildDate = \"N/A\"" > config/generated.go
|
||||
@echo -e "\nconst EOLDate = \"N/A\"" >> config/generated.go
|
||||
@echo -e "\nconst Version = \"0.0.1-SNAPSHOT\"" >> config/generated.go
|
||||
|
||||
|
||||
update-vfs:
|
||||
cd $(FRAMEWORK_FOLDER) && cd cmd/vfs && $(GO) build && cp vfs ~/
|
||||
@if [ -d $(APP_STATIC_FOLDER) ]; then echo "generate static files";(cd $(APP_STATIC_FOLDER) && ~/vfs -ignore="static.go|.DS_Store" -o static.go -pkg $(APP_STATIC_PACKAGE) . ) fi
|
||||
|
||||
config: init update-vfs update-generated-file
|
||||
@echo "update configs"
|
||||
@# $(GO) env
|
||||
@mkdir -p $(OUTPUT_DIR)
|
||||
@cp $(APP_CONFIG) $(OUTPUT_DIR)/$(APP_CONFIG)
|
||||
|
||||
|
||||
dist: cross-build package
|
||||
|
||||
dist-major-platform: all package
|
||||
|
||||
dist-all-platform: all-platform package-all-platform
|
||||
|
||||
package:
|
||||
@echo "Packaging"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/mac-amd64.tar.gz mac-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-amd64.tar.gz linux-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows-amd64.tar.gz windows-amd64 $(APP_CONFIG)
|
||||
|
||||
package-all-platform: package-darwin-platform package-linux-platform package-windows-platform
|
||||
@echo "Packaging all"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/freebsd-amd64.tar.gz $(APP_NAME)-freebsd-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/freebsd-386.tar.gz $(APP_NAME)-freebsd-386 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/netbsd-amd64.tar.gz $(APP_NAME)-netbsd-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/netbsd-386.tar.gz $(APP_NAME)-netbsd-386 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/openbsd-amd64.tar.gz $(APP_NAME)-openbsd-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/openbsd-386.tar.gz $(APP_NAME)-openbsd-386 $(APP_CONFIG)
|
||||
|
||||
package-darwin-platform:
|
||||
@echo "Packaging Darwin"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/mac-amd64.tar.gz $(APP_NAME)-mac-amd64 $(APP_CONFIG)
|
||||
# cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/mac-386.tar.gz $(APP_NAME)-mac-386 $(APP_CONFIG)
|
||||
# cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/mac-arm64.tar.gz $(APP_NAME)-mac-arm64 $(APP_CONFIG)
|
||||
|
||||
package-linux-platform:
|
||||
@echo "Packaging Linux"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-amd64.tar.gz $(APP_NAME)-linux-amd64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-mips.tar.gz $(APP_NAME)-linux-mips $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-mipsle.tar.gz $(APP_NAME)-linux-mipsle $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-mips64.tar.gz $(APP_NAME)-linux-mips64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-mips64le.tar.gz $(APP_NAME)-linux-mips64le $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-386.tar.gz $(APP_NAME)-linux-386 $(APP_CONFIG)
|
||||
|
||||
package-linux-arm-platform:
|
||||
@echo "Packaging Linux (ARM)"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-arm64.tar.gz $(APP_NAME)-linux-arm64 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-armv5.tar.gz $(APP_NAME)-linux-armv5 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-armv6.tar.gz $(APP_NAME)-linux-armv6 $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/linux-armv7.tar.gz $(APP_NAME)-linux-armv7 $(APP_CONFIG)
|
||||
|
||||
package-windows-platform:
|
||||
@echo "Packaging Windows"
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows-amd64.tar.gz $(APP_NAME)-windows-amd64.exe $(APP_CONFIG)
|
||||
cd $(OUTPUT_DIR) && tar cfz $(OUTPUT_DIR)/windows-386.tar.gz $(APP_NAME)-windows-386.exe $(APP_CONFIG)
|
||||
|
||||
test:
|
||||
go get -u github.com/kardianos/govendor
|
||||
go get github.com/stretchr/testify/assert
|
||||
govendor test +local
|
||||
go test -timeout 60s ./...
|
||||
#GORACE="halt_on_error=1" go test ./... -race -timeout 120s --ignore ./vendor
|
||||
#go test -bench=. -benchmem
|
||||
|
|
|
@ -58,6 +58,7 @@ npm install -g cnpm --registry=https://registry.npm.taobao.org
|
|||
### 下载项目依赖包
|
||||
```
|
||||
cnpm install
|
||||
cnpm install -g cross-env
|
||||
```
|
||||
|
||||
### 启动开发模式
|
||||
|
|
2
main.go
2
main.go
|
@ -32,7 +32,7 @@ func main() {
|
|||
terminalFooter += (" / // |/ // __// // |/ // / / //_ _// \\ \n")
|
||||
terminalFooter += (" / // || // _/ / // || // / / /_ / / / o | \n")
|
||||
terminalFooter += ("/_//_/|_//_/ /_//_/|_//_/() /___//_/ /__,' \n\n")
|
||||
terminalFooter += ("©2020 INFINI.LTD, All Rights Reserved.\n")
|
||||
terminalFooter += ("©INFINI.LTD, All Rights Reserved.\n")
|
||||
|
||||
app := framework.NewApp("search-center", "the easiest way to operate your own search center.",
|
||||
config.Version, config.LastCommitLog, config.BuildDate,config.EOLDate, terminalHeader, terminalFooter)
|
||||
|
|
|
@ -17,8 +17,7 @@ web:
|
|||
binding: 0.0.0.0:9000
|
||||
skip_occupied_port: true
|
||||
|
||||
modules:
|
||||
- name: elastic
|
||||
elastic:
|
||||
elasticsearch: default
|
||||
enabled: true
|
||||
store:
|
||||
|
|
|
@ -67,13 +67,13 @@ export default {
|
|||
// pathRewrite: { '^/server': '' },
|
||||
// },
|
||||
// },
|
||||
// proxy: {
|
||||
// '/_search-center/': {
|
||||
// target: 'http://localhost:9000',
|
||||
// changeOrigin: true,
|
||||
// // pathRewrite: { '^/server': '' },
|
||||
// },
|
||||
// },
|
||||
proxy: {
|
||||
'/elasticsearch/': {
|
||||
target: 'http://localhost:9000',
|
||||
changeOrigin: true,
|
||||
// pathRewrite: { '^/server': '' },
|
||||
},
|
||||
},
|
||||
ignoreMomentLocale: true,
|
||||
lessLoaderOptions: {
|
||||
javascriptEnabled: true,
|
||||
|
@ -85,7 +85,8 @@ export default {
|
|||
if (
|
||||
context.resourcePath.includes('node_modules') ||
|
||||
context.resourcePath.includes('ant.design.pro.less') ||
|
||||
context.resourcePath.includes('global.less')
|
||||
context.resourcePath.includes('global.less') ||
|
||||
context.resourcePath.includes('.scss')
|
||||
) {
|
||||
return localName;
|
||||
}
|
||||
|
@ -124,4 +125,5 @@ export default {
|
|||
// // htmlSuffix: true,
|
||||
// dynamicRoot: true,
|
||||
// },
|
||||
sass: { },
|
||||
};
|
||||
|
|
|
@ -25,51 +25,84 @@ export default [
|
|||
icon: 'cluster',
|
||||
routes: [
|
||||
// { path: '/', redirect: '/platform/gateway' },
|
||||
{
|
||||
path: '/cluster/overview/',
|
||||
name: 'overview',
|
||||
component: './Cluster/Overview',
|
||||
}, {
|
||||
// {
|
||||
// path: '/cluster/overview/',
|
||||
// name: 'overview',
|
||||
// component: './Cluster/Overview',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: '/cluster/overview/:cluster_id',
|
||||
name: 'overview',
|
||||
component: './Cluster/Overview',
|
||||
hideInMenu: true,
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/cluster/monitoring/:cluster_id',
|
||||
name: 'cluster',
|
||||
component: './Cluster/ClusterMonitor',
|
||||
hideInMenu: true,
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
}, {
|
||||
path: '/cluster/metrics/',
|
||||
name: 'monitoring',
|
||||
component: './Cluster/Metrics',
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
}, {
|
||||
path: '/cluster/metrics/:cluster_id',
|
||||
name: 'monitoring',
|
||||
component: './Cluster/Metrics',
|
||||
hideInMenu: true,
|
||||
}, {
|
||||
path: '/cluster/logs/',
|
||||
name: 'logging',
|
||||
component: './Cluster/SearchMonitor',
|
||||
},{
|
||||
path: '/cluster/settings/',
|
||||
name: 'settings',
|
||||
component: './Cluster/Settings/Base',
|
||||
routes: [
|
||||
{
|
||||
path: '/cluster/settings',
|
||||
redirect: '/cluster/settings/repository',
|
||||
},
|
||||
{
|
||||
path: '/cluster/settings/repository',
|
||||
component: './Cluster/Settings/Repository',
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// path: '/cluster/logs/',
|
||||
// name: 'logging',
|
||||
// component: './Cluster/SearchMonitor',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },{
|
||||
// path: '/cluster/settings/',
|
||||
// name: 'settings',
|
||||
// component: './Cluster/Settings/Base',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/cluster/settings',
|
||||
// redirect: '/cluster/settings/repository',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/cluster/settings/repository',
|
||||
// component: './Cluster/Settings/Repository',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
]
|
||||
},
|
||||
//devtools
|
||||
{
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
path: '/dev_tool',
|
||||
name: 'devtool',
|
||||
icon: 'code',
|
||||
component: './DevTool/Console',
|
||||
},
|
||||
|
||||
//data
|
||||
{
|
||||
|
@ -96,215 +129,307 @@ export default [
|
|||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/data/overview',
|
||||
// name: 'overview',
|
||||
// component: './DataManagement/IndexSummary',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }, {
|
||||
// path: '/data/index',
|
||||
// name: 'index',
|
||||
// component: './DataManagement/Index',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },{
|
||||
// path: '/data/document',
|
||||
// name: 'document',
|
||||
// component: './DataManagement/Document',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }, {
|
||||
// path: '/data/template',
|
||||
// name: 'template',
|
||||
// component: './DataManagement/IndexTemplate',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/data/lifecycle',
|
||||
// name: 'lifecycle',
|
||||
// component: './DataManagement/IndexLifeCycle',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: '/data/overview',
|
||||
name: 'overview',
|
||||
component: './DataManagement/IndexSummary',
|
||||
}, {
|
||||
path: '/data/index',
|
||||
name: 'index',
|
||||
component: './DataManagement/Index',
|
||||
},{
|
||||
path: '/data/document',
|
||||
name: 'document',
|
||||
component: './DataManagement/Document',
|
||||
}, {
|
||||
path: '/data/template',
|
||||
name: 'template',
|
||||
component: './DataManagement/IndexTemplate',
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
path: '/data/discover',
|
||||
name: 'discover',
|
||||
component: './DataManagement/Discover',
|
||||
},
|
||||
{
|
||||
path: '/data/lifecycle',
|
||||
name: 'lifecycle',
|
||||
component: './DataManagement/IndexLifeCycle',
|
||||
routes:[
|
||||
{ path: '/', redirect: '/' },
|
||||
],
|
||||
path: '/data/views/',
|
||||
name: 'indexPatterns',
|
||||
component: './DataManagement/IndexPatterns',
|
||||
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
//search
|
||||
{
|
||||
path: '/search',
|
||||
name: 'search',
|
||||
icon: 'search',
|
||||
routes: [
|
||||
{
|
||||
path: '/search/overview',
|
||||
name: 'overview',
|
||||
component: './SearchManage/template/Template',
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
{
|
||||
path: '/search/template/:cluster_id',
|
||||
component: './SearchManage/template/SearchTemplate',
|
||||
},
|
||||
{
|
||||
path: '/search/template/history',
|
||||
component: './SearchManage/template/History',
|
||||
},
|
||||
]
|
||||
}, {
|
||||
path: '/search/alias',
|
||||
name: 'alias',
|
||||
component: './SearchManage/alias/Alias',
|
||||
routes: [
|
||||
{
|
||||
path: '/search/alias',
|
||||
redirect: '/search/alias/index',
|
||||
},
|
||||
{
|
||||
path: '/search/alias/index',
|
||||
component: './SearchManage/alias/AliasManage',
|
||||
},
|
||||
{
|
||||
path: '/search/alias/rule',
|
||||
component: './SearchManage/alias/Rule',
|
||||
}
|
||||
]
|
||||
}, {
|
||||
path: '/search/dict',
|
||||
name: 'dict',
|
||||
component: './SearchManage/dict/Dict',
|
||||
routes: [
|
||||
{
|
||||
path: '/search/dict',
|
||||
redirect: '/search/dict/professional',
|
||||
},
|
||||
{
|
||||
path: '/search/dict/professional',
|
||||
component: './SearchManage/dict/Pro',
|
||||
},
|
||||
{
|
||||
path: '/search/dict/common',
|
||||
component: './SearchManage/dict/Common',
|
||||
}
|
||||
]
|
||||
}, {
|
||||
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',
|
||||
},
|
||||
{
|
||||
path: '/search/analyzer/test',
|
||||
component: './SearchManage/analyzer/AnalyzerTest',
|
||||
}
|
||||
]
|
||||
}//, {
|
||||
// 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
|
||||
{
|
||||
path: '/sync',
|
||||
name: 'synchronize',
|
||||
icon: 'sync',
|
||||
routes: [
|
||||
{
|
||||
path: '/sync/overview',
|
||||
name: 'overview',
|
||||
component: './Synchronize/Pipes',
|
||||
},
|
||||
{
|
||||
path: '/sync/pipeline',
|
||||
name: 'pipeline',
|
||||
component: './Synchronize/Pipes',
|
||||
routes: [
|
||||
{
|
||||
path: '/sync/pipeline',
|
||||
redirect: '/sync/pipeline/logstash',
|
||||
},
|
||||
{
|
||||
path: '/sync/pipeline/ingestpipeline',
|
||||
component: './Synchronize/IngestPipeline',
|
||||
}, {
|
||||
path: '/sync/pipeline/logstash',
|
||||
component: './Synchronize/LogstashConfig',
|
||||
}]
|
||||
},{
|
||||
path: '/sync/rebuild',
|
||||
name: 'rebuild',
|
||||
component: './Synchronize/RebuildList',
|
||||
},
|
||||
{
|
||||
path: '/sync/rebuild/new',
|
||||
component: './Synchronize/Rebuild',
|
||||
hideInMenu: true,
|
||||
},{
|
||||
path: '/sync/inout',
|
||||
name: 'inout',
|
||||
component: './Synchronize/Import',
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
//backup
|
||||
{
|
||||
path: '/backup',
|
||||
name: 'backup',
|
||||
icon: 'cloud',
|
||||
routes: [
|
||||
{
|
||||
path: '/backup/overview',
|
||||
name: 'overview',
|
||||
component: './SearchManage/template/Template',
|
||||
},
|
||||
{
|
||||
path: '/backup/bakandrestore',
|
||||
name: 'index',
|
||||
component: './Backup/BakAndRestore',
|
||||
},{
|
||||
path: '/backup/lifecycle',
|
||||
name: 'lifecycle',
|
||||
component: './Backup/BakCycle',
|
||||
}
|
||||
]
|
||||
},
|
||||
//
|
||||
//
|
||||
// //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',
|
||||
// // }
|
||||
// //]
|
||||
// //},
|
||||
// ]
|
||||
// },
|
||||
//
|
||||
// //sync
|
||||
// {
|
||||
// path: '/sync',
|
||||
// name: 'synchronize',
|
||||
// icon: 'sync',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/sync/overview',
|
||||
// name: 'overview',
|
||||
// component: './Synchronize/Pipes',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/sync/pipeline',
|
||||
// name: 'pipeline',
|
||||
// component: './Synchronize/Pipes',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/sync/pipeline',
|
||||
// redirect: '/sync/pipeline/logstash',
|
||||
// },
|
||||
// {
|
||||
// path: '/sync/pipeline/ingestpipeline',
|
||||
// component: './Synchronize/IngestPipeline',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }, {
|
||||
// path: '/sync/pipeline/logstash',
|
||||
// component: './Synchronize/LogstashConfig',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }]
|
||||
// },{
|
||||
// path: '/sync/rebuild',
|
||||
// name: 'rebuild',
|
||||
// component: './Synchronize/RebuildList',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/sync/rebuild/new',
|
||||
// component: './Synchronize/Rebuild',
|
||||
// hideInMenu: true,
|
||||
// },{
|
||||
// path: '/sync/inout',
|
||||
// name: 'inout',
|
||||
// component: './Synchronize/Import',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
//
|
||||
// //backup
|
||||
// {
|
||||
// path: '/backup',
|
||||
// name: 'backup',
|
||||
// icon: 'cloud',
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/backup/overview',
|
||||
// name: 'overview',
|
||||
// component: './SearchManage/template/Template',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/backup/bakandrestore',
|
||||
// name: 'index',
|
||||
// component: './Backup/BakAndRestore',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// },{
|
||||
// path: '/backup/lifecycle',
|
||||
// name: 'lifecycle',
|
||||
// component: './Backup/BakCycle',
|
||||
// routes:[
|
||||
// { path: '/', redirect: '/' },
|
||||
// ],
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
|
||||
//settings
|
||||
{
|
||||
|
@ -323,77 +448,78 @@ export default [
|
|||
component: './System/Cluster/Form',
|
||||
hideInMenu: true
|
||||
},
|
||||
{
|
||||
path: '/system/settings',
|
||||
name: 'settings',
|
||||
component: './System/Settings/Base',
|
||||
hideChildrenInMenu: true,
|
||||
routes: [
|
||||
{
|
||||
path: '/system/settings',
|
||||
redirect: '/system/settings/global',
|
||||
},
|
||||
{
|
||||
path: '/system/settings/global',
|
||||
component: './System/Settings/Global',
|
||||
}, {
|
||||
path: '/system/settings/gateway',
|
||||
component: './System/Settings/Gateway',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/system/security',
|
||||
name: 'security',
|
||||
component: './System/Security/Base',
|
||||
hideChildrenInMenu: true,
|
||||
routes: [
|
||||
{
|
||||
path: '/system/security',
|
||||
redirect: '/system/security/general',
|
||||
},
|
||||
{
|
||||
path: '/system/security/general',
|
||||
component: './System/Security/General',
|
||||
}, {
|
||||
path: '/system/security/sso',
|
||||
component: './System/Security/SSO',
|
||||
}, {
|
||||
path: '/system/security/roles',
|
||||
component: './System/Security/Roles',
|
||||
}, {
|
||||
path: '/system/security/users',
|
||||
component: './System/Security/Users',
|
||||
}, {
|
||||
path: '/system/security/certs',
|
||||
component: './System/Security/Certs',
|
||||
},
|
||||
]
|
||||
}, {
|
||||
path: '/system/logs',
|
||||
name: 'logs',
|
||||
component: './System/Logs/Base',
|
||||
hideChildrenInMenu: true,
|
||||
routes: [
|
||||
{
|
||||
path: '/system/logs',
|
||||
redirect: '/system/logs/overview',
|
||||
},
|
||||
{
|
||||
path: '/system/logs/overview',
|
||||
component: './System/Logs/Overview',
|
||||
}, {
|
||||
path: '/system/logs/audit',
|
||||
component: './System/Logs/Audit',
|
||||
}, {
|
||||
path: '/system/logs/query',
|
||||
component: './System/Logs/Audit',
|
||||
}, {
|
||||
path: '/system/logs/slow',
|
||||
component: './System/Logs/Audit',
|
||||
},
|
||||
]
|
||||
},
|
||||
// {
|
||||
// path: '/system/settings',
|
||||
// name: 'settings',
|
||||
// component: './System/Settings/Base',
|
||||
// hideChildrenInMenu: true,
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/system/settings',
|
||||
// redirect: '/system/settings/global',
|
||||
// },
|
||||
// {
|
||||
// path: '/system/settings/global',
|
||||
// component: './System/Settings/Global',
|
||||
// }, {
|
||||
// path: '/system/settings/gateway',
|
||||
// component: './System/Settings/Gateway',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/system/security',
|
||||
// name: 'security',
|
||||
// component: './System/Security/Base',
|
||||
// hideChildrenInMenu: true,
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/system/security',
|
||||
// redirect: '/system/security/general',
|
||||
// },
|
||||
// {
|
||||
// path: '/system/security/general',
|
||||
// component: './System/Security/General',
|
||||
// }, {
|
||||
// path: '/system/security/sso',
|
||||
// component: './System/Security/SSO',
|
||||
// }, {
|
||||
// path: '/system/security/roles',
|
||||
// component: './System/Security/Roles',
|
||||
// }, {
|
||||
// path: '/system/security/users',
|
||||
// component: './System/Security/Users',
|
||||
// }, {
|
||||
// path: '/system/security/certs',
|
||||
// component: './System/Security/Certs',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/system/logs',
|
||||
// name: 'logs',
|
||||
// component: './System/Logs/Base',
|
||||
// hideChildrenInMenu: true,
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/system/logs',
|
||||
// redirect: '/system/logs/overview',
|
||||
// },
|
||||
// {
|
||||
// path: '/system/logs/overview',
|
||||
// component: './System/Logs/Overview',
|
||||
// }, {
|
||||
// path: '/system/logs/audit',
|
||||
// component: './System/Logs/Audit',
|
||||
// }, {
|
||||
// path: '/system/logs/query',
|
||||
// component: './System/Logs/Audit',
|
||||
// }, {
|
||||
// path: '/system/logs/slow',
|
||||
// component: './System/Logs/Audit',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
]
|
||||
},
|
||||
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
const d = moment.duration;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,66 @@
|
|||
const savedObjectsResult = {"page":1,"per_page":10000,"total":4,"saved_objects":[{"type":"index-pattern","id":"c7fbafd0-34a9-11eb-925f-9db57376c4ce","attributes":{"title":".monitoring-es-7-mb-*"},"references":[],"migrationVersion":{"index-pattern":"7.6.0"},"updated_at":"2020-12-02T14:34:38.010Z","version":"WzgyNCw3XQ==","namespaces":["default"],"score":0},{"type":"index-pattern","id":"861ea7f0-3a9b-11eb-9b55-45d33507027a","attributes":{"title":"mock_log*"},"references":[],"migrationVersion":{"index-pattern":"7.6.0"},"updated_at":"2020-12-10T04:09:09.044Z","version":"WzE3NTgsMTBd","namespaces":["default"],"score":0},{"type":"index-pattern","id":"1a28c950-0f6b-11eb-9512-2d0c0eda237d","attributes":{"title":"gateway_requests*"},"references":[],"migrationVersion":{"index-pattern":"7.6.0"},"updated_at":"2021-05-22T11:04:23.811Z","version":"WzkxMTgsNDhd","namespaces":["default"],"score":0},{"type":"index-pattern","id":"1ccce5c0-bb9a-11eb-957b-939add21a246","attributes":{"title":"test-custom*"},"references":[],"migrationVersion":{"index-pattern":"7.6.0"},"updated_at":"2021-06-03T14:51:14.139Z","version":"WzEwMTEzLDQ4XQ==","namespaces":["default"],"score":0}]};
|
||||
|
||||
const resolveIndexResult1 = {"indices":[{"name":".apm-agent-configuration","attributes":["open"]},{"name":".apm-custom-link","attributes":["open"]},{"name":".async-search","attributes":["open"]},{"name":".infini-search-center_cluster","attributes":["open"]},{"name":".infini-search-center_dict","attributes":["open"]},{"name":".infini-search-center_monitoring","attributes":["open"]},{"name":".infini-search-center_reindex","attributes":["open"]},{"name":".infini-search-center_searchtemplate","attributes":["open"]},{"name":".infini-search-center_searchtemplatehistory","attributes":["open"]},{"name":".kibana-event-log-7.10.0-000004","aliases":[".kibana-event-log-7.10.0"],"attributes":["open"]},{"name":".kibana-event-log-7.10.0-000005","aliases":[".kibana-event-log-7.10.0"],"attributes":["open"]},{"name":".kibana-event-log-7.10.0-000006","aliases":[".kibana-event-log-7.10.0"],"attributes":["open"]},{"name":".kibana-event-log-7.10.0-000007","aliases":[".kibana-event-log-7.10.0"],"attributes":["open"]},{"name":".kibana_1","aliases":[".kibana"],"attributes":["open"]},{"name":".kibana_2","attributes":["open"]},{"name":".kibana_task_manager_1","aliases":[".kibana_task_manager"],"attributes":["open"]},{"name":".tasks","attributes":["open"]},{"name":"cluster","attributes":["open"]},{"name":"dict","attributes":["open"]},{"name":"gateway_requests","attributes":["open"]},{"name":"infini-dict","attributes":["open"]},{"name":"infini-reindex","attributes":["open"]},{"name":"metricbeat-7.10.0-2021.02.03-000001","aliases":["metricbeat-7.10.0"],"attributes":["open"]},{"name":"metricbeat-7.10.0-2021.03.06-000002","aliases":["metricbeat-7.10.0"],"attributes":["open"]},{"name":"metricbeat-7.10.0-2021.04.07-000003","aliases":["metricbeat-7.10.0"],"attributes":["open"]},{"name":"metricbeat-7.10.0-2021.05.07-000004","aliases":["metricbeat-7.10.0"],"attributes":["open"]},{"name":"metricbeat-7.10.0-2021.06.06-000005","aliases":["metricbeat-7.10.0"],"attributes":["open"]},{"name":"mock_log","attributes":["open"]},{"name":"nginx_mock_log","attributes":["open"]},{"name":"reindex","attributes":["open"]},{"name":"test-custom","aliases":["custom"],"attributes":["open"]},{"name":"test-custom1","aliases":["custom"],"attributes":["open"]},{"name":"test-custom8","aliases":["custom"],"attributes":["open"]},{"name":"test-custom9","aliases":["custom"],"attributes":["open"]}],"aliases":[{"name":".kibana","indices":[".kibana_1"]},{"name":".kibana-event-log-7.10.0","indices":[".kibana-event-log-7.10.0-000004",".kibana-event-log-7.10.0-000005",".kibana-event-log-7.10.0-000006",".kibana-event-log-7.10.0-000007"]},{"name":".kibana_task_manager","indices":[".kibana_task_manager_1"]},{"name":"custom","indices":["test-custom","test-custom1","test-custom8","test-custom9"]},{"name":"metricbeat-7.10.0","indices":["metricbeat-7.10.0-2021.02.03-000001","metricbeat-7.10.0-2021.03.06-000002","metricbeat-7.10.0-2021.04.07-000003","metricbeat-7.10.0-2021.05.07-000004","metricbeat-7.10.0-2021.06.06-000005"]}],"data_streams":[]};
|
||||
|
||||
const resolveIndexResult2 = {"indices":[],"aliases":[],"data_streams":[]};
|
||||
|
||||
export default {
|
||||
'GET /elasticsearch/:clusterID/saved_objects/_find': (req, res) =>{
|
||||
return res.json(savedObjectsResult);
|
||||
},
|
||||
'GET /elasticsearch/:clusterID/internal/index-pattern-management/resolve_index/:pattern': (req, res)=>{
|
||||
const {pattern} = req.params;
|
||||
if(pattern == '*')
|
||||
return res.json(resolveIndexResult1);
|
||||
else if(pattern == '*:*'){
|
||||
return res.json(resolveIndexResult2);
|
||||
}else{
|
||||
const result = {...resolveIndexResult1};
|
||||
result.aliases = result.aliases.filter(alias=>alias.name.startsWith(pattern.replace('*', '')))
|
||||
result.indices = result.indices.filter(index=>index.name.startsWith(pattern.replace('*', '')))
|
||||
return res.json(result);
|
||||
}
|
||||
},
|
||||
'POST /elasticsearch/:clusterID/saved_objects/_bulk_get': (req, res) => {
|
||||
if(req.body && req.body.length > 0 ){
|
||||
let mockObj =
|
||||
{
|
||||
"attributes": {
|
||||
"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\"}}}]",
|
||||
"timeFieldName": "created_at",
|
||||
"title": "test*",
|
||||
"fieldFormatMap": `{"age":{"id":"bytes","params":{"parsedUrl":{"origin":"http://localhost:9000","pathname":"/","basePath":""}}}}`,
|
||||
},
|
||||
"id": "1ccce5c0-bb9a-11eb-957b-939add21a246",
|
||||
"migrationVersion": {
|
||||
"index-pattern": "7.6.0"
|
||||
},
|
||||
"namespaces": [
|
||||
"default"
|
||||
],
|
||||
"score": 0,
|
||||
"type": "index-pattern",
|
||||
"updated_at": "2021-06-27T10:13:23.639105+08:00",
|
||||
// "version":"WzEwMTEzLDQ4XQ=="
|
||||
|
||||
}//({"id":"1ccce5c0-bb9a-11eb-957b-939add21a246","type":"index-pattern","namespaces":["default"],"updated_at":"2021-06-03T14:51:14.139Z","version":"WzEwMTEzLDQ4XQ==","attributes":{"title":"test-custom*","timeFieldName":"created_at","fields":"[{\"count\":4,\"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\":4,\"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\":3,\"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"}});
|
||||
let savedObjects = [];
|
||||
req.body.forEach((reqObj)=>{
|
||||
savedObjects.push({
|
||||
...mockObj,
|
||||
id: reqObj.id,
|
||||
})
|
||||
})
|
||||
return res.json({
|
||||
saved_objects: savedObjects,
|
||||
})
|
||||
}
|
||||
return res.json({"saved_objects":[{"id":"telemetry","type":"telemetry","namespaces":[],"updated_at":"2020-11-23T11:30:51.234Z","version":"WzgsMV0=","attributes":{"userHasSeenNotice":true},"references":[]}]});
|
||||
},
|
||||
'GET /elasticsearch/:clusterID/index_patterns/_fields_for_wildcard': (req, res)=>{
|
||||
return res.json({"fields":[{"name":"_id","type":"string","esTypes":["_id"],"searchable":true,"aggregatable":true,"readFromDocValues":false},{"name":"_index","type":"string","esTypes":["_index"],"searchable":true,"aggregatable":true,"readFromDocValues":false},{"name":"_score","type":"number","searchable":false,"aggregatable":false,"readFromDocValues":false},{"name":"_source","type":"_source","esTypes":["_source"],"searchable":false,"aggregatable":false,"readFromDocValues":false},{"name":"_type","type":"string","esTypes":["_type"],"searchable":true,"aggregatable":true,"readFromDocValues":false},{"name":"address","type":"string","esTypes":["text"],"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"address.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"address"}}},{"name":"age","type":"conflict","esTypes":["text","long"],"searchable":true,"aggregatable":true,"readFromDocValues":false,"conflictDescriptions":{"text":["test-custom1"],"long":["test-custom","test-custom8","test-custom9"]}},{"name":"age.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"age"}}},{"name":"created_at","type":"date","esTypes":["date"],"searchable":true,"aggregatable":true,"readFromDocValues":true},{"name":"email","type":"string","esTypes":["text"],"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"email.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"email"}}},{"name":"hobbies","type":"string","esTypes":["text"],"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"hobbies.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"hobbies"}}},{"name":"id","type":"string","esTypes":["text"],"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"id.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"id"}}},{"name":"name","type":"string","esTypes":["text"],"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"name.keyword","type":"string","esTypes":["keyword"],"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"name"}}}]})
|
||||
},
|
||||
'GET elasticsearch/:clusterID/setting/defaultIndex': (req, res)=>{
|
||||
return res.json('');
|
||||
}
|
||||
}
|
|
@ -12,6 +12,15 @@ export default {
|
|||
|
||||
// curl -XPOST http://localhost:8000/elasticsearch/uuid/_proxy\?path=%2F_search&method=GET?pretty -d '{ "size": 1 }'
|
||||
'POST /elasticsearch/:id/_proxy': function(req, res){
|
||||
const {path} = req.query;
|
||||
switch(path){
|
||||
case '_mapping':
|
||||
return res.send({"test-custom9":{"mappings":{"properties":{"address":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"age":{"type":"long"},"created_at":{"type":"date"},"email":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"hobbies":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"id":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}},"test-custom1":{"mappings":{"properties":{"address":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"age":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"created_at":{"type":"date"},"email":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"hobbies":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"id":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}},"test-custom":{"mappings":{"properties":{"address":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"age":{"type":"long"},"created_at":{"type":"date"},"email":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"hobbies":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"id":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}},"test-custom8":{"mappings":{"properties":{"address":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"age":{"type":"long"},"created_at":{"type":"date"},"email":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"hobbies":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"id":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}}});
|
||||
case '_aliases':
|
||||
return res.send({"test-custom8":{"aliases":{"custom":{"filter":{"match":{"name":"test"}},"index_routing":"1","search_routing":"1"}}},"test-custom9":{"aliases":{"custom":{"filter":{"match":{"name":"test"}},"index_routing":"1","search_routing":"1"}}},"test-custom1":{"aliases":{"custom":{"filter":{"match":{"name":"test"}},"index_routing":"1","search_routing":"1"}}},"test-custom":{"aliases":{"custom":{"filter":{"match":{"name":"test"}},"index_routing":"1","search_routing":"1","is_write_index":true}}}});
|
||||
case 'template':
|
||||
return res.send({"search-center":{"order":0,"index_patterns":["infini-*"],"settings":{"index":{"max_result_window":"10000000","number_of_shards":"1"}},"mappings":{"dynamic_templates":[{"strings":{"mapping":{"ignore_above":256,"type":"keyword"},"match_mapping_type":"string"}}]},"aliases":{}}});
|
||||
}
|
||||
res.send({
|
||||
"took" : 1055,
|
||||
"timed_out" : false,
|
||||
|
@ -138,23 +147,23 @@ export default {
|
|||
},
|
||||
|
||||
//加载常用命令
|
||||
'GET /elasticsearch/:id/command/:id': function(req, res){
|
||||
res.send({
|
||||
"_id": "c0oc4kkgq9s8qss2uk50",
|
||||
"_source": {
|
||||
"created" : "2021-02-02T13:23:16.799Z",
|
||||
"request" : {
|
||||
"method" : "POST",
|
||||
"path" : "/myindex/_search",
|
||||
"body" : "{ \"query\": { \"match\": { \"name\": \"medcl\" } } }"
|
||||
},
|
||||
"status":200,
|
||||
"title":"一个常用查询的例子",
|
||||
"tag":["example","search"]
|
||||
},
|
||||
"found": true
|
||||
});
|
||||
},
|
||||
// 'GET /elasticsearch/:id/command/:id': function(req, res){
|
||||
// res.send({
|
||||
// "_id": "c0oc4kkgq9s8qss2uk50",
|
||||
// "_source": {
|
||||
// "created" : "2021-02-02T13:23:16.799Z",
|
||||
// "request" : {
|
||||
// "method" : "POST",
|
||||
// "path" : "/myindex/_search",
|
||||
// "body" : "{ \"query\": { \"match\": { \"name\": \"medcl\" } } }"
|
||||
// },
|
||||
// "status":200,
|
||||
// "title":"一个常用查询的例子",
|
||||
// "tag":["example","search"]
|
||||
// },
|
||||
// "found": true
|
||||
// });
|
||||
// },
|
||||
|
||||
//删除常用命令
|
||||
'DELETE /elasticsearch/:id/command/:id': function(req, res){
|
||||
|
@ -194,7 +203,23 @@ export default {
|
|||
"path" : "/myindex/_search",
|
||||
"body" : "{ \"query\": { \"match\": { \"name\": \"medcl\" } } }"
|
||||
},
|
||||
"title":"一个常用查询的例子",
|
||||
"title":"command1",
|
||||
"tag":["example","search"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"_index" : "gateway-command-7.9.2-000001",
|
||||
"_type" : "_doc",
|
||||
"_id" : "VLvqYncBwyX1iJ4H4cBA",
|
||||
"_score" : 1.0,
|
||||
"_source" : {
|
||||
"created" : "2021-02-02T13:23:16.799Z",
|
||||
"request" : {
|
||||
"method" : "GET",
|
||||
"path" : "/myindex/_search",
|
||||
"body" : "{ \"query\": { \"match\": { \"name\": \"medcl\" } } }"
|
||||
},
|
||||
"title":"command2",
|
||||
"tag":["example","search"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,20 +9,28 @@
|
|||
"@antv/g2-brush": "^0.0.2",
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"@elastic/charts": "^25.0.1",
|
||||
"@elastic/datemath": "^5.0.3",
|
||||
"@elastic/eui": "^34.4.0",
|
||||
"@elastic/numeral": "^2.5.1",
|
||||
"@hapi/boom": "^9.1.3",
|
||||
"@monaco-editor/react": "^3.7.4",
|
||||
"@svgdotjs/svg.js": "^3.0.16",
|
||||
"antd": "^3.26.18",
|
||||
"antd-table-infinity": "^1.1.6",
|
||||
"bizcharts": "^3.2.2",
|
||||
"bizcharts-plugin-slider": "^2.0.3",
|
||||
"brace": "^0.11.1",
|
||||
"classnames": "^2.2.6",
|
||||
"cluster": "^0.7.7",
|
||||
"console": "^0.7.2",
|
||||
"deep-freeze-strict": "^1.1.1",
|
||||
"dns": "^0.2.2",
|
||||
"dva": "^2.4.0",
|
||||
"enquire-js": "^0.2.1",
|
||||
"fp-ts": "^2.10.5",
|
||||
"hash.js": "^1.1.5",
|
||||
"honeycomb-grid": "^3.1.7",
|
||||
"jquery": "^3.6.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash-decorators": "^6.0.0",
|
||||
"luxon": "^1.26.0",
|
||||
|
@ -30,6 +38,7 @@
|
|||
"module": "^1.2.5",
|
||||
"moment": "^2.29.1",
|
||||
"moment-timezone": "^0.5.32",
|
||||
"nano-css": "^5.3.1",
|
||||
"node-ssh": "^8.0.0",
|
||||
"numeral": "^2.0.6",
|
||||
"nzh": "^1.0.3",
|
||||
|
@ -37,8 +46,10 @@
|
|||
"path-to-regexp": "^2.4.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"qs": "^6.5.2",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rc-animate": "^2.4.4",
|
||||
"react": "^16.5.1",
|
||||
"react-calendar-heatmap": "^1.8.1",
|
||||
"react-container-query": "^0.11.0",
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-document-title": "^2.0.3",
|
||||
|
@ -46,12 +57,19 @@
|
|||
"react-fittext": "^1.0.0",
|
||||
"react-grid-layout": "^1.2.0",
|
||||
"react-highlight-words": "^0.16.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-json-prettify": "^0.2.0",
|
||||
"react-json-view": "^1.19.1",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"react-sparklines": "^1.7.0",
|
||||
"repl": "^0.1.3"
|
||||
"react-use": "^17.2.4",
|
||||
"readline": "^1.3.0",
|
||||
"repl": "^0.1.3",
|
||||
"reqwest": "^2.0.5",
|
||||
"rison-node": "^2.1.1",
|
||||
"rxjs": "^7.2.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"use-query-params": "^1.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"antd-pro-merge-less": "^0.1.0",
|
||||
|
@ -62,6 +80,7 @@
|
|||
"babel-plugin-dva-hmr": "^0.4.1",
|
||||
"babel-plugin-import": "^1.6.3",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"cross-env": "^7.0.3",
|
||||
"egg": "^2.4.1",
|
||||
"egg-bin": "^4.3.7",
|
||||
"egg-ci": "^1.8.0",
|
||||
|
@ -84,7 +103,11 @@
|
|||
"mockjs": "^1.0.1-beta3",
|
||||
"moment-duration-format": "^2.3.2",
|
||||
"node-fetch": "^2.6.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"redbox-react": "^1.5.0",
|
||||
"sass": "^1.35.1",
|
||||
"sass-loader": "^10.1.1",
|
||||
"ts-loader": "^8.0.2",
|
||||
"umi": "^2.1.2",
|
||||
"umi-plugin-ga": "^1.1.3",
|
||||
"umi-plugin-react": "^1.1.1"
|
||||
|
@ -94,12 +117,13 @@
|
|||
},
|
||||
"scripts": {
|
||||
"dev": "umi dev",
|
||||
"build": "umi build",
|
||||
"build": "NODE_OPTIONS=--max_old_space_size=4096 umi build",
|
||||
"autod": "autod",
|
||||
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up -d",
|
||||
"docker:stop-dev": "docker-compose -f ./docker/docker-compose.dev.yml down",
|
||||
"docker:build": "docker-compose -f ./docker/docker-compose.build.yml up",
|
||||
"docker:start-mysql": "docker-compose -f ./docker/docker-compose-mysql.dev.yml up -d"
|
||||
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up --remove-orphans -d",
|
||||
"docker:stop-dev": "docker-compose -f ./docker/docker-compose.dev.yml down",
|
||||
"docker:build": "docker-compose -f ./docker/docker-compose.build.yml up --remove-orphans",
|
||||
"docker:start-mysql": "docker-compose -f ./docker/docker-compose-mysql.dev.yml up --remove-orphans -d",
|
||||
"postinstall": "rm -rf ./node_modules/_ts-loader@6.0.3@ts-loader"
|
||||
},
|
||||
"ci": {
|
||||
"version": "8",
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 112 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.9 KiB |
|
@ -74,7 +74,7 @@ class DropdownSelect extends React.Component{
|
|||
hasMore={!this.state.loading && this.state.hasMore}
|
||||
useWindow={false}
|
||||
>
|
||||
<List
|
||||
{/* <List
|
||||
grid={{
|
||||
gutter: 16,
|
||||
sm: 4,
|
||||
|
@ -97,7 +97,15 @@ class DropdownSelect extends React.Component{
|
|||
<Spin />
|
||||
</div>
|
||||
)}
|
||||
</List>
|
||||
</List> */}
|
||||
<div className={styles.dslist}>
|
||||
{(this.props.data || []).map((item)=>{
|
||||
return <div className={styles.item}><Button key={item[labelField]} onClick={() => {
|
||||
this.handleItemClick(item)
|
||||
}}
|
||||
className={_.isEqual(item, value) ? styles.btnitem + " " + styles.selected : styles.btnitem}>{item[labelField]}</Button></div>
|
||||
})}
|
||||
</div>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
{!this.state.loading && this.state.hasMore && (
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
}
|
||||
.btnitem{
|
||||
border-radius: 0px;
|
||||
width: 100px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.selected{
|
||||
color: #1890FF;
|
||||
|
@ -50,4 +51,9 @@
|
|||
.dropmenu{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.dslist{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
|
@ -77,7 +77,7 @@ export default class GlobalHeaderRight extends PureComponent {
|
|||
}
|
||||
return (
|
||||
<div className={className}>
|
||||
<HeaderSearch
|
||||
{/* <HeaderSearch
|
||||
className={`${styles.action} ${styles.search}`}
|
||||
placeholder={formatMessage({ id: 'component.globalHeader.search' })}
|
||||
dataSource={[
|
||||
|
@ -91,11 +91,14 @@ export default class GlobalHeaderRight extends PureComponent {
|
|||
onPressEnter={value => {
|
||||
console.log('enter', value); // eslint-disable-line
|
||||
}}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<a className={styles.action}> <Icon type="code" /></a>
|
||||
<a className={styles.action} onClick={()=>{
|
||||
const {history, selectedCluster} = this.props;
|
||||
history.push(`/dev_tool/elasticsearch/${selectedCluster.id}/`);
|
||||
}}> <Icon type="code" /></a>
|
||||
|
||||
<NoticeIcon
|
||||
{/* <NoticeIcon
|
||||
className={styles.action}
|
||||
count={currentUser.notifyCount}
|
||||
onItemClick={(item, tabProps) => {
|
||||
|
@ -131,8 +134,8 @@ export default class GlobalHeaderRight extends PureComponent {
|
|||
emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
|
||||
emptyImage="https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg"
|
||||
/>
|
||||
</NoticeIcon>
|
||||
{currentUser.name ? (
|
||||
</NoticeIcon> */}
|
||||
{/* {currentUser.name ? (
|
||||
<Dropdown overlay={menu}>
|
||||
<span className={`${styles.action} ${styles.account}`}>
|
||||
<Avatar
|
||||
|
@ -146,7 +149,7 @@ export default class GlobalHeaderRight extends PureComponent {
|
|||
</Dropdown>
|
||||
) : (
|
||||
<Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
|
||||
)}
|
||||
)} */}
|
||||
<SelectLang className={styles.action} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -57,19 +57,30 @@ export default class GlobalHeader extends PureComponent {
|
|||
labelField="name"
|
||||
visible={clusterVisible}
|
||||
onChange={(item)=>{
|
||||
this.props.handleSaveGlobalState({
|
||||
selectedCluster: item
|
||||
const rel = this.props.handleSaveGlobalState({
|
||||
selectedCluster: item,
|
||||
selectedClusterID: item.id,
|
||||
}).then(()=>{
|
||||
const {dispatch,history} = this.props;
|
||||
dispatch({
|
||||
type:'global/rewriteURL',
|
||||
payload:{
|
||||
history,
|
||||
pathname: history.location.pathname,
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const path1=this.props.location.pathname
|
||||
// const path1=this.props.location.pathname
|
||||
|
||||
if (path1[path1.length-1] !=='/'){
|
||||
const currentPath=path.dirname(path1);
|
||||
router.replace(currentPath+'/'+item.id);
|
||||
}else{
|
||||
router.replace(path1+item.id);
|
||||
}
|
||||
// if (path1[path1.length-1] !=='/'){
|
||||
// const currentPath=path.dirname(path1);
|
||||
// router.replace(currentPath+'/'+item.id);
|
||||
// }else{
|
||||
// router.replace(path1+item.id);
|
||||
// }
|
||||
//location.reload()
|
||||
|
||||
}}
|
||||
size={56}
|
||||
fetchData={
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.header{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.searchbox{
|
||||
margin-bottom: 10px;
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
import {List, Avatar, Button, Skeleton, Divider,Row,Col} from 'antd';
|
||||
import { Icon,Input } from 'antd';
|
||||
const { Search } = Input;
|
||||
import { Badge } from 'antd';
|
||||
import style from './LoadMoreList.css'
|
||||
import reqwest from 'reqwest';
|
||||
const count = 3;
|
||||
const fakeDataUrl = `https://randomuser.me/api/?results=${count}&inc=name,gender,email,nat&noinfo`;
|
||||
|
||||
class LoadMoreList extends React.Component {
|
||||
state = {
|
||||
initLoading: true,
|
||||
loading: false,
|
||||
data: [],
|
||||
list: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.getData(res => {
|
||||
this.setState({
|
||||
initLoading: false,
|
||||
data: res.results,
|
||||
list: res.results,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getData = callback => {
|
||||
reqwest({
|
||||
url: fakeDataUrl,
|
||||
type: 'json',
|
||||
method: 'get',
|
||||
contentType: 'application/json',
|
||||
success: res => {
|
||||
callback(res);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLoadMore = () => {
|
||||
this.setState({
|
||||
loading: true,
|
||||
list: this.state.data.concat([...new Array(count)].map(() => ({ loading: true, name: {} }))),
|
||||
});
|
||||
this.getData(res => {
|
||||
const data = this.state.data.concat(res.results);
|
||||
this.setState(
|
||||
{
|
||||
data,
|
||||
list: data,
|
||||
loading: false,
|
||||
},
|
||||
() => {
|
||||
// Resetting window's offsetTop so as to display react-virtualized demo underfloor.
|
||||
// In real scene, you can using public method of react-virtualized:
|
||||
// https://stackoverflow.com/questions/46700726/how-to-use-public-method-updateposition-of-react-virtualized
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { initLoading, loading, list } = this.state;
|
||||
const loadMore =
|
||||
!initLoading && !loading ? (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop: 12,
|
||||
height: 32,
|
||||
lineHeight: '32px',
|
||||
}}
|
||||
>
|
||||
<Button onClick={this.onLoadMore}>Loading more</Button>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<dvi>
|
||||
|
||||
<div className={style.header}>
|
||||
<Row type="flex" justify="space-between" align="bottom">
|
||||
<Col >
|
||||
<a href="#" className="head-example" >Elasticsearch 集群</a>
|
||||
|
||||
<Badge
|
||||
count={4}
|
||||
style={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset' }}
|
||||
/>
|
||||
</Col>
|
||||
<Col >
|
||||
<a href={'#'}>
|
||||
<Icon type="plus" />
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
</div>
|
||||
|
||||
<Search className={style.searchbox} placeholder="input search text" onSearch={value => console.log(value)} enterButton />
|
||||
|
||||
|
||||
<List
|
||||
className="demo-loadmore-list"
|
||||
loading={initLoading}
|
||||
itemLayout="horizontal"
|
||||
loadMore={loadMore}
|
||||
dataSource={list}
|
||||
renderItem={item => (
|
||||
<List.Item
|
||||
actions={[<a key="list-loadmore-edit"><Icon type="setting" /></a>]}
|
||||
>
|
||||
<Skeleton avatar title={false} loading={item.loading} active>
|
||||
<List.Item.Meta
|
||||
avatar={
|
||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
}
|
||||
title={<a href="https://ant.design">{item.name.last}</a>}
|
||||
/>
|
||||
<div>
|
||||
|
||||
<Icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" title={'Green'} />
|
||||
|
||||
</div>
|
||||
</Skeleton>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</dvi>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default LoadMoreList;
|
|
@ -88,8 +88,27 @@ export default class SiderMenu extends PureComponent {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
renderIcon(collapsed,icon,logo){
|
||||
|
||||
if (collapsed){
|
||||
return (<div className={styles.icon} id="logo">
|
||||
<Link to="/">
|
||||
<img src={icon} alt="logo" />
|
||||
{/*<h1>{formatMessage({ id: 'app.setting.appname' })}</h1>*/}
|
||||
</Link>
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (<div className={styles.logo} id="logo">
|
||||
<Link to="/">
|
||||
<img src={logo} alt="logo" />
|
||||
</Link>
|
||||
</div>);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { logo, collapsed, onCollapse, fixSiderbar, theme } = this.props;
|
||||
const { icon,logo, collapsed, onCollapse, fixSiderbar, theme } = this.props;
|
||||
const { openKeys } = this.state;
|
||||
const defaultProps = collapsed ? {} : { openKeys };
|
||||
|
||||
|
@ -109,12 +128,7 @@ export default class SiderMenu extends PureComponent {
|
|||
theme={theme}
|
||||
className={siderClassName}
|
||||
>
|
||||
<div className={styles.logo} id="logo">
|
||||
<Link to="/">
|
||||
<img src={logo} alt="logo" />
|
||||
<h1>{formatMessage({ id: 'app.setting.appname' })}</h1>
|
||||
</Link>
|
||||
</div>
|
||||
{this.renderIcon(collapsed,icon,logo)}
|
||||
<BaseMenu
|
||||
{...this.props}
|
||||
mode="inline"
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
|
||||
@nav-header-height: 64px;
|
||||
|
||||
.icon {
|
||||
height: @nav-header-height;
|
||||
position: relative;
|
||||
line-height: @nav-header-height;
|
||||
padding-left: (@menu-collapsed-width - 32px) / 2;
|
||||
transition: all 0.3s;
|
||||
background: #ffffff;
|
||||
img {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
max-height: 32px;
|
||||
max-width:32px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: @nav-header-height;
|
||||
position: relative;
|
||||
|
@ -13,8 +28,9 @@
|
|||
img {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
max-height: 32px;
|
||||
max-width:32px;
|
||||
//max-height: 32px;
|
||||
//max-width:32px;
|
||||
max-width: 200px;
|
||||
}
|
||||
h1 {
|
||||
color: #000000;
|
||||
|
@ -88,4 +104,10 @@
|
|||
transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out;
|
||||
opacity: 1;
|
||||
}
|
||||
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
|
||||
background-color: #939ea0;
|
||||
}
|
||||
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected a {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// @ts-ignore
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Modal, Form, Input, Tag } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
interface ITagGeneratorProps {
|
||||
value?: Array<string>,
|
||||
onChange?: (val: Array<string>) => void;
|
||||
}
|
||||
|
||||
const TagGenerator = ({ value = [], onChange }: ITagGeneratorProps) => {
|
||||
const [inputVisible, setInputVisible] = useState<boolean>(false);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setInputValue(e.target.value);
|
||||
};
|
||||
|
||||
const showInput = () => {
|
||||
setInputVisible(true);
|
||||
};
|
||||
|
||||
const handleInputConfirm = useCallback((e) => {
|
||||
onChange([...(value || []), e.target.value]);
|
||||
setInputVisible(false);
|
||||
setInputValue('');
|
||||
}, [value]);
|
||||
|
||||
const handleRemove = useCallback((index) => {
|
||||
const newValue = [...value];
|
||||
newValue.splice(index, 1);
|
||||
onChange(newValue);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{value.map((tag, index) => (
|
||||
<Tag key={index} closable style={{ padding: '4px 6px', fontSize: 16, margin: '0 10px 10px 0' }} onClose={() => handleRemove(index)}>{tag}</Tag>
|
||||
))}
|
||||
{inputVisible && <Input value={inputValue} onChange={handleInputChange} style={{ width: 100 }} onBlur={handleInputConfirm} onPressEnter={handleInputConfirm} />}
|
||||
{!inputVisible && (
|
||||
<Tag onClick={showInput} style={{ padding: '4px 6px', fontSize: 16 }}>
|
||||
<PlusOutlined /> 新建标签
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
interface ICommonCommandModalProps {
|
||||
onClose: () => void;
|
||||
onConfirm: (params: Record<string, any>) => void;
|
||||
form: any;
|
||||
}
|
||||
|
||||
const CommonCommandModal = Form.create()((props: ICommonCommandModalProps) => {
|
||||
const { form } = props;
|
||||
|
||||
const handleConfirm = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
props.onConfirm(values);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal title="保存常用命令" visible={true} onCancel={props.onClose} onOk={handleConfirm} cancelText="取消" okText="确认">
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="标题">
|
||||
{form.getFieldDecorator('title', {
|
||||
rules: [{ required: true, message: '请输入标题' }]
|
||||
})(<Input />)}
|
||||
</Form.Item>
|
||||
<Form.Item label="标签">
|
||||
{form.getFieldDecorator('tag')( <TagGenerator />)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
|
||||
export default CommonCommandModal;
|
|
@ -0,0 +1,35 @@
|
|||
.Console {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh);
|
||||
display: flex;
|
||||
|
||||
.ConsoleInput_wrapper {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.ConsoleOutput_wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.resizer {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
width: 14px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #fafbfd;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: col-resize;
|
||||
|
||||
&:hover {
|
||||
background-color: #cce1f0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// @ts-ignore
|
||||
import React, { useRef, useMemo } from 'react';
|
||||
import ConsoleInput from './ConsoleInput';
|
||||
import ConsoleOutput from './ConsoleOutput';
|
||||
import { Panel } from './Panel';
|
||||
import PanelsContainer from './PanelContainer';
|
||||
import { PanelContextProvider } from '../contexts/panel_context';
|
||||
import { PanelRegistry } from '../contexts/panel_context/registry';
|
||||
import './Console.scss';
|
||||
import { RequestContextProvider, useRequestReadContext } from '../contexts/request_context';
|
||||
import {EditorContextProvider} from '../contexts/editor_context/editor_context';
|
||||
import { ServicesContextProvider } from '../contexts/services_context';
|
||||
import { createHistory, History, createStorage, createSettings } from '../services';
|
||||
import { create } from '../storage/local_storage_object_client';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import {RequestStatusBar} from './request_status_bar';
|
||||
|
||||
interface props {
|
||||
selectedCluster: any;
|
||||
}
|
||||
|
||||
const INITIAL_PANEL_WIDTH = 50;
|
||||
const PANEL_MIN_WIDTH = '300px';
|
||||
|
||||
const ConsoleWrapper = ({
|
||||
selectedCluster
|
||||
}:props) => {
|
||||
|
||||
const {
|
||||
requestInFlight: requestInProgress,
|
||||
lastResult: { data: requestData, error: requestError },
|
||||
} = useRequestReadContext();
|
||||
|
||||
const lastDatum = requestData?.[requestData.length - 1] ?? requestError;
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<EuiFlexGroup className="consoleContainer"
|
||||
style={{height:30, background:'#fff'}}
|
||||
gutterSize="none"
|
||||
direction="column">
|
||||
<EuiFlexItem className="conApp__tabsExtension">
|
||||
<RequestStatusBar
|
||||
requestInProgress={requestInProgress}
|
||||
// selectedCluster={selectedCluster}
|
||||
requestResult={
|
||||
lastDatum
|
||||
? {
|
||||
method: lastDatum.request.method.toUpperCase(),
|
||||
endpoint: lastDatum.request.path,
|
||||
statusCode: lastDatum.response.statusCode,
|
||||
statusText: lastDatum.response.statusText,
|
||||
timeElapsedMs: lastDatum.response.timeMs,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
const Console = (params:props) => {
|
||||
const registryRef = useRef(new PanelRegistry());
|
||||
// const [consoleInputKey] = useMemo(()=>{
|
||||
// return [selectedCluster.id + '-console-input'];
|
||||
// },[selectedCluster])
|
||||
|
||||
const {storage, history, objectStorageClient, settings} = useMemo(()=>{
|
||||
const storage = createStorage({
|
||||
engine: window.localStorage,
|
||||
prefix: 'sense:',
|
||||
});
|
||||
const history: History = createHistory({ storage });
|
||||
const objectStorageClient = create(storage);
|
||||
const settings = createSettings({storage});
|
||||
return {storage, history, objectStorageClient, settings};
|
||||
}, [])
|
||||
return ( <PanelContextProvider registry={registryRef.current}>
|
||||
<RequestContextProvider>
|
||||
<EditorContextProvider>
|
||||
<ServicesContextProvider value={{ services: { history, storage, objectStorageClient, settings} }}>
|
||||
<ConsoleWrapper {...params} />
|
||||
</ServicesContextProvider>
|
||||
</EditorContextProvider>
|
||||
</RequestContextProvider>
|
||||
</PanelContextProvider>
|
||||
);
|
||||
|
||||
}
|
||||
export default Console;
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
.conApp {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.conApp__editor {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
|
||||
// Required on IE11 to render ace editor correctly after first input.
|
||||
position: relative;
|
||||
|
||||
&__spinner {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.conApp__output {
|
||||
display: flex;
|
||||
flex: 1 1 1px;
|
||||
}
|
||||
|
||||
.conApp__editorContent,
|
||||
.conApp__outputContent {
|
||||
height: 100%;
|
||||
flex: 1 1 1px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.conApp__editorActions {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
line-height: 1;
|
||||
min-width: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
line-height: inherit;
|
||||
cursor: pointer;
|
||||
// padding: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.conApp__editorActionButton {
|
||||
padding: 0 4px;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.conApp__editorActionButton--success {
|
||||
color: #017D73;
|
||||
}
|
||||
|
||||
.conApp__resizer {
|
||||
// Give the aria selection border priority when the divider is selected on IE11 and Chrome
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
// SASSTODO: This component seems to not be used anymore?
|
||||
// Possibly replaced by the Ace version
|
||||
.conApp__autoComplete {
|
||||
position: absolute;
|
||||
left: -1000px;
|
||||
visibility: hidden;
|
||||
/* by pass any other element in ace and resize bar, but not modal popups */
|
||||
z-index: 1002;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.conApp__settingsModal {
|
||||
min-width: 460px;
|
||||
}
|
||||
|
||||
.conApp__requestProgressBarContainer {
|
||||
position: relative;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.conApp__tabsExtension {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
.ace_method {
|
||||
color: #c80a68;
|
||||
}
|
||||
|
||||
|
||||
.ace_url, .ace_start_triple_quote, .ace_end_triple_quote {
|
||||
color: #00756c;
|
||||
}
|
||||
|
||||
.conApp {
|
||||
.euiButtonIcon--primary:not([class*='isDisabled']){
|
||||
box-shadow: none !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
// @ts-ignore
|
||||
import React, { useRef, useEffect, CSSProperties, useMemo } from 'react';
|
||||
import ace from 'brace';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { SenseEditor } from '../entities/sense_editor';
|
||||
import { LegacyCoreEditor } from '../modules/legacy_core_editor/legacy_core_editor';
|
||||
import ConsoleMenu from './ConsoleMenu';
|
||||
// import { RequestContextProvider } from '../contexts/request_context';
|
||||
import { getDocumentation, autoIndent } from '../entities/console_menu_actions';
|
||||
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 'antd/dist/antd.css';
|
||||
import {retrieveAutoCompleteInfo} from '../modules/mappings/mappings';
|
||||
import {useSaveCurrentTextObject} from '../hooks/use_save_current_text_object';
|
||||
import {useEditorReadContext} from '../contexts/editor_context/editor_context';
|
||||
import {useDataInit} from '../hooks/use_data_init';
|
||||
import { useServicesContext } from '../contexts';
|
||||
import {applyCurrentSettings} from './apply_editor_settings';
|
||||
import { subscribeResizeChecker } from './subscribe_console_resize_checker';
|
||||
|
||||
const abs: CSSProperties = {
|
||||
position: 'absolute',
|
||||
top: '0',
|
||||
left: '0',
|
||||
bottom: '0',
|
||||
right: '0',
|
||||
};
|
||||
|
||||
// interface IConsoleInputProps {
|
||||
// onExecuteCommand?: () => void;
|
||||
// onQueryHistoryCommands: () => void;
|
||||
// onLoadCommonCommands: () => void;
|
||||
// onPatchCommonCommand: (id: string, params: ICommonCommandParams) => void;
|
||||
// onDeleteCommonCommand: (id: string) => void;
|
||||
// }
|
||||
|
||||
const SendRequestButton = (props: any) => {
|
||||
const sendCurrentRequestToES = useSendCurrentRequestToES();
|
||||
const saveCurrentTextObject = useSaveCurrentTextObject();
|
||||
|
||||
const {sendCurrentRequestToESRef, saveCurrentTextObjectRef} = props;
|
||||
useEffect(()=>{
|
||||
sendCurrentRequestToESRef.current = sendCurrentRequestToES
|
||||
saveCurrentTextObjectRef.current = saveCurrentTextObject
|
||||
}, [sendCurrentRequestToESRef, saveCurrentTextObjectRef])
|
||||
|
||||
|
||||
return (
|
||||
<EuiToolTip
|
||||
content={'点击发送请求'}
|
||||
>
|
||||
<button
|
||||
data-test-subj="sendRequestButton"
|
||||
aria-label={'Click to send request'}
|
||||
className="conApp__editorActionButton conApp__editorActionButton--success"
|
||||
onClick={sendCurrentRequestToES}
|
||||
>
|
||||
<EuiIcon type="play" />
|
||||
</button>
|
||||
</EuiToolTip>
|
||||
);
|
||||
};
|
||||
|
||||
interface ConsoleInputProps {
|
||||
clusterID: string,
|
||||
initialText: string,
|
||||
}
|
||||
|
||||
const DEFAULT_INPUT_VALUE = `GET _search
|
||||
{
|
||||
"query": {
|
||||
"match_all": {}
|
||||
}
|
||||
}`;
|
||||
|
||||
const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => {
|
||||
const editorRef = useRef<HTMLDivElement | null>(null);
|
||||
const editorActionsRef = useRef<HTMLDivElement | null>(null);
|
||||
const editorInstanceRef = useRef<SenseEditor | null>(null);
|
||||
|
||||
const setInputEditor = useSetInputEditor();
|
||||
const consoleMenuRef = useRef<ConsoleMenu | null>(null);
|
||||
const aceEditorRef = useRef<ace.Editor | null>(null);
|
||||
|
||||
const sendCurrentRequestToESRef = useRef(()=>{});
|
||||
const saveCurrentTextObjectRef = useRef((content:string)=>{});
|
||||
|
||||
const {services:{settings}} = useServicesContext();
|
||||
|
||||
useEffect(() => {
|
||||
const aceEditor = ace.edit(editorRef.current!);
|
||||
aceEditorRef.current = aceEditor;
|
||||
const legacyCoreEditor = new LegacyCoreEditor(aceEditor, editorActionsRef.current as HTMLElement);
|
||||
aceEditor.commands.addCommand({
|
||||
name: 'exec_request',
|
||||
bindKey: 'ctrl+enter',
|
||||
exec: ()=>{
|
||||
sendCurrentRequestToESRef.current();
|
||||
}
|
||||
})
|
||||
const senseEditor = new SenseEditor(legacyCoreEditor);
|
||||
// senseEditor.highlightCurrentRequestsAndUpdateActionBar();
|
||||
editorInstanceRef.current = senseEditor;
|
||||
setInputEditor(senseEditor);
|
||||
senseEditor.update(initialText || DEFAULT_INPUT_VALUE);
|
||||
applyCurrentSettings(senseEditor!.getCoreEditor(), {fontSize:14, wrapMode: true,});
|
||||
|
||||
function setupAutosave() {
|
||||
let timer: number;
|
||||
const saveDelay = 500;
|
||||
|
||||
senseEditor.getCoreEditor().on('change', () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
timer = window.setTimeout(saveCurrentState, saveDelay);
|
||||
});
|
||||
}
|
||||
|
||||
function saveCurrentState() {
|
||||
try {
|
||||
const content = senseEditor.getCoreEditor().getValue();
|
||||
saveCurrentTextObjectRef.current(content);
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
// Ignoring saving error
|
||||
}
|
||||
}
|
||||
|
||||
const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, senseEditor);
|
||||
setupAutosave();
|
||||
|
||||
return () => {
|
||||
unsubscribeResizer();
|
||||
if (editorInstanceRef.current) {
|
||||
editorInstanceRef.current.getCoreEditor().destroy();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
useEffect(()=>{
|
||||
retrieveAutoCompleteInfo(settings, settings.getAutocomplete());
|
||||
},[clusterID])
|
||||
|
||||
const handleSaveAsCommonCommand = async () => {
|
||||
const editor = registry.getInputEditor();
|
||||
const requests = await editor.getRequestsInRange();
|
||||
const formattedRequest = requests.map(request => ({
|
||||
method: request.method,
|
||||
path: request.url,
|
||||
body: (request.data || [])[0],
|
||||
}));
|
||||
return formattedRequest;
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div style={abs} data-test-subj="console-application" className="conApp">
|
||||
<div className="conApp__editor">
|
||||
<ul className="conApp__autoComplete" id="autocomplete" />
|
||||
<EuiFlexGroup
|
||||
className="conApp__editorActions"
|
||||
id="ConAppEditorActions"
|
||||
gutterSize="none"
|
||||
responsive={false}
|
||||
ref={editorActionsRef}
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<SendRequestButton sendCurrentRequestToESRef={sendCurrentRequestToESRef} saveCurrentTextObjectRef={saveCurrentTextObjectRef}/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<ConsoleMenu
|
||||
getCurl={() => {
|
||||
return editorInstanceRef.current!.getRequestsAsCURL('');
|
||||
}}
|
||||
getDocumentation={() => {
|
||||
return getDocumentation(editorInstanceRef.current!, '');
|
||||
}}
|
||||
autoIndent={(event) => {
|
||||
autoIndent(editorInstanceRef.current!, event);
|
||||
}}
|
||||
saveAsCommonCommand={handleSaveAsCommonCommand}
|
||||
ref={consoleMenuRef}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<div
|
||||
ref={editorRef}
|
||||
id="ConAppEditor"
|
||||
className="conApp__editorContent"
|
||||
data-test-subj="request-editor"
|
||||
onClick={()=>{consoleMenuRef.current?.closePopover(); aceEditorRef.current?.focus()}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ConsoleInput = ({clusterID}:ConsoleInputProps)=>{
|
||||
const { done, error, retry } = useDataInit();
|
||||
const { currentTextObject } = useEditorReadContext();
|
||||
return done ? <ConsoleInputUI clusterID={clusterID} initialText={currentTextObject?.text}/>: <></>
|
||||
}
|
||||
|
||||
export default ConsoleInput;
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { EuiIcon, EuiContextMenuPanel, EuiContextMenuItem, EuiPopover } from '@elastic/eui';
|
||||
import { ESRequestParams } from '../entities/es_request';
|
||||
import {notification} from 'antd';
|
||||
|
||||
import CommonCommandModal from './CommonCommandModal';
|
||||
import {saveCommonCommand} from '../modules/es';
|
||||
import {pushCommand} from '../modules/mappings/mappings';
|
||||
|
||||
interface Props {
|
||||
getCurl: () => Promise<string>;
|
||||
getDocumentation: () => Promise<string | null>;
|
||||
autoIndent: (ev: React.MouseEvent) => void;
|
||||
saveAsCommonCommand: () => Promise<ESRequestParams>;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isPopoverOpen: boolean;
|
||||
curlCode: string;
|
||||
modalVisible: boolean;
|
||||
}
|
||||
|
||||
export default class ConsoleMenu extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
curlCode: '',
|
||||
isPopoverOpen: false,
|
||||
modalVisible: false,
|
||||
};
|
||||
}
|
||||
|
||||
mouseEnter = () => {
|
||||
if (this.state.isPopoverOpen) return;
|
||||
this.props.getCurl().then((text) => {
|
||||
this.setState({ curlCode: text });
|
||||
});
|
||||
};
|
||||
|
||||
async copyAsCurl() {
|
||||
try {
|
||||
await this.copyText(this.state.curlCode);
|
||||
notification.open({
|
||||
message: 'Request copied as cURL',
|
||||
placement: 'bottomRight'
|
||||
});
|
||||
} catch (e) {
|
||||
notification.error({
|
||||
message: 'Could not copy request as cURL',
|
||||
placement: 'bottomRight'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async copyText(text: string) {
|
||||
if (window.navigator?.clipboard) {
|
||||
await window.navigator.clipboard.writeText(text);
|
||||
return;
|
||||
}
|
||||
throw new Error('Could not copy to clipboard!');
|
||||
}
|
||||
|
||||
onButtonClick = () => {
|
||||
this.setState((prevState) => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen,
|
||||
}));
|
||||
};
|
||||
|
||||
closePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: false,
|
||||
});
|
||||
};
|
||||
|
||||
openDocs = async () => {
|
||||
this.closePopover();
|
||||
const documentation = await this.props.getDocumentation();
|
||||
if (!documentation) {
|
||||
return;
|
||||
}
|
||||
window.open(documentation, '_blank');
|
||||
};
|
||||
|
||||
autoIndent = (event: React.MouseEvent) => {
|
||||
this.closePopover();
|
||||
this.props.autoIndent(event);
|
||||
};
|
||||
|
||||
saveAsCommonCommand = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: false,
|
||||
modalVisible: true
|
||||
});
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ modalVisible: false });
|
||||
};
|
||||
|
||||
handleConfirm = async (params: Record<string, any>) => {
|
||||
const requests = await this.props.saveAsCommonCommand();
|
||||
const reqBody = {
|
||||
...params,
|
||||
requests,
|
||||
};
|
||||
const result = await (await saveCommonCommand(reqBody))?.json();
|
||||
if(result.error){
|
||||
notification.error({
|
||||
message: result.error
|
||||
});
|
||||
}else{
|
||||
this.handleClose();
|
||||
notification.success({
|
||||
message:'保存成功'
|
||||
});
|
||||
pushCommand(result);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const button = (
|
||||
<button
|
||||
className="euiButtonIcon--primary"
|
||||
onClick={this.onButtonClick}
|
||||
>
|
||||
<EuiIcon type="wrench" />
|
||||
</button>
|
||||
);
|
||||
|
||||
const items = [
|
||||
<EuiContextMenuItem
|
||||
key="Copy as cURL"
|
||||
id="ConCopyAsCurl"
|
||||
disabled={!window.navigator?.clipboard}
|
||||
onClick={() => {
|
||||
this.closePopover();
|
||||
this.copyAsCurl();
|
||||
}}
|
||||
>
|
||||
复制为curl命令
|
||||
</EuiContextMenuItem>,
|
||||
<EuiContextMenuItem
|
||||
key="Auto indent"
|
||||
onClick={this.autoIndent}
|
||||
>
|
||||
自动缩进
|
||||
</EuiContextMenuItem>,
|
||||
<EuiContextMenuItem
|
||||
key="Save as common command"
|
||||
onClick={this.saveAsCommonCommand}
|
||||
>
|
||||
保存为常用命令
|
||||
</EuiContextMenuItem>,
|
||||
];
|
||||
|
||||
return (
|
||||
<span onMouseEnter={this.mouseEnter}>
|
||||
<EuiPopover
|
||||
id="contextMenu"
|
||||
button={button}
|
||||
isOpen={this.state.isPopoverOpen}
|
||||
closePopover={this.closePopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<EuiContextMenuPanel items={items} />
|
||||
</EuiPopover>
|
||||
{this.state.modalVisible && <CommonCommandModal onClose={this.handleClose} onConfirm={this.handleConfirm} />}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
// @ts-ignore
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import 'brace/mode/text';
|
||||
import 'brace/mode/json';
|
||||
import 'brace/mode/yaml';
|
||||
import { CustomAceEditor, createReadOnlyAceEditor } from '../modules/legacy_core_editor/create_readonly';
|
||||
import { useRequestReadContext } from '../contexts/request_context';
|
||||
import './ConsoleInput.scss';
|
||||
|
||||
import {applyCurrentSettings} from './apply_editor_settings';
|
||||
import { subscribeResizeChecker } from './subscribe_console_resize_checker';
|
||||
|
||||
const isJSONContentType = (contentType?: string) =>
|
||||
Boolean(contentType && contentType.indexOf('application/json') >= 0);
|
||||
|
||||
function modeForContentType(contentType?: string) {
|
||||
if (!contentType) {
|
||||
return 'ace/mode/text';
|
||||
}
|
||||
if (isJSONContentType(contentType)) {
|
||||
return 'ace/mode/json';
|
||||
} else if (contentType.indexOf('application/yaml') >= 0) {
|
||||
return 'ace/mode/yaml';
|
||||
}
|
||||
return 'ace/mode/text';
|
||||
}
|
||||
|
||||
interface props {
|
||||
clusterID: string;
|
||||
}
|
||||
|
||||
function ConsoleOutput({clusterID}: props) {
|
||||
const editorRef = useRef<null | HTMLDivElement>(null);
|
||||
const editorInstanceRef = useRef<null | CustomAceEditor>(null);
|
||||
const inputId = 'ConAppOutputTextarea';
|
||||
const {
|
||||
lastResult: { data, error },
|
||||
} = useRequestReadContext();
|
||||
|
||||
useEffect(()=>{
|
||||
editorInstanceRef.current?.setValue('');
|
||||
},[clusterID])
|
||||
|
||||
useEffect(() => {
|
||||
editorInstanceRef.current = createReadOnlyAceEditor(editorRef.current!);
|
||||
const textarea = editorRef.current!.querySelector('textarea')!;
|
||||
textarea.setAttribute('id', inputId);
|
||||
textarea.setAttribute('readonly', 'true');
|
||||
applyCurrentSettings(editorInstanceRef.current!, {fontSize:14, wrapMode: true,})
|
||||
const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editorInstanceRef.current!);
|
||||
|
||||
return () => {
|
||||
unsubscribeResizer();
|
||||
editorInstanceRef.current!.destroy();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const editor = editorInstanceRef.current!;
|
||||
if (data) {
|
||||
//const mode = modeForContentType(data[0].response.contentType);
|
||||
editor.update(
|
||||
data
|
||||
.map((result) => {
|
||||
const { value, contentType } = result.response;
|
||||
if (isJSONContentType(contentType)) {
|
||||
let comment = '';
|
||||
let strValue = value as string;
|
||||
if(strValue[0]=='#'){
|
||||
const idx = strValue.indexOf('\n');
|
||||
comment = strValue.slice(0, idx);
|
||||
strValue = strValue.slice(idx)
|
||||
return comment + '\n' + JSON.stringify(JSON.parse(strValue), null, 2);
|
||||
}
|
||||
return JSON.stringify(JSON.parse(strValue), null, 2);
|
||||
|
||||
}
|
||||
return value;
|
||||
})
|
||||
.join('\n'),
|
||||
// mode
|
||||
);
|
||||
|
||||
} else if (error) {
|
||||
const mode = modeForContentType(error.response.contentType);
|
||||
editor.update(error.response.value as string, mode);
|
||||
} else {
|
||||
editor.update('');
|
||||
}
|
||||
}, [data, error]);
|
||||
|
||||
return (
|
||||
<div ref={editorRef} className="conApp__outputContent" data-test-subj="response-editor">
|
||||
<div id="ConAppOutput" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConsoleOutput;
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import React, { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
|
||||
import { usePanelContext } from '../contexts/panel_context';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode[] | ReactNode;
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* initial width of the panel in percents
|
||||
*/
|
||||
initialWidth?: number;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export function Panel({ children, className, initialWidth = 100, style = {} }: Props) {
|
||||
const [width, setWidth] = useState(`${initialWidth}%`);
|
||||
const { registry } = usePanelContext();
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
registry.registerPanel({
|
||||
width: initialWidth,
|
||||
setWidth(value) {
|
||||
setWidth(value + '%');
|
||||
this.width = value;
|
||||
},
|
||||
getWidth() {
|
||||
return divRef.current!.getBoundingClientRect().width;
|
||||
},
|
||||
});
|
||||
}, [initialWidth, registry]);
|
||||
|
||||
return (
|
||||
<div className={className} ref={divRef} style={{ ...style, width, display: 'flex' }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import React, { Children, ReactNode, useRef, useState, useCallback, useEffect } from 'react';
|
||||
|
||||
import { keys } from '@elastic/eui';
|
||||
import { PanelContextProvider } from '../contexts/panel_context';
|
||||
import { Resizer, ResizerMouseEvent, ResizerKeyDownEvent } from './Resizer';
|
||||
import { PanelRegistry } from '../contexts/panel_context/registry';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
resizerClassName?: string;
|
||||
onPanelWidthChange?: (arrayOfPanelWidths: number[]) => any;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isDragging: boolean;
|
||||
currentResizerPos: number;
|
||||
}
|
||||
|
||||
const initialState: State = { isDragging: false, currentResizerPos: -1 };
|
||||
|
||||
const pxToPercent = (proportion: number, whole: number) => (proportion / whole) * 100;
|
||||
|
||||
const PanelsContainer = ({
|
||||
children,
|
||||
className,
|
||||
onPanelWidthChange,
|
||||
resizerClassName,
|
||||
}: Props) => {
|
||||
const childrenArray = Children.toArray(children);
|
||||
const [firstChild, secondChild] = childrenArray;
|
||||
|
||||
const registryRef = useRef(new PanelRegistry());
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [state, setState] = useState<State>(initialState);
|
||||
|
||||
const getContainerWidth = () => {
|
||||
return containerRef.current!.getBoundingClientRect().width;
|
||||
};
|
||||
|
||||
const handleMouseDown = useCallback(
|
||||
(event: ResizerMouseEvent) => {
|
||||
setState({
|
||||
...state,
|
||||
isDragging: true,
|
||||
currentResizerPos: event.clientX,
|
||||
});
|
||||
},
|
||||
[state]
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(ev: ResizerKeyDownEvent) => {
|
||||
const { key } = ev;
|
||||
|
||||
if (key === keys.ARROW_LEFT || key === keys.ARROW_RIGHT) {
|
||||
ev.preventDefault();
|
||||
|
||||
const { current: registry } = registryRef;
|
||||
const [left, right] = registry.getPanels();
|
||||
|
||||
const leftPercent = left.width - (key === keys.ARROW_LEFT ? 1 : -1);
|
||||
const rightPercent = right.width - (key === keys.ARROW_RIGHT ? 1 : -1);
|
||||
|
||||
left.setWidth(leftPercent);
|
||||
right.setWidth(rightPercent);
|
||||
|
||||
if (onPanelWidthChange) {
|
||||
onPanelWidthChange([leftPercent, rightPercent]);
|
||||
}
|
||||
}
|
||||
},
|
||||
[onPanelWidthChange]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// For now we only support bi-split
|
||||
if (childrenArray.length > 2) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[Split Panels Container] Detected more than two children; ignoring additional children.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [childrenArray.length]);
|
||||
|
||||
const childrenWithResizer = [
|
||||
firstChild,
|
||||
<Resizer
|
||||
key={'resizer'}
|
||||
className={resizerClassName}
|
||||
onKeyDown={handleKeyDown}
|
||||
onMouseDown={handleMouseDown}
|
||||
/>,
|
||||
secondChild,
|
||||
];
|
||||
|
||||
return (
|
||||
<PanelContextProvider registry={registryRef.current}>
|
||||
<div
|
||||
className={className}
|
||||
ref={containerRef}
|
||||
style={{ display: 'flex', height: '100%', width: '100%' }}
|
||||
onMouseMove={(event) => {
|
||||
if (state.isDragging) {
|
||||
const { clientX: x } = event;
|
||||
const { current: registry } = registryRef;
|
||||
const [left, right] = registry.getPanels();
|
||||
const delta = x - state.currentResizerPos;
|
||||
const containerWidth = getContainerWidth();
|
||||
const leftPercent = pxToPercent(left.getWidth() + delta, containerWidth);
|
||||
const rightPercent = pxToPercent(right.getWidth() - delta, containerWidth);
|
||||
left.setWidth(leftPercent);
|
||||
right.setWidth(rightPercent);
|
||||
|
||||
if (onPanelWidthChange) {
|
||||
onPanelWidthChange([leftPercent, rightPercent]);
|
||||
}
|
||||
|
||||
setState({ ...state, currentResizerPos: x });
|
||||
}
|
||||
}}
|
||||
onMouseUp={() => {
|
||||
setState(initialState);
|
||||
}}
|
||||
>
|
||||
{childrenWithResizer}
|
||||
</div>
|
||||
</PanelContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default PanelsContainer;
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
|
||||
export type ResizerMouseEvent = React.MouseEvent<HTMLButtonElement, MouseEvent>;
|
||||
export type ResizerKeyDownEvent = React.KeyboardEvent<HTMLButtonElement>;
|
||||
|
||||
export interface Props {
|
||||
onKeyDown: (eve: ResizerKeyDownEvent) => void;
|
||||
onMouseDown: (eve: ResizerMouseEvent) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Resizer(props: Props) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
>
|
||||
<EuiIcon type="grabHorizontal" />
|
||||
</button>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// @ts-ignore
|
||||
import React from 'react';
|
||||
import { EuiIcon, EuiToolTip } from '@elastic/eui/es';
|
||||
import { useSendCurrentRequestToES } from '../hooks/use_send_current_request_to_es';
|
||||
|
||||
const SendRequestButton = () => {
|
||||
const sendCurrentRequestToES = useSendCurrentRequestToES();
|
||||
|
||||
return (
|
||||
<EuiToolTip
|
||||
content={'Click to send request'}
|
||||
>
|
||||
<button
|
||||
data-test-subj="sendRequestButton"
|
||||
aria-label={'Click to send request'}
|
||||
className="conApp__editorActionButton conApp__editorActionButton--success"
|
||||
onClick={sendCurrentRequestToES}
|
||||
>
|
||||
<EuiIcon type="play" />
|
||||
</button>
|
||||
</EuiToolTip>
|
||||
);
|
||||
};
|
||||
|
||||
export default SendRequestButton;
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { DevToolsSettings } from '../services';
|
||||
import { CoreEditor } from '../entities/core_editor';
|
||||
import { CustomAceEditor } from '../modules/legacy_core_editor/create_readonly';
|
||||
|
||||
export function applyCurrentSettings(
|
||||
editor: CoreEditor | CustomAceEditor,
|
||||
settings: DevToolsSettings
|
||||
) {
|
||||
if ((editor as any).setStyles) {
|
||||
(editor as CoreEditor).setStyles({
|
||||
wrapLines: settings.wrapMode,
|
||||
fontSize: settings.fontSize + 'px',
|
||||
});
|
||||
} else {
|
||||
(editor as CustomAceEditor).getSession().setUseWrapMode(settings.wrapMode);
|
||||
(editor as CustomAceEditor).container.style.fontSize = settings.fontSize + 'px';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { RequestStatusBar } from './request_status_bar';
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiText, EuiToolTip } from '@elastic/eui';
|
||||
|
||||
export interface Props {
|
||||
requestInProgress: boolean;
|
||||
requestResult?: {
|
||||
// Status code of the request, e.g., 200
|
||||
statusCode: number;
|
||||
|
||||
// Status text of the request, e.g., OK
|
||||
statusText: string;
|
||||
|
||||
// Method of the request, e.g., GET
|
||||
method: string;
|
||||
|
||||
// The path of endpoint that was called, e.g., /_search
|
||||
endpoint: string;
|
||||
|
||||
// The time, in milliseconds, that the last request took
|
||||
timeElapsedMs: number;
|
||||
};
|
||||
}
|
||||
|
||||
const mapStatusCodeToBadgeColor = (statusCode: number) => {
|
||||
if (statusCode <= 199) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
if (statusCode <= 299) {
|
||||
return 'secondary';
|
||||
}
|
||||
|
||||
if (statusCode <= 399) {
|
||||
return 'primary';
|
||||
}
|
||||
|
||||
if (statusCode <= 499) {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return 'danger';
|
||||
};
|
||||
|
||||
export const RequestStatusBar: FunctionComponent<Props> = ({
|
||||
requestInProgress,
|
||||
requestResult,
|
||||
}) => {
|
||||
let content: React.ReactNode = null;
|
||||
|
||||
if (requestInProgress) {
|
||||
content = (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBadge color="hollow">
|
||||
Request in progress
|
||||
</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
} else if (requestResult) {
|
||||
const { endpoint, method, statusCode, statusText, timeElapsedMs } = requestResult;
|
||||
|
||||
content = (
|
||||
<>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={
|
||||
<EuiText size="s">{`${method} ${
|
||||
endpoint.startsWith('/') ? endpoint : '/' + endpoint
|
||||
}`}</EuiText>
|
||||
}
|
||||
>
|
||||
<EuiBadge color={mapStatusCodeToBadgeColor(statusCode)}>
|
||||
{/* Use to ensure that no matter the width we don't allow line breaks */}
|
||||
{statusCode} - {statusText}
|
||||
</EuiBadge>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={
|
||||
<EuiText size="s">
|
||||
Time Elapsed
|
||||
</EuiText>
|
||||
}
|
||||
>
|
||||
<EuiText size="s">
|
||||
<EuiBadge color="default">
|
||||
{timeElapsedMs} {'ms'}
|
||||
</EuiBadge>
|
||||
</EuiText>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
justifyContent="flexEnd"
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
gutterSize="s"
|
||||
responsive={false}
|
||||
>
|
||||
{content}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ResizeChecker } from '../../kibana_utils/public/resize_checker';
|
||||
|
||||
export function subscribeResizeChecker(el: HTMLElement, ...editors: any[]) {
|
||||
const checker = new ResizeChecker(el);
|
||||
checker.on('resize', () =>
|
||||
editors.forEach((e) => {
|
||||
if (e.getCoreEditor) {
|
||||
e.getCoreEditor().resize();
|
||||
} else {
|
||||
e.resize();
|
||||
}
|
||||
|
||||
if (e.updateActionsBar) {
|
||||
e.updateActionsBar();
|
||||
}
|
||||
})
|
||||
);
|
||||
return () => checker.destroy();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { Context, useContext } from 'react';
|
||||
|
||||
export const createUseContext = <T>(Ctx: Context<T>, name: string) => {
|
||||
return () => {
|
||||
const ctx = useContext(Ctx);
|
||||
if (!ctx) {
|
||||
throw new Error(`${name} should be used inside of ${name}Provider!`);
|
||||
}
|
||||
return ctx;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import React, { createContext, Dispatch, useReducer } from 'react';
|
||||
import * as editor from '../../stores/editor';
|
||||
import { createUseContext } from '../create_use_context';
|
||||
|
||||
const EditorReadContext = createContext<editor.Store>(editor.initialValue);
|
||||
const EditorActionContext = createContext<Dispatch<editor.Action>>(() => {});
|
||||
|
||||
export interface EditorContextArgs {
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
export function EditorContextProvider({ children }: EditorContextArgs) {
|
||||
const [state, dispatch] = useReducer(editor.reducer, editor.initialValue, (value) => ({
|
||||
...value,
|
||||
}));
|
||||
return (
|
||||
<EditorReadContext.Provider value={state}>
|
||||
<EditorActionContext.Provider value={dispatch}>{children}</EditorActionContext.Provider>
|
||||
</EditorReadContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useEditorReadContext = createUseContext(EditorReadContext, 'EditorReadContext');
|
||||
export const useEditorActionContext = createUseContext(EditorActionContext, 'EditorActionContext');
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { SenseEditor } from '../../entities/sense_editor';
|
||||
|
||||
export class EditorRegistry {
|
||||
private inputEditor: SenseEditor | undefined;
|
||||
|
||||
setInputEditor(inputEditor: SenseEditor) {
|
||||
this.inputEditor = inputEditor;
|
||||
}
|
||||
|
||||
getInputEditor() {
|
||||
return this.inputEditor!;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a single instance of this and use as private state.
|
||||
export const instance = new EditorRegistry();
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export {
|
||||
EditorContextProvider,
|
||||
useEditorReadContext,
|
||||
useEditorActionContext,
|
||||
} from './editor_context';
|
|
@ -0,0 +1,2 @@
|
|||
export * from './services_context';
|
||||
export * from './editor_context';
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import { PanelRegistry } from './registry';
|
||||
|
||||
const PanelContext = createContext({ registry: new PanelRegistry() });
|
||||
|
||||
interface ContextProps {
|
||||
children: any;
|
||||
registry: PanelRegistry;
|
||||
}
|
||||
|
||||
export function PanelContextProvider({ children, registry }: ContextProps) {
|
||||
return <PanelContext.Provider value={{ registry }}>{children}</PanelContext.Provider>;
|
||||
}
|
||||
|
||||
export const usePanelContext = () => {
|
||||
const context = useContext(PanelContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('usePanelContext must be used within a <PanelContextProvider />');
|
||||
}
|
||||
return context;
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export interface PanelController {
|
||||
setWidth: (percent: number) => void;
|
||||
getWidth: () => number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class PanelRegistry {
|
||||
private panels: PanelController[] = [];
|
||||
|
||||
registerPanel(panel: PanelController) {
|
||||
this.panels.push(panel);
|
||||
}
|
||||
|
||||
getPanels() {
|
||||
return this.panels;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import React, { createContext, useReducer, Dispatch } from 'react';
|
||||
import { createUseContext } from './create_use_context';
|
||||
import * as store from '../stores/request';
|
||||
|
||||
const RequestReadContext = createContext<store.Store>(store.initialValue);
|
||||
const RequestActionContext = createContext<Dispatch<store.Actions>>(() => {});
|
||||
|
||||
export function RequestContextProvider({ children }: { children: React.ReactNode }) {
|
||||
const [state, dispatch] = useReducer(store.reducer, store.initialValue);
|
||||
return (
|
||||
<RequestReadContext.Provider value={state}>
|
||||
<RequestActionContext.Provider value={dispatch}>{children}</RequestActionContext.Provider>
|
||||
</RequestReadContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useRequestReadContext = createUseContext(RequestReadContext, 'RequestReadContext');
|
||||
export const useRequestActionContext = createUseContext(
|
||||
RequestActionContext,
|
||||
'RequestActionContext'
|
||||
);
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import React, { createContext, useContext, useEffect } from 'react';
|
||||
import { History, Storage, Settings } from '../services';
|
||||
import { ObjectStorageClient } from '../entities/storage';
|
||||
|
||||
interface ContextServices {
|
||||
history: History;
|
||||
storage: Storage;
|
||||
objectStorageClient: ObjectStorageClient;
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
export interface ContextValue {
|
||||
services: ContextServices;
|
||||
}
|
||||
|
||||
interface ContextProps {
|
||||
value: ContextValue;
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
const ServicesContext = createContext<ContextValue | null>(null);
|
||||
|
||||
export function ServicesContextProvider({ children, value }: ContextProps) {
|
||||
return <ServicesContext.Provider value={value}>{children}</ServicesContext.Provider>;
|
||||
}
|
||||
|
||||
export const useServicesContext = () => {
|
||||
const context = useContext(ServicesContext);
|
||||
if (context == null) {
|
||||
throw new Error('useServicesContext must be used inside the ServicesContextProvider.');
|
||||
}
|
||||
return context!;
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
import { IEditSession, TokenInfo as BraceTokenInfo } from 'brace';
|
||||
import { TokensProvider } from './tokens_provider';
|
||||
import { Token } from './token';
|
||||
import { Position } from './position';
|
||||
|
||||
interface TokenInfo extends BraceTokenInfo {
|
||||
type: string;
|
||||
}
|
||||
|
||||
const toToken = (lineNumber: number, column: number, token: TokenInfo): Token => ({
|
||||
type: token.type,
|
||||
value: token.value,
|
||||
position: {
|
||||
lineNumber,
|
||||
column,
|
||||
},
|
||||
});
|
||||
|
||||
const toTokens = (lineNumber: number, tokens: TokenInfo[]): Token[] => {
|
||||
let acc = '';
|
||||
return tokens.map((token) => {
|
||||
const column = acc.length + 1;
|
||||
acc += token.value;
|
||||
return toToken(lineNumber, column, token);
|
||||
});
|
||||
};
|
||||
|
||||
const extractTokenFromAceTokenRow = (
|
||||
lineNumber: number,
|
||||
column: number,
|
||||
aceTokens: TokenInfo[]
|
||||
) => {
|
||||
let acc = '';
|
||||
for (const token of aceTokens) {
|
||||
const start = acc.length + 1;
|
||||
acc += token.value;
|
||||
const end = acc.length;
|
||||
if (column < start) continue;
|
||||
if (column > end + 1) continue;
|
||||
return toToken(lineNumber, start, token);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export class AceTokensProvider implements TokensProvider {
|
||||
constructor(private readonly session: IEditSession) {}
|
||||
|
||||
getTokens(lineNumber: number): Token[] | null {
|
||||
if (lineNumber < 1) return null;
|
||||
|
||||
// Important: must use a .session.getLength because this is a cached value.
|
||||
// Calculating line length here will lead to performance issues because this function
|
||||
// may be called inside of tight loops.
|
||||
const lineCount = this.session.getLength();
|
||||
if (lineNumber > lineCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tokens = (this.session.getTokens(lineNumber - 1) as unknown) as TokenInfo[];
|
||||
if (!tokens || !tokens.length) {
|
||||
// We are inside of the document but have no tokens for this line. Return an empty
|
||||
// array to represent this empty line.
|
||||
return [];
|
||||
}
|
||||
|
||||
return toTokens(lineNumber, tokens);
|
||||
}
|
||||
|
||||
getTokenAt(pos: Position): Token | null {
|
||||
const tokens = (this.session.getTokens(pos.lineNumber - 1) as unknown) as TokenInfo[];
|
||||
if (tokens) {
|
||||
return extractTokenFromAceTokenRow(pos.lineNumber, pos.column, tokens);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import { CoreEditor } from './core_editor';
|
||||
import { Range } from './position';
|
||||
import { Token } from './token';
|
||||
|
||||
export interface ResultTerm {
|
||||
context?: AutoCompleteContext;
|
||||
insertValue?: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface AutoCompleteContext {
|
||||
autoCompleteSet?: null | ResultTerm[];
|
||||
endpoint?: null | {
|
||||
paramsAutocomplete: {
|
||||
getTopLevelComponents: (method?: string | null) => unknown;
|
||||
};
|
||||
bodyAutocompleteRootComponents: unknown;
|
||||
id?: string;
|
||||
documentation?: string;
|
||||
};
|
||||
urlPath?: null | unknown;
|
||||
urlParamsTokenPath?: Array<Record<string, string>> | null;
|
||||
method?: string | null;
|
||||
token?: Token;
|
||||
activeScheme?: unknown;
|
||||
replacingToken?: boolean;
|
||||
rangeToReplace?: Range;
|
||||
autoCompleteType?: null | string;
|
||||
editor?: CoreEditor;
|
||||
|
||||
/**
|
||||
* The tokenized user input that prompted the current autocomplete at the cursor. This can be out of sync with
|
||||
* the input that is currently being displayed in the editor.
|
||||
*/
|
||||
createdWithToken?: Token | null;
|
||||
|
||||
/**
|
||||
* The tokenized user input that is currently being displayed at the cursor in the editor when the user accepted
|
||||
* the autocomplete suggestion.
|
||||
*/
|
||||
updatedForToken?: Token | null;
|
||||
|
||||
addTemplate?: unknown;
|
||||
prefixToAdd?: string;
|
||||
suffixToAdd?: string;
|
||||
textBoxPosition?: { lineNumber: number; column: number };
|
||||
urlTokenPath?: string[];
|
||||
otherTokenValues?: string;
|
||||
requestStartRow?: number | null;
|
||||
bodyTokenPath?: string[] | null;
|
||||
endpointComponentResolver?: unknown;
|
||||
globalComponentResolver?: unknown;
|
||||
documentation?: string;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { SenseEditor } from './sense_editor';
|
||||
import { getEndpointFromPosition} from '../modules/autocomplete/get_endpoint_from_position';
|
||||
|
||||
export async function autoIndent(editor: SenseEditor, event: React.MouseEvent) {
|
||||
event.preventDefault();
|
||||
await editor.autoIndent();
|
||||
editor.getCoreEditor().getContainer().focus();
|
||||
}
|
||||
|
||||
export function getDocumentation(
|
||||
editor: SenseEditor,
|
||||
docLinkVersion: string
|
||||
): Promise<string | null> {
|
||||
return editor.getRequestsInRange().then((requests) => {
|
||||
if (!requests || requests.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const position = requests[0].range.end;
|
||||
position.column = position.column - 1;
|
||||
const endpoint = getEndpointFromPosition(editor.getCoreEditor(), position, editor.parser);
|
||||
if (endpoint && endpoint.documentation && endpoint.documentation.indexOf('http') !== -1) {
|
||||
return endpoint.documentation
|
||||
.replace('/master/', `/${docLinkVersion}/`)
|
||||
.replace('/current/', `/${docLinkVersion}/`);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
import { TokensProvider } from './tokens_provider';
|
||||
import { Token } from './token';
|
||||
|
||||
type MarkerRef = any;
|
||||
|
||||
export type EditorEvent =
|
||||
| 'tokenizerUpdate'
|
||||
| 'changeCursor'
|
||||
| 'changeScrollTop'
|
||||
| 'change'
|
||||
| 'changeSelection';
|
||||
|
||||
export type AutoCompleterFunction = (
|
||||
pos: Position,
|
||||
prefix: string,
|
||||
callback: (...args: unknown[]) => void
|
||||
) => void;
|
||||
|
||||
export interface Position {
|
||||
/**
|
||||
* The line number, not zero-indexed.
|
||||
*
|
||||
* E.g., if given line number 1, this would refer to the first line visible.
|
||||
*/
|
||||
lineNumber: number;
|
||||
|
||||
/**
|
||||
* The column number, not zero-indexed.
|
||||
*
|
||||
* E.g., if given column number 1, this would refer to the first character of a column.
|
||||
*/
|
||||
column: number;
|
||||
}
|
||||
|
||||
export interface Range {
|
||||
/**
|
||||
* The start point of the range.
|
||||
*/
|
||||
start: Position;
|
||||
|
||||
/**
|
||||
* The end point of the range.
|
||||
*/
|
||||
end: Position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of the different states the current position can be in.
|
||||
*
|
||||
* Current implementation uses low-level binary operations OR ('|') and AND ('&') to, respectively:
|
||||
*
|
||||
* - Create a combination of acceptable states.
|
||||
* - Extract the states from the acceptable combination.
|
||||
*
|
||||
* E.g.
|
||||
* ```ts
|
||||
* const acceptableStates = LINE_MODE.REQUEST_START | LINE_MODE.IN_REQUEST; // binary '110'
|
||||
*
|
||||
* // Is MULTI_DOC_CUR_DOC_END ('1000') acceptable?
|
||||
* Boolean(acceptableStates & LINE_MODE.MULTI_DOC_CUR_DOC_END) // false
|
||||
*
|
||||
* // Is REQUEST_START ('10') acceptable?
|
||||
* Boolean(acceptableStates & LINE_MODE.REQUEST_START) // true
|
||||
* ```
|
||||
*
|
||||
* This implementation will probably be changed to something more accessible in future but is documented
|
||||
* here for reference.
|
||||
*/
|
||||
export enum LINE_MODE {
|
||||
REQUEST_START = 2,
|
||||
IN_REQUEST = 4,
|
||||
MULTI_DOC_CUR_DOC_END = 8,
|
||||
REQUEST_END = 16,
|
||||
BETWEEN_REQUESTS = 32,
|
||||
UNKNOWN = 64,
|
||||
}
|
||||
|
||||
/**
|
||||
* The CoreEditor is a component separate from the Editor implementation that provides Console
|
||||
* app specific business logic. The CoreEditor is an interface to the lower-level editor implementation
|
||||
* being used which is usually vendor code such as Ace or Monaco.
|
||||
*/
|
||||
export interface CoreEditor {
|
||||
/**
|
||||
* Get the current position of the cursor.
|
||||
*/
|
||||
getCurrentPosition(): Position;
|
||||
|
||||
/**
|
||||
* Get the contents of the editor.
|
||||
*/
|
||||
getValue(): string;
|
||||
|
||||
/**
|
||||
* Sets the contents of the editor.
|
||||
*
|
||||
* Returns a promise so that callers can wait for re-tokenizing to complete.
|
||||
*/
|
||||
setValue(value: string, forceRetokenize: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the contents of the editor at a specific line.
|
||||
*/
|
||||
getLineValue(lineNumber: number): string;
|
||||
|
||||
/**
|
||||
* Insert a string value at the current cursor position.
|
||||
*/
|
||||
insert(value: string): void;
|
||||
|
||||
/**
|
||||
* Insert a string value at the indicated position.
|
||||
*/
|
||||
insert(pos: Position, value: string): void;
|
||||
|
||||
/**
|
||||
* Replace a range of text.
|
||||
*/
|
||||
replace(rangeToReplace: Range, value: string): void;
|
||||
|
||||
/**
|
||||
* Clear the selected range.
|
||||
*/
|
||||
clearSelection(): void;
|
||||
|
||||
/**
|
||||
* Returns the {@link Range} for currently selected text
|
||||
*/
|
||||
getSelectionRange(): Range;
|
||||
|
||||
/**
|
||||
* Move the cursor to the indicated position.
|
||||
*/
|
||||
moveCursorToPosition(pos: Position): void;
|
||||
|
||||
/**
|
||||
* Get the token at the indicated position. The token considered "at" the position is the
|
||||
* one directly preceding the position.
|
||||
*
|
||||
* Returns null if there is no such token.
|
||||
*/
|
||||
getTokenAt(pos: Position): Token | null;
|
||||
|
||||
/**
|
||||
* Get an iterable token provider.
|
||||
*/
|
||||
getTokenProvider(): TokensProvider;
|
||||
|
||||
/**
|
||||
* Get the contents of the editor between two points.
|
||||
*/
|
||||
getValueInRange(range: Range): string;
|
||||
|
||||
/**
|
||||
* Get the lexer state at the end of a specific line.
|
||||
*/
|
||||
getLineState(lineNumber: number): string;
|
||||
|
||||
/**
|
||||
* Get line content between and including the start and end lines provided.
|
||||
*/
|
||||
getLines(startLine: number, endLine: number): string[];
|
||||
|
||||
/**
|
||||
* Replace a range in the current buffer with the provided value.
|
||||
*/
|
||||
replaceRange(range: Range, value: string): void;
|
||||
|
||||
/**
|
||||
* Return the current line count in the buffer.
|
||||
*
|
||||
* @remark
|
||||
* This function should be usable in a tight loop and must make used of a cached
|
||||
* line count.
|
||||
*/
|
||||
getLineCount(): number;
|
||||
|
||||
/**
|
||||
* A legacy mechanism which gives consumers of this interface a chance to wait for
|
||||
* latest tokenization to complete.
|
||||
*/
|
||||
waitForLatestTokens(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Mark a range in the current buffer
|
||||
*/
|
||||
addMarker(range: Range): MarkerRef;
|
||||
|
||||
/**
|
||||
* Mark a range in the current buffer
|
||||
*/
|
||||
removeMarker(ref: MarkerRef): void;
|
||||
|
||||
/**
|
||||
* Get a number that represents the current wrap limit on a line
|
||||
*/
|
||||
getWrapLimit(): number;
|
||||
|
||||
/**
|
||||
* Register a listener for predefined editor events
|
||||
*/
|
||||
on(event: EditorEvent, listener: () => void): void;
|
||||
|
||||
/**
|
||||
* Unregister a listener for predefined editor events
|
||||
*/
|
||||
off(event: EditorEvent, listener: () => void): void;
|
||||
|
||||
/**
|
||||
* Execute a predefined editor command.
|
||||
*/
|
||||
execCommand(cmd: string): void;
|
||||
|
||||
/**
|
||||
* Returns a boolean value indicating whether or not the completer UI is currently showing in
|
||||
* the editor
|
||||
*/
|
||||
isCompleterActive(): boolean;
|
||||
|
||||
/**
|
||||
* Get the HTML container element for this editor instance
|
||||
*/
|
||||
getContainer(): HTMLDivElement;
|
||||
|
||||
/**
|
||||
* Because the core editor should not know about requests, but can know about ranges we still
|
||||
* have this backdoor to update UI in response to request range changes, for example, as the user
|
||||
* moves the cursor around
|
||||
*/
|
||||
legacyUpdateUI(opts: unknown): void;
|
||||
|
||||
/**
|
||||
* A method to for the editor to resize, useful when, for instance, window size changes.
|
||||
*/
|
||||
resize(): void;
|
||||
|
||||
/**
|
||||
* Expose a way to set styles on the editor
|
||||
*/
|
||||
setStyles(styles: { wrapLines: boolean; fontSize: string }): void;
|
||||
|
||||
/**
|
||||
* Register a keyboard shortcut and provide a function to be called.
|
||||
*/
|
||||
registerKeyboardShortcut(opts: {
|
||||
keys: string | { win?: string; mac?: string };
|
||||
fn: () => void;
|
||||
name: string;
|
||||
}): void;
|
||||
|
||||
/**
|
||||
* Register a completions function that will be called when the editor
|
||||
* detects a change
|
||||
*/
|
||||
registerAutocompleter(autocompleter: AutoCompleterFunction): void;
|
||||
|
||||
/**
|
||||
* Release any resources in use by the editor.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
export interface ESRequest {
|
||||
method: string;
|
||||
endpoint: string;
|
||||
data?: string;
|
||||
}
|
||||
|
||||
export interface ESRequestParams {
|
||||
method: string,
|
||||
path: string,
|
||||
body?: string,
|
||||
}
|
||||
|
||||
export type BaseResponseType =
|
||||
| 'application/json'
|
||||
| 'text/csv'
|
||||
| 'text/tab-separated-values'
|
||||
| 'text/plain'
|
||||
| 'application/yaml'
|
||||
| 'unknown';
|
||||
|
||||
export interface EsRequestArgs {
|
||||
requests: Array<{ url: string; method: string; data: string[] }>;
|
||||
}
|
||||
|
||||
export interface ESResponseObject<V = unknown> {
|
||||
statusCode: number;
|
||||
statusText: string;
|
||||
timeMs: number;
|
||||
contentType: BaseResponseType;
|
||||
value: V;
|
||||
}
|
||||
|
||||
export interface ESRequestResult<V = unknown> {
|
||||
request: { data: string; method: string; path: string };
|
||||
response: ESResponseObject<V>;
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import ace from 'brace';
|
||||
import { Editor as IAceEditor, IEditSession as IAceEditSession } from 'brace';
|
||||
import $ from 'jquery';
|
||||
import { CoreEditor, AutoCompleterFunction, EditorEvent } from './core_editor';
|
||||
import { Position, Range } from './position';
|
||||
import { Token } from './token';
|
||||
import { TokensProvider } from './tokens_provider';
|
||||
import { AceTokensProvider } from './ace_tokens_providers';
|
||||
|
||||
// @ts-ignore
|
||||
import * as InputMode from './mode/input';
|
||||
|
||||
const _AceRange = ace.acequire('ace/range').Range;
|
||||
|
||||
const rangeToAceRange = ({ start, end }: Range) =>
|
||||
new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1);
|
||||
|
||||
export class LegacyCoreEditor implements CoreEditor {
|
||||
private _aceOnPaste: Function;
|
||||
$actions: JQuery<HTMLElement>;
|
||||
resize: () => void;
|
||||
|
||||
constructor(private readonly editor: IAceEditor, actions: HTMLElement) {
|
||||
this.$actions = $(actions);
|
||||
this.editor.setShowPrintMargin(false);
|
||||
|
||||
const session = this.editor.getSession();
|
||||
session.setMode(new InputMode.Mode());
|
||||
((session as unknown) as { setFoldStyle: (style: string) => void }).setFoldStyle(
|
||||
'markbeginend'
|
||||
);
|
||||
session.setTabSize(2);
|
||||
session.setUseWrapMode(true);
|
||||
|
||||
// Intercept ace on paste handler.
|
||||
this._aceOnPaste = this.editor.onPaste;
|
||||
this.editor.onPaste = this.DO_NOT_USE_onPaste.bind(this);
|
||||
|
||||
this.editor.setOptions({
|
||||
enableBasicAutocompletion: true,
|
||||
});
|
||||
|
||||
this.editor.$blockScrolling = Infinity;
|
||||
this.hideActionsBar();
|
||||
this.editor.focus();
|
||||
}
|
||||
|
||||
// dirty check for tokenizer state, uses a lot less cycles
|
||||
// than listening for tokenizerUpdate
|
||||
waitForLatestTokens(): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
const session = this.editor.getSession();
|
||||
const checkInterval = 25;
|
||||
|
||||
const check = () => {
|
||||
// If the bgTokenizer doesn't exist, we can assume that the underlying editor has been
|
||||
// torn down, e.g. by closing the History tab, and we don't need to do anything further.
|
||||
if (session.bgTokenizer) {
|
||||
// Wait until the bgTokenizer is done running before executing the callback.
|
||||
if (((session.bgTokenizer as unknown) as { running: boolean }).running) {
|
||||
setTimeout(check, checkInterval);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(check, 0);
|
||||
});
|
||||
}
|
||||
|
||||
getLineState(lineNumber: number) {
|
||||
const session = this.editor.getSession();
|
||||
return session.getState(lineNumber - 1);
|
||||
}
|
||||
|
||||
getValueInRange(range: Range): string {
|
||||
return this.editor.getSession().getTextRange(rangeToAceRange(range));
|
||||
}
|
||||
|
||||
getTokenProvider(): TokensProvider {
|
||||
return new AceTokensProvider(this.editor.getSession());
|
||||
}
|
||||
|
||||
getValue(): string {
|
||||
return this.editor.getValue();
|
||||
}
|
||||
|
||||
async setValue(text: string, forceRetokenize: boolean): Promise<void> {
|
||||
const session = this.editor.getSession();
|
||||
session.setValue(text);
|
||||
if (forceRetokenize) {
|
||||
await this.forceRetokenize();
|
||||
}
|
||||
}
|
||||
|
||||
getLineValue(lineNumber: number): string {
|
||||
const session = this.editor.getSession();
|
||||
return session.getLine(lineNumber - 1);
|
||||
}
|
||||
|
||||
getCurrentPosition(): Position {
|
||||
const cursorPosition = this.editor.getCursorPosition();
|
||||
return {
|
||||
lineNumber: cursorPosition.row + 1,
|
||||
column: cursorPosition.column + 1,
|
||||
};
|
||||
}
|
||||
|
||||
clearSelection(): void {
|
||||
this.editor.clearSelection();
|
||||
}
|
||||
|
||||
getTokenAt(pos: Position): Token | null {
|
||||
const provider = this.getTokenProvider();
|
||||
return provider.getTokenAt(pos);
|
||||
}
|
||||
|
||||
insert(valueOrPos: string | Position, value?: string): void {
|
||||
if (typeof valueOrPos === 'string') {
|
||||
this.editor.insert(valueOrPos);
|
||||
return;
|
||||
}
|
||||
const document = this.editor.getSession().getDocument();
|
||||
document.insert(
|
||||
{
|
||||
column: valueOrPos.column - 1,
|
||||
row: valueOrPos.lineNumber - 1,
|
||||
},
|
||||
value || ''
|
||||
);
|
||||
}
|
||||
|
||||
moveCursorToPosition(pos: Position): void {
|
||||
this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 });
|
||||
}
|
||||
|
||||
replace(range: Range, value: string): void {
|
||||
const session = this.editor.getSession();
|
||||
session.replace(rangeToAceRange(range), value);
|
||||
}
|
||||
|
||||
getLines(startLine: number, endLine: number): string[] {
|
||||
const session = this.editor.getSession();
|
||||
return session.getLines(startLine - 1, endLine - 1);
|
||||
}
|
||||
|
||||
replaceRange(range: Range, value: string) {
|
||||
const pos = this.editor.getCursorPosition();
|
||||
this.editor.getSession().replace(rangeToAceRange(range), value);
|
||||
|
||||
const maxRow = Math.max(range.start.lineNumber - 1 + value.split('\n').length - 1, 1);
|
||||
pos.row = Math.min(pos.row, maxRow);
|
||||
this.editor.moveCursorToPosition(pos);
|
||||
// ACE UPGRADE - check if needed - at the moment the above may trigger a selection.
|
||||
this.editor.clearSelection();
|
||||
}
|
||||
|
||||
getSelectionRange() {
|
||||
const result = this.editor.getSelectionRange();
|
||||
return {
|
||||
start: {
|
||||
lineNumber: result.start.row + 1,
|
||||
column: result.start.column + 1,
|
||||
},
|
||||
end: {
|
||||
lineNumber: result.end.row + 1,
|
||||
column: result.end.column + 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getLineCount() {
|
||||
// Only use this function to return line count as it uses
|
||||
// a cache.
|
||||
return this.editor.getSession().getLength();
|
||||
}
|
||||
|
||||
addMarker(range: Range) {
|
||||
return this.editor
|
||||
.getSession()
|
||||
.addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false);
|
||||
}
|
||||
|
||||
removeMarker(ref: number) {
|
||||
this.editor.getSession().removeMarker(ref);
|
||||
}
|
||||
|
||||
getWrapLimit(): number {
|
||||
return this.editor.getSession().getWrapLimit();
|
||||
}
|
||||
|
||||
on(event: EditorEvent, listener: () => void) {
|
||||
if (event === 'changeCursor') {
|
||||
this.editor.getSession().selection.on(event, listener);
|
||||
} else if (event === 'changeSelection') {
|
||||
this.editor.on(event, listener);
|
||||
} else {
|
||||
this.editor.getSession().on(event, listener);
|
||||
}
|
||||
}
|
||||
|
||||
off(event: EditorEvent, listener: () => void) {
|
||||
if (event === 'changeSelection') {
|
||||
this.editor.off(event, listener);
|
||||
}
|
||||
}
|
||||
|
||||
isCompleterActive() {
|
||||
return Boolean(
|
||||
((this.editor as unknown) as { completer: { activated: unknown } }).completer &&
|
||||
((this.editor as unknown) as { completer: { activated: unknown } }).completer.activated
|
||||
);
|
||||
}
|
||||
|
||||
private forceRetokenize() {
|
||||
const session = this.editor.getSession();
|
||||
return new Promise<void>((resolve) => {
|
||||
// force update of tokens, but not on this thread to allow for ace rendering.
|
||||
setTimeout(function () {
|
||||
let i;
|
||||
for (i = 0; i < session.getLength(); i++) {
|
||||
session.getTokens(i);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
private DO_NOT_USE_onPaste(text: string) {
|
||||
this._aceOnPaste.call(this.editor, text);
|
||||
}
|
||||
|
||||
private setActionsBar = (value: number | null, topOrBottom: 'top' | 'bottom' = 'top') => {
|
||||
if (value === null) {
|
||||
this.$actions.css('visibility', 'hidden');
|
||||
} else {
|
||||
if (topOrBottom === 'top') {
|
||||
this.$actions.css({
|
||||
bottom: 'auto',
|
||||
top: value,
|
||||
visibility: 'visible',
|
||||
});
|
||||
} else {
|
||||
this.$actions.css({
|
||||
top: 'auto',
|
||||
bottom: value,
|
||||
visibility: 'visible',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private hideActionsBar = () => {
|
||||
this.setActionsBar(null);
|
||||
};
|
||||
|
||||
execCommand(cmd: string) {
|
||||
this.editor.execCommand(cmd);
|
||||
}
|
||||
|
||||
getContainer(): HTMLDivElement {
|
||||
return this.editor.container as HTMLDivElement;
|
||||
}
|
||||
|
||||
setStyles(styles: { wrapLines: boolean; fontSize: string }) {
|
||||
this.editor.getSession().setUseWrapMode(styles.wrapLines);
|
||||
this.editor.container.style.fontSize = styles.fontSize;
|
||||
}
|
||||
|
||||
registerKeyboardShortcut(opts: { keys: string; fn: () => void; name: string }): void {
|
||||
this.editor.commands.addCommand({
|
||||
exec: opts.fn,
|
||||
name: opts.name,
|
||||
bindKey: opts.keys,
|
||||
});
|
||||
}
|
||||
|
||||
legacyUpdateUI(range: Range) {
|
||||
if (!this.$actions) {
|
||||
return;
|
||||
}
|
||||
if (range) {
|
||||
// elements are positioned relative to the editor's container
|
||||
// pageY is relative to page, so subtract the offset
|
||||
// from pageY to get the new top value
|
||||
const offsetFromPage = $(this.editor.container).offset()!.top;
|
||||
const startLine = range.start.lineNumber;
|
||||
const startColumn = range.start.column;
|
||||
const firstLine = this.getLineValue(startLine);
|
||||
const maxLineLength = this.getWrapLimit() - 5;
|
||||
const isWrapping = firstLine.length > maxLineLength;
|
||||
const totalOffset = offsetFromPage - (window.pageYOffset || 0);
|
||||
const getScreenCoords = (line: number) =>
|
||||
this.editor.renderer.textToScreenCoordinates(line - 1, startColumn).pageY - totalOffset;
|
||||
const topOfReq = getScreenCoords(startLine);
|
||||
|
||||
if (topOfReq >= 0) {
|
||||
const { bottom: maxBottom } = this.editor.container.getBoundingClientRect();
|
||||
if (topOfReq > maxBottom - totalOffset) {
|
||||
this.setActionsBar(0, 'bottom');
|
||||
return;
|
||||
}
|
||||
let offset = 0;
|
||||
if (isWrapping) {
|
||||
// Try get the line height of the text area in pixels.
|
||||
const textArea = $(this.editor.container.querySelector('textArea')!);
|
||||
const hasRoomOnNextLine = this.getLineValue(startLine).length < maxLineLength;
|
||||
if (textArea && hasRoomOnNextLine) {
|
||||
// Line height + the number of wraps we have on a line.
|
||||
offset += this.getLineValue(startLine).length * textArea.height()!;
|
||||
} else {
|
||||
if (startLine > 1) {
|
||||
this.setActionsBar(getScreenCoords(startLine - 1));
|
||||
return;
|
||||
}
|
||||
this.setActionsBar(getScreenCoords(startLine + 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.setActionsBar(topOfReq + offset);
|
||||
return;
|
||||
}
|
||||
|
||||
const bottomOfReq =
|
||||
this.editor.renderer.textToScreenCoordinates(range.end.lineNumber, range.end.column).pageY -
|
||||
offsetFromPage;
|
||||
|
||||
if (bottomOfReq >= 0) {
|
||||
this.setActionsBar(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAutocompleter(autocompleter: AutoCompleterFunction): void {
|
||||
// Hook into Ace
|
||||
|
||||
// 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([
|
||||
{
|
||||
identifierRegexps: [
|
||||
/[a-zA-Z_0-9\.\$\-\u00A2-\uFFFF]/, // adds support for dot character
|
||||
],
|
||||
getCompletions: (
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
DO_NOT_USE_1: IAceEditor,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
DO_NOT_USE_2: IAceEditSession,
|
||||
pos: { row: number; column: number },
|
||||
prefix: string,
|
||||
callback: (...args: unknown[]) => void
|
||||
) => {
|
||||
const position: Position = {
|
||||
lineNumber: pos.row + 1,
|
||||
column: pos.column + 1,
|
||||
};
|
||||
autocompleter(position, prefix, callback);
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.editor.destroy();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
export interface Position {
|
||||
/**
|
||||
* The line number, not zero-indexed.
|
||||
*
|
||||
* E.g., if given line number 1, this would refer to the first line visible.
|
||||
*/
|
||||
lineNumber: number;
|
||||
|
||||
/**
|
||||
* The column number, not zero-indexed.
|
||||
*
|
||||
* E.g., if given column number 1, this would refer to the first character of a column.
|
||||
*/
|
||||
column: number;
|
||||
}
|
||||
|
||||
export interface Range {
|
||||
/**
|
||||
* The start point of the range.
|
||||
*/
|
||||
start: Position;
|
||||
|
||||
/**
|
||||
* The end point of the range.
|
||||
*/
|
||||
end: Position;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
import { Token } from './token';
|
||||
import { TokenIterator } from './token_iterator';
|
||||
import { CoreEditor } from './core_editor';
|
||||
|
||||
export const MODE = {
|
||||
REQUEST_START: 2,
|
||||
IN_REQUEST: 4,
|
||||
MULTI_DOC_CUR_DOC_END: 8,
|
||||
REQUEST_END: 16,
|
||||
BETWEEN_REQUESTS: 32,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default class RowParser {
|
||||
constructor(private readonly editor: CoreEditor) {}
|
||||
|
||||
MODE = MODE;
|
||||
|
||||
getRowParseMode(lineNumber = this.editor.getCurrentPosition().lineNumber) {
|
||||
const linesCount = this.editor.getLineCount();
|
||||
if (lineNumber > linesCount || lineNumber < 1) {
|
||||
return MODE.BETWEEN_REQUESTS;
|
||||
}
|
||||
const mode = this.editor.getLineState(lineNumber);
|
||||
if (!mode) {
|
||||
return MODE.BETWEEN_REQUESTS;
|
||||
} // shouldn't really happen
|
||||
|
||||
// If another "start" mode is added here because we want to allow for new language highlighting
|
||||
// please see https://github.com/elastic/kibana/pull/51446 for a discussion on why
|
||||
// should consider a different approach.
|
||||
if (mode !== 'start' && mode !== 'start-sql') {
|
||||
return MODE.IN_REQUEST;
|
||||
}
|
||||
let line = (this.editor.getLineValue(lineNumber) || '').trim();
|
||||
if (!line || line[0] === '#') {
|
||||
return MODE.BETWEEN_REQUESTS;
|
||||
} // empty line or a comment waiting for a new req to start
|
||||
|
||||
if (line.indexOf('}', line.length - 1) >= 0) {
|
||||
// check for a multi doc request (must start a new json doc immediately after this one end.
|
||||
lineNumber++;
|
||||
if (lineNumber < linesCount + 1) {
|
||||
line = (this.editor.getLineValue(lineNumber) || '').trim();
|
||||
if (line.indexOf('{') === 0) {
|
||||
// next line is another doc in a multi doc
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request
|
||||
}
|
||||
|
||||
// check for single line requests
|
||||
lineNumber++;
|
||||
if (lineNumber >= linesCount + 1) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return MODE.REQUEST_START | MODE.REQUEST_END;
|
||||
}
|
||||
line = (this.editor.getLineValue(lineNumber) || '').trim();
|
||||
if (line.indexOf('{') !== 0) {
|
||||
// next line is another request
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return MODE.REQUEST_START | MODE.REQUEST_END;
|
||||
}
|
||||
|
||||
return MODE.REQUEST_START;
|
||||
}
|
||||
|
||||
rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: number) {
|
||||
const mode = this.getRowParseMode(lineNumber);
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return (mode & value) > 0;
|
||||
}
|
||||
|
||||
isEndRequestRow(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
return this.rowPredicate(row, editor, MODE.REQUEST_END);
|
||||
}
|
||||
|
||||
isRequestEdge(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START);
|
||||
}
|
||||
|
||||
isStartRequestRow(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
return this.rowPredicate(row, editor, MODE.REQUEST_START);
|
||||
}
|
||||
|
||||
isInBetweenRequestsRow(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS);
|
||||
}
|
||||
|
||||
isInRequestsRow(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
return this.rowPredicate(row, editor, MODE.IN_REQUEST);
|
||||
}
|
||||
|
||||
isMultiDocDocEndRow(row?: number, _e?: CoreEditor) {
|
||||
const editor = _e || this.editor;
|
||||
return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END);
|
||||
}
|
||||
|
||||
isEmptyToken(tokenOrTokenIter: TokenIterator | Token | null) {
|
||||
const token =
|
||||
tokenOrTokenIter && (tokenOrTokenIter as TokenIterator).getCurrentToken
|
||||
? (tokenOrTokenIter as TokenIterator).getCurrentToken()
|
||||
: tokenOrTokenIter;
|
||||
return !token || (token as Token).type === 'whitespace';
|
||||
}
|
||||
|
||||
isUrlOrMethodToken(tokenOrTokenIter: TokenIterator | Token) {
|
||||
const t = (tokenOrTokenIter as TokenIterator)?.getCurrentToken() || (tokenOrTokenIter as Token);
|
||||
return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0);
|
||||
}
|
||||
|
||||
nextNonEmptyToken(tokenIter: TokenIterator) {
|
||||
let t = tokenIter.stepForward();
|
||||
while (t && this.isEmptyToken(t)) {
|
||||
t = tokenIter.stepForward();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
prevNonEmptyToken(tokenIter: TokenIterator) {
|
||||
let t = tokenIter.stepBackward();
|
||||
// empty rows return null token.
|
||||
while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t))
|
||||
t = tokenIter.stepBackward();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
import _ from 'lodash';
|
||||
import { collapseLiteralStrings } from '../utils/xjson';
|
||||
import RowParser from './row_parser';
|
||||
import { CoreEditor } from './core_editor';
|
||||
import { Position, Range } from './position';
|
||||
import { createTokenIterator } from '../factories/token_iterator';
|
||||
import createAutocompleter from '../modules/autocomplete/autocomplete';
|
||||
import * as utils from '../utils/autocomplete';
|
||||
import * as es from '../modules/es';
|
||||
|
||||
export class SenseEditor {
|
||||
currentReqRange: (Range & { markerRef: unknown }) | null;
|
||||
parser: RowParser;
|
||||
|
||||
private readonly autocomplete: ReturnType<typeof createAutocompleter>;
|
||||
|
||||
constructor(private readonly coreEditor: CoreEditor) {
|
||||
this.currentReqRange = null;
|
||||
this.parser = new RowParser(this.coreEditor);
|
||||
this.autocomplete = createAutocompleter({
|
||||
coreEditor,
|
||||
parser: this.parser,
|
||||
});
|
||||
this.coreEditor.registerAutocompleter(this.autocomplete.getCompletions);
|
||||
this.coreEditor.on(
|
||||
'tokenizerUpdate',
|
||||
this.highlightCurrentRequestsAndUpdateActionBar.bind(this)
|
||||
);
|
||||
this.coreEditor.on('changeCursor', this.highlightCurrentRequestsAndUpdateActionBar.bind(this));
|
||||
this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this));
|
||||
}
|
||||
|
||||
prevRequestStart = (rowOrPos?: number | Position): Position => {
|
||||
let curRow: number;
|
||||
|
||||
if (rowOrPos == null) {
|
||||
curRow = this.coreEditor.getCurrentPosition().lineNumber;
|
||||
} else if (_.isObject(rowOrPos)) {
|
||||
curRow = (rowOrPos as Position).lineNumber;
|
||||
} else {
|
||||
curRow = rowOrPos as number;
|
||||
}
|
||||
|
||||
while (curRow > 0 && !this.parser.isStartRequestRow(curRow, this.coreEditor)) curRow--;
|
||||
|
||||
return {
|
||||
lineNumber: curRow,
|
||||
column: 1,
|
||||
};
|
||||
};
|
||||
|
||||
nextRequestStart = (rowOrPos?: number | Position) => {
|
||||
let curRow: number;
|
||||
if (rowOrPos == null) {
|
||||
curRow = this.coreEditor.getCurrentPosition().lineNumber;
|
||||
} else if (_.isObject(rowOrPos)) {
|
||||
curRow = (rowOrPos as Position).lineNumber;
|
||||
} else {
|
||||
curRow = rowOrPos as number;
|
||||
}
|
||||
const maxLines = this.coreEditor.getLineCount();
|
||||
for (; curRow < maxLines - 1; curRow++) {
|
||||
if (this.parser.isStartRequestRow(curRow, this.coreEditor)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
row: curRow,
|
||||
column: 0,
|
||||
};
|
||||
};
|
||||
|
||||
autoIndent = _.debounce(async () => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
const reqRange = await this.getRequestRange();
|
||||
if (!reqRange) {
|
||||
return;
|
||||
}
|
||||
const parsedReq = await this.getRequest();
|
||||
|
||||
if (!parsedReq) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parsedReq.data && parsedReq.data.length > 0) {
|
||||
let indent = parsedReq.data.length === 1; // unindent multi docs by default
|
||||
let formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent);
|
||||
if (!formattedData.changed) {
|
||||
// toggle.
|
||||
indent = !indent;
|
||||
formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent);
|
||||
}
|
||||
parsedReq.data = formattedData.data;
|
||||
|
||||
this.replaceRequestRange(parsedReq, reqRange);
|
||||
}
|
||||
}, 25);
|
||||
|
||||
update = async (data: string, reTokenizeAll = false) => {
|
||||
return this.coreEditor.setValue(data, reTokenizeAll);
|
||||
};
|
||||
|
||||
replaceRequestRange = (
|
||||
newRequest: { method: string; url: string; data: string | string[] },
|
||||
requestRange: Range
|
||||
) => {
|
||||
const text = utils.textFromRequest(newRequest);
|
||||
if (requestRange) {
|
||||
this.coreEditor.replaceRange(requestRange, text);
|
||||
} else {
|
||||
// just insert where we are
|
||||
this.coreEditor.insert(this.coreEditor.getCurrentPosition(), text);
|
||||
}
|
||||
};
|
||||
|
||||
getRequestRange = async (lineNumber?: number): Promise<Range | null> => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
|
||||
if (this.parser.isInBetweenRequestsRow(lineNumber)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const reqStart = this.prevRequestStart(lineNumber);
|
||||
const reqEnd = this.nextRequestEnd(reqStart);
|
||||
|
||||
return {
|
||||
start: {
|
||||
...reqStart,
|
||||
},
|
||||
end: {
|
||||
...reqEnd,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
expandRangeToRequestEdges = async (
|
||||
range = this.coreEditor.getSelectionRange()
|
||||
): Promise<Range | null> => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
|
||||
let startLineNumber = range.start.lineNumber;
|
||||
let endLineNumber = range.end.lineNumber;
|
||||
const maxLine = Math.max(1, this.coreEditor.getLineCount());
|
||||
|
||||
if (this.parser.isInBetweenRequestsRow(startLineNumber)) {
|
||||
/* Do nothing... */
|
||||
} else {
|
||||
for (; startLineNumber >= 1; startLineNumber--) {
|
||||
if (this.parser.isStartRequestRow(startLineNumber)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startLineNumber < 1 || startLineNumber > endLineNumber) {
|
||||
return null;
|
||||
}
|
||||
// move end row to the previous request end if between requests, otherwise walk forward
|
||||
if (this.parser.isInBetweenRequestsRow(endLineNumber)) {
|
||||
for (; endLineNumber >= startLineNumber; endLineNumber--) {
|
||||
if (this.parser.isEndRequestRow(endLineNumber)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (; endLineNumber <= maxLine; endLineNumber++) {
|
||||
if (this.parser.isEndRequestRow(endLineNumber)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (endLineNumber < startLineNumber || endLineNumber > maxLine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const endColumn =
|
||||
(this.coreEditor.getLineValue(endLineNumber) || '').replace(/\s+$/, '').length + 1;
|
||||
return {
|
||||
start: {
|
||||
lineNumber: startLineNumber,
|
||||
column: 1,
|
||||
},
|
||||
end: {
|
||||
lineNumber: endLineNumber,
|
||||
column: endColumn,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
getRequestInRange = async (range?: Range) => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
if (!range) {
|
||||
return null;
|
||||
}
|
||||
const request: {
|
||||
method: string;
|
||||
data: string[];
|
||||
url: string;
|
||||
range: Range;
|
||||
} = {
|
||||
method: '',
|
||||
data: [],
|
||||
url: '',
|
||||
range,
|
||||
};
|
||||
|
||||
const pos = range.start;
|
||||
const tokenIter = createTokenIterator({ editor: this.coreEditor, position: pos });
|
||||
let t = tokenIter.getCurrentToken();
|
||||
if (this.parser.isEmptyToken(t)) {
|
||||
// if the row starts with some spaces, skip them.
|
||||
t = this.parser.nextNonEmptyToken(tokenIter);
|
||||
}
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
request.method = t.value;
|
||||
t = this.parser.nextNonEmptyToken(tokenIter);
|
||||
|
||||
if (!t || t.type === 'method') {
|
||||
return null;
|
||||
}
|
||||
|
||||
request.url = '';
|
||||
|
||||
while (t && t.type && t.type.indexOf('url') === 0) {
|
||||
request.url += t.value;
|
||||
t = tokenIter.stepForward();
|
||||
}
|
||||
if (this.parser.isEmptyToken(t)) {
|
||||
// if the url row ends with some spaces, skip them.
|
||||
t = this.parser.nextNonEmptyToken(tokenIter);
|
||||
}
|
||||
let bodyStartLineNumber = (t ? 0 : 1) + tokenIter.getCurrentPosition().lineNumber; // artificially increase end of docs.
|
||||
let dataEndPos: Position;
|
||||
while (
|
||||
bodyStartLineNumber < range.end.lineNumber ||
|
||||
(bodyStartLineNumber === range.end.lineNumber && 1 < range.end.column)
|
||||
) {
|
||||
dataEndPos = this.nextDataDocEnd({
|
||||
lineNumber: bodyStartLineNumber,
|
||||
column: 1,
|
||||
});
|
||||
const bodyRange: Range = {
|
||||
start: {
|
||||
lineNumber: bodyStartLineNumber,
|
||||
column: 1,
|
||||
},
|
||||
end: dataEndPos,
|
||||
};
|
||||
const data = this.coreEditor.getValueInRange(bodyRange)!;
|
||||
request.data.push(data.trim());
|
||||
bodyStartLineNumber = dataEndPos.lineNumber + 1;
|
||||
}
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
getRequestsInRange = async (
|
||||
range = this.coreEditor.getSelectionRange(),
|
||||
includeNonRequestBlocks = false
|
||||
): Promise<any[]> => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
if (!range) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const expandedRange = await this.expandRangeToRequestEdges(range);
|
||||
|
||||
if (!expandedRange) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const requests: unknown[] = [];
|
||||
|
||||
let rangeStartCursor = expandedRange.start.lineNumber;
|
||||
const endLineNumber = expandedRange.end.lineNumber;
|
||||
|
||||
// move to the next request start (during the second iterations this may not be exactly on a request
|
||||
let currentLineNumber = expandedRange.start.lineNumber;
|
||||
|
||||
const flushNonRequestBlock = () => {
|
||||
if (includeNonRequestBlocks) {
|
||||
const nonRequestPrefixBlock = this.coreEditor
|
||||
.getLines(rangeStartCursor, currentLineNumber - 1)
|
||||
.join('\n');
|
||||
if (nonRequestPrefixBlock) {
|
||||
requests.push(nonRequestPrefixBlock);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while (currentLineNumber <= endLineNumber) {
|
||||
if (this.parser.isStartRequestRow(currentLineNumber)) {
|
||||
flushNonRequestBlock();
|
||||
const request = await this.getRequest(currentLineNumber);
|
||||
if (!request) {
|
||||
// Something has probably gone wrong.
|
||||
return requests;
|
||||
} else {
|
||||
requests.push(request);
|
||||
rangeStartCursor = currentLineNumber = request.range.end.lineNumber + 1;
|
||||
}
|
||||
} else {
|
||||
++currentLineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
flushNonRequestBlock();
|
||||
|
||||
return requests;
|
||||
};
|
||||
|
||||
getRequest = async (row?: number) => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
if (this.parser.isInBetweenRequestsRow(row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const range = await this.getRequestRange(row);
|
||||
return this.getRequestInRange(range!);
|
||||
};
|
||||
|
||||
moveToPreviousRequestEdge = async () => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
const pos = this.coreEditor.getCurrentPosition();
|
||||
for (
|
||||
pos.lineNumber--;
|
||||
pos.lineNumber > 1 && !this.parser.isRequestEdge(pos.lineNumber);
|
||||
pos.lineNumber--
|
||||
) {
|
||||
// loop for side effects
|
||||
}
|
||||
this.coreEditor.moveCursorToPosition({
|
||||
lineNumber: pos.lineNumber,
|
||||
column: 1,
|
||||
});
|
||||
};
|
||||
|
||||
moveToNextRequestEdge = async (moveOnlyIfNotOnEdge: boolean) => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
const pos = this.coreEditor.getCurrentPosition();
|
||||
const maxRow = this.coreEditor.getLineCount();
|
||||
if (!moveOnlyIfNotOnEdge) {
|
||||
pos.lineNumber++;
|
||||
}
|
||||
for (
|
||||
;
|
||||
pos.lineNumber < maxRow && !this.parser.isRequestEdge(pos.lineNumber);
|
||||
pos.lineNumber++
|
||||
) {
|
||||
// loop for side effects
|
||||
}
|
||||
this.coreEditor.moveCursorToPosition({
|
||||
lineNumber: pos.lineNumber,
|
||||
column: 1,
|
||||
});
|
||||
};
|
||||
|
||||
nextRequestEnd = (pos: Position): Position => {
|
||||
pos = pos || this.coreEditor.getCurrentPosition();
|
||||
const maxLines = this.coreEditor.getLineCount();
|
||||
let curLineNumber = pos.lineNumber;
|
||||
for (; curLineNumber <= maxLines; ++curLineNumber) {
|
||||
const curRowMode = this.parser.getRowParseMode(curLineNumber);
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) {
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const column =
|
||||
(this.coreEditor.getLineValue(curLineNumber) || '').replace(/\s+$/, '').length + 1;
|
||||
|
||||
return {
|
||||
lineNumber: curLineNumber,
|
||||
column,
|
||||
};
|
||||
};
|
||||
|
||||
nextDataDocEnd = (pos: Position): Position => {
|
||||
pos = pos || this.coreEditor.getCurrentPosition();
|
||||
let curLineNumber = pos.lineNumber;
|
||||
const maxLines = this.coreEditor.getLineCount();
|
||||
for (; curLineNumber < maxLines; curLineNumber++) {
|
||||
const curRowMode = this.parser.getRowParseMode(curLineNumber);
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) {
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if ((curRowMode & this.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) {
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const column =
|
||||
(this.coreEditor.getLineValue(curLineNumber) || '').length +
|
||||
1; /* Range goes to 1 after last char */
|
||||
|
||||
return {
|
||||
lineNumber: curLineNumber,
|
||||
column,
|
||||
};
|
||||
};
|
||||
|
||||
highlightCurrentRequestsAndUpdateActionBar = _.debounce(async () => {
|
||||
await this.coreEditor.waitForLatestTokens();
|
||||
const expandedRange = await this.expandRangeToRequestEdges();
|
||||
if (expandedRange === null && this.currentReqRange === null) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
expandedRange !== null &&
|
||||
this.currentReqRange !== null &&
|
||||
expandedRange.start.lineNumber === this.currentReqRange.start.lineNumber &&
|
||||
expandedRange.end.lineNumber === this.currentReqRange.end.lineNumber
|
||||
) {
|
||||
// same request, now see if we are on the first line and update the action bar
|
||||
const cursorLineNumber = this.coreEditor.getCurrentPosition().lineNumber;
|
||||
if (cursorLineNumber === this.currentReqRange.start.lineNumber) {
|
||||
this.updateActionsBar();
|
||||
}
|
||||
return; // nothing to do..
|
||||
}
|
||||
|
||||
if (this.currentReqRange) {
|
||||
this.coreEditor.removeMarker(this.currentReqRange.markerRef);
|
||||
}
|
||||
|
||||
this.currentReqRange = expandedRange as any;
|
||||
if (this.currentReqRange) {
|
||||
this.currentReqRange.markerRef = this.coreEditor.addMarker(this.currentReqRange);
|
||||
}
|
||||
this.updateActionsBar();
|
||||
}, 25);
|
||||
|
||||
getRequestsAsCURL = async (elasticsearchBaseUrl: string, range?: Range): Promise<string> => {
|
||||
const requests = await this.getRequestsInRange(range, true);
|
||||
const result = _.map(requests, (req) => {
|
||||
if (typeof req === 'string') {
|
||||
// no request block
|
||||
return req;
|
||||
}
|
||||
|
||||
const esPath = req.url;
|
||||
const esMethod = req.method;
|
||||
const esData = req.data;
|
||||
|
||||
// this is the first url defined in elasticsearch.hosts
|
||||
const url = es.constructESUrl(elasticsearchBaseUrl, esPath);
|
||||
|
||||
let ret = 'curl -X' + esMethod + ' "' + url + '"';
|
||||
if (esData && esData.length) {
|
||||
ret += " -H 'Content-Type: application/json' -d'\n";
|
||||
const dataAsString = collapseLiteralStrings(esData.join('\n'));
|
||||
|
||||
// We escape single quoted strings that that are wrapped in single quoted strings
|
||||
ret += dataAsString.replace(/'/g, "'\\''");
|
||||
if (esData.length > 1) {
|
||||
ret += '\n';
|
||||
} // end with a new line
|
||||
ret += "'";
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
return result.join('\n');
|
||||
};
|
||||
|
||||
updateActionsBar = () => this.coreEditor.legacyUpdateUI(this.currentReqRange);
|
||||
|
||||
getCoreEditor() {
|
||||
return this.coreEditor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { TextObject } from './text_object';
|
||||
|
||||
export interface IdObject {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ObjectStorage<O extends IdObject> {
|
||||
/**
|
||||
* Creates a new object in the underlying persistance layer.
|
||||
*
|
||||
* @remarks Does not accept an ID, a new ID is generated and returned with the newly created object.
|
||||
*/
|
||||
create(obj: Omit<O, 'id'>): Promise<O>;
|
||||
|
||||
/**
|
||||
* This method should update specific object in the persistance layer.
|
||||
*/
|
||||
update(obj: O): Promise<void>;
|
||||
|
||||
/**
|
||||
* A function that will return all of the objects in the persistance layer.
|
||||
*
|
||||
* @remarks Unless an error is thrown this function should always return an array (empty if there are not objects present).
|
||||
*/
|
||||
findAll(): Promise<O[]>;
|
||||
}
|
||||
|
||||
export interface ObjectStorageClient {
|
||||
text: ObjectStorage<TextObject>;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export const textObjectTypeName = 'text-object';
|
||||
|
||||
/**
|
||||
* Describes the shape of persisted objects that contain information about the current text in the
|
||||
* text editor.
|
||||
*/
|
||||
export interface TextObject {
|
||||
/**
|
||||
* An ID that uniquely identifies this object.
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* UNIX timestamp of when the object was created.
|
||||
*/
|
||||
createdAt: number;
|
||||
|
||||
/**
|
||||
* UNIX timestamp of when the object was last updated.
|
||||
*/
|
||||
updatedAt: number;
|
||||
|
||||
/**
|
||||
* Text value input by the user.
|
||||
*
|
||||
* Used to re-populate a text editor buffer.
|
||||
*/
|
||||
text: string;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { Position } from './position';
|
||||
|
||||
export interface Token {
|
||||
/**
|
||||
* The value of the token.
|
||||
*
|
||||
* Can be an empty string.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* The type of the token. E.g., "whitespace". All of the types are
|
||||
* enumerated by the token lexer.
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* The position of the first character of the token.
|
||||
*/
|
||||
position: Position;
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
import { Token } from './token';
|
||||
import { Position } from './position';
|
||||
import { TokensProvider } from './tokens_provider';
|
||||
|
||||
function isColumnInTokenRange(column: number, token: Token) {
|
||||
if (column < token.position.column) {
|
||||
return false;
|
||||
}
|
||||
return column <= token.position.column + token.value.length;
|
||||
}
|
||||
|
||||
export class TokenIterator {
|
||||
private currentTokenIdx = -1;
|
||||
private currentPosition: Position = { lineNumber: -1, column: -1 };
|
||||
private tokensLineCache: Token[];
|
||||
|
||||
constructor(private readonly provider: TokensProvider, startPosition: Position) {
|
||||
this.tokensLineCache = this.provider.getTokens(startPosition.lineNumber) || [];
|
||||
const tokenIdx = this.tokensLineCache.findIndex((token) =>
|
||||
isColumnInTokenRange(startPosition.column, token)
|
||||
);
|
||||
if (tokenIdx > -1) {
|
||||
this.updatePosition({
|
||||
tokenIdx,
|
||||
position: this.tokensLineCache[tokenIdx].position,
|
||||
});
|
||||
} else {
|
||||
this.updatePosition({ tokenIdx: -1, position: startPosition });
|
||||
}
|
||||
}
|
||||
|
||||
private updateLineTokens(tokens: Token[]) {
|
||||
this.tokensLineCache = tokens;
|
||||
}
|
||||
|
||||
private updatePosition(info: { tokenIdx: number; position: Position }) {
|
||||
this.currentTokenIdx = info.tokenIdx;
|
||||
this.currentPosition = { ...info.position };
|
||||
}
|
||||
|
||||
private step(direction: 1 | -1): Token | null {
|
||||
const nextIdx = this.currentTokenIdx + direction;
|
||||
|
||||
let nextToken = this.tokensLineCache[nextIdx];
|
||||
// Check current row
|
||||
if (nextToken) {
|
||||
this.updatePosition({
|
||||
tokenIdx: nextIdx,
|
||||
position: nextToken.position,
|
||||
});
|
||||
return nextToken;
|
||||
}
|
||||
|
||||
// Check next line
|
||||
const nextLineNumber = this.currentPosition.lineNumber + direction;
|
||||
const nextLineTokens = this.provider.getTokens(nextLineNumber);
|
||||
if (nextLineTokens) {
|
||||
this.updateLineTokens(nextLineTokens);
|
||||
let idx: number;
|
||||
if (direction > 0) {
|
||||
nextToken = nextLineTokens[0];
|
||||
idx = 0;
|
||||
} else {
|
||||
nextToken = nextLineTokens[nextLineTokens.length - 1];
|
||||
idx = nextToken ? nextLineTokens.length - 1 : 0;
|
||||
}
|
||||
|
||||
const nextPosition = nextToken
|
||||
? nextToken.position
|
||||
: { column: 1, lineNumber: nextLineNumber };
|
||||
this.updatePosition({ tokenIdx: idx, position: nextPosition });
|
||||
return nextToken || null;
|
||||
}
|
||||
|
||||
// We have reached the beginning or the end
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the token under the iterator's internal cursor.
|
||||
*/
|
||||
public getCurrentToken(): Token | null {
|
||||
return this.tokensLineCache[this.currentTokenIdx] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position in the document.
|
||||
*
|
||||
* This will correspond to the position of a token.
|
||||
*
|
||||
* Note: this method may not be that useful given {@link getCurrentToken}.
|
||||
*/
|
||||
public getCurrentPosition(): Position {
|
||||
return this.currentPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the previous token in the document.
|
||||
*
|
||||
* Stepping to the previous token can return null under the following conditions:
|
||||
*
|
||||
* 1. We are at the beginning of the document.
|
||||
* 2. The preceding line is empty - no tokens.
|
||||
* 3. We are in an empty document - not text, so no tokens.
|
||||
*/
|
||||
public stepBackward(): Token | null {
|
||||
return this.step(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* See documentation for {@link stepBackward}.
|
||||
*
|
||||
* Steps forward.
|
||||
*/
|
||||
public stepForward(): Token | null {
|
||||
return this.step(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line number of the current token.
|
||||
*
|
||||
* Can be considered a convenience method for:
|
||||
*
|
||||
* ```ts
|
||||
* it.getCurrentToken().lineNumber;
|
||||
* ```
|
||||
*/
|
||||
public getCurrentTokenLineNumber(): number | null {
|
||||
const currentToken = this.getCurrentToken();
|
||||
if (currentToken) {
|
||||
return currentToken.position.lineNumber;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See documentation for {@link getCurrentTokenLineNumber}.
|
||||
*
|
||||
* Substitutes `column` for `lineNumber`.
|
||||
*/
|
||||
public getCurrentTokenColumn(): number | null {
|
||||
const currentToken = this.getCurrentToken();
|
||||
if (currentToken) {
|
||||
return currentToken.position.column;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { Position } from './position';
|
||||
import { Token } from './token';
|
||||
|
||||
export interface TokensProvider {
|
||||
/**
|
||||
* Special values in this interface are `null` and an empty array `[]`.
|
||||
* - `null` means that we are outside of the document range (i.e., have requested tokens for a non-existent line).
|
||||
* - An empty array means that we are on an empty line.
|
||||
*/
|
||||
getTokens(lineNumber: number): Token[] | null;
|
||||
|
||||
/**
|
||||
* Get the token at the specified position.
|
||||
*
|
||||
* The token "at" the position is considered to the token directly preceding
|
||||
* the indicated cursor position.
|
||||
*
|
||||
* Returns null if there is not a token that meets this criteria or if the position is outside
|
||||
* of the document range.
|
||||
*/
|
||||
getTokenAt(pos: Position): Token | null;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { CoreEditor } from '../entities/core_editor';
|
||||
import { Position} from '../entities/position';
|
||||
import { TokenIterator } from '../entities/token_iterator';
|
||||
|
||||
interface Dependencies {
|
||||
position: Position;
|
||||
editor: CoreEditor;
|
||||
}
|
||||
|
||||
export function createTokenIterator({ editor, position }: Dependencies) {
|
||||
const provider = editor.getTokenProvider();
|
||||
return new TokenIterator(provider, position);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { History } from '../../services';
|
||||
import { ObjectStorageClient } from '../../entities/storage';
|
||||
|
||||
export interface Dependencies {
|
||||
history: History;
|
||||
objectStorageClient: ObjectStorageClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Once off migration to new text object data structure
|
||||
*/
|
||||
export async function migrateToTextObjects({
|
||||
history,
|
||||
objectStorageClient: objectStorageClient,
|
||||
}: Dependencies): Promise<void> {
|
||||
const legacyTextContent = history.getLegacySavedEditorState();
|
||||
|
||||
if (!legacyTextContent) return;
|
||||
|
||||
await objectStorageClient.text.create({
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
text: legacyTextContent.content,
|
||||
});
|
||||
|
||||
history.deleteLegacySavedEditorState();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export { useDataInit } from './use_data_init';
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { migrateToTextObjects } from './data_migration';
|
||||
import { useEditorActionContext, useServicesContext } from '../../contexts';
|
||||
|
||||
export const useDataInit = () => {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [done, setDone] = useState<boolean>(false);
|
||||
const [retryToken, setRetryToken] = useState<object>({});
|
||||
|
||||
const retry = useCallback(() => {
|
||||
setRetryToken({});
|
||||
setDone(false);
|
||||
setError(null);
|
||||
}, []);
|
||||
|
||||
const {
|
||||
services: { objectStorageClient, history },
|
||||
} = useServicesContext();
|
||||
|
||||
const dispatch = useEditorActionContext();
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
try {
|
||||
await migrateToTextObjects({ history, objectStorageClient });
|
||||
const results = await objectStorageClient.text.findAll();
|
||||
if (!results.length) {
|
||||
const newObject = await objectStorageClient.text.create({
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
text: '',
|
||||
});
|
||||
dispatch({ type: 'setCurrentTextObject', payload: newObject });
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'setCurrentTextObject',
|
||||
// For backwards compatibility, we sort here according to date created to
|
||||
// always take the first item created.
|
||||
payload: results.sort((a, b) => a.createdAt - b.createdAt)[0],
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
} finally {
|
||||
setDone(true);
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
}, [dispatch, objectStorageClient, history, retryToken]);
|
||||
|
||||
return {
|
||||
error,
|
||||
done,
|
||||
retry,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { throttle } from 'lodash';
|
||||
import { useEditorReadContext, useServicesContext } from '../contexts';
|
||||
|
||||
const WAIT_MS = 500;
|
||||
|
||||
export const useSaveCurrentTextObject = () => {
|
||||
const promiseChainRef = useRef(Promise.resolve());
|
||||
|
||||
const {
|
||||
services: { objectStorageClient },
|
||||
} = useServicesContext();
|
||||
|
||||
const { currentTextObject } = useEditorReadContext();
|
||||
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
return useCallback(
|
||||
throttle(
|
||||
(text: string) => {
|
||||
const { current: promise } = promiseChainRef;
|
||||
if (!currentTextObject) return;
|
||||
promise.finally(() =>
|
||||
objectStorageClient.text.update({ ...currentTextObject, text, updatedAt: Date.now() })
|
||||
);
|
||||
},
|
||||
WAIT_MS,
|
||||
{ trailing: true }
|
||||
),
|
||||
[objectStorageClient, currentTextObject]
|
||||
);
|
||||
};
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { sendRequestToES } from './send_request_to_es';
|
||||
import { instance as registry } from '../../contexts/editor_context/editor_registry';
|
||||
import { useRequestActionContext } from '../../contexts/request_context';
|
||||
import { useServicesContext } from '../../contexts/services_context';
|
||||
import {getCommand} from '../../modules/mappings/mappings';
|
||||
|
||||
function buildRawCommonCommandRequest(cmd:any){
|
||||
const {requests} = cmd._source;
|
||||
const strReqs = requests.map((req: any)=>{
|
||||
const {method, path, body} = req;
|
||||
return `${method} ${path}\n${body}`;
|
||||
})
|
||||
return strReqs.join('\n');
|
||||
}
|
||||
export const useSendCurrentRequestToES = () => {
|
||||
const dispatch = useRequestActionContext();
|
||||
const { services: { history } } = useServicesContext();
|
||||
|
||||
return useCallback(async () => {
|
||||
try {
|
||||
const editor = registry.getInputEditor();
|
||||
const requests = await editor.getRequestsInRange();
|
||||
if (!requests.length) {
|
||||
console.log('No request selected. Select a request by placing the cursor inside it.');
|
||||
return;
|
||||
}
|
||||
const {url, method} = requests[0];
|
||||
if(method === 'LOAD'){
|
||||
const cmd = getCommand(url);
|
||||
// const curPostion = editor.currentReqRange //(editor.getCoreEditor().getCurrentPosition());
|
||||
const lineNumber = editor.getCoreEditor().getCurrentPosition().lineNumber;
|
||||
let crange = await editor.getRequestRange(lineNumber)
|
||||
const rawRequest = buildRawCommonCommandRequest(cmd)
|
||||
await editor.getCoreEditor().replaceRange(crange as any, rawRequest);
|
||||
// await editor.autoIndent();
|
||||
// editor.getCoreEditor().getContainer().focus();
|
||||
// crange = await editor.getRequestRange(lineNumber)
|
||||
|
||||
// editor.getCoreEditor().moveCursorToPosition({
|
||||
// ...crange?.end as any,
|
||||
// // column: editor.getCoreEditor().getLineValue(lineNumber).length + 1,
|
||||
// });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: 'sendRequest', payload: undefined });
|
||||
|
||||
// @ts-ignore
|
||||
const results = await sendRequestToES({ requests });
|
||||
|
||||
// let saveToHistoryError: undefined | Error;
|
||||
|
||||
// results.forEach(({ request: { path, method, data } }) => {
|
||||
// try {
|
||||
// history.addToHistory(path, method, data);
|
||||
// } catch (e) {
|
||||
// // Grab only the first error
|
||||
// if (!saveToHistoryError) {
|
||||
// saveToHistoryError = e;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (saveToHistoryError) {
|
||||
// console.log('save to history error')
|
||||
// }
|
||||
//
|
||||
dispatch({
|
||||
type: 'requestSuccess',
|
||||
payload: {
|
||||
data: results,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
if (e?.response) {
|
||||
dispatch({
|
||||
type: 'requestFail',
|
||||
payload: e,
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'requestFail',
|
||||
payload: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [dispatch, history]);
|
||||
};
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { send } from '../../modules/es';
|
||||
import { EsRequestArgs, ESRequestResult } from '../../entities/es_request';
|
||||
import { collapseLiteralStrings } from '../../utils/json_xjson_translation_tools';
|
||||
import { extractWarningMessages } from '../../utils/autocomplete';
|
||||
|
||||
let CURRENT_REQ_ID = 0;
|
||||
export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]> {
|
||||
const requests = args.requests.slice();
|
||||
return new Promise((resolve, reject) => {
|
||||
const reqId = ++CURRENT_REQ_ID;
|
||||
const results: ESRequestResult[] = [];
|
||||
if (reqId !== CURRENT_REQ_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requests.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isMultiRequest = requests.length > 1;
|
||||
|
||||
const sendNextRequest = () => {
|
||||
if (reqId !== CURRENT_REQ_ID) {
|
||||
resolve(results);
|
||||
return;
|
||||
}
|
||||
if (requests.length === 0) {
|
||||
resolve(results);
|
||||
return;
|
||||
}
|
||||
const req = requests.shift()!;
|
||||
const esPath = req.url;
|
||||
const esMethod = req.method;
|
||||
let esData = collapseLiteralStrings(req.data.join('\n'));
|
||||
if (esData) {
|
||||
esData += '\n';
|
||||
} // append a new line for bulk requests.
|
||||
|
||||
const startTime = Date.now();
|
||||
send(esMethod, esPath, esData).always(
|
||||
(dataOrjqXHR, textStatus: string, jqXhrORerrorThrown) => {
|
||||
if (reqId !== CURRENT_REQ_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const xhr = dataOrjqXHR.promise ? dataOrjqXHR : jqXhrORerrorThrown;
|
||||
|
||||
const isSuccess =
|
||||
typeof xhr.status === 'number' &&
|
||||
// Things like DELETE index where the index is not there are OK.
|
||||
((xhr.status >= 200 && xhr.status < 300) || xhr.status === 404);
|
||||
|
||||
if (isSuccess) {
|
||||
let value = xhr.responseText;
|
||||
|
||||
const warnings = xhr.getResponseHeader('warning');
|
||||
if (warnings) {
|
||||
const warningMessages = extractWarningMessages(warnings);
|
||||
value = warningMessages.join('\n') + '\n' + value;
|
||||
}
|
||||
|
||||
if (isMultiRequest) {
|
||||
value = '# ' + req.method + ' ' + req.url + '\n' + value;
|
||||
}
|
||||
|
||||
results.push({
|
||||
response: {
|
||||
timeMs: Date.now() - startTime,
|
||||
statusCode: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
contentType: xhr.getResponseHeader('Content-Type'),
|
||||
value,
|
||||
},
|
||||
request: {
|
||||
data: esData,
|
||||
method: esMethod,
|
||||
path: esPath,
|
||||
},
|
||||
});
|
||||
|
||||
// single request terminate via sendNextRequest as well
|
||||
sendNextRequest();
|
||||
} else {
|
||||
let value;
|
||||
let contentType: string;
|
||||
if (xhr.responseText) {
|
||||
value = xhr.responseText; // ES error should be shown
|
||||
contentType = xhr.getResponseHeader('Content-Type');
|
||||
} else {
|
||||
value = 'Request failed to get to the server (status code: ' + xhr.status + ')';
|
||||
contentType = 'text/plain';
|
||||
}
|
||||
if (isMultiRequest) {
|
||||
value = '# ' + req.method + ' ' + req.url + '\n' + value;
|
||||
}
|
||||
reject({
|
||||
response: {
|
||||
value,
|
||||
contentType,
|
||||
timeMs: Date.now() - startTime,
|
||||
statusCode: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
},
|
||||
request: {
|
||||
data: esData,
|
||||
method: esMethod,
|
||||
path: esPath,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
sendNextRequest();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useEditorActionContext } from '../contexts/editor_context';
|
||||
import { instance as registry } from '../contexts/editor_context/editor_registry';
|
||||
import { SenseEditor } from '../entities/sense_editor';
|
||||
|
||||
export const useSetInputEditor = () => {
|
||||
const dispatch = useEditorActionContext();
|
||||
|
||||
return useCallback(
|
||||
(editor: SenseEditor) => {
|
||||
dispatch({ type: 'setInputEditor', payload: editor });
|
||||
registry.setInputEditor(editor);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { WalkingState, walkTokenPath, wrapComponentWithDefaults } from './engine';
|
||||
import {
|
||||
ConstantComponent,
|
||||
SharedComponent,
|
||||
ObjectComponent,
|
||||
ConditionalProxy,
|
||||
GlobalOnlyComponent,
|
||||
} from './components';
|
||||
|
||||
function CompilingContext(endpointId, parametrizedComponentFactories) {
|
||||
this.parametrizedComponentFactories = parametrizedComponentFactories;
|
||||
this.endpointId = endpointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object to resolve scope links (syntax endpoint.path1.path2)
|
||||
* @param link the link either string (endpoint.path1.path2, or .path1.path2) or a function (context,editor)
|
||||
* which returns a description to be compiled
|
||||
* @constructor
|
||||
* @param compilingContext
|
||||
*
|
||||
*
|
||||
* For this to work we expect the context to include a method context.endpointComponentResolver(endpoint)
|
||||
* which should return the top level components for the given endpoint
|
||||
*/
|
||||
|
||||
function resolvePathToComponents(tokenPath, context, editor, components) {
|
||||
const walkStates = walkTokenPath(
|
||||
tokenPath,
|
||||
[new WalkingState('ROOT', components, [])],
|
||||
context,
|
||||
editor
|
||||
);
|
||||
const result = [].concat.apply([], _.map(walkStates, 'components'));
|
||||
return result;
|
||||
}
|
||||
|
||||
class ScopeResolver extends SharedComponent {
|
||||
constructor(link, compilingContext) {
|
||||
super('__scope_link');
|
||||
if (_.isString(link) && link[0] === '.') {
|
||||
// relative link, inject current endpoint
|
||||
if (link === '.') {
|
||||
link = compilingContext.endpointId;
|
||||
} else {
|
||||
link = compilingContext.endpointId + link;
|
||||
}
|
||||
}
|
||||
this.link = link;
|
||||
this.compilingContext = compilingContext;
|
||||
}
|
||||
|
||||
resolveLinkToComponents(context, editor) {
|
||||
if (_.isFunction(this.link)) {
|
||||
const desc = this.link(context, editor);
|
||||
return compileDescription(desc, this.compilingContext);
|
||||
}
|
||||
if (!_.isString(this.link)) {
|
||||
throw new Error('unsupported link format', this.link);
|
||||
}
|
||||
|
||||
let path = this.link.replace(/\./g, '{').split(/(\{)/);
|
||||
const endpoint = path[0];
|
||||
let components;
|
||||
try {
|
||||
if (endpoint === 'GLOBAL') {
|
||||
// global rules need an extra indirection
|
||||
if (path.length < 3) {
|
||||
throw new Error('missing term in global link: ' + this.link);
|
||||
}
|
||||
const term = path[2];
|
||||
components = context.globalComponentResolver(term);
|
||||
path = path.slice(3);
|
||||
} else {
|
||||
path = path.slice(1);
|
||||
components = context.endpointComponentResolver(endpoint);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error('failed to resolve link [' + this.link + ']: ' + e);
|
||||
}
|
||||
return resolvePathToComponents(path, context, editor, components);
|
||||
}
|
||||
|
||||
getTerms(context, editor) {
|
||||
const options = [];
|
||||
const components = this.resolveLinkToComponents(context, editor);
|
||||
_.each(components, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
const result = {
|
||||
next: [],
|
||||
};
|
||||
const components = this.resolveLinkToComponents(context, editor);
|
||||
_.each(components, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
function getTemplate(description) {
|
||||
if (description.__template) {
|
||||
if (description.__raw && _.isString(description.__template)) {
|
||||
return {
|
||||
// This is a special secret attribute that gets passed through to indicate that
|
||||
// the raw value should be passed through to the console without JSON.stringifying it
|
||||
// first.
|
||||
//
|
||||
// Primary use case is to allow __templates to contain extended JSON special values like
|
||||
// triple quotes.
|
||||
__raw: true,
|
||||
value: description.__template,
|
||||
};
|
||||
}
|
||||
return description.__template;
|
||||
} else if (description.__one_of) {
|
||||
return getTemplate(description.__one_of[0]);
|
||||
} else if (description.__any_of) {
|
||||
return [];
|
||||
} else if (description.__scope_link) {
|
||||
// assume an object for now.
|
||||
return {};
|
||||
} else if (Array.isArray(description)) {
|
||||
if (description.length === 1) {
|
||||
if (_.isObject(description[0])) {
|
||||
// shortcut to save typing
|
||||
const innerTemplate = getTemplate(description[0]);
|
||||
|
||||
return innerTemplate != null ? [innerTemplate] : [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
} else if (_.isObject(description)) {
|
||||
return {};
|
||||
} else if (_.isString(description) && !/^\{.*\}$/.test(description)) {
|
||||
return description;
|
||||
} else {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
function getOptions(description) {
|
||||
const options = {};
|
||||
const template = getTemplate(description);
|
||||
|
||||
if (!_.isUndefined(template)) {
|
||||
options.template = template;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description a json dict describing the endpoint
|
||||
* @param compilingContext
|
||||
*/
|
||||
function compileDescription(description, compilingContext) {
|
||||
if (Array.isArray(description)) {
|
||||
return [compileList(description, compilingContext)];
|
||||
} else if (_.isObject(description)) {
|
||||
// test for objects list as arrays are also objects
|
||||
if (description.__scope_link) {
|
||||
return [new ScopeResolver(description.__scope_link, compilingContext)];
|
||||
}
|
||||
if (description.__any_of) {
|
||||
return [compileList(description.__any_of, compilingContext)];
|
||||
}
|
||||
if (description.__one_of) {
|
||||
return _.flatten(
|
||||
_.map(description.__one_of, function (d) {
|
||||
return compileDescription(d, compilingContext);
|
||||
})
|
||||
);
|
||||
}
|
||||
const obj = compileObject(description, compilingContext);
|
||||
if (description.__condition) {
|
||||
return [compileCondition(description.__condition, obj, compilingContext)];
|
||||
} else {
|
||||
return [obj];
|
||||
}
|
||||
} else if (_.isString(description) && /^\{.*\}$/.test(description)) {
|
||||
return [compileParametrizedValue(description, compilingContext)];
|
||||
} else {
|
||||
return [new ConstantComponent(description)];
|
||||
}
|
||||
}
|
||||
|
||||
function compileParametrizedValue(value, compilingContext, template) {
|
||||
value = value.substr(1, value.length - 2).toLowerCase();
|
||||
let component = compilingContext.parametrizedComponentFactories.getComponent(value, true);
|
||||
if (!component) {
|
||||
throw new Error("no factory found for '" + value + "'");
|
||||
}
|
||||
component = component(value, null, template);
|
||||
if (!_.isUndefined(template)) {
|
||||
component = wrapComponentWithDefaults(component, { template: template });
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
function compileObject(objDescription, compilingContext) {
|
||||
const objectC = new ConstantComponent('{');
|
||||
const constants = [];
|
||||
const patterns = [];
|
||||
_.each(objDescription, function (desc, key) {
|
||||
if (key.indexOf('__') === 0) {
|
||||
// meta key
|
||||
return;
|
||||
}
|
||||
|
||||
const options = getOptions(desc);
|
||||
let component;
|
||||
if (/^\{.*\}$/.test(key)) {
|
||||
component = compileParametrizedValue(key, compilingContext, options.template);
|
||||
patterns.push(component);
|
||||
} else if (key === '*') {
|
||||
component = new SharedComponent(key);
|
||||
patterns.push(component);
|
||||
} else {
|
||||
options.name = key;
|
||||
component = new ConstantComponent(key, null, [options]);
|
||||
constants.push(component);
|
||||
}
|
||||
_.map(compileDescription(desc, compilingContext), function (subComponent) {
|
||||
component.addComponent(subComponent);
|
||||
});
|
||||
});
|
||||
objectC.addComponent(new ObjectComponent('inner', constants, patterns));
|
||||
return objectC;
|
||||
}
|
||||
|
||||
function compileList(listRule, compilingContext) {
|
||||
const listC = new ConstantComponent('[');
|
||||
_.each(listRule, function (desc) {
|
||||
_.each(compileDescription(desc, compilingContext), function (component) {
|
||||
listC.addComponent(component);
|
||||
});
|
||||
});
|
||||
return listC;
|
||||
}
|
||||
|
||||
/** takes a compiled object and wraps in a {@link ConditionalProxy }*/
|
||||
function compileCondition(description, compiledObject) {
|
||||
if (description.lines_regex) {
|
||||
return new ConditionalProxy(function (context, editor) {
|
||||
const lines = editor
|
||||
.getLines(context.requestStartRow, editor.getCurrentPosition().lineNumber)
|
||||
.join('\n');
|
||||
return new RegExp(description.lines_regex, 'm').test(lines);
|
||||
}, compiledObject);
|
||||
} else {
|
||||
throw 'unknown condition type - got: ' + JSON.stringify(description);
|
||||
}
|
||||
}
|
||||
|
||||
// a list of component that match anything but give auto complete suggestions based on global API entries.
|
||||
export function globalsOnlyAutocompleteComponents() {
|
||||
return [new GlobalOnlyComponent('__global__')];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endpointId id of the endpoint being compiled.
|
||||
* @param description a json dict describing the endpoint
|
||||
* @param endpointComponentResolver a function (endpoint,context,editor) which should resolve an endpoint
|
||||
* to it's list of compiled components.
|
||||
* @param parametrizedComponentFactories a dict of the following structure
|
||||
* that will be used as a fall back for pattern keys (i.e.: {type} ,resolved without the $s)
|
||||
* {
|
||||
* TYPE: function (part, parent, endpoint) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export function compileBodyDescription(endpointId, description, parametrizedComponentFactories) {
|
||||
return compileDescription(
|
||||
description,
|
||||
new CompilingContext(endpointId, parametrizedComponentFactories)
|
||||
);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export const URL_PATH_END_MARKER = '__url_path_end__';
|
||||
|
||||
export class AcceptEndpointComponent extends SharedComponent {
|
||||
constructor(endpoint, parent) {
|
||||
super(endpoint.id, parent);
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (token !== URL_PATH_END_MARKER) {
|
||||
return null;
|
||||
}
|
||||
if (this.endpoint.methods && -1 === _.indexOf(this.endpoint.methods, context.method)) {
|
||||
return null;
|
||||
}
|
||||
const r = super.match(token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.endpoint = this.endpoint;
|
||||
if (_.isNumber(this.endpoint.priority)) {
|
||||
r.priority = this.endpoint.priority;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export class AutocompleteComponent {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
/** called to get the possible suggestions for tokens, when this object is at the end of
|
||||
* the resolving chain (and thus can suggest possible continuation paths)
|
||||
*/
|
||||
getTerms() {
|
||||
return [];
|
||||
}
|
||||
/*
|
||||
if the current matcher matches this term, this method should return an object with the following keys
|
||||
{
|
||||
context_values: {
|
||||
values extract from term that should be added to the context
|
||||
}
|
||||
next: AutocompleteComponent(s) to use next
|
||||
priority: optional priority to solve collisions between multiple paths. Min value is used across entire chain
|
||||
}
|
||||
*/
|
||||
match() {
|
||||
return {
|
||||
next: this.next,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// import { ListComponent } from './list_component';
|
||||
|
||||
// export class CommandAutoCompleteComponent extends ListComponent {
|
||||
// constructor(name, list, parent, multiValued) {
|
||||
// super(name, list, parent, multiValued);
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getCommands } from '../../mappings/mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
export class CommandAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, getCommands, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'command';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'command';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class ConditionalProxy extends SharedComponent {
|
||||
constructor(predicate, delegate) {
|
||||
super('__condition');
|
||||
this.predicate = predicate;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
getTerms(context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.getTerms(context, editor);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.match(token, context, editor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class ConstantComponent extends SharedComponent {
|
||||
constructor(name, parent, options) {
|
||||
super(name, parent);
|
||||
if (_.isString(options)) {
|
||||
options = [options];
|
||||
}
|
||||
this.options = options || [name];
|
||||
}
|
||||
getTerms() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
addOption(options) {
|
||||
if (!Array.isArray(options)) {
|
||||
options = [options];
|
||||
}
|
||||
|
||||
[].push.apply(this.options, options);
|
||||
this.options = _.uniq(this.options);
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (token !== this.name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.match(token, context, editor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getFields } from '../../mappings/mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
|
||||
function FieldGenerator(context) {
|
||||
return _.map(getFields(context.indices, context.types), function (field) {
|
||||
return { name: field.name, meta: field.type };
|
||||
});
|
||||
}
|
||||
|
||||
export class FieldAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, FieldGenerator, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, function (token) {
|
||||
return token.match(/[^\w.?*]/);
|
||||
});
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'field';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'fields';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { ConstantComponent } from './constant_component';
|
||||
|
||||
// @ts-ignore
|
||||
export class FullRequestComponent extends ConstantComponent {
|
||||
private readonly name: string;
|
||||
constructor(name: string, parent: unknown, private readonly template: string) {
|
||||
super(name, parent);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
getTerms() {
|
||||
return [{ name: this.name, snippet: this.template }];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class GlobalOnlyComponent extends SharedComponent {
|
||||
getTerms() {
|
||||
return null;
|
||||
}
|
||||
|
||||
match(token, context) {
|
||||
const result = {
|
||||
next: [],
|
||||
};
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
}
|
||||
// just loop back to us
|
||||
result.next = [this];
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class IdAutocompleteComponent extends SharedComponent {
|
||||
constructor(name, parent, multi) {
|
||||
super(name, parent);
|
||||
this.multi_match = multi;
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
if (!this.multi_match && Array.isArray(token)) {
|
||||
return null;
|
||||
}
|
||||
token = Array.isArray(token) ? token : [token];
|
||||
if (
|
||||
_.find(token, function (t) {
|
||||
return t.match(/[\/,]/);
|
||||
})
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const r = super.match(token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.id = token;
|
||||
return r;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export { AutocompleteComponent } from './autocomplete_component';
|
||||
export { SharedComponent } from './shared_component';
|
||||
export { ConstantComponent } from './constant_component';
|
||||
export { ListComponent } from './list_component';
|
||||
export { SimpleParamComponent } from './simple_param_component';
|
||||
export { ConditionalProxy } from './conditional_proxy';
|
||||
export { GlobalOnlyComponent } from './global_only_component';
|
||||
export { ObjectComponent } from './object_component';
|
||||
export { AcceptEndpointComponent, URL_PATH_END_MARKER } from './accept_endpoint_component';
|
||||
export { UrlPatternMatcher } from './url_pattern_matcher';
|
||||
export { IndexAutocompleteComponent } from './index_autocomplete_component';
|
||||
export { FieldAutocompleteComponent } from './field_autocomplete_component';
|
||||
export { TypeAutocompleteComponent } from './type_autocomplete_component';
|
||||
export { IdAutocompleteComponent } from './id_autocomplete_component';
|
||||
export { TemplateAutocompleteComponent } from './template_autocomplete_component';
|
||||
export { UsernameAutocompleteComponent } from './username_autocomplete_component';
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getIndices } from '../../mappings/mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
export class IndexAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, getIndices, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'index';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'indices';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
/** A component that suggests one of the give options, but accepts anything */
|
||||
export class ListComponent extends SharedComponent {
|
||||
constructor(name, list, parent, multiValued, allowNonValidValues) {
|
||||
super(name, parent);
|
||||
this.listGenerator = Array.isArray(list)
|
||||
? function () {
|
||||
return list;
|
||||
}
|
||||
: list;
|
||||
this.multiValued = _.isUndefined(multiValued) ? true : multiValued;
|
||||
this.allowNonValidValues = _.isUndefined(allowNonValidValues) ? false : allowNonValidValues;
|
||||
}
|
||||
getTerms(context, editor) {
|
||||
if (!this.multiValued && context.otherTokenValues) {
|
||||
// already have a value -> no suggestions
|
||||
return [];
|
||||
}
|
||||
let alreadySet = context.otherTokenValues || [];
|
||||
if (_.isString(alreadySet)) {
|
||||
alreadySet = [alreadySet];
|
||||
}
|
||||
let ret = _.difference(this.listGenerator(context, editor), alreadySet);
|
||||
|
||||
if (this.getDefaultTermMeta()) {
|
||||
const meta = this.getDefaultTermMeta();
|
||||
ret = _.map(ret, function (term) {
|
||||
if (_.isString(term)) {
|
||||
term = { name: term };
|
||||
}
|
||||
return _.defaults(term, { meta: meta });
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify we have all tokens
|
||||
const list = this.listGenerator();
|
||||
const notFound = _.some(tokens, function (token) {
|
||||
return list.indexOf(token) === -1;
|
||||
});
|
||||
|
||||
if (notFound) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
if (!Array.isArray(token)) {
|
||||
token = [token];
|
||||
}
|
||||
if (!this.allowNonValidValues && !this.validateTokens(token, context, editor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = super.match(token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.getContextKey()] = token;
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './index';
|
||||
/**
|
||||
* @param constants list of components that represent constant keys
|
||||
* @param patternsAndWildCards list of components that represent patterns and should be matched only if
|
||||
* there is no constant matches
|
||||
*/
|
||||
export class ObjectComponent extends SharedComponent {
|
||||
constructor(name, constants, patternsAndWildCards) {
|
||||
super(name);
|
||||
this.constants = constants;
|
||||
this.patternsAndWildCards = patternsAndWildCards;
|
||||
}
|
||||
getTerms(context, editor) {
|
||||
const options = [];
|
||||
_.each(this.constants, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
const result = {
|
||||
next: [],
|
||||
};
|
||||
_.each(this.constants, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
}
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { AutocompleteComponent } from './autocomplete_component';
|
||||
export class SharedComponent extends AutocompleteComponent {
|
||||
constructor(name, parent) {
|
||||
super(name);
|
||||
this._nextDict = {};
|
||||
if (parent) {
|
||||
parent.addComponent(this);
|
||||
}
|
||||
// for debugging purposes
|
||||
this._parent = parent;
|
||||
}
|
||||
/* return the first component with a given name */
|
||||
getComponent(name) {
|
||||
return (this._nextDict[name] || [undefined])[0];
|
||||
}
|
||||
|
||||
addComponent(component) {
|
||||
const current = this._nextDict[component.name] || [];
|
||||
current.push(component);
|
||||
this._nextDict[component.name] = current;
|
||||
this.next = [].concat.apply([], _.values(this._nextDict));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class SimpleParamComponent extends SharedComponent {
|
||||
constructor(name, parent) {
|
||||
super(name, parent);
|
||||
}
|
||||
match(token, context, editor) {
|
||||
const result = super.match(token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.name] = token;
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { getTemplates } from '../../mappings/mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
|
||||
export class TemplateAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent) {
|
||||
super(name, getTemplates, parent, true, true);
|
||||
}
|
||||
getContextKey() {
|
||||
return 'template';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { ListComponent } from './list_component';
|
||||
import { getTypes } from '../../mappings/mappings';
|
||||
function TypeGenerator(context) {
|
||||
return getTypes(context.indices);
|
||||
}
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
export class TypeAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, TypeGenerator, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'type';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'types';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
SharedComponent,
|
||||
ConstantComponent,
|
||||
AcceptEndpointComponent,
|
||||
ListComponent,
|
||||
SimpleParamComponent,
|
||||
} from './index';
|
||||
|
||||
import { FullRequestComponent } from './full_request_component';
|
||||
|
||||
/**
|
||||
* @param parametrizedComponentFactories a dict of the following structure
|
||||
* that will be used as a fall back for pattern parameters (i.e.: {indices})
|
||||
* {
|
||||
* indices: function (part, parent) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
* @constructor
|
||||
*/
|
||||
export class UrlPatternMatcher {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
constructor(parametrizedComponentFactories) {
|
||||
// We'll group endpoints by the methods which are attached to them,
|
||||
//to avoid suggesting endpoints that are incompatible with the
|
||||
//method that the user has entered.
|
||||
['HEAD', 'GET', 'PUT', 'POST', 'DELETE'].forEach((method) => {
|
||||
this[method] = {
|
||||
rootComponent: new SharedComponent('ROOT'),
|
||||
parametrizedComponentFactories: parametrizedComponentFactories || {
|
||||
getComponent: () => {},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
addEndpoint(pattern, endpoint) {
|
||||
endpoint.methods.forEach((method) => {
|
||||
let c;
|
||||
let activeComponent = this[method].rootComponent;
|
||||
if (endpoint.template) {
|
||||
new FullRequestComponent(pattern + '[body]', activeComponent, endpoint.template);
|
||||
}
|
||||
const endpointComponents = endpoint.url_components || {};
|
||||
const partList = pattern.split('/');
|
||||
_.each(partList, (part, partIndex) => {
|
||||
if (part.search(/^{.+}$/) >= 0) {
|
||||
part = part.substr(1, part.length - 2);
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
return;
|
||||
}
|
||||
// a new path, resolve.
|
||||
|
||||
if ((c = endpointComponents[part])) {
|
||||
// endpoint specific. Support list
|
||||
if (Array.isArray(c)) {
|
||||
c = new ListComponent(part, c, activeComponent);
|
||||
} else if (_.isObject(c) && c.type === 'list') {
|
||||
c = new ListComponent(
|
||||
part,
|
||||
c.list,
|
||||
activeComponent,
|
||||
c.multiValued,
|
||||
c.allow_non_valid
|
||||
);
|
||||
} else {
|
||||
console.warn('incorrectly configured url component ', part, ' in endpoint', endpoint);
|
||||
c = new SharedComponent(part);
|
||||
}
|
||||
} else if ((c = this[method].parametrizedComponentFactories.getComponent(part))) {
|
||||
// c is a f
|
||||
c = c(part, activeComponent);
|
||||
} else {
|
||||
// just accept whatever with not suggestions
|
||||
c = new SimpleParamComponent(part, activeComponent);
|
||||
}
|
||||
|
||||
activeComponent = c;
|
||||
} else {
|
||||
// not pattern
|
||||
let lookAhead = part;
|
||||
let s;
|
||||
|
||||
for (partIndex++; partIndex < partList.length; partIndex++) {
|
||||
s = partList[partIndex];
|
||||
if (s.indexOf('{') >= 0) {
|
||||
break;
|
||||
}
|
||||
lookAhead += '/' + s;
|
||||
}
|
||||
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
activeComponent.addOption(lookAhead);
|
||||
} else {
|
||||
c = new ConstantComponent(part, activeComponent, lookAhead);
|
||||
activeComponent = c;
|
||||
}
|
||||
}
|
||||
});
|
||||
// mark end of endpoint path
|
||||
new AcceptEndpointComponent(endpoint, activeComponent);
|
||||
});
|
||||
}
|
||||
|
||||
getTopLevelComponents = function (method) {
|
||||
const methodRoot = this[method];
|
||||
if (!methodRoot) {
|
||||
return [];
|
||||
}
|
||||
return methodRoot.rootComponent.next;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getIndices } from '../../mappings/mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
function nonValidUsernameType(token) {
|
||||
return token[0] === '_';
|
||||
}
|
||||
export class UsernameAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, getIndices, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
return !_.find(tokens, nonValidUsernameType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'username';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'username';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
export function wrapComponentWithDefaults(component, defaults) {
|
||||
const originalGetTerms = component.getTerms;
|
||||
component.getTerms = function (context, editor) {
|
||||
let result = originalGetTerms.call(component, context, editor);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
result = _.map(result, (term) => {
|
||||
if (!_.isObject(term)) {
|
||||
term = { name: term };
|
||||
}
|
||||
return _.defaults(term, defaults);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
return component;
|
||||
}
|
||||
|
||||
const tracer = function () {
|
||||
if (window.engine_trace) {
|
||||
console.log.call(console, ...arguments);
|
||||
}
|
||||
};
|
||||
|
||||
function passThroughContext(context, extensionList) {
|
||||
function PTC() {}
|
||||
|
||||
PTC.prototype = context;
|
||||
const result = new PTC();
|
||||
if (extensionList) {
|
||||
extensionList.unshift(result);
|
||||
_.assign.apply(_, extensionList);
|
||||
extensionList.shift();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function WalkingState(parentName, components, contextExtensionList, depth, priority) {
|
||||
this.parentName = parentName;
|
||||
this.components = components;
|
||||
this.contextExtensionList = contextExtensionList;
|
||||
this.depth = depth || 0;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
export function walkTokenPath(tokenPath, walkingStates, context, editor) {
|
||||
if (!tokenPath || tokenPath.length === 0) {
|
||||
return walkingStates;
|
||||
}
|
||||
const token = tokenPath[0];
|
||||
const nextWalkingStates = [];
|
||||
|
||||
_.each(walkingStates, function (ws) {
|
||||
const contextForState = passThroughContext(context, ws.contextExtensionList);
|
||||
_.each(ws.components, function (component) {
|
||||
const result = component.match(token, contextForState, editor);
|
||||
if (result && !_.isEmpty(result)) {
|
||||
let next;
|
||||
let extensionList;
|
||||
if (result.next && !Array.isArray(result.next)) {
|
||||
next = [result.next];
|
||||
} else {
|
||||
next = result.next;
|
||||
}
|
||||
if (result.context_values) {
|
||||
extensionList = [];
|
||||
[].push.apply(extensionList, ws.contextExtensionList);
|
||||
extensionList.push(result.context_values);
|
||||
} else {
|
||||
extensionList = ws.contextExtensionList;
|
||||
}
|
||||
|
||||
let priority = ws.priority;
|
||||
if (_.isNumber(result.priority)) {
|
||||
if (_.isNumber(priority)) {
|
||||
priority = Math.min(priority, result.priority);
|
||||
} else {
|
||||
priority = result.priority;
|
||||
}
|
||||
}
|
||||
|
||||
nextWalkingStates.push(
|
||||
new WalkingState(component.name, next, extensionList, ws.depth + 1, priority)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (nextWalkingStates.length === 0) {
|
||||
// no where to go, still return context variables returned so far..
|
||||
return _.map(walkingStates, function (ws) {
|
||||
return new WalkingState(ws.name, [], ws.contextExtensionList);
|
||||
});
|
||||
}
|
||||
|
||||
return walkTokenPath(tokenPath.slice(1), nextWalkingStates, context, editor);
|
||||
}
|
||||
|
||||
export function populateContext(tokenPath, context, editor, includeAutoComplete, components) {
|
||||
let walkStates = walkTokenPath(
|
||||
tokenPath,
|
||||
[new WalkingState('ROOT', components, [])],
|
||||
context,
|
||||
editor
|
||||
);
|
||||
if (includeAutoComplete) {
|
||||
let autoCompleteSet = [];
|
||||
_.each(walkStates, function (ws) {
|
||||
const contextForState = passThroughContext(context, ws.contextExtensionList);
|
||||
_.each(ws.components, function (component) {
|
||||
_.each(component.getTerms(contextForState, editor), function (term) {
|
||||
if (!_.isObject(term)) {
|
||||
term = { name: term };
|
||||
}
|
||||
autoCompleteSet.push(term);
|
||||
});
|
||||
});
|
||||
});
|
||||
autoCompleteSet = _.uniq(autoCompleteSet);
|
||||
context.autoCompleteSet = autoCompleteSet;
|
||||
}
|
||||
|
||||
// apply what values were set so far to context, selecting the deepest on which sets the context
|
||||
if (walkStates.length !== 0) {
|
||||
let wsToUse;
|
||||
walkStates = _.sortBy(walkStates, function (ws) {
|
||||
return _.isNumber(ws.priority) ? ws.priority : Number.MAX_VALUE;
|
||||
});
|
||||
wsToUse = _.find(walkStates, function (ws) {
|
||||
return _.isEmpty(ws.components);
|
||||
});
|
||||
|
||||
if (!wsToUse && walkStates.length > 1 && !includeAutoComplete) {
|
||||
console.info(
|
||||
"more then one context active for current path, but autocomplete isn't requested",
|
||||
walkStates
|
||||
);
|
||||
}
|
||||
|
||||
if (!wsToUse) {
|
||||
wsToUse = walkStates[0];
|
||||
}
|
||||
|
||||
_.each(wsToUse.contextExtensionList, function (extension) {
|
||||
_.assign(context, extension);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import { CoreEditor } from '../../entities/core_editor';
|
||||
import { Position } from '../../entities/position';
|
||||
import { getCurrentMethodAndTokenPaths } from './autocomplete';
|
||||
import RowParser from '../../entities/row_parser';
|
||||
|
||||
// @ts-ignore
|
||||
import { getTopLevelUrlCompleteComponents } from '../kb/kb';
|
||||
// @ts-ignore
|
||||
import { populateContext } from './engine';
|
||||
|
||||
export function getEndpointFromPosition(editor: CoreEditor, pos: Position, parser: RowParser) {
|
||||
const lineValue = editor.getLineValue(pos.lineNumber);
|
||||
const context = {
|
||||
...getCurrentMethodAndTokenPaths(
|
||||
editor,
|
||||
{
|
||||
column: lineValue.length + 1 /* Go to the very end of the line */,
|
||||
lineNumber: pos.lineNumber,
|
||||
},
|
||||
parser,
|
||||
true
|
||||
),
|
||||
};
|
||||
const components = getTopLevelUrlCompleteComponents(context.method);
|
||||
populateContext(context.urlTokenPath, context, editor, true, components);
|
||||
return context.endpoint;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { ConstantComponent, ListComponent, SharedComponent } from './components';
|
||||
|
||||
export class ParamComponent extends ConstantComponent {
|
||||
constructor(name, parent, description) {
|
||||
super(name, parent);
|
||||
this.description = description;
|
||||
}
|
||||
getTerms() {
|
||||
const t = { name: this.name };
|
||||
if (this.description === '__flag__') {
|
||||
t.meta = 'flag';
|
||||
} else {
|
||||
t.meta = 'param';
|
||||
t.insertValue = this.name + '=';
|
||||
}
|
||||
return [t];
|
||||
}
|
||||
}
|
||||
|
||||
export class UrlParams {
|
||||
constructor(description, defaults) {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
this.rootComponent = new SharedComponent('ROOT');
|
||||
if (_.isUndefined(defaults)) {
|
||||
defaults = {
|
||||
pretty: '__flag__',
|
||||
format: ['json', 'yaml'],
|
||||
filter_path: '',
|
||||
};
|
||||
}
|
||||
description = _.clone(description || {});
|
||||
_.defaults(description, defaults);
|
||||
_.each(description, (pDescription, param) => {
|
||||
const component = new ParamComponent(param, this.rootComponent, pDescription);
|
||||
if (Array.isArray(pDescription)) {
|
||||
new ListComponent(param, pDescription, component);
|
||||
} else if (pDescription === '__flag__') {
|
||||
new ListComponent(param, ['true', 'false'], component);
|
||||
}
|
||||
});
|
||||
}
|
||||
getTopLevelComponents() {
|
||||
return this.rootComponent.next;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import $ from 'jquery';
|
||||
// @ts-ignore
|
||||
import { stringify } from 'query-string';
|
||||
|
||||
interface SendOptions {
|
||||
asSystemRequest?: boolean;
|
||||
}
|
||||
|
||||
const esVersion: string[] = [];
|
||||
|
||||
export function getVersion() {
|
||||
return esVersion;
|
||||
}
|
||||
|
||||
export function getContentType(body: unknown) {
|
||||
if (!body) return;
|
||||
return 'application/json';
|
||||
}
|
||||
|
||||
export function extractClusterIDFromURL(){
|
||||
const matchs = location.hash.match(/\/elasticsearch\/(\w+)\/?/);
|
||||
if(!matchs){
|
||||
return ''
|
||||
}
|
||||
return matchs[1];
|
||||
}
|
||||
|
||||
export function send(
|
||||
method: string,
|
||||
path: string,
|
||||
data: string | object,
|
||||
{ asSystemRequest }: SendOptions = {}
|
||||
) {
|
||||
const wrappedDfd = $.Deferred();
|
||||
|
||||
const clusterID = extractClusterIDFromURL();
|
||||
if(!clusterID){
|
||||
console.log('can not get clusterid from url');
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
const options: JQuery.AjaxSettings = {
|
||||
url: `/elasticsearch/${clusterID}/_proxy?` + stringify({ path, method }),
|
||||
headers: {
|
||||
'infini-xsrf': 'search-center',
|
||||
...(asSystemRequest && { 'infini-request': 'true' }),
|
||||
},
|
||||
data,
|
||||
contentType: getContentType(data),
|
||||
cache: false,
|
||||
crossDomain: true,
|
||||
type: 'POST',
|
||||
dataType: 'json', // disable automatic guessing
|
||||
};
|
||||
|
||||
$.ajax(options).then(
|
||||
(responseData: any, textStatus: string, jqXHR: unknown) => {
|
||||
wrappedDfd.resolveWith({}, [responseData, textStatus, jqXHR]);
|
||||
},
|
||||
((jqXHR: { status: number; responseText: string }, textStatus: string, errorThrown: Error) => {
|
||||
if (jqXHR.status === 0) {
|
||||
jqXHR.responseText =
|
||||
"\n\nFailed to connect to Console's backend.\nPlease check the server is up and running";
|
||||
}
|
||||
wrappedDfd.rejectWith({}, [jqXHR, textStatus, errorThrown]);
|
||||
}) as any
|
||||
);
|
||||
return wrappedDfd;
|
||||
}
|
||||
|
||||
export function queryCommonCommands(title?: string) {
|
||||
const clusterID = extractClusterIDFromURL();
|
||||
if(!clusterID){
|
||||
console.log('can not get clusterid from url');
|
||||
return;
|
||||
}
|
||||
let url = `/elasticsearch/${clusterID}/command/_search`;
|
||||
if(title){
|
||||
url +=`?title=${title}`
|
||||
}
|
||||
return fetch(url, {
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
export function constructESUrl(baseUri: string, path: string) {
|
||||
baseUri = baseUri.replace(/\/+$/, '');
|
||||
path = path.replace(/^\/+/, '');
|
||||
return baseUri + '/' + path;
|
||||
}
|
||||
|
||||
export function saveCommonCommand(params: any) {
|
||||
const clusterID = extractClusterIDFromURL();
|
||||
if(!clusterID){
|
||||
console.log('can not get clusterid from url');
|
||||
return;
|
||||
}
|
||||
return fetch(`/elasticsearch/${clusterID}/command`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(params),
|
||||
headers:{
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { UrlPatternMatcher } from '../autocomplete/components';
|
||||
import { UrlParams } from '../autocomplete/url_params';
|
||||
import {
|
||||
globalsOnlyAutocompleteComponents,
|
||||
compileBodyDescription,
|
||||
} from '../autocomplete/body_completer';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param urlParametrizedComponentFactories a dictionary of factory functions
|
||||
* that will be used as fallback for parametrized path part (i.e., {indices} )
|
||||
* see UrlPatternMatcher
|
||||
* @constructor
|
||||
* @param bodyParametrizedComponentFactories same as urlParametrizedComponentFactories but used for body compilation
|
||||
*/
|
||||
function Api(urlParametrizedComponentFactories, bodyParametrizedComponentFactories) {
|
||||
this.globalRules = Object.create(null);
|
||||
this.endpoints = Object.create(null);
|
||||
this.urlPatternMatcher = new UrlPatternMatcher(urlParametrizedComponentFactories);
|
||||
this.globalBodyComponentFactories = bodyParametrizedComponentFactories;
|
||||
this.name = '';
|
||||
}
|
||||
|
||||
(function (cls) {
|
||||
cls.addGlobalAutocompleteRules = function (parentNode, rules) {
|
||||
this.globalRules[parentNode] = compileBodyDescription(
|
||||
'GLOBAL.' + parentNode,
|
||||
rules,
|
||||
this.globalBodyComponentFactories
|
||||
);
|
||||
};
|
||||
|
||||
cls.getGlobalAutocompleteComponents = function (term, throwOnMissing) {
|
||||
const result = this.globalRules[term];
|
||||
if (_.isUndefined(result) && (throwOnMissing || _.isUndefined(throwOnMissing))) {
|
||||
throw new Error("failed to resolve global components for ['" + term + "']");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
cls.addEndpointDescription = function (endpoint, description) {
|
||||
const copiedDescription = {};
|
||||
_.assign(copiedDescription, description || {});
|
||||
_.defaults(copiedDescription, {
|
||||
id: endpoint,
|
||||
patterns: [endpoint],
|
||||
methods: ['GET'],
|
||||
});
|
||||
_.each(copiedDescription.patterns, (p) => {
|
||||
this.urlPatternMatcher.addEndpoint(p, copiedDescription);
|
||||
});
|
||||
|
||||
copiedDescription.paramsAutocomplete = new UrlParams(copiedDescription.url_params);
|
||||
copiedDescription.bodyAutocompleteRootComponents = compileBodyDescription(
|
||||
copiedDescription.id,
|
||||
copiedDescription.data_autocomplete_rules,
|
||||
this.globalBodyComponentFactories
|
||||
);
|
||||
|
||||
this.endpoints[endpoint] = copiedDescription;
|
||||
};
|
||||
|
||||
cls.getEndpointDescriptionByEndpoint = function (endpoint) {
|
||||
return this.endpoints[endpoint];
|
||||
};
|
||||
|
||||
cls.getTopLevelUrlCompleteComponents = function (method) {
|
||||
return this.urlPatternMatcher.getTopLevelComponents(method);
|
||||
};
|
||||
|
||||
cls.getUnmatchedEndpointComponents = function () {
|
||||
return globalsOnlyAutocompleteComponents();
|
||||
};
|
||||
|
||||
cls.clear = function () {
|
||||
this.endpoints = {};
|
||||
this.globalRules = {};
|
||||
};
|
||||
})(Api.prototype);
|
||||
|
||||
export default Api;
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export * from './kb';
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
import {
|
||||
TypeAutocompleteComponent,
|
||||
IdAutocompleteComponent,
|
||||
IndexAutocompleteComponent,
|
||||
FieldAutocompleteComponent,
|
||||
ListComponent,
|
||||
TemplateAutocompleteComponent,
|
||||
UsernameAutocompleteComponent,
|
||||
} from '../autocomplete/components';
|
||||
import { SpecDefinitionsService } from '../../server/services/spec_definitions_service';
|
||||
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Api from './api';
|
||||
|
||||
let ACTIVE_API = new Api();
|
||||
const isNotAnIndexName = (name) => name[0] === '_' && name !== '_all';
|
||||
|
||||
const idAutocompleteComponentFactory = (name, parent) => {
|
||||
return new IdAutocompleteComponent(name, parent);
|
||||
};
|
||||
const parametrizedComponentFactories = {
|
||||
getComponent: function (name, parent, provideDefault) {
|
||||
if (this[name]) {
|
||||
return this[name];
|
||||
} else if (provideDefault) {
|
||||
return idAutocompleteComponentFactory;
|
||||
}
|
||||
},
|
||||
index: function (name, parent) {
|
||||
if (isNotAnIndexName(name)) return;
|
||||
return new IndexAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
indices: function (name, parent) {
|
||||
if (isNotAnIndexName(name)) return;
|
||||
return new IndexAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
type: function (name, parent) {
|
||||
return new TypeAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
types: function (name, parent) {
|
||||
return new TypeAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
id: function (name, parent) {
|
||||
return idAutocompleteComponentFactory(name, parent);
|
||||
},
|
||||
transform_id: function (name, parent) {
|
||||
return idAutocompleteComponentFactory(name, parent);
|
||||
},
|
||||
username: function (name, parent) {
|
||||
return new UsernameAutocompleteComponent(name, parent);
|
||||
},
|
||||
user: function (name, parent) {
|
||||
return new UsernameAutocompleteComponent(name, parent);
|
||||
},
|
||||
template: function (name, parent) {
|
||||
return new TemplateAutocompleteComponent(name, parent);
|
||||
},
|
||||
task_id: function (name, parent) {
|
||||
return idAutocompleteComponentFactory(name, parent);
|
||||
},
|
||||
ids: function (name, parent) {
|
||||
return idAutocompleteComponentFactory(name, parent, true);
|
||||
},
|
||||
fields: function (name, parent) {
|
||||
return new FieldAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
field: function (name, parent) {
|
||||
return new FieldAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
nodes: function (name, parent) {
|
||||
return new ListComponent(
|
||||
name,
|
||||
['_local', '_master', 'data:true', 'data:false', 'master:true', 'master:false'],
|
||||
parent
|
||||
);
|
||||
},
|
||||
node: function (name, parent) {
|
||||
return new ListComponent(name, [], parent, false);
|
||||
},
|
||||
};
|
||||
|
||||
export function getUnmatchedEndpointComponents() {
|
||||
return ACTIVE_API.getUnmatchedEndpointComponents();
|
||||
}
|
||||
|
||||
export function getEndpointDescriptionByEndpoint(endpoint) {
|
||||
return ACTIVE_API.getEndpointDescriptionByEndpoint(endpoint);
|
||||
}
|
||||
|
||||
export function getEndpointBodyCompleteComponents(endpoint) {
|
||||
const desc = getEndpointDescriptionByEndpoint(endpoint);
|
||||
if (!desc) {
|
||||
throw new Error("failed to resolve endpoint ['" + endpoint + "']");
|
||||
}
|
||||
return desc.bodyAutocompleteRootComponents;
|
||||
}
|
||||
|
||||
export function getTopLevelUrlCompleteComponents(method) {
|
||||
return ACTIVE_API.getTopLevelUrlCompleteComponents(method);
|
||||
}
|
||||
|
||||
export function getGlobalAutocompleteComponents(term, throwOnMissing) {
|
||||
return ACTIVE_API.getGlobalAutocompleteComponents(term, throwOnMissing);
|
||||
}
|
||||
|
||||
function loadApisFromJson(
|
||||
json,
|
||||
urlParametrizedComponentFactories,
|
||||
bodyParametrizedComponentFactories
|
||||
) {
|
||||
urlParametrizedComponentFactories =
|
||||
urlParametrizedComponentFactories || parametrizedComponentFactories;
|
||||
bodyParametrizedComponentFactories =
|
||||
bodyParametrizedComponentFactories || urlParametrizedComponentFactories;
|
||||
const api = new Api(urlParametrizedComponentFactories, bodyParametrizedComponentFactories);
|
||||
const names = [];
|
||||
_.each(json, function (apiJson, name) {
|
||||
names.unshift(name);
|
||||
_.each(apiJson.globals || {}, function (globalJson, globalName) {
|
||||
api.addGlobalAutocompleteRules(globalName, globalJson);
|
||||
});
|
||||
_.each(apiJson.endpoints || {}, function (endpointJson, endpointName) {
|
||||
api.addEndpointDescription(endpointName, endpointJson);
|
||||
});
|
||||
});
|
||||
api.name = names.join(',');
|
||||
return api;
|
||||
}
|
||||
|
||||
const specDefinitionsService = new SpecDefinitionsService();
|
||||
specDefinitionsService.start();
|
||||
const json = specDefinitionsService.asJson();
|
||||
ACTIVE_API = loadApisFromJson({ es: json });
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export {
|
||||
ElasticsearchSqlHighlightRules,
|
||||
ScriptHighlightRules,
|
||||
XJsonHighlightRules,
|
||||
addXJsonToRules,
|
||||
XJsonMode,
|
||||
installXJsonMode,
|
||||
} from './modes';
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
export {
|
||||
ElasticsearchSqlHighlightRules,
|
||||
ScriptHighlightRules,
|
||||
XJsonHighlightRules,
|
||||
addXJsonToRules,
|
||||
} from './lexer_rules';
|
||||
|
||||
export { installXJsonMode, XJsonMode } from './x_json';
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue