This is an automated email from the ASF dual-hosted git repository.
wusheng 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 e9811f0c refactor(UI): Optimize router for better usability (#834)
e9811f0c is described below
commit e9811f0cfbca8dad30eddddf467c6bac54068978
Author: Fine0830 <[email protected]>
AuthorDate: Tue Nov 4 16:51:07 2025 +0800
refactor(UI): Optimize router for better usability (#834)
---
CHANGES.md | 1 +
ui/src/components/GroupTree/index.vue | 2 -
ui/src/router/constants.js | 47 ++++++
ui/src/router/index.js | 283 ++++------------------------------
ui/src/router/modules/dashboard.js | 27 ++++
ui/src/router/modules/measure.js | 58 +++++++
ui/src/router/modules/property.js | 50 ++++++
ui/src/router/modules/query.js | 27 ++++
ui/src/router/modules/stream.js | 52 +++++++
ui/src/router/modules/trace.js | 52 +++++++
ui/src/router/routeFactory.js | 113 ++++++++++++++
ui/src/views/Measure/index.vue | 3 +-
ui/src/views/Property/index.vue | 3 +-
ui/src/views/Stream/index.vue | 3 +-
ui/src/views/Trace/index.vue | 3 +-
ui/src/views/constants.js | 21 +++
16 files changed, 489 insertions(+), 256 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 0b0e8b89..12224018 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -53,6 +53,7 @@ Release Notes.
- Implement Trace Tree for debug mode.
- Implement bydbQL.
- UI: Implement the Query Page for BydbQL.
+- Refactor router for better usability.
- Implement the handoff queue for Trace.
### Bug Fixes
diff --git a/ui/src/components/GroupTree/index.vue
b/ui/src/components/GroupTree/index.vue
index f1bdb9ba..54dcc261 100644
--- a/ui/src/components/GroupTree/index.vue
+++ b/ui/src/components/GroupTree/index.vue
@@ -361,7 +361,6 @@
operator: 'create',
group: currentNode.value.group,
type,
- schema: props.type,
},
};
router.push(route);
@@ -382,7 +381,6 @@
group: currentNode.value.group,
name: currentNode.value.name,
type,
- schema: props.type,
},
};
router.push(route);
diff --git a/ui/src/router/constants.js b/ui/src/router/constants.js
new file mode 100644
index 00000000..d4433cd4
--- /dev/null
+++ b/ui/src/router/constants.js
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/** Base path for all BanyanDB routes */
+export const BASE_PATH = '/banyandb';
+
+/** Route parameter patterns for CRUD operations */
+export const ROUTE_PARAMS = {
+ OPERATOR_READ: ':type/:operator/:group/:name',
+ OPERATOR_CREATE: ':type/:operator/:group',
+ OPERATOR_EDIT: ':type/:operator/:group/:name',
+};
+
+/** Schema type identifiers */
+export const SCHEMA_TYPES = {
+ STREAM: 'stream',
+ MEASURE: 'measure',
+ PROPERTY: 'property',
+ TRACE: 'trace',
+};
+
+/** Component paths for dynamic imports (reference only) */
+export const COMPONENTS = {
+ START: '@/components/Start/index.vue',
+ INDEX_RULE: '@/components/IndexRule/index.vue',
+ INDEX_RULE_EDITOR: '@/components/IndexRule/Editor.vue',
+ INDEX_RULE_BINDING: '@/components/IndexRuleBinding/index.vue',
+ INDEX_RULE_BINDING_EDITOR: '@/components/IndexRuleBinding/Editor.vue',
+ TOPN_AGG: '@/components/TopNAggregation/index.vue',
+ TOPN_AGG_EDITOR: '@/components/TopNAggregation/Editor.vue',
+};
diff --git a/ui/src/router/index.js b/ui/src/router/index.js
index 2cf7c368..08542e4e 100644
--- a/ui/src/router/index.js
+++ b/ui/src/router/index.js
@@ -20,272 +20,55 @@
import { createRouter, createWebHistory } from 'vue-router';
import Header from '@/components/Header/index.vue';
import { MENU_DEFAULT_PATH } from '@/components/Header/components/constants';
+import { BASE_PATH } from './constants';
+// Import route modules
+import dashboardRoute from './modules/dashboard';
+import streamRoutes from './modules/stream';
+import measureRoutes from './modules/measure';
+import propertyRoutes from './modules/property';
+import traceRoutes from './modules/trace';
+import queryRoute from './modules/query';
+
+/**
+ * Router configuration for BanyanDB UI
+ *
+ * Route structure:
+ * - / : Redirects to /banyandb
+ * - /banyandb : Main application layout with header
+ * - /dashboard : Dashboard view
+ * - /stream : Stream schema management
+ * - /measure : Measure schema management
+ * - /property : Property management
+ * - /trace : Trace schema management
+ * - /query : BydbQL query interface
+ * - /* : 404 error page
+ * Structure: /banyandb/{module}/{operation}
+ * Modules: dashboard, stream, measure, property, trace, query
+ */
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
+ // Root redirect
{
path: '/',
- redirect: '/banyandb',
+ redirect: BASE_PATH,
},
+ // Main application routes
{
- path: '/banyandb',
+ path: BASE_PATH,
component: Header,
name: 'banyandb',
redirect: MENU_DEFAULT_PATH,
- meta: {
- keepAlive: false,
- },
- children: [
- {
- path: '/banyandb/dashboard',
- name: 'dashboard',
- component: () => import('@/views/Dashboard/index.vue'),
- },
- {
- path: '/banyandb/stream',
- name: 'streamHome',
- redirect: '/banyandb/stream/start',
- component: () => import('@/views/Stream/index.vue'),
- children: [
- {
- path: '/banyandb/stream/start',
- name: 'streamStart',
- component: () => import('@/components/Start/index.vue'),
- meta: {
- type: 'stream',
- },
- },
- {
- path:
'/banyandb/stream/operator-read/:type/:operator/:group/:name',
- name: 'stream',
- component: () => import('@/views/Stream/stream.vue'),
- },
- {
- path: '/banyandb/stream/operator-create/:type/:operator/:group',
- name: 'create-stream',
- component: () => import('@/views/Stream/createEdit.vue'),
- },
- {
- path:
'/banyandb/stream/operator-edit/:type/:operator/:group/:name',
- name: 'edit-stream',
- component: () => import('@/views/Stream/createEdit.vue'),
- },
- {
- path:
'/banyandb/stream/index-rule/operator-read/:type/:operator/:group/:name',
- name: 'stream-index-rule',
- component: () => import('@/components/IndexRule/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-create/:type/:operator/:group',
- name: 'stream-create-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-edit/:type/:operator/:group/:name',
- name: 'stream-edit-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/stream/index-rule-binding/operator-read/:type/:operator/:group/:name',
- name: 'stream-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-create/:type/:operator/:group',
- name: 'stream-create-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-edit/:type/:operator/:group/:name',
- name: 'stream-edit-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- ],
- },
- {
- path: '/banyandb/measure',
- name: 'measureHome',
- redirect: '/banyandb/measure/start',
- component: () => import('@/views/Measure/index.vue'),
- children: [
- {
- path: '/banyandb/measure/start',
- name: 'measureStart',
- component: () => import('@/components/Start/index.vue'),
- meta: {
- type: 'measure',
- },
- },
- {
- path:
'/banyandb/measure/operator-read/:type/:operator/:group/:name',
- name: 'measure',
- component: () => import('@/views/Measure/measure.vue'),
- },
- {
- path: '/banyandb/measure/operator-create/:type/:operator/:group',
- name: 'create-measure',
- component: () => import('@/views/Measure/createEdit.vue'),
- },
- {
- path:
'/banyandb/measure/operator-edit/:type/:operator/:group/:name',
- name: 'edit-measure',
- component: () => import('@/views/Stream/createEdit.vue'),
- },
- {
- path:
'/banyandb/measure/index-rule/operator-read/:type/:operator/:group/:name',
- name: 'measure-index-rule',
- component: () => import('@/components/IndexRule/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-create/:type/:operator/:group',
- name: 'measure-create-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-edit/:type/:operator/:group/:name',
- name: 'measure-edit-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/measure/index-rule-binding/operator-read/:type/:operator/:group/:name',
- name: 'measure-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-create/:type/:operator/:group',
- name: 'measure-create-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-edit/:type/:operator/:group/:name',
- name: 'measure-edit-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- {
- path:
'/banyandb/measure/topn-agg/operator-read/:type/:operator/:group/:name',
- name: 'measure-topn-agg',
- component: () =>
import('@/components/TopNAggregation/index.vue'),
- },
- {
- path:
'/banyandb/:schema/topn-agg/operator-create/:type/:operator/:group',
- name: 'measure-create-topn-agg',
- component: () =>
import('@/components/TopNAggregation/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/topn-agg/operator-edit/:type/:operator/:group/:name',
- name: 'measure-edit-topn-agg',
- component: () =>
import('@/components/TopNAggregation/Editor.vue'),
- },
- ],
- },
- {
- path: '/banyandb/property',
- name: 'Property',
- redirect: '/banyandb/property/start',
- component: () => import('@/views/Property/index.vue'),
- children: [
- {
- path: '/banyandb/property/start',
- name: 'propertyStart',
- component: () => import('@/components/Start/index.vue'),
- meta: {
- type: 'property',
- },
- },
- {
- path:
'/banyandb/property/operator-read/:type/:operator/:group/:name',
- name: 'property',
- component: () =>
import('@/components/Property/PropertyRead.vue'),
- },
- {
- path:
'/banyandb/property/operator-edit/:type/:operator/:group/:name',
- name: 'edit-property',
- component: () => import('@/views/Property/createEdit.vue'),
- },
- {
- path:
'/banyandb/property/operator-create/:type/:operator/:group',
- name: 'create-property',
- component: () => import('@/views/Property/createEdit.vue'),
- },
- ],
- },
- {
- path: '/banyandb/trace',
- name: 'traceHome',
- redirect: '/banyandb/trace/start',
- component: () => import('@/views/Trace/index.vue'),
- children: [
- {
- path: '/banyandb/trace/start',
- name: 'traceStart',
- component: () => import('@/components/Start/index.vue'),
- meta: {
- type: 'trace',
- },
- },
- {
- path:
'/banyandb/trace/operator-read/:type/:operator/:group/:name',
- name: 'trace',
- component: () => import('@/components/Trace/TraceRead.vue'),
- },
- {
- path:
'/banyandb/trace/operator-edit/:type/:operator/:group/:name',
- name: 'edit-trace',
- component: () => import('@/views/Trace/createEdit.vue'),
- },
- {
- path: '/banyandb/trace/operator-create/:type/:operator/:group',
- name: 'create-trace',
- component: () => import('@/views/Trace/createEdit.vue'),
- },
- {
- path:
'/banyandb/trace/index-rule/operator-read/:type/:operator/:group/:name',
- name: 'trace-index-rule',
- component: () => import('@/components/IndexRule/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-create/:type/:operator/:group',
- name: 'trace-create-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule/operator-edit/:type/:operator/:group/:name',
- name: 'trace-edit-index-rule',
- component: () => import('@/components/IndexRule/Editor.vue'),
- },
- {
- path:
'/banyandb/trace/index-rule-binding/operator-read/:type/:operator/:group/:name',
- name: 'trace-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/index.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-create/:type/:operator/:group',
- name: 'trace-create-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- {
- path:
'/banyandb/:schema/index-rule-binding/operator-edit/:type/:operator/:group/:name',
- name: 'trace-edit-index-rule-binding',
- component: () =>
import('@/components/IndexRuleBinding/Editor.vue'),
- },
- ],
- },
- {
- path: '/banyandb/query',
- name: 'query',
- component: () => import('@/views/Query/BydbQL.vue'),
- },
- ],
+ meta: { keepAlive: false },
+ children: [dashboardRoute, streamRoutes, measureRoutes, propertyRoutes,
traceRoutes, queryRoute],
},
+ // 404 Not Found
{
- // will match everything
path: '/:pathMatch(.*)',
name: 'NotFound',
component: Header,
- meta: {
- keepAlive: false,
- },
+ meta: { keepAlive: false },
children: [
{
path: '/:pathMatch(.*)',
diff --git a/ui/src/router/modules/dashboard.js
b/ui/src/router/modules/dashboard.js
new file mode 100644
index 00000000..19748828
--- /dev/null
+++ b/ui/src/router/modules/dashboard.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH } from '../constants';
+
+/** Dashboard route */
+export default {
+ path: `${BASE_PATH}/dashboard`,
+ name: 'dashboard',
+ component: () => import('@/views/Dashboard/index.vue'),
+};
diff --git a/ui/src/router/modules/measure.js b/ui/src/router/modules/measure.js
new file mode 100644
index 00000000..46aa7e39
--- /dev/null
+++ b/ui/src/router/modules/measure.js
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH, SCHEMA_TYPES, ROUTE_PARAMS } from '../constants';
+import {
+ createStartRoute,
+ createIndexRuleRoutes,
+ createIndexRuleBindingRoutes,
+ createTopNAggRoutes,
+} from '../routeFactory';
+
+/**
+ * Measure schema routes
+ * Includes: CRUD, index rules, index rule bindings, TopN aggregations
+ */
+export default {
+ path: `${BASE_PATH}/measure`,
+ name: 'measureHome',
+ redirect: `${BASE_PATH}/measure/start`,
+ component: () => import('@/views/Measure/index.vue'),
+ children: [
+ createStartRoute(SCHEMA_TYPES.MEASURE),
+ {
+ path: ROUTE_PARAMS.OPERATOR_READ,
+ name: SCHEMA_TYPES.MEASURE,
+ component: () => import('@/views/Measure/measure.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_CREATE,
+ name: `create-${SCHEMA_TYPES.MEASURE}`,
+ component: () => import('@/views/Measure/createEdit.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_EDIT,
+ name: `edit-${SCHEMA_TYPES.MEASURE}`,
+ component: () => import('@/views/Measure/createEdit.vue'),
+ },
+ ...createIndexRuleRoutes(SCHEMA_TYPES.MEASURE),
+ ...createIndexRuleBindingRoutes(SCHEMA_TYPES.MEASURE),
+ ...createTopNAggRoutes(SCHEMA_TYPES.MEASURE),
+ ],
+};
diff --git a/ui/src/router/modules/property.js
b/ui/src/router/modules/property.js
new file mode 100644
index 00000000..335b9bfc
--- /dev/null
+++ b/ui/src/router/modules/property.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH, SCHEMA_TYPES, ROUTE_PARAMS } from '../constants';
+import { createStartRoute } from '../routeFactory';
+
+/**
+ * Property routes
+ * Includes: CRUD only
+ */
+export default {
+ path: `${BASE_PATH}/property`,
+ name: 'Property',
+ redirect: `${BASE_PATH}/property/start`,
+ component: () => import('@/views/Property/index.vue'),
+ children: [
+ createStartRoute(SCHEMA_TYPES.PROPERTY),
+ {
+ path: ROUTE_PARAMS.OPERATOR_READ,
+ name: SCHEMA_TYPES.PROPERTY,
+ component: () => import('@/components/Property/PropertyRead.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_CREATE,
+ name: `create-${SCHEMA_TYPES.PROPERTY}`,
+ component: () => import('@/views/Property/createEdit.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_EDIT,
+ name: `edit-${SCHEMA_TYPES.PROPERTY}`,
+ component: () => import('@/views/Property/createEdit.vue'),
+ },
+ ],
+};
diff --git a/ui/src/router/modules/query.js b/ui/src/router/modules/query.js
new file mode 100644
index 00000000..11bcf646
--- /dev/null
+++ b/ui/src/router/modules/query.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH } from '../constants';
+
+/** BydbQL query interface route */
+export default {
+ path: `${BASE_PATH}/query`,
+ name: 'BydbQL',
+ component: () => import('@/views/Query/BydbQL.vue'),
+};
diff --git a/ui/src/router/modules/stream.js b/ui/src/router/modules/stream.js
new file mode 100644
index 00000000..3cf12525
--- /dev/null
+++ b/ui/src/router/modules/stream.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH, SCHEMA_TYPES, ROUTE_PARAMS } from '../constants';
+import { createStartRoute, createIndexRuleRoutes, createIndexRuleBindingRoutes
} from '../routeFactory';
+
+/**
+ * Stream schema routes
+ * Includes: CRUD, index rules, index rule bindings
+ */
+export default {
+ path: `${BASE_PATH}/stream`,
+ name: 'streamHome',
+ redirect: `${BASE_PATH}/stream/start`,
+ component: () => import('@/views/Stream/index.vue'),
+ children: [
+ createStartRoute(SCHEMA_TYPES.STREAM),
+ {
+ path: ROUTE_PARAMS.OPERATOR_READ,
+ name: SCHEMA_TYPES.STREAM,
+ component: () => import('@/views/Stream/stream.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_CREATE,
+ name: `create-${SCHEMA_TYPES.STREAM}`,
+ component: () => import('@/views/Stream/createEdit.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_EDIT,
+ name: `edit-${SCHEMA_TYPES.STREAM}`,
+ component: () => import('@/views/Stream/createEdit.vue'),
+ },
+ ...createIndexRuleRoutes(SCHEMA_TYPES.STREAM),
+ ...createIndexRuleBindingRoutes(SCHEMA_TYPES.STREAM),
+ ],
+};
diff --git a/ui/src/router/modules/trace.js b/ui/src/router/modules/trace.js
new file mode 100644
index 00000000..102b26db
--- /dev/null
+++ b/ui/src/router/modules/trace.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+import { BASE_PATH, SCHEMA_TYPES, ROUTE_PARAMS } from '../constants';
+import { createStartRoute, createIndexRuleRoutes, createIndexRuleBindingRoutes
} from '../routeFactory';
+
+/**
+ * Trace schema routes
+ * Includes: CRUD, index rules, index rule bindings
+ */
+export default {
+ path: `${BASE_PATH}/trace`,
+ name: 'traceHome',
+ redirect: `${BASE_PATH}/trace/start`,
+ component: () => import('@/views/Trace/index.vue'),
+ children: [
+ createStartRoute(SCHEMA_TYPES.TRACE),
+ {
+ path: ROUTE_PARAMS.OPERATOR_READ,
+ name: SCHEMA_TYPES.TRACE,
+ component: () => import('@/components/Trace/TraceRead.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_CREATE,
+ name: `create-${SCHEMA_TYPES.TRACE}`,
+ component: () => import('@/views/Trace/createEdit.vue'),
+ },
+ {
+ path: ROUTE_PARAMS.OPERATOR_EDIT,
+ name: `edit-${SCHEMA_TYPES.TRACE}`,
+ component: () => import('@/views/Trace/createEdit.vue'),
+ },
+ ...createIndexRuleRoutes(SCHEMA_TYPES.TRACE),
+ ...createIndexRuleBindingRoutes(SCHEMA_TYPES.TRACE),
+ ],
+};
diff --git a/ui/src/router/routeFactory.js b/ui/src/router/routeFactory.js
new file mode 100644
index 00000000..649166d5
--- /dev/null
+++ b/ui/src/router/routeFactory.js
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+import { ROUTE_PARAMS } from './constants';
+
+/**
+ * Route Factory Functions
+ *
+ * Generate route configurations with consistent patterns.
+ * All routes use relative paths (nested under parent routes in modules).
+ * CRUD routes are defined inline in modules for Vite static import
compatibility.
+ */
+
+/**
+ * Creates start page route
+ * @param {string} schemaType - Schema type (stream, measure, trace, property)
+ */
+export function createStartRoute(schemaType) {
+ return {
+ path: 'start',
+ name: `${schemaType}Start`,
+ component: () => import('@/components/Start/index.vue'),
+ meta: { type: schemaType },
+ };
+}
+
+/**
+ * Creates index rule routes (read, create, edit)
+ * @param {string} schemaType - Schema type
+ */
+export function createIndexRuleRoutes(schemaType) {
+ return [
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_READ}`,
+ name: `${schemaType}-index-rule`,
+ component: () => import('@/components/IndexRule/index.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_CREATE}`,
+ name: `${schemaType}-create-index-rule`,
+ component: () => import('@/components/IndexRule/Editor.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_EDIT}`,
+ name: `${schemaType}-edit-index-rule`,
+ component: () => import('@/components/IndexRule/Editor.vue'),
+ },
+ ];
+}
+
+/**
+ * Creates index rule binding routes (read, create, edit)
+ * @param {string} schemaType - Schema type
+ */
+export function createIndexRuleBindingRoutes(schemaType) {
+ return [
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_READ}`,
+ name: `${schemaType}-index-rule-binding`,
+ component: () => import('@/components/IndexRuleBinding/index.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_CREATE}`,
+ name: `${schemaType}-create-index-rule-binding`,
+ component: () => import('@/components/IndexRuleBinding/Editor.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_EDIT}`,
+ name: `${schemaType}-edit-index-rule-binding`,
+ component: () => import('@/components/IndexRuleBinding/Editor.vue'),
+ },
+ ];
+}
+
+/**
+ * Creates TopN aggregation routes (measure only)
+ * @param {string} schemaType - Schema type (typically 'measure')
+ */
+export function createTopNAggRoutes(schemaType) {
+ return [
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_READ}`,
+ name: `${schemaType}-topn-agg`,
+ component: () => import('@/components/TopNAggregation/index.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_CREATE}`,
+ name: `${schemaType}-create-topn-agg`,
+ component: () => import('@/components/TopNAggregation/Editor.vue'),
+ },
+ {
+ path: `${ROUTE_PARAMS.OPERATOR_EDIT}`,
+ name: `${schemaType}-edit-topn-agg`,
+ component: () => import('@/components/TopNAggregation/Editor.vue'),
+ },
+ ];
+}
diff --git a/ui/src/views/Measure/index.vue b/ui/src/views/Measure/index.vue
index d8ad6a73..740366a5 100644
--- a/ui/src/views/Measure/index.vue
+++ b/ui/src/views/Measure/index.vue
@@ -22,9 +22,10 @@
import TopNav from '@/components/TopNav/index.vue';
import { reactive } from 'vue';
import { CatalogToGroupType } from '@/components/common/data';
+ import { ASIDE_WIDTH } from '../constants';
const data = reactive({
- width: '200px',
+ width: `${ASIDE_WIDTH}px`,
});
function setWidth(width) {
diff --git a/ui/src/views/Property/index.vue b/ui/src/views/Property/index.vue
index 21ce8902..e0db3e20 100644
--- a/ui/src/views/Property/index.vue
+++ b/ui/src/views/Property/index.vue
@@ -22,9 +22,10 @@
import GroupTree from '@/components/GroupTree/index.vue';
import TopNav from '@/components/TopNav/index.vue';
import { CatalogToGroupType } from '@/components/common/data';
+ import { ASIDE_WIDTH } from '../constants';
const data = reactive({
- width: '200px',
+ width: `${ASIDE_WIDTH}px`,
});
function setWidth(width) {
diff --git a/ui/src/views/Stream/index.vue b/ui/src/views/Stream/index.vue
index 724305fa..b50351ac 100644
--- a/ui/src/views/Stream/index.vue
+++ b/ui/src/views/Stream/index.vue
@@ -22,9 +22,10 @@
import GroupTree from '@/components/GroupTree/index.vue';
import TopNav from '@/components/TopNav/index.vue';
import { CatalogToGroupType } from '@/components/common/data';
+ import { ASIDE_WIDTH } from '../constants';
const data = reactive({
- width: '200px',
+ width: `${ASIDE_WIDTH}px`,
});
function setWidth(width) {
diff --git a/ui/src/views/Trace/index.vue b/ui/src/views/Trace/index.vue
index 2148334b..c5a117cb 100644
--- a/ui/src/views/Trace/index.vue
+++ b/ui/src/views/Trace/index.vue
@@ -22,9 +22,10 @@
import GroupTree from '@/components/GroupTree/index.vue';
import TopNav from '@/components/TopNav/index.vue';
import { CatalogToGroupType } from '@/components/common/data';
+ import { ASIDE_WIDTH } from '../constants';
const data = reactive({
- width: '200px',
+ width: `${ASIDE_WIDTH}px`,
});
function setWidth(width) {
diff --git a/ui/src/views/constants.js b/ui/src/views/constants.js
new file mode 100644
index 00000000..e06a0778
--- /dev/null
+++ b/ui/src/views/constants.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/** Width of the aside menu */
+export const ASIDE_WIDTH = 280;