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) {
