This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git
The following commit(s) were added to refs/heads/main by this push:
new 36256a14 Add CRUD function for Index rule (#285)
36256a14 is described below
commit 36256a1418e4bdae2e5d37b4330e1b6bedcd5060
Author: Wu ChuSheng <[email protected]>
AuthorDate: Mon Jun 26 17:03:57 2023 +0800
Add CRUD function for Index rule (#285)
* Init IndexRule
* Add router
* Add IndexRule Reader and Editor
* Add Delete Index-rule
---
ui/src/api/index.js | 44 ++++
ui/src/components/Aside/index.vue | 336 ++++++++++++++++++++++++--
ui/src/components/IndexRule/Editor.vue | 332 +++++++++++++++++++++++++
ui/src/components/IndexRule/index.vue | 109 +++++++++
ui/src/components/IndexRuleBinding/Editor.vue | 26 ++
ui/src/components/IndexRuleBinding/index.vue | 26 ++
ui/src/components/Read/index.vue | 2 +-
ui/src/components/TopNav/index.vue | 7 +-
ui/src/router/index.js | 30 +++
9 files changed, 883 insertions(+), 29 deletions(-)
diff --git a/ui/src/api/index.js b/ui/src/api/index.js
index 50cf5010..059782c9 100644
--- a/ui/src/api/index.js
+++ b/ui/src/api/index.js
@@ -95,4 +95,48 @@ export function editResources(type, group, name, data) {
method: 'put',
data: data
})
+}
+
+export function getindexRuleList(name) {
+ return request({
+ url: `/api/v1/index-rule/schema/lists/${name}`,
+ method: 'get'
+ })
+}
+
+export function getindexRuleBindingList(name) {
+ return request({
+ url: `/api/v1/index-rule-binding/schema/lists/${name}`,
+ method: 'get'
+ })
+}
+
+export function getIndexRuleOrIndexRuleBinding(type, group, name) {
+ return request({
+ url: `/api/v1/${type}/schema/${group}/${name}`,
+ method: 'get'
+ })
+}
+
+export function createIndexRuleOrIndexRuleBinding(type, data) {
+ return request({
+ url: `/api/v1/${type}/schema`,
+ method: 'post',
+ data: data
+ })
+}
+
+export function updatendexRuleOrIndexRuleBinding(type, group, name, data) {
+ return request({
+ url: `/api/v1/${type}/schema/${group}/${name}`,
+ method: 'put',
+ data: data
+ })
+}
+
+export function deleteIndexRuleOrIndexRuleBinding(type, group, name) {
+ return request({
+ url: `/api/v1/${type}/schema/${group}/${name}`,
+ method: 'delete'
+ })
}
\ No newline at end of file
diff --git a/ui/src/components/Aside/index.vue
b/ui/src/components/Aside/index.vue
index 4096bf28..bb5a4a9c 100644
--- a/ui/src/components/Aside/index.vue
+++ b/ui/src/components/Aside/index.vue
@@ -19,7 +19,7 @@
<script setup>
import RigheMenu from '@/components/RightMenu/index.vue'
-import { getGroupList, getStreamOrMeasureList, deleteStreamOrMeasure,
deleteGroup, createGroup, editGroup, createResources } from '@/api/index'
+import { deleteIndexRuleOrIndexRuleBinding, getindexRuleList,
getindexRuleBindingList, getGroupList, getStreamOrMeasureList,
deleteStreamOrMeasure, deleteGroup, createGroup, editGroup, createResources }
from '@/api/index'
import { ElMessage, ElMessageBox } from 'element-plus'
import { watch, getCurrentInstance } from "@vue/runtime-core"
import { useRouter, useRoute } from 'vue-router'
@@ -77,10 +77,6 @@ const groupMenu = [
icon: "el-icon-folder",
name: "edit group",
id: "edit Group"
- }, {
- icon: "el-icon-document",
- name: "new resources",
- id: "create resources"
}, {
icon: "el-icon-refresh-right",
name: "refresh",
@@ -103,13 +99,62 @@ const resourceMenu = [
id: "delete resources"
}
]
+const StreamMenu = [
+ {
+ icon: "el-icon-document",
+ name: "new resources",
+ id: "create resources"
+ },
+]
+const indexRuleMenu = [
+ {
+ icon: "el-icon-document",
+ name: "new index-rule",
+ id: "create index-rule"
+ }
+]
+const indexRuleBindMenu = [
+ {
+ icon: "el-icon-document",
+ name: "new index-rule-binding",
+ id: "create index-rule-binding"
+ }
+]
+const indexRuleItemMenu = [
+ {
+ icon: "el-icon-document",
+ name: "edit index-rule",
+ id: "edit index-rule"
+ },
+ {
+ icon: "el-icon-delete",
+ name: "delete",
+ id: "delete index-rule"
+ }
+]
+const indexRuleBindingItemMenu = [
+ {
+ icon: "el-icon-document",
+ name: "edit index-rule-binding",
+ id: "edit index-rule-binding"
+ },
+ {
+ icon: "el-icon-delete",
+ name: "delete",
+ id: "delete index-rule-binding"
+ }
+]
const menuItemFunction = {
"new group": openCreateGroup,
"edit group": openEditGroup,
"new resources": openCreateResource,
- "refresh": getGroupList,
+ "refresh": getGroupLists,
"delete": openDeletaDialog,
- "edit resources": openEditResource
+ "edit resources": openEditResource,
+ 'new index-rule': openCreateIndexRuleOrIndexRuleBinding,
+ 'edit index-rule': openEditIndexRuleOrIndexRuleBinding,
+ 'new index-rule-binding': openCreateIndexRuleOrIndexRuleBinding,
+ 'edit index-rule-binding': openEditIndexRuleOrIndexRuleBinding
}
// rules
@@ -199,6 +244,40 @@ function getGroupLists() {
})
})
})
+ if (props.type == 'stream') {
+ let promiseIndexRule = data.groupLists.map((item) => {
+ let name = item.metadata.name
+ return new Promise((resolve, reject) => {
+ getindexRuleList(name)
+ .then(res => {
+ if (res.status == 200) {
+ item.indexRule = res.data.indexRule
+ resolve()
+ }
+ })
+ .catch((err) => {
+ reject(err)
+ })
+ })
+ })
+ let promiseIndexRuleBinding = data.groupLists.map((item)
=> {
+ let name = item.metadata.name
+ return new Promise((resolve, reject) => {
+ getindexRuleBindingList(name)
+ .then(res => {
+ if (res.status == 200) {
+ item.indexRuleBinding =
res.data.indexRuleBinding
+ resolve()
+ }
+ })
+ .catch((err) => {
+ reject(err)
+ })
+ })
+ })
+ promise = promise.concat(promiseIndexRule)
+ promise = promise.concat(promiseIndexRuleBinding)
+ }
Promise.all(promise).then(() => {
data.showSearch = true
data.groupListsCopy =
JSON.parse(JSON.stringify(data.groupLists))
@@ -294,6 +373,38 @@ function rightClickResources(e, index, childIndex) {
data.rightClickType = 'resources'
openRightMenu(e)
}
+function rightClickStream(e, index) {
+ data.rightMenuList = StreamMenu
+ data.clickIndex = index
+ data.rightClickType = 'group'
+ openRightMenu(e)
+}
+function rightClickIndexRule(e, index) {
+ data.rightMenuList = indexRuleMenu
+ data.clickIndex = index
+ data.rightClickType = 'index-rule'
+ openRightMenu(e)
+}
+function rightClickIndexRuleBinding(e, index) {
+ data.rightMenuList = indexRuleBindMenu
+ data.clickIndex = index
+ data.rightClickType = 'index-rule-binding'
+ openRightMenu(e)
+}
+function rightClickIndexRuleItem(e, index, childIndex) {
+ data.rightMenuList = indexRuleItemMenu
+ data.clickIndex = index
+ data.clickChildIndex = childIndex
+ data.rightClickType = 'index-rule'
+ openRightMenu(e)
+}
+function rightClickIndexRuleBindingItem(e, index, childIndex) {
+ data.rightMenuList = indexRuleBindingItemMenu
+ data.clickIndex = index
+ data.clickChildIndex = childIndex
+ data.rightClickType = 'index-rule-binding'
+ openRightMenu(e)
+}
function openRightMenu(e) {
data.showRightMenu = true
data.top = e.pageY
@@ -320,6 +431,73 @@ function stopPropagation(e) {
}
// CRUD operator
+function openCreateIndexRuleOrIndexRuleBinding() {
+ const route = {
+ name: `create-${data.rightClickType}`,
+ params: {
+ operator: 'create',
+ group: data.groupLists[data.clickIndex].metadata.name,
+ name: '',
+ type: data.rightClickType
+ }
+ }
+ router.push(route)
+ const add = {
+ label: data.groupLists[data.clickIndex].metadata.name,
+ type: `Create-${data.rightClickType}`,
+ route
+ }
+ data.activeMenu = ''
+ $bus.emit('AddTabs', add)
+}
+
+function openEditIndexRuleOrIndexRuleBinding() {
+ const typeFlag = {
+ 'index-rule': 'indexRule',
+ 'index-rule-binding': 'indexRuleBinding'
+ }
+ const route = {
+ name: `edit-${data.rightClickType}`,
+ params: {
+ operator: 'edit',
+ group: data.groupLists[data.clickIndex].metadata.name,
+ name:
data.groupLists[data.clickIndex][typeFlag[data.rightClickType]][data.clickChildIndex].metadata.name,
+ type: data.rightClickType
+ }
+ }
+ router.push(route)
+ const add = {
+ label:
data.groupLists[data.clickIndex][typeFlag[data.rightClickType]][data.clickChildIndex].metadata.name,
+ type: `Edit-${data.rightClickType}`,
+ route
+ }
+ $bus.emit('AddTabs', add)
+}
+function openIndexRuleOrIndexRuleBinding(index, childIndex, type) {
+ const typeFlag = {
+ 'indexRule': 'index-rule',
+ 'indexRuleBinding': 'index-rule-binding'
+ }
+ const group = data.groupLists[index][type][childIndex].metadata.group
+ const name = data.groupLists[index][type][childIndex].metadata.name
+ const route = {
+ name: `${typeFlag[type]}`,
+ params: {
+ group: group,
+ name: name,
+ operator: 'read',
+ type: typeFlag[type]
+ }
+ }
+ router.push(route)
+ const add = {
+ label: name,
+ type: `Read-${typeFlag[type]}`,
+ route
+ }
+ data.activeMenu = `${group}-${name}`
+ $bus.emit('AddTabs', add)
+}
function openCreateGroup() {
data.setGroup = 'create'
data.dialogGroupVisible = true
@@ -368,11 +546,13 @@ function openEditResource() {
$bus.emit('AddTabs', add)
}
function openDeletaDialog() {
- ElMessageBox.confirm('Are you sure to delete this resource?')
+ ElMessageBox.confirm('Are you sure to delete?')
.then(() => {
let group = data.groupLists[data.clickIndex].metadata.name
if (data.rightClickType == 'group') {
return deleteGroupFunction(group)
+ } else if (data.rightClickType == 'index-rule') {
+ return deleteIndexRuleFunction()
}
return deleteResource(group)
})
@@ -380,6 +560,28 @@ function openDeletaDialog() {
// catch error
})
}
+function deleteIndexRuleFunction() {
+ $loadingCreate()
+ let group = data.groupLists[data.clickIndex].metadata.name
+ let name =
data.groupLists[data.clickIndex].indexRule[data.clickChildIndex].metadata.name
+ deleteIndexRuleOrIndexRuleBinding("index-rule", group, name)
+ .then((res) => {
+ if (res.status == 200) {
+ if (res.data.deleted) {
+ ElMessage({
+ message: 'Delete succeeded',
+ type: "success",
+ duration: 5000
+ })
+ getGroupLists()
+ $bus.emit('deleteResource', name)
+ }
+ }
+ })
+ .finally(() => {
+ $loadingClose()
+ })
+}
function deleteGroupFunction(group) {
// delete group
$loadingCreate()
@@ -537,8 +739,8 @@ initActiveMenu()
<template>
<div style="display: flex; flex-direction: column; width: 100%;">
<div class="size flex" style="display: flex; flex-direction: column;
width: 100%;">
- <el-input v-if="data.showSearch" class="aside-search"
v-model="data.search" placeholder="Search"
- :prefix-icon="Search" clearable />
+ <el-input v-if="data.showSearch && props.type == 'measure'"
class="aside-search" v-model="data.search"
+ placeholder="Search" :prefix-icon="Search" clearable />
<el-menu v-if="data.groupLists.length > 0"
:collapse="data.isCollapse" :default-active="data.activeMenu">
<div v-for="(item, index) in data.groupLists"
:key="item.metadata.name"
@contextmenu.prevent="rightClickGroup($event, index)">
@@ -551,20 +753,106 @@ initActiveMenu()
{{ item.metadata.name }}
</span>
</template>
- <div v-for="(child, childIndex) in item.children"
:key="child.metadata.name">
- <div
@contextmenu.prevent="rightClickResources($event, index, childIndex)">
- <el-menu-item
:index="`${child.metadata.group}-${child.metadata.name}`"
- @click="openResources(index, childIndex)">
- <template #title>
- <el-icon>
- <Document />
- </el-icon>
- <span slot="title"
:title="child.metadata.name" style="width: 90%"
- class="text-overflow-hidden">
- {{ child.metadata.name }}
- </span>
- </template>
- </el-menu-item>
+ <el-sub-menu v-if="props.type == 'stream'"
:index="`${item.metadata.name}-${index}-index-rule`"
+ @contextmenu.prevent="rightClickIndexRule($event,
index)">
+ <template #title>
+ <el-icon>
+ <Folder />
+ </el-icon>
+ <span slot="title" title="Index-Rule"
style="width: 70%" class="text-overflow-hidden">
+ Index-Rule
+ </span>
+ </template>
+ <div v-for="(child, childIndex) in item.indexRule"
:key="child.metadata.name">
+ <div
@contextmenu.prevent="rightClickIndexRuleItem($event, index, childIndex)">
+ <el-menu-item
@click="openIndexRuleOrIndexRuleBinding(index, childIndex, 'indexRule')"
+
:index="`${child.metadata.group}-${child.metadata.name}`">
+ <template #title>
+ <el-icon>
+ <Document />
+ </el-icon>
+ <span slot="title"
:title="child.metadata.name" style="width: 90%"
+ class="text-overflow-hidden">
+ {{ child.metadata.name }}
+ </span>
+ </template>
+ </el-menu-item>
+ </div>
+ </div>
+ </el-sub-menu>
+ <el-sub-menu v-if="props.type == 'stream'"
+
:index="`${item.metadata.name}-${index}-index-rule-binding`"
+
@contextmenu.prevent="rightClickIndexRuleBinding($event, index)">
+ <template #title>
+ <el-icon>
+ <Folder />
+ </el-icon>
+ <span slot="title" title="Index-Rule-Binding"
style="width: 70%"
+ class="text-overflow-hidden">
+ Index-Rule-Binding
+ </span>
+ </template>
+ <div v-for="(child, childIndex) in
item.indexRuleBinding" :key="child.metadata.name">
+ <div
@contextmenu.prevent="rightClickIndexRuleBindingItem($event, index,
childIndex)">
+ <el-menu-item
+
@click="openIndexRuleOrIndexRuleBinding(index, childIndex, 'indexRuleBinding')"
+
:index="`${child.metadata.group}-${child.metadata.name}`">
+ <template #title>
+ <el-icon>
+ <Document />
+ </el-icon>
+ <span slot="title"
:title="child.metadata.name" style="width: 90%"
+ class="text-overflow-hidden">
+ {{ child.metadata.name }}
+ </span>
+ </template>
+ </el-menu-item>
+ </div>
+ </div>
+ </el-sub-menu>
+ <el-sub-menu v-if="props.type == 'stream'"
@contextmenu.prevent="rightClickStream($event, index)"
+ :index="`${item.metadata.name}-${index}-stream`">
+ <template #title>
+ <el-icon>
+ <Folder />
+ </el-icon>
+ <span slot="title" title="Stream"
style="width: 70%" class="text-overflow-hidden">
+ Stream
+ </span>
+ </template>
+ <div v-for="(child, childIndex) in item.children"
:key="child.metadata.name">
+ <div
@contextmenu.prevent="rightClickResources($event, index, childIndex)">
+ <el-menu-item
:index="`${child.metadata.group}-${child.metadata.name}`"
+ @click="openResources(index,
childIndex)">
+ <template #title>
+ <el-icon>
+ <Document />
+ </el-icon>
+ <span slot="title"
:title="child.metadata.name" style="width: 90%"
+ class="text-overflow-hidden">
+ {{ child.metadata.name }}
+ </span>
+ </template>
+ </el-menu-item>
+ </div>
+ </div>
+ </el-sub-menu>
+ <div v-if="props.type == 'measure'">
+ <div v-for="(child, childIndex) in item.children"
:key="child.metadata.name">
+ <div
@contextmenu.prevent="rightClickResources($event, index, childIndex)">
+ <el-menu-item
:index="`${child.metadata.group}-${child.metadata.name}`"
+ @click="openResources(index,
childIndex)">
+ <template #title>
+ <el-icon>
+ <Document />
+ </el-icon>
+ <span slot="title"
:title="child.metadata.name" style="width: 90%"
+ class="text-overflow-hidden">
+ {{ child.metadata.name }}
+ </span>
+ </template>
+ </el-menu-item>
+ </div>
</div>
</div>
</el-sub-menu>
diff --git a/ui/src/components/IndexRule/Editor.vue
b/ui/src/components/IndexRule/Editor.vue
new file mode 100644
index 00000000..4e4cef35
--- /dev/null
+++ b/ui/src/components/IndexRule/Editor.vue
@@ -0,0 +1,332 @@
+<!--
+ ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
+ ~ license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright
+ ~ ownership. Apache Software Foundation (ASF) 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.
+-->
+
+<script lang="ts" setup>
+import { reactive, ref } from 'vue'
+import { watch, getCurrentInstance } from '@vue/runtime-core'
+import { useRoute, useRouter } from 'vue-router'
+import type { FormInstance } from 'element-plus'
+import { createIndexRuleOrIndexRuleBinding, getIndexRuleOrIndexRuleBinding,
updatendexRuleOrIndexRuleBinding } from '@/api/index'
+import { ElMessage } from 'element-plus'
+const $loadingCreate =
getCurrentInstance().appContext.config.globalProperties.$loadingCreate
+const $loadingClose =
getCurrentInstance().appContext.config.globalProperties.$loadingClose
+const $bus = getCurrentInstance().appContext.config.globalProperties.mittBus
+const ruleFormRef = ref<FormInstance>()
+
+const route = useRoute()
+const router = useRouter()
+const rules = {
+ group: [
+ {
+ required: true, message: 'Please enter the group', trigger: 'blur'
+ }
+ ],
+ name: [
+ {
+ required: true, message: 'Please enter the name', trigger: 'blur'
+ }
+ ],
+ analyzer: [
+ {
+ required: true, message: 'Please select the analyzer', trigger: 'blur'
+ }
+ ],
+ location: [
+ {
+ required: true, message: 'Please select the location', trigger: 'blur'
+ }
+ ],
+ tags: [
+ {
+ required: true, message: 'Please select the tags', trigger: 'blur'
+ }
+ ],
+ type: [
+ {
+ required: true, message: 'Please select the type', trigger: 'blur'
+ }
+ ]
+}
+const typeList = [
+ {
+ label: "TYPE_UNSPECIFIED",
+ value: "TYPE_UNSPECIFIED"
+ },
+ {
+ label: "TYPE_TREE",
+ value: "TYPE_TREE"
+ },
+ {
+ label: "TYPE_INVERTED",
+ value: "TYPE_INVERTED"
+ }
+]
+const locationList = [
+ {
+ label: "LOCATION_UNSPECIFIED",
+ value: "LOCATION_UNSPECIFIED"
+ },
+ {
+ label: "LOCATION_SERIES",
+ value: "LOCATION_SERIES"
+ },
+ {
+ label: "LOCATION_GLOBAL",
+ value: "LOCATION_GLOBAL"
+ }
+]
+const analyzerList = [
+ {
+ label: "ANALYZER_UNSPECIFIED",
+ value: "ANALYZER_UNSPECIFIED"
+ },
+ {
+ label: "ANALYZER_KEYWORD",
+ value: "ANALYZER_KEYWORD"
+ },
+ {
+ label: "ANALYZER_STANDARD",
+ value: "ANALYZER_STANDARD"
+ },
+ {
+ label: "ANALYZER_SIMPLE",
+ value: "ANALYZER_SIMPLE"
+ }
+]
+const data = reactive({
+ group: route.params.group,
+ name: route.params.name,
+ type: route.params.type,
+ operator: route.params.operator,
+ form: {
+ group: route.params.group,
+ name: route.params.name || '',
+ analyzer: '',
+ location: '',
+ tags: [],
+ type: ''
+ }
+})
+
+
+watch(() => route, () => {
+ data.form = {
+ group: route.params.group,
+ name: route.params.name || '',
+ analyzer: '',
+ location: '',
+ tags: [],
+ type: ''
+ }
+ data.group = route.params.group
+ data.name = route.params.name
+ data.type = route.params.type
+ data.operator = route.params.operator
+ initData()
+}, {
+ immediate: true,
+ deep: true
+})
+const submit = async (formEl: FormInstance | undefined) => {
+ if (!formEl) return
+ await formEl.validate((valid) => {
+ if (valid) {
+ const param = {
+ indexRule: {
+ metadata: {
+ group: data.form.group,
+ name: data.form.name
+ },
+ tags: data.form.tags,
+ type: data.form.type,
+ location: data.form.location,
+ analyzer: data.form.analyzer
+ }
+ }
+ $loadingCreate()
+ if (data.operator == 'create') {
+ return createIndexRuleOrIndexRuleBinding("index-rule", param)
+ .then(res => {
+ if (res.status == 200) {
+ ElMessage({
+ message: 'Create successed',
+ type: "success",
+ duration: 5000
+ })
+ $bus.emit('refreshAside')
+ $bus.emit('deleteGroup', data.form.group)
+ openIndexRule()
+ }
+ })
+ .catch(err => {
+ ElMessage({
+ message: 'Please refresh and try again. Error: ' + err,
+ type: "error",
+ duration: 3000
+ })
+ })
+ .finally(() => {
+ $loadingClose()
+ })
+ } else {
+ return updatendexRuleOrIndexRuleBinding("index-rule", data.form.group,
data.form.name, param)
+ .then(res => {
+ if (res.status == 200) {
+ ElMessage({
+ message: 'Edit successed',
+ type: "success",
+ duration: 5000
+ })
+ $bus.emit('refreshAside')
+ $bus.emit('deleteResource', data.form.group)
+ openIndexRule()
+ }
+ })
+ .catch(err => {
+ ElMessage({
+ message: 'Please refresh and try again. Error: ' + err,
+ type: "error",
+ duration: 3000
+ })
+ })
+ .finally(() => {
+ $loadingClose()
+ })
+ }
+ }
+ })
+}
+
+function openIndexRule() {
+ const route = {
+ name: data.type + '',
+ params: {
+ group: data.form.group,
+ name: data.form.name,
+ operator: 'read',
+ type: data.type + ''
+ }
+ }
+ router.push(route)
+ const add = {
+ label: data.form.name,
+ type: `Read-${data.type}`,
+ route
+ }
+ $bus.emit('changeAside', data.form)
+ $bus.emit('AddTabs', add)
+}
+
+function initData() {
+ if (data.operator == 'edit' && data.form.group && data.form.name) {
+ $loadingCreate()
+ getIndexRuleOrIndexRuleBinding("index-rule", data.form.group,
data.form.name)
+ .then(res => {
+ if (res.status == 200) {
+ const indexRule = res.data.indexRule
+ data.form = {
+ group: indexRule.metadata.group,
+ name: indexRule.metadata.name,
+ analyzer: indexRule.analyzer,
+ location: indexRule.location,
+ tags: indexRule.tags,
+ type: indexRule.type
+ }
+ }
+ })
+ .catch(err => {
+ ElMessage({
+ message: 'Please refresh and try again. Error: ' + err,
+ type: "error",
+ duration: 3000
+ })
+ })
+ .finally(() => {
+ $loadingClose()
+ })
+ }
+}
+</script>
+
+<template>
+ <div>
+ <el-card>
+ <template #header>
+ <el-row>
+ <el-col :span="12">
+ <div class="flex align-item-center" style="height: 30px; width:
100%;">
+ <div class="flex" style="height: 30px;">
+ <span class="text-bold">Group:</span>
+ <span style="margin-right: 20px;">{{ data.group }}</span>
+ <span class="text-bold" v-if="data.operator ==
'edit'">Name:</span>
+ <span style="margin-right: 20px;">{{ data.name }}</span>
+ <span class="text-bold">Type:</span>
+ <span style="margin-right: 20px;">{{ data.type }}</span>
+ <span class="text-bold">Operation:</span>
+ <span>{{ data.operator }}</span>
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="12">
+ <div class="flex align-item-center justify-end" style="height:
30px;">
+ <el-button size="small" type="primary"
@click="submit(ruleFormRef)" color="#6E38F7">submit</el-button>
+ </div>
+ </el-col>
+ </el-row>
+ </template>
+ <el-form ref="ruleFormRef" :rules="rules" label-position="left"
label-width="100px" :model="data.form"
+ style="width: 50%;">
+ <el-form-item label="Group" prop="group">
+ <el-input v-model="data.form.group" clearable
:disabled="true"></el-input>
+ </el-form-item>
+ <el-form-item label="Name" prop="name">
+ <el-input v-model="data.form.name" :disabled="data.operator ==
'edit'" clearable
+ placeholder="Input Name"></el-input>
+ </el-form-item>
+ <el-form-item label="Analyzer" prop="analyzer">
+ <el-select v-model="data.form.analyzer" placeholder="Choose
Analyzer" style="width: 100%;" clearable>
+ <el-option v-for="item in analyzerList" :key="item.value"
:label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="Location" prop="location">
+ <el-select v-model="data.form.location" placeholder="Choose
Location" style="width: 100%;" clearable>
+ <el-option v-for="item in locationList" :key="item.value"
:label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="Tags" prop="tags">
+ <el-select v-model="data.form.tags" allow-create filterable
default-first-option placeholder="Input Tags"
+ style="width: 100%;" clearable multiple></el-select>
+ </el-form-item>
+ <el-form-item label="Type" prop="type">
+ <el-select v-model="data.form.type" placeholder="Choose Type"
style="width: 100%;" clearable>
+ <el-option v-for="item in typeList" :key="item.value"
:label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ </el-card>
+ </div>
+</template>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-card {
+ margin: 15px;
+ }
+}
+</style>
\ No newline at end of file
diff --git a/ui/src/components/IndexRule/index.vue
b/ui/src/components/IndexRule/index.vue
new file mode 100644
index 00000000..c9531e39
--- /dev/null
+++ b/ui/src/components/IndexRule/index.vue
@@ -0,0 +1,109 @@
+<!--
+ ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
+ ~ license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright
+ ~ ownership. Apache Software Foundation (ASF) 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.
+-->
+
+<script setup>
+import { reactive } from 'vue';
+import { watch, getCurrentInstance } from '@vue/runtime-core'
+import { useRoute } from 'vue-router'
+import { getIndexRuleOrIndexRuleBinding } from '@/api/index'
+
+const { proxy } = getCurrentInstance()
+const $loadingCreate =
getCurrentInstance().appContext.config.globalProperties.$loadingCreate
+const $loadingClose = proxy.$loadingClose
+
+const data = reactive({
+ group: '',
+ name: '',
+ type: '',
+ operator: '',
+ indexRule: {}
+})
+
+const route = useRoute()
+
+watch(() => route, () => {
+ data.group = route.params.group
+ data.name = route.params.name
+ data.type = route.params.type
+ data.operator = route.params.operator
+ initData()
+}, {
+ immediate: true,
+ deep: true
+})
+
+function initData() {
+ $loadingCreate()
+ getIndexRuleOrIndexRuleBinding(data.type, data.group, data.name)
+ .then(result => {
+ data.indexRule = result.data.indexRule
+ })
+ .catch(err => {
+ ElMessage({
+ message: 'Please refresh and try again. Error: ' + err,
+ type: "error",
+ duration: 3000
+ })
+ })
+ .finally(() => {
+ $loadingClose()
+ })
+}
+</script>
+
+<template>
+ <div>
+ <el-card>
+ <template #header>
+ <div class="flex">
+ <span class="text-bold">Group:</span>
+ <span style="margin-right: 20px;">{{ data.group }}</span>
+ <span class="text-bold">Name:</span>
+ <span style="margin-right: 20px;">{{ data.name }}</span>
+ <span class="text-bold">Type:</span>
+ <span style="margin-right: 20px;">{{ data.type }}</span>
+ <span class="text-bold">Operation:</span>
+ <span>Read</span>
+ </div>
+ </template>
+ <el-form label-position="left" label-width="100px"
:model="data.indexRule" style="width: 50%;">
+ <el-form-item label="Analyzer">
+ <el-input v-model="data.indexRule.analyzer"
:disabled="true"></el-input>
+ </el-form-item>
+ <el-form-item label="Location">
+ <el-input v-model="data.indexRule.location"
:disabled="true"></el-input>
+ </el-form-item>
+ <el-form-item label="Tags">
+ <el-select v-model="data.indexRule.tags" style="width: 100%;"
:disabled="true" multiple></el-select>
+ </el-form-item>
+ <el-form-item label="Type">
+ <el-input v-model="data.indexRule.type" :disabled="true"></el-input>
+ </el-form-item>
+ </el-form>
+ </el-card>
+ </div>
+</template>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-card {
+ margin: 15px;
+ }
+}
+</style>
\ No newline at end of file
diff --git a/ui/src/components/IndexRuleBinding/Editor.vue
b/ui/src/components/IndexRuleBinding/Editor.vue
new file mode 100644
index 00000000..68570dad
--- /dev/null
+++ b/ui/src/components/IndexRuleBinding/Editor.vue
@@ -0,0 +1,26 @@
+<!--
+ ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
+ ~ license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright
+ ~ ownership. Apache Software Foundation (ASF) 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.
+-->
+
+<script setup></script>
+
+<template>
+ 123456Editor
+</template>
+
+<style></style>
\ No newline at end of file
diff --git a/ui/src/components/IndexRuleBinding/index.vue
b/ui/src/components/IndexRuleBinding/index.vue
new file mode 100644
index 00000000..f8d4369c
--- /dev/null
+++ b/ui/src/components/IndexRuleBinding/index.vue
@@ -0,0 +1,26 @@
+<!--
+ ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
+ ~ license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright
+ ~ ownership. Apache Software Foundation (ASF) 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.
+-->
+
+<script setup></script>
+
+<template>
+ 123456
+</template>
+
+<style></style>
\ No newline at end of file
diff --git a/ui/src/components/Read/index.vue b/ui/src/components/Read/index.vue
index 53c34519..945ffc9d 100644
--- a/ui/src/components/Read/index.vue
+++ b/ui/src/components/Read/index.vue
@@ -115,7 +115,7 @@ const data = reactive({
tableFields: [],
handleFields: "",
group: route.params.group,
- name: route.params.group,
+ name: route.params.name,
type: route.params.type,
tagFamily: 0,
tagFamilies: [],
diff --git a/ui/src/components/TopNav/index.vue
b/ui/src/components/TopNav/index.vue
index 1feb4b83..c91801b7 100644
--- a/ui/src/components/TopNav/index.vue
+++ b/ui/src/components/TopNav/index.vue
@@ -21,7 +21,6 @@
import { reactive } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { getCurrentInstance } from '@vue/runtime-core'
-import { ElStep } from 'element-plus';
const router = useRouter()
const route = useRoute()
@@ -69,15 +68,15 @@ function initData() {
if (operator == 'read') {
routeData.name = type
add.label = name
- add.type = 'Read'
+ add.type = type == 'index-rule' || type == 'index-rule' ?
`Read-${type}` : 'Read'
} else if (operator == 'edit') {
routeData.name = `edit-${type}`
add.label = name
- add.type = 'Edit'
+ add.type = type == 'index-rule' || type == 'index-rule' ?
`Edit-${type}` : 'Edit'
} else {
routeData.name = `create-${type}`
add.label = group
- add.type = 'Create'
+ add.type = type == 'index-rule' || type == 'index-rule' ?
`Create-${type}` : 'Create'
}
data.tabsList.push(add)
}
diff --git a/ui/src/router/index.js b/ui/src/router/index.js
index 3ab1a2a6..e19f41cd 100644
--- a/ui/src/router/index.js
+++ b/ui/src/router/index.js
@@ -70,6 +70,36 @@ const router = createRouter({
path:
'/banyandb/stream/operator-edit/:type/:operator/:group/:name',
name: 'edit-stream',
component: () => import('@/views/Stream/createEdit.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule/operator/:type/:operator/:group',
+ name: 'create-index-rule',
+ component: () => import('@/components/IndexRule/Editor.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule/operator/:type/:operator/:group/:name',
+ name: 'edit-index-rule',
+ component: () => import('@/components/IndexRule/Editor.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule/operator/:type/:operator/:group/:name',
+ name: 'index-rule',
+ component: () => import('@/components/IndexRule/index.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule-binding/operator/:type/:operator/:group',
+ name: 'create-index-rule-binding',
+ component: () =>
import('@/components/IndexRuleBinding/Editor.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule-binding/operator/:type/:operator/:group/:name',
+ name: 'edit-index-rule-binding',
+ component: () =>
import('@/components/IndexRuleBinding/Editor.vue')
+ },
+ {
+ path:
'/banyandb/stream/index-rule-binding/operator/:type/:operator/:group/:name',
+ name: 'index-rule-binding',
+ component: () =>
import('@/components/IndexRuleBinding/index.vue')
}
]
},