This is an automated email from the ASF dual-hosted git repository.

imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph-toolchain.git

commit 3860d161661e9a9dfab0bc116d894a33e9b4e106
Author: dark <[email protected]>
AuthorDate: Fri Aug 14 12:39:02 2026 +0800

    fix(operations): preserve navigation context
---
 .../hubble-fe/src/pages/Operations/navigation.js   | 32 ++++++++++++++
 .../hubble-fe/src/pages/Operations/topology.js     |  9 ++++
 .../hubble-fe/src/pages/Schema/EditLayer.js        | 51 +++++++++++++++++-----
 3 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/hugegraph-hubble/hubble-fe/src/pages/Operations/navigation.js 
b/hugegraph-hubble/hubble-fe/src/pages/Operations/navigation.js
new file mode 100644
index 000000000..30570e008
--- /dev/null
+++ b/hugegraph-hubble/hubble-fe/src/pages/Operations/navigation.js
@@ -0,0 +1,32 @@
+/*
+ *
+ * Licensed to the 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. The 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.
+ */
+
+const DEFAULT_NODE_RETURN_TO = '/operations/nodes';
+const SAFE_RETURN_TO = /^\/operations\/(?:overview|nodes)(?:\?[^#]*)?$/;
+
+const operationsReturnState = location => ({
+    operationsReturnTo: `${location.pathname}${location.search}`,
+});
+
+const operationsReturnTo = location => {
+    const target = location.state?.operationsReturnTo;
+    return typeof target === 'string' && SAFE_RETURN_TO.test(target)
+        ? target : DEFAULT_NODE_RETURN_TO;
+};
+
+export {DEFAULT_NODE_RETURN_TO, operationsReturnState, operationsReturnTo};
diff --git a/hugegraph-hubble/hubble-fe/src/pages/Operations/topology.js 
b/hugegraph-hubble/hubble-fe/src/pages/Operations/topology.js
index 19077e7b3..d89fe5ed1 100644
--- a/hugegraph-hubble/hubble-fe/src/pages/Operations/topology.js
+++ b/hugegraph-hubble/hubble-fe/src/pages/Operations/topology.js
@@ -27,6 +27,14 @@ const hasStaleMetrics = node => 
Object.values(node?.metric_statuses ?? {})
     .some(status => status?.stale || status?.availability === 'UNAVAILABLE'
         || status?.availability === 'MALFORMED');
 
+const storeLeaderCount = node => {
+    if (node?.type !== 'STORE') {
+        return null;
+    }
+    const value = Number(node?.metrics?.backend?.leaders);
+    return Number.isFinite(value) && value >= 0 ? value : null;
+};
+
 const selectAttentionNodes = (nodes = [], limit = 5) => {
     if (!Array.isArray(nodes)) {
         return [];
@@ -114,4 +122,5 @@ export {
     formatMetricValue,
     formatObservedAge,
     formatObservedAt,
+    storeLeaderCount,
 };
diff --git a/hugegraph-hubble/hubble-fe/src/pages/Schema/EditLayer.js 
b/hugegraph-hubble/hubble-fe/src/pages/Schema/EditLayer.js
index 58b0c0da8..8439cba74 100644
--- a/hugegraph-hubble/hubble-fe/src/pages/Schema/EditLayer.js
+++ b/hugegraph-hubble/hubble-fe/src/pages/Schema/EditLayer.js
@@ -49,7 +49,27 @@ export const schemaTemplateBusinessError = (res, t, action, 
name) => {
     return t(`schema_template.${action}_failed`);
 };
 
-const EditLayer = ({visible, onCancel, graphspace, refresh, mode, detail}) => {
+export const validateSchemaTemplateFields = async form => {
+    try {
+        return await form.validateFields();
+    }
+    catch (error) {
+        if (Array.isArray(error?.errorFields)) {
+            return null;
+        }
+        throw error;
+    }
+};
+
+const EditLayer = ({
+    visible,
+    onCancel,
+    graphspace,
+    refresh,
+    mode,
+    detail,
+    validateForm = validateSchemaTemplateFields,
+}) => {
     const {t} = useTranslation();
     const [form] = Form.useForm();
     const [loading, setLoading] = useState(false);
@@ -100,17 +120,26 @@ const EditLayer = ({visible, onCancel, graphspace, 
refresh, mode, detail}) => {
         });
     }, [graphspace, onCancel, refresh, t]);
 
-    const onFinish = useCallback(() => {
-        form.validateFields().then(values => {
-            setLoading(true);
-            if (mode === 'create') {
-                addSchema(values);
-                return;
-            }
+    const onFinish = useCallback(async () => {
+        let values;
+        try {
+            values = await validateForm(form);
+        }
+        catch {
+            message.error(t('common.msg.operation_failed'));
+            return;
+        }
+        if (!values) {
+            return;
+        }
+        setLoading(true);
+        if (mode === 'create') {
+            addSchema(values);
+            return;
+        }
 
-            updateSchema(detailName, values);
-        });
-    }, [addSchema, detailName, form, mode, updateSchema]);
+        updateSchema(detailName, values);
+    }, [addSchema, detailName, form, mode, t, updateSchema, validateForm]);
 
     useEffect(() => {
         if (!visible) {

Reply via email to