diff --git a/hugegraph-dist/release-docs/LICENSE b/hugegraph-dist/release-docs/LICENSE index 7543d0822..6b0c88c01 100644 --- a/hugegraph-dist/release-docs/LICENSE +++ b/hugegraph-dist/release-docs/LICENSE @@ -484,6 +484,7 @@ See licenses/ for text of these licenses. hugegraph-hubble/ui/favicon.ico (Apache License, Version 2.0) * kotlin-stdlib (org.jetbrains.kotlin:kotlin-stdlib:1.6.20 - https://github.com/JetBrains/kotlin) (Apache License, Version 2.0) * kotlin-stdlib-common (org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31 - https://github.com/JetBrains/kotlin) + (Apache License, Version 2.0) * kotlin-stdlib-common (org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20 - https://github.com/JetBrains/kotlin) (Apache License, Version 2.0) * kotlin-stdlib-jdk7 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71 - https://github.com/JetBrains/kotlin) (Apache License, Version 2.0) * kotlin-stdlib-jdk7 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10 - https://github.com/JetBrains/kotlin) (Apache License, Version 2.0) * kotlin-stdlib-jdk8 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71 - https://github.com/JetBrains/kotlin) diff --git a/hugegraph-dist/scripts/dependency/known-dependencies.txt b/hugegraph-dist/scripts/dependency/known-dependencies.txt index ba38b94c2..b9a88cddf 100644 --- a/hugegraph-dist/scripts/dependency/known-dependencies.txt +++ b/hugegraph-dist/scripts/dependency/known-dependencies.txt @@ -348,6 +348,7 @@ kerby-xdr-1.0.1.jar kerby-xdr-2.0.0.jar kotlin-stdlib-1.6.20.jar kotlin-stdlib-common-1.5.31.jar +kotlin-stdlib-common-1.6.20.jar kotlin-stdlib-jdk7-1.2.71.jar kotlin-stdlib-jdk7-1.6.10.jar kotlin-stdlib-jdk8-1.2.71.jar diff --git a/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.js b/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.js new file mode 100644 index 000000000..cb1915d59 --- /dev/null +++ b/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.js @@ -0,0 +1,46 @@ +/* + * 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. + */ + +import {Input} from 'antd'; +import {useTranslation} from 'react-i18next'; + +import {isValidFavoriteName} from '../../utils/rules'; + +const FavoriteNameInput = props => { + const {t} = useTranslation(); + const {value, ...inputProps} = props; + const invalid = value && !isValidFavoriteName(value); + + return ( + <> + + {invalid && ( +
+ {t('common.validation.favorite_name_rule')} +
+ )} + + ); +}; + +export default FavoriteNameInput; diff --git a/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.test.js b/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.test.js new file mode 100644 index 000000000..ee6a6de81 --- /dev/null +++ b/hugegraph-hubble/hubble-fe/src/components/FavoriteNameInput/index.test.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +import {fireEvent, render, screen} from '@testing-library/react'; +import {useCallback, useState} from 'react'; + +import FavoriteNameInput from './index'; + +jest.mock('react-i18next', () => ({ + initReactI18next: {type: '3rdParty', init: jest.fn()}, + useTranslation: () => ({t: key => key}), +})); + +test('explains invalid favorite names and clears the error for valid names', () => { + const FavoriteNameEditor = () => { + const [name, setName] = useState(''); + const onChange = useCallback(e => setName(e.target.value), []); + return ; + }; + render(); + + const input = screen.getByRole('textbox'); + fireEvent.change(input, {target: {value: 'query-name'}}); + expect(screen.getByRole('alert')).toHaveTextContent( + 'common.validation.favorite_name_rule' + ); + + fireEvent.change(input, {target: {value: 'query_name'}}); + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); +}); diff --git a/hugegraph-hubble/hubble-fe/src/i18n/resources/en-US/components/common.json b/hugegraph-hubble/hubble-fe/src/i18n/resources/en-US/components/common.json index 44f8f3a96..f2fdcafe8 100644 --- a/hugegraph-hubble/hubble-fe/src/i18n/resources/en-US/components/common.json +++ b/hugegraph-hubble/hubble-fe/src/i18n/resources/en-US/components/common.json @@ -27,6 +27,7 @@ "normal_name_rule": "Use Chinese characters, letters, numbers, or underscores only, up to 20 characters", "jdbc_rule": "Enter a valid JDBC URL, for example: jdbc:mysql://127.0.0.1:3306/db_name", "account_name_rule": "Account name must be within 16 characters and cannot start or end with an underscore", + "favorite_name_rule": "Use Chinese characters, letters, numbers, or underscores only, up to 48 characters", "invalid_data_format": "Invalid data format" } }, diff --git a/hugegraph-hubble/hubble-fe/src/i18n/resources/zh-CN/components/common.json b/hugegraph-hubble/hubble-fe/src/i18n/resources/zh-CN/components/common.json index 5e3147c27..e8a4e004e 100644 --- a/hugegraph-hubble/hubble-fe/src/i18n/resources/zh-CN/components/common.json +++ b/hugegraph-hubble/hubble-fe/src/i18n/resources/zh-CN/components/common.json @@ -27,6 +27,7 @@ "normal_name_rule": "只能包含中文、字母、数字、_, 不能超过20个字符", "jdbc_rule": "请输入正确的jdbc url, 例如:jdbc:mysql://127.0.0.1:3306/db_name", "account_name_rule": "账号名不超过16个字符,且不能以下划线开始和结尾", + "favorite_name_rule": "只能包含中文、字母、数字、_, 不能超过48个字符", "invalid_data_format": "非法的数据格式" } }, diff --git a/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/ExecuteLog/index.js b/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/ExecuteLog/index.js index 310309e02..d4cf55c01 100644 --- a/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/ExecuteLog/index.js +++ b/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/ExecuteLog/index.js @@ -22,8 +22,10 @@ import React, {useState, useCallback} from 'react'; import {useTranslation} from 'react-i18next'; -import {Button, Table, Space, Tag, Input, Popconfirm} from 'antd'; +import {Button, Table, Space, Tag, Popconfirm} from 'antd'; import ExecutionContent from '../../../../components/ExecutionContent'; +import FavoriteNameInput from '../../../../components/FavoriteNameInput'; +import {isValidFavoriteName} from '../../../../utils/rules'; import c from './index.module.scss'; const EXECUTE_TYPE_KEY = { @@ -67,17 +69,14 @@ const ExecuteLog = props => { } = props; const [favoriteName, setFavoriteName] = useState(); - const [disabledFavorite, setDisabledFavorite] = useState(true); const onFavoraiteName = useCallback( e => { setFavoriteName(e.target.value); - e.target.value ? setDisabledFavorite(false) : setDisabledFavorite(true); }, []); const onFavoriteCard = useCallback(() => { setFavoriteName(''); - setDisabledFavorite(true); }, []); const updateAddCollection = useCallback( @@ -97,11 +96,9 @@ const ExecuteLog = props => {
{t('analysis.logs.favorite_statement')}
- @@ -169,7 +166,7 @@ const ExecuteLog = props => { placement="left" title={favoriteContent(rowData)} onConfirm={createValueHandler(onAddFavorite, rowData.content)} - okButtonProps={{disabled: disabledFavorite}} + okButtonProps={{disabled: !isValidFavoriteName(favoriteName)}} okText={t('analysis.logs.action.favorite')} cancelText={t('common.action.cancel')} > diff --git a/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/Favorite/index.js b/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/Favorite/index.js index dbbbe8aeb..7a90e5191 100644 --- a/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/Favorite/index.js +++ b/hugegraph-hubble/hubble-fe/src/modules/algorithm/LogsDetail/Favorite/index.js @@ -25,6 +25,8 @@ import {useTranslation} from 'react-i18next'; import Highlighter from 'react-highlight-words'; import {Button, Table, Input, Popconfirm, Modal} from 'antd'; import ExecutionContent from '../../../../components/ExecutionContent'; +import FavoriteNameInput from '../../../../components/FavoriteNameInput'; +import {isValidFavoriteName} from '../../../../utils/rules'; import c from './index.module.scss'; const createValueHandler = (handler, value) => () => handler(value); @@ -48,7 +50,6 @@ const Favorite = props => { const [favoriteName, setFavoriteName] = useState(); const [searchCache, setSearchCache] = useState(''); const [search, setSearch] = useState(''); - const [isDisabledName, setDisabledName] = useState(false); const changeCollection = useCallback( rowData => { @@ -72,7 +73,6 @@ const Favorite = props => { const onChangeFavoraiteName = useCallback( e => { setFavoriteName(e.target.value); - e.target.value ? setDisabledName(false) : setDisabledName(true); }, []); const onConfirm = id => { @@ -90,11 +90,9 @@ const Favorite = props => {
{t('analysis.logs.edit_name')}
- @@ -159,7 +157,7 @@ const Favorite = props => { title={editFavoriteForm} onConfirm={createValueHandler(onSaveEditFavorite, rowData)} okText={t('analysis.logs.action.save')} - okButtonProps={{disabled: isDisabledName}} + okButtonProps={{disabled: !isValidFavoriteName(favoriteName)}} cancelText={t('common.action.cancel')} >