You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by ji...@apache.org on 2022/05/10 14:49:14 UTC
[incubator-hugegraph-toolchain] branch master updated: feat:supplementary algorithms UI (#270)
This is an automated email from the ASF dual-hosted git repository.
jin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph-toolchain.git
The following commit(s) were added to refs/heads/master by this push:
new 10c020c feat:supplementary algorithms UI (#270)
10c020c is described below
commit 10c020cc2d952ce4a4e4a14e7cad48204bbedf5d
Author: Crayon <we...@gmail.com>
AuthorDate: Tue May 10 22:49:08 2022 +0800
feat:supplementary algorithms UI (#270)
---
.../graph-management/GraphManagementList.tsx | 22 +-
.../graph-management/GraphManagementSidebar.tsx | 11 +-
.../async-tasks/AsyncTaskList.less | 3 +-
.../graph-management/async-tasks/AsyncTaskList.tsx | 17 +-
.../graph-management/data-analyze/DataAnalyze.less | 92 +-
.../graph-management/data-analyze/DataAnalyze.tsx | 7 +-
.../data-analyze/DataAnalyzeInfoDrawer.tsx | 2 +-
.../data-analyze/ExecLogAndQueryCollections.tsx | 438 +++++-
.../data-analyze/QueryAndAlgorithmLibrary.tsx | 608 ++------
.../data-analyze/algorithm/AllPath.tsx | 118 +-
.../data-analyze/algorithm/CustomPath.tsx | 1098 ++++++++++++++
.../data-analyze/algorithm/FocusDetection.tsx | 86 +-
.../data-analyze/algorithm/Jaccard.tsx | 261 ++++
.../algorithm/{ShortestPathAll.tsx => KHop.tsx} | 307 ++--
.../{LoopDetection.tsx => KStepNeighbor.tsx} | 202 ++-
.../data-analyze/algorithm/LoopDetection.tsx | 59 +-
.../data-analyze/algorithm/ModelSimilarity.tsx | 1536 ++++++++++----------
.../data-analyze/algorithm/NeighborRank.tsx | 196 +--
.../{ShortestPathAll.tsx => PersonalRank.tsx} | 332 +++--
...rtestPathAll.tsx => RadiographicInspection.tsx} | 327 ++---
.../{LoopDetection.tsx => SameNeighbor.tsx} | 214 +--
.../{ShortestPathAll.tsx => ShortestPath.tsx} | 267 ++--
.../data-analyze/algorithm/ShortestPathAll.tsx | 70 +-
...ll.tsx => SingleSourceWeightedShortestPath.tsx} | 411 ++++--
...hortestPathAll.tsx => WeightedShortestPath.tsx} | 353 +++--
.../data-analyze/query-result/GraphPopOver.tsx | 52 +-
.../query-result/QueryFilterOptions.tsx | 2 +-
.../data-analyze/query-result/QueryResult.tsx | 4 -
.../data-analyze/query-result/TableQueryResult.tsx | 4 +
.../data-import/import-tasks/ImportTasks.less | 5 -
.../import-tasks/datamap-configs/EdgeMap.tsx | 26 +-
.../import-tasks/datamap-configs/FileConfigs.tsx | 3 +
.../import-tasks/datamap-configs/VertexMap.tsx | 40 +-
.../metadata-configs/MetadataConfigs.tsx | 19 +-
.../metadata-configs/edge-type/EdgeTypeList.tsx | 202 +--
.../metadata-configs/edge-type/ReuseEdgeTypes.tsx | 70 +-
.../graph-view/CheckAndEditEdge.tsx | 114 +-
.../graph-view/CheckAndEditVertex.tsx | 108 +-
.../metadata-configs/graph-view/CheckProperty.tsx | 1 +
.../metadata-configs/graph-view/CreateVertex.tsx | 109 +-
.../metadata-configs/graph-view/GraphView.less | 7 +-
.../metadata-configs/graph-view/GraphView.tsx | 11 +-
.../metadata-configs/property/ReuseProperties.tsx | 48 +-
.../vertex-type/ReuseVertexTypes.tsx | 63 +-
.../vertex-type/VertexTypeList.tsx | 174 ++-
.../resources/en-US/graph-managment/addition.json | 3 +-
.../resources/zh-CN/graph-managment/addition.json | 3 +-
.../data-import/import-tasks/ImportTasks.json | 3 +-
.../zh-CN/graph-managment/dataAnalyze.json | 449 +++++-
hugegraph-hubble/hubble-fe/src/index.less | 9 +-
.../dataAnalyzeStore/algorithmAnalyzerStore.ts | 1480 ++++++++++++++++---
.../dataAnalyzeStore/dataAnalyzeStore.ts | 612 +++++---
.../dataImportStore/dataMapStore.ts | 42 +-
.../GraphManagementStore/graphManagementStore.ts | 44 +-
.../metadataConfigsStore/edgeTypeStore.ts | 295 ++--
.../metadataConfigsStore/graphViewStore.ts | 9 +-
.../metadataConfigsStore/metadataConfigsStore.ts | 70 +-
.../metadataConfigsStore/vertexTypeStore.ts | 244 ++--
.../factory/dataAnalyzeStore/algorithmStore.ts | 284 +++-
.../factory/dataAnalyzeStore/dataAnalyzeStore.ts | 5 +
.../types/GraphManagementStore/dataAnalyzeStore.ts | 134 +-
.../hubble-fe/src/stores/utils/index.ts | 18 +
.../hubble-fe/src/utils/calcAlgorithmFormWidth.ts | 7 +
.../src/utils/filterEmptyAlgorightmParams.ts | 19 +
.../src/utils/formatAlgorithmStatement.ts | 254 ++++
hugegraph-hubble/hubble-fe/src/utils/index.ts | 21 +-
.../hubble-fe/src/utils/isDataTypeNumeric.ts | 10 +
67 files changed, 8098 insertions(+), 4016 deletions(-)
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementList.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementList.tsx
index 73b5789..3b645c1 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementList.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementList.tsx
@@ -26,7 +26,6 @@ import HintIcon from '../../assets/imgs/ic_question_mark.svg';
import { GraphData } from '../../stores/types/GraphManagementStore/graphManagementStore';
import { useTranslation } from 'react-i18next';
-
const commonInputProps = {
size: 'medium',
width: 420
@@ -234,7 +233,7 @@ const GraphManagementListItem: React.FC<
value: 'delete'
}
];
-
+
const disabledDropdownList = [
{
label: t('addition.common.edit'),
@@ -338,6 +337,9 @@ const GraphManagementListItem: React.FC<
'password',
'edit'
)}
+ originInputProps={{
+ type: 'password'
+ }}
/>
</div>
<div>
@@ -368,7 +370,9 @@ const GraphManagementListItem: React.FC<
) : (
<div className="graph-management-list" key={id}>
<div className="graph-management-list-item">
- <div className="graph-management-list-title">{t('addition.graphManagementList.id')}</div>
+ <div className="graph-management-list-title">
+ {t('addition.graphManagementList.id')}
+ </div>
<div className="graph-management-list-data">
<span title={name}>
<Highlighter
@@ -381,7 +385,9 @@ const GraphManagementListItem: React.FC<
</div>
</div>
<div className="graph-management-list-item">
- <div className="graph-management-list-title">{t('addition.graphManagementList.name')}</div>
+ <div className="graph-management-list-title">
+ {t('addition.graphManagementList.name')}
+ </div>
<div className="graph-management-list-data">
<span title={graph}>
<Highlighter
@@ -394,7 +400,9 @@ const GraphManagementListItem: React.FC<
</div>
</div>
<div className="graph-management-list-item">
- <div className="graph-management-list-title">{t('addition.graphManagementList.host')}</div>
+ <div className="graph-management-list-title">
+ {t('addition.graphManagementList.host')}
+ </div>
<div className="graph-management-list-data" title={host}>
{host}
</div>
@@ -408,7 +416,9 @@ const GraphManagementListItem: React.FC<
</div>
</div>
<div className="graph-management-list-item">
- <div className="graph-management-list-title">{t('addition.graphManagementList.creation-time')}</div>
+ <div className="graph-management-list-title">
+ {t('addition.graphManagementList.creation-time')}
+ </div>
<div className="graph-management-list-data" title={create_time}>
{create_time}
</div>
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementSidebar.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementSidebar.tsx
index 7363ea6..eb48501 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementSidebar.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/GraphManagementSidebar.tsx
@@ -10,7 +10,6 @@ import {
ImportManagerStoreContext
} from '../../stores';
-import BackIcon from '../../assets/imgs/ic_topback.svg';
import ArrowIcon from '../../assets/imgs/ic_arrow_white.svg';
import DataAnalyzeIconNormal from '../../assets/imgs/ic_shuju_normal.svg';
import DataAnalyzeIconPressed from '../../assets/imgs/ic_shuju_pressed.svg';
@@ -43,11 +42,6 @@ const GraphManagementSidebar: React.FC = observer(() => {
expand: graphManagementStore.isExpanded
});
- const sidebarGoBackClassName = classnames({
- 'data-analyze-sidebar-go-back': true,
- expand: graphManagementStore.isExpanded
- });
-
const sidebarGraphSelectionClassName = classnames({
'data-analyze-sidebar-graph-selection': true,
expand: graphManagementStore.isExpanded
@@ -91,9 +85,8 @@ const GraphManagementSidebar: React.FC = observer(() => {
const handleSelectId = useCallback(
(value: string) => {
- const id = graphManagementStore.idList.find(
- ({ name }) => name === value
- )!.id;
+ const id = graphManagementStore.idList.find(({ name }) => name === value)!
+ .id;
dataAnalyzeStore.resetIdState();
setLocation(`/graph-management/${id}/data-analyze`);
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.less b/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.less
index 7fa8e6e..b33bbe7 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.less
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.less
@@ -59,7 +59,8 @@
line-height: 22px;
text-align: center;
- &.new,
+ &.scheduling,
+ &.scheduled,
&.queued,
&.restoring,
&.running {
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.tsx
index 6a3f995..315dd30 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/async-tasks/AsyncTaskList.tsx
@@ -10,14 +10,7 @@ import classnames from 'classnames';
import { useRoute } from 'wouter';
import { useTranslation } from 'react-i18next';
import { isEmpty, size, intersection, without } from 'lodash-es';
-import {
- Breadcrumb,
- Input,
- Button,
- Message,
- Table,
- Loading
-} from 'hubble-ui';
+import { Breadcrumb, Input, Button, Message, Table, Loading } from 'hubble-ui';
import {
GraphManagementStoreContext,
@@ -151,7 +144,7 @@ const AsyncTaskList: React.FC = observer(() => {
{t('async-tasks.table-filters.task-type.gremlin')}
</div>
<div onClick={handleFilterOptions('type', 'algorithm')}>
- {t('async-tasks.table-filters.task-type.algorithm')}{' '}
+ {t('async-tasks.table-filters.task-type.algorithm')}
</div>
<div onClick={handleFilterOptions('type', 'remove_schema')}>
{t('async-tasks.table-filters.task-type.remove-schema')}
@@ -231,6 +224,10 @@ const AsyncTaskList: React.FC = observer(() => {
timeString += ' ' + restTime + 'ms';
}
+ if (restTime <= 0) {
+ timeString = '0s';
+ }
+
return <div className="no-line-break">{timeString}</div>;
}
},
@@ -412,7 +409,7 @@ const AsyncTaskList: React.FC = observer(() => {
<div className="async-task-list-content-header">
<Input.Search
size="medium"
- width={205}
+ width={215}
placeholder={t('async-tasks.placeholders.search')}
value={asyncTasksStore.searchWords}
onChange={handleSearchChange}
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.less b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.less
index 559ac2d..76b6994 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.less
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.less
@@ -192,12 +192,33 @@
}
}
+ .query-tab-algorithm-wrapper,
.query-tab-content-wrapper {
padding: 16px;
background: #fff;
border-radius: 3px 3px 3px 3px;
}
+ .query-tab-algorithm-wrapper {
+ // min-width: 1220px;
+ overflow: auto;
+
+ .new-fc-one-input-error.new-fc-one-input-error-right {
+ left: 0;
+ top: 30px;
+ }
+ }
+
+ .query-tab-algorithm-hint {
+ width: fit-content;
+ box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.15);
+ line-height: 18px;
+ padding: 16px;
+ color: #e64552;
+ font-size: 14px;
+ text-align: center;
+ }
+
.query-tab-content {
display: flex;
}
@@ -238,15 +259,6 @@
background-color: #f2f7ff;
cursor: pointer;
}
-
- &.query-tab-content-menu-item-disabled {
- color: #ccc;
- cursor: not-allowed;
-
- &:hover {
- background-color: #fff;
- }
- }
}
}
@@ -303,10 +315,6 @@
padding: 16px 8px;
margin-bottom: 16px;
- &-invalid {
- border: 1px solid #e64552;
- }
-
&:last-child {
margin-bottom: 0;
}
@@ -322,6 +330,40 @@
}
}
+ .query-tab-content-internal-expand-row {
+ width: 390px;
+ display: flex;
+ // justify-content: space-between;
+ height: 32px;
+ margin-bottom: 16px;
+ }
+
+ .query-tab-content-internal-expand-input {
+ margin: 0 14px 0 16px;
+ }
+
+ .query-tab-content-internal-expand-manipulation {
+ &-enable,
+ &-disabled {
+ font-size: 14px;
+ line-height: 20px;
+ margin-bottom: 32px;
+ padding-left: 172px;
+
+ & span {
+ cursor: pointer;
+ }
+ }
+
+ &-enable {
+ color: #2b65ff;
+ }
+
+ &-disabled {
+ color: #999;
+ }
+ }
+
.query-tab-code-edit {
width: calc(100% - 55px);
@@ -441,6 +483,7 @@
border-right: 1px solid #e0e0e0;
display: flex;
flex-direction: column;
+ overflow-y: auto;
&-options {
width: 61px;
@@ -595,6 +638,14 @@
& > img {
margin-bottom: 10px;
}
+
+ & > span {
+ display: block;
+ width: 80%;
+ text-align: center;
+ max-height: 200px;
+ overflow: auto;
+ }
}
}
@@ -830,8 +881,12 @@
}
& > div {
- flex-basis: 50%;
+ // flex-basis: 50%;
line-height: 32px;
+
+ &:first-child {
+ width: 162px;
+ }
}
}
}
@@ -1131,3 +1186,12 @@ div.vis-tooltip {
pointer-events: none;
z-index: 5;
}
+
+// refer to index.less, this should be fixed in the future version
+.data-analyze-dynamic-add-options .new-fc-one-input-all-container {
+ position: relative;
+}
+
+.data-analyze-graph-node-info .new-fc-one-input-all-container {
+ position: relative;
+}
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.tsx
index cc65fdf..efa3cd3 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyze.tsx
@@ -44,6 +44,7 @@ const DataAnalyze: React.FC = observer(() => {
dataAnalyzeStore.setCurrentId(Number(params.id));
dataAnalyzeStore.fetchValueTypes();
dataAnalyzeStore.fetchVertexTypes();
+ dataAnalyzeStore.fetchAllPropertyIndexes('vertex');
dataAnalyzeStore.fetchEdgeTypes();
dataAnalyzeStore.fetchAllNodeStyle();
dataAnalyzeStore.fetchAllEdgeStyle();
@@ -70,9 +71,9 @@ const DataAnalyze: React.FC = observer(() => {
{t('addition.dataAnalyze.return-home')}
</Button>
]}
- visible={Object.values(dataAnalyzeStore.errorInfo)
- .map(({ code }) => code)
- .includes(401)}
+ visible={graphManagementStore.graphData.some(
+ ({ id, enabled }) => dataAnalyzeStore.currentId === id && !enabled
+ )}
destroyOnClose
needCloseIcon={false}
>
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyzeInfoDrawer.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyzeInfoDrawer.tsx
index eef6d43..541b97d 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyzeInfoDrawer.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DataAnalyzeInfoDrawer.tsx
@@ -299,7 +299,7 @@ const DataAnalyzeInfoDrawer: React.FC = observer(() => {
marginTop: !isEdit ? 0 : nullableIndex === 0 ? 8 : 32
}}
>
- <div>{key}: </div>
+ <div title={key}>{key}: </div>
{!isEdit ? (
<div>{convertArrayToString(value)}</div>
) : (
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/ExecLogAndQueryCollections.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/ExecLogAndQueryCollections.tsx
index 23ed923..10aa402 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/ExecLogAndQueryCollections.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/ExecLogAndQueryCollections.tsx
@@ -1,10 +1,12 @@
import React, { useState, useContext, useEffect, useCallback } from 'react';
import { observer } from 'mobx-react';
import classnames from 'classnames';
-import { isUndefined } from 'lodash-es';
+import { isUndefined, cloneDeep, isEmpty, isNull } from 'lodash-es';
import Highlighter from 'react-highlight-words';
import { useRoute, useLocation } from 'wouter';
import { useTranslation } from 'react-i18next';
+
+import { v4 } from 'uuid';
import { Table, Input, Button, Message } from 'hubble-ui';
import { Tooltip } from '../../common';
@@ -13,16 +15,53 @@ import {
DataAnalyzeStoreContext,
AsyncTasksStoreContext
} from '../../../stores';
+import { formatAlgorithmStatement } from '../../../utils';
-import type { TFunction } from 'i18next';
import type {
ExecutionLogs,
- FavoriteQuery
+ FavoriteQuery,
+ LoopDetectionParams,
+ FocusDetectionParams,
+ ShortestPathAlgorithmParams,
+ ShortestPathAllAlgorithmParams,
+ AllPathAlgorithmParams,
+ KStepNeighbor,
+ KHop,
+ RadiographicInspection,
+ SameNeighbor,
+ Jaccard,
+ WeightedShortestPath,
+ SingleSourceWeightedShortestPath,
+ PersonalRank,
+ ModelSimilarityParams,
+ NeighborRankParams,
+ CustomPathParams,
+ CustomPathRule
} from '../../../stores/types/GraphManagementStore/dataAnalyzeStore';
import { Algorithm } from '../../../stores/factory/dataAnalyzeStore/algorithmStore';
import ArrowIcon from '../../../assets/imgs/ic_arrow_16.svg';
import EmptyIcon from '../../../assets/imgs/ic_sousuo_empty.svg';
+import { toJS } from 'mobx';
+
+export const AlgorithmInternalNameMapping: Record<string, string> = {
+ rings: 'loop-detection',
+ crosspoints: 'focus-detection',
+ shortpath: 'shortest-path',
+ allshortpath: 'shortest-path-all',
+ paths: 'all-path',
+ fsimilarity: 'model-similarity',
+ neighborrank: 'neighbor-rank',
+ kneighbor: 'k-step-neighbor',
+ kout: 'k-hop',
+ customizedpaths: 'custom-path',
+ rays: 'radiographic-inspection',
+ sameneighbors: 'same-neighbor',
+ weightedshortpath: 'weighted-shortest-path',
+ singleshortpath: 'single-source-weighted-shortest-path',
+ jaccardsimilarity: 'jaccard',
+ personalrank: 'personal-rank'
+};
const styles = {
tableCenter: {
@@ -39,6 +78,7 @@ const styles = {
const ExecLogAndQueryCollections: React.FC = observer(() => {
const asyncTasksStore = useContext(AsyncTasksStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStoreContext);
+ const { algorithmAnalyzerStore } = dataAnalyzeStore;
const [tabIndex, setTabIndex] = useState(0);
const [, params] = useRoute('/graph-management/:id/data-analyze');
const { t } = useTranslation();
@@ -80,6 +120,7 @@ const ExecLogAndQueryCollections: React.FC = observer(() => {
<ExecutionContent
type={rowData.type}
content={text}
+ algorithmName={rowData.algorithm_name}
highlightText=""
/>
);
@@ -208,7 +249,12 @@ const ExecLogAndQueryCollections: React.FC = observer(() => {
className="exec-log-manipulation"
onClick={loadStatements(
rowData.content,
- rowData.type === 'GREMLIN_ASYNC' ? 'task' : 'query'
+ rowData.type === 'GREMLIN_ASYNC'
+ ? 'task'
+ : rowData.type === 'GREMLIN'
+ ? 'query'
+ : 'algorithm',
+ rowData.algorithm_name
)}
>
{t('addition.operate.load-statement')}
@@ -383,8 +429,356 @@ const ExecLogAndQueryCollections: React.FC = observer(() => {
);
const loadStatements = useCallback(
- (content: string, type?: 'query' | 'task') => () => {
+ (
+ content: string,
+ type?: 'query' | 'task' | 'algorithm',
+ algorithmName?: string
+ ) => () => {
if (!dataAnalyzeStore.isLoadingGraph) {
+ if (type === 'algorithm') {
+ const params: Record<string, any> = JSON.parse(content);
+ dataAnalyzeStore.setCurrentTab('algorithm-analyze');
+
+ if (params.hasOwnProperty('direction')) {
+ params.direction = params.direction.toUpperCase();
+ }
+
+ if (params.hasOwnProperty('label')) {
+ params['label'] === null && (params['label'] = '__all__');
+ }
+
+ window.scrollTo(0, 0);
+
+ switch (algorithmName) {
+ case 'rings':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.loopDetection
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateLoopDetectionParams(
+ key as keyof LoopDetectionParams,
+ params[key]
+ );
+ });
+
+ return;
+ case 'crosspoints':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.focusDetection
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateFocusDetectionParams(
+ key as keyof FocusDetectionParams,
+ params[key]
+ );
+ });
+
+ return;
+ case 'shortpath':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.shortestPath
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateShortestPathParams(
+ key as keyof ShortestPathAlgorithmParams,
+ params[key]
+ );
+ });
+
+ return;
+ case 'allshortpath':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.shortestPathAll
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateShortestPathAllParams(
+ key as keyof ShortestPathAllAlgorithmParams,
+ params[key]
+ );
+ });
+
+ return;
+ case 'paths':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(Algorithm.allPath);
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateAllPathParams(
+ key as keyof AllPathAlgorithmParams,
+ params[key]
+ );
+ });
+
+ return;
+ case 'fsimilarity': {
+ const clonedParams = cloneDeep(params);
+
+ if (isEmpty(params.sources.ids)) {
+ clonedParams.method = 'property';
+ } else {
+ clonedParams.method = 'id';
+ }
+
+ clonedParams.source = clonedParams.sources.ids.join(',');
+ clonedParams.vertexType = clonedParams.sources.label;
+ clonedParams.vertexProperty = Object.entries(
+ clonedParams.sources.properties
+ );
+
+ if (isEmpty(clonedParams.vertexProperty)) {
+ clonedParams.vertexProperty = [['', '']];
+ } else {
+ clonedParams.vertexProperty = clonedParams.vertexProperty.map(
+ ([key, value]: [string, string[]]) => [key, value.join(',')]
+ );
+ }
+
+ clonedParams.least_neighbor = clonedParams.min_neighbors;
+ clonedParams.similarity = clonedParams.alpha;
+ clonedParams.least_similar = clonedParams.min_similars;
+ clonedParams.max_similar = clonedParams.top;
+ clonedParams.property_filter = clonedParams.group_property;
+ clonedParams.least_property_number = clonedParams.min_groups;
+ clonedParams.return_common_connection =
+ clonedParams.with_intermediary;
+ clonedParams.return_complete_info = clonedParams.with_vertex;
+
+ delete clonedParams.sources;
+ delete clonedParams.min_neighbors;
+ delete clonedParams.alpha;
+ delete clonedParams.min_similars;
+ delete clonedParams.top;
+ delete clonedParams.group_property;
+ delete clonedParams.min_groups;
+ delete clonedParams.with_intermediary;
+ delete clonedParams.with_vertex;
+
+ Object.keys(clonedParams).forEach((key) => {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ key as keyof ModelSimilarityParams,
+ clonedParams[key]
+ );
+ });
+
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.modelSimilarity
+ );
+
+ return;
+ }
+ case 'neighborrank': {
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.neighborRank
+ );
+
+ const clonedParams = cloneDeep(params) as NeighborRankParams;
+
+ // remove neighborrank validate rules first;
+ algorithmAnalyzerStore.removeValidateNeighborRankRule(0);
+ clonedParams.steps.forEach(({ labels }, index) => {
+ clonedParams.steps[index].uuid = v4();
+ // add neighborrank rule validation per each
+ algorithmAnalyzerStore.addValidateNeighborRankRule();
+
+ if (isEmpty(labels)) {
+ clonedParams.steps[index].labels = ['__all__'];
+ }
+ });
+
+ Object.keys(clonedParams).forEach((key) => {
+ algorithmAnalyzerStore.mutateNeighborRankParams(
+ key as keyof NeighborRankParams,
+ // @ts-ignore
+ clonedParams[key]
+ );
+ });
+
+ return;
+ }
+ case 'kneighbor':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.kStepNeighbor
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
+ key as keyof KStepNeighbor,
+ params[key]
+ );
+ });
+
+ return;
+ case 'kout':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(Algorithm.kHop);
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateKHopParams(
+ key as keyof KHop,
+ params[key]
+ );
+ });
+
+ return;
+ case 'customizedpaths':
+ const clonedParams = cloneDeep(params);
+
+ if (isEmpty(params.sources.ids)) {
+ clonedParams.method = 'property';
+ } else {
+ clonedParams.method = 'id';
+ }
+ clonedParams.source = clonedParams.sources.ids.join(',');
+ clonedParams.vertexType = clonedParams.sources.label;
+ clonedParams.vertexProperty = Object.entries(
+ clonedParams.sources.properties
+ );
+
+ if (isEmpty(clonedParams.vertexProperty)) {
+ clonedParams.vertexProperty = [['', '']];
+ } else {
+ clonedParams.vertexProperty = clonedParams.vertexProperty.map(
+ ([key, value]: [string, string[]]) => [key, value.join(',')]
+ );
+
+ clonedParams.vertexProperty = Object.keys(
+ clonedParams.vertexProperty
+ ).map((key) => [
+ key,
+ clonedParams.vertexProperty[key].join(',')
+ ]);
+ }
+
+ clonedParams.steps.forEach((step: any, index: number) => {
+ const { labels, properties, weight_by, default_weight } = step;
+ clonedParams.steps[index].uuid = v4();
+
+ if (isEmpty(labels)) {
+ step.labels = dataAnalyzeStore.edgeTypes.map(
+ ({ name }) => name
+ );
+ }
+
+ if (isEmpty(properties)) {
+ step.properties = [['', '']];
+ } else {
+ step.properties = Object.keys(step.properties).map((key) => [
+ key,
+ step.properties[key].join(',')
+ ]);
+ }
+
+ if (clonedParams.sort_by === 'NONE') {
+ step.weight_by = '';
+ step.default_weight = '';
+ } else {
+ if (!isNull(weight_by)) {
+ step.default_weight = '';
+ } else {
+ // custom weight
+ step.weight_by = '__CUSTOM_WEIGHT__';
+ step.default_weight = default_weight;
+ }
+ }
+ });
+
+ delete clonedParams.sources;
+
+ Object.keys(clonedParams).forEach((key) => {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ key as keyof CustomPathParams,
+ clonedParams[key]
+ );
+ });
+
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.customPath
+ );
+
+ return;
+ case 'rays':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.radiographicInspection
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
+ key as keyof RadiographicInspection,
+ params[key]
+ );
+ });
+
+ return;
+ case 'sameneighbors':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.sameNeighbor
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ key as keyof SameNeighbor,
+ params[key]
+ );
+ });
+
+ return;
+ case 'weightedshortpath':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.weightedShortestPath
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
+ key as keyof WeightedShortestPath,
+ params[key]
+ );
+ });
+
+ return;
+ case 'singleshortpath':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.singleSourceWeightedShortestPath
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ key as keyof SingleSourceWeightedShortestPath,
+ params[key]
+ );
+ });
+
+ return;
+ case 'jaccardsimilarity':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(Algorithm.jaccard);
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutateJaccardParams(
+ key as keyof Jaccard,
+ params[key]
+ );
+ });
+
+ return;
+ case 'personalrank':
+ algorithmAnalyzerStore.changeCurrentAlgorithm(
+ Algorithm.personalRankRecommendation
+ );
+
+ Object.keys(params).forEach((key) => {
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ key as keyof PersonalRank,
+ params[key]
+ );
+ });
+
+ return;
+ default:
+ return;
+ }
+ }
+
if (!isUndefined(type)) {
type === 'task'
? dataAnalyzeStore.setQueryMode('task')
@@ -556,13 +950,15 @@ const ExecutionContent: React.FC<{
type: string;
content: string;
highlightText: string;
-}> = observer(({ type, content, highlightText }) => {
+ algorithmName?: string;
+}> = observer(({ type, content, highlightText, algorithmName }) => {
const dataAnalyzeStore = useContext(DataAnalyzeStoreContext);
- const { t } = useTranslation();
+ const { t, i18n } = useTranslation();
const [isExpand, switchExpand] = useState(dataAnalyzeStore.isSearched.status);
+
const statements =
type === 'ALGORITHM'
- ? formatAlgorithmStatement(content, Algorithm.shortestPath, t)
+ ? formatAlgorithmStatement(content, algorithmName, t, i18n)
: content.split('\n').filter((statement) => statement !== '');
const arrowIconClassName = classnames({
@@ -670,30 +1066,4 @@ export const DeleteConfirm: React.FC<DeleteConfirmProps> = observer(
}
);
-function formatAlgorithmStatement(
- content: string,
- algorithmType: string,
- translator: TFunction
-) {
- const convertedString = content
- .replace(/^.*\(/, '')
- .replace(/\)$/, '')
- .replace(/ /g, '');
- const statements: string[] = [
- translator(`data-analyze.algorithm-list.${algorithmType}`)
- ];
-
- convertedString.split(',').forEach((item) => {
- const [key, value] = item.split('=');
-
- statements.push(
- `${translator(
- `data-analyze.algorithm-forms.shortest-path.options.${key}`
- )} ${value}`
- );
- });
-
- return statements;
-}
-
export default ExecLogAndQueryCollections;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/QueryAndAlgorithmLibrary.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/QueryAndAlgorithmLibrary.tsx
index 0bfb56e..0fa932a 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/QueryAndAlgorithmLibrary.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/QueryAndAlgorithmLibrary.tsx
@@ -10,15 +10,7 @@ import { observer } from 'mobx-react';
import CodeMirror from 'codemirror';
import { useTranslation } from 'react-i18next';
import classnames from 'classnames';
-import {
- Button,
- Tooltip,
- Alert,
- Dropdown,
- Input,
- Radio,
- Select
-} from 'hubble-ui';
+import { Button, Tooltip, Alert, Dropdown } from 'hubble-ui';
import 'codemirror/lib/codemirror.css';
import 'react-popper-tooltip/dist/styles.css';
@@ -31,10 +23,20 @@ import { useMultiKeyPress } from '../../../hooks';
import LoopDetection from './algorithm/LoopDetection';
import FocusDetection from './algorithm/FocusDetection';
+import ShortestPath from './algorithm/ShortestPath';
import ShortestPathAll from './algorithm/ShortestPathAll';
import AllPath from './algorithm/AllPath';
import ModelSimilarity from './algorithm/ModelSimilarity';
import NeighborRank from './algorithm/NeighborRank';
+import KStepNeighbor from './algorithm/KStepNeighbor';
+import KHop from './algorithm/KHop';
+import CustomPath from './algorithm/CustomPath';
+import RadiographicInspection from './algorithm/RadiographicInspection';
+import SameNeighbor from './algorithm/SameNeighbor';
+import WeightedShortestPath from './algorithm/WeightedShortestPath';
+import SingleSourceWeightedShortestPath from './algorithm/SingleSourceWeightedShortestPath';
+import Jaccard from './algorithm/Jaccard';
+import PersonalRank from './algorithm/PersonalRank';
import ArrowIcon from '../../../assets/imgs/ic_arrow_16.svg';
import QuestionMarkIcon from '../../../assets/imgs/ic_question_mark.svg';
@@ -52,28 +54,32 @@ export const styles = {
const codeRegexp = /[A-Za-z0-9]+/;
-const algorithmWhiteList: string[] = [
- Algorithm.shortestPath,
- Algorithm.loopDetection,
- Algorithm.focusDetection,
- Algorithm.shortestPathAll,
- Algorithm.allPath,
- Algorithm.modelSimilarity,
- Algorithm.neighborRankRecommendation
-];
-
const QueryAndAlgorithmLibrary: React.FC = observer(() => {
const dataAnalyzeStore = useContext(DataAnalyzeStoreContext);
+ const { algorithmAnalyzerStore } = dataAnalyzeStore;
const { t } = useTranslation();
const handleTabChange = (tab: string) => () => {
dataAnalyzeStore.resetSwitchTabState();
if (tab !== dataAnalyzeStore.currentTab) {
+ // reset codeEditor value
dataAnalyzeStore.mutateCodeEditorText('');
+
+ // reset default selection of edge labels
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'labels',
+ dataAnalyzeStore.edgeTypes.map(({ name }) => name),
+ 0
+ );
}
dataAnalyzeStore.setCurrentTab(tab);
+ // need manually set codeMirror text value to empty here
+ dataAnalyzeStore.codeEditorInstance?.setValue('');
+ // reset algorithm tab to list
+ algorithmAnalyzerStore.changeCurrentAlgorithm('');
+ algorithmAnalyzerStore.switchCollapse(false);
};
return (
@@ -202,6 +208,7 @@ export const GremlinQuery: React.FC = observer(() => {
);
};
+ dataAnalyzeStore.assignCodeEditorInstance(codeEditor.current);
codeEditor.current.on('change', handleCodeEditorChange);
reaction(
@@ -211,15 +218,6 @@ export const GremlinQuery: React.FC = observer(() => {
}
);
- reaction(
- () => dataAnalyzeStore.pulse,
- () => {
- (codeEditor.current as CodeMirror.Editor).setValue(
- dataAnalyzeStore.codeEditorText
- );
- }
- );
-
return () => {
(codeEditor.current as CodeMirror.Editor).off(
'change',
@@ -229,6 +227,17 @@ export const GremlinQuery: React.FC = observer(() => {
}
}, [dataAnalyzeStore]);
+ // weird, mobx@reaction is not working when puluse changed, setValue()
+ // has no influence
+ useEffect(() => {
+ if (codeEditor?.current && dataAnalyzeStore.codeEditorText !== '') {
+ (codeEditor.current as CodeMirror.Editor).setValue(
+ dataAnalyzeStore.codeEditorText
+ );
+ }
+ }, [dataAnalyzeStore.pulse]);
+ // }, [dataAnalyzeStore.pulse, codeEditor?.current]);
+
useEffect(() => {
if (
keyPressed.has('Tab') &&
@@ -429,465 +438,47 @@ export const AlgorithmQuery: React.FC = observer(() => {
algorithmAnalyzerStore.shortestPathAlgorithmParams.max_depth !== '';
const handleChangeAlgorithm = (algorithm: string) => () => {
- // disable other algorithm now
- if (algorithmWhiteList.includes(algorithm)) {
- algorithmAnalyzerStore.changeCurrentAlgorithm(algorithm);
- }
+ algorithmAnalyzerStore.changeCurrentAlgorithm(algorithm);
+ };
+
+ const handleExpandClick = () => {
+ algorithmAnalyzerStore.switchCollapse(!algorithmAnalyzerStore.isCollapse);
};
const renderForms = () => {
switch (algorithmAnalyzerStore.currentAlgorithm) {
- case Algorithm.shortestPath:
- return (
- <div className="query-tab-content-form">
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.source'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.source
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.source
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'source',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams('source');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'source'
- );
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.label'
- )}
- </span>
- </div>
- <Select
- size="medium"
- trigger="click"
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.label
- }
- notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.no-edge-types'
- )}
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- width={400}
- onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'label',
- value
- );
- }}
- >
- <Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path.pre-value')}
- </Select.Option>
- {dataAnalyzeStore.edgeTypes.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.target'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-target-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.target
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.target
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'target',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams('target');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'target'
- );
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.max_degree'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.max_degree
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams
- .max_degree
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'max_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams(
- 'max_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'max_degree'
- );
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.direction'
- )}
- </span>
- </div>
- <Radio.Group
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.direction
- }
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'direction',
- e.target.value
- );
- }}
- >
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.skip_degree'
- )}
- </span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path.hint.skip-degree'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.skip_degree
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams
- .skip_degree
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'skip_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams(
- 'skip_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'skip_degree'
- );
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.max_depth'
- )}
- </span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path.hint.max-depth'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.max_depth
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.max_depth
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'max_depth',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams(
- 'max_depth'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'max_depth'
- );
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path.options.capacity'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore
- .validateShortestPathParamsErrorMessage.capacity
- }
- value={
- algorithmAnalyzerStore.shortestPathAlgorithmParams.capacity
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'capacity',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathParams(
- 'capacity'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathParams(
- 'capacity'
- );
- }
- }}
- />
- </div>
- </div>
- <div
- className="query-tab-content-form-row"
- style={{ marginLeft: 92, justifyContent: 'flex-start' }}
- >
- <Button
- type="primary"
- style={styles.primaryButton}
- disabled={
- !isValidExec ||
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- onClick={async () => {
- algorithmAnalyzerStore.switchCollapse(true);
- dataAnalyzeStore.switchGraphLoaded(false);
-
- const timerId = dataAnalyzeStore.addTempExecLog();
- await dataAnalyzeStore.fetchGraphs({
- url: 'shortpath',
- type: Algorithm.shortestPath
- });
- await dataAnalyzeStore.fetchExecutionLogs();
- window.clearTimeout(timerId);
- }}
- >
- {t('data-analyze.manipulations.execution')}
- </Button>
- <Button
- style={styles.primaryButton}
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- onClick={() => {
- algorithmAnalyzerStore.resetShortestPathParams();
- // temp solution
- algorithmAnalyzerStore.mutateShortestPathParams(
- 'label',
- '__all__'
- );
- }}
- >
- {t('data-analyze.manipulations.reset')}
- </Button>
- </div>
- </div>
- );
case Algorithm.loopDetection:
return <LoopDetection />;
case Algorithm.focusDetection:
return <FocusDetection />;
+ case Algorithm.shortestPath:
+ return <ShortestPath />;
case Algorithm.shortestPathAll:
return <ShortestPathAll />;
case Algorithm.allPath:
return <AllPath />;
case Algorithm.modelSimilarity:
return <ModelSimilarity />;
- case Algorithm.neighborRankRecommendation:
+ case Algorithm.neighborRank:
return <NeighborRank />;
+ case Algorithm.kStepNeighbor:
+ return <KStepNeighbor />;
+ case Algorithm.kHop:
+ return <KHop />;
+ case Algorithm.customPath:
+ return <CustomPath />;
+ case Algorithm.radiographicInspection:
+ return <RadiographicInspection />;
+ case Algorithm.sameNeighbor:
+ return <SameNeighbor />;
+ case Algorithm.weightedShortestPath:
+ return <WeightedShortestPath />;
+ case Algorithm.singleSourceWeightedShortestPath:
+ return <SingleSourceWeightedShortestPath />;
+ case Algorithm.jaccard:
+ return <Jaccard />;
+ case Algorithm.personalRankRecommendation:
+ return <PersonalRank />;
}
};
@@ -898,7 +489,7 @@ export const AlgorithmQuery: React.FC = observer(() => {
}, []);
return (
- <div className="query-tab-content-wrapper">
+ <div className="query-tab-algorithm-wrapper">
<div className="query-tab-content-title">
{algorithmAnalyzerStore.currentAlgorithm === '' ? (
<span>{t('data-analyze.algorithm-list.title')}</span>
@@ -912,16 +503,21 @@ export const AlgorithmQuery: React.FC = observer(() => {
marginRight: 12
}}
onClick={() => {
- algorithmAnalyzerStore.dispose();
+ algorithmAnalyzerStore.switchCollapse(false);
+ algorithmAnalyzerStore.changeCurrentAlgorithm('');
}}
/>
- <span>
+ <span onClick={handleExpandClick} style={{ cursor: 'pointer' }}>
{t(
`data-analyze.algorithm-list.${algorithmAnalyzerStore.currentAlgorithm}`
)}
</span>
</div>
)}
+ <div
+ style={{ flex: 'auto', height: 24, cursor: 'pointer' }}
+ onClick={handleExpandClick}
+ ></div>
<img
src={ArrowIcon}
alt="expand-collpase"
@@ -930,11 +526,7 @@ export const AlgorithmQuery: React.FC = observer(() => {
? 'rotate(0deg)'
: 'rotate(180deg)'
}}
- onClick={() => {
- algorithmAnalyzerStore.switchCollapse(
- !algorithmAnalyzerStore.isCollapse
- );
- }}
+ onClick={handleExpandClick}
/>
</div>
{algorithmAnalyzerStore.isCollapse ? null : algorithmAnalyzerStore.currentAlgorithm ===
@@ -948,14 +540,7 @@ export const AlgorithmQuery: React.FC = observer(() => {
Algorithm.shortestPathAll,
Algorithm.allPath
].map((algorithm) => (
- <span
- className={
- algorithmWhiteList.includes(algorithm)
- ? ''
- : 'query-tab-content-menu-item-disabled'
- }
- onClick={handleChangeAlgorithm(algorithm)}
- >
+ <span onClick={handleChangeAlgorithm(algorithm)} key={algorithm}>
{t(`data-analyze.algorithm-list.${algorithm}`)}
</span>
))}
@@ -963,57 +548,32 @@ export const AlgorithmQuery: React.FC = observer(() => {
<div className="query-tab-content-menu">
{[
Algorithm.modelSimilarity,
- Algorithm.neighborRankRecommendation,
- Algorithm.realTimeRecommendation,
+ Algorithm.neighborRank,
Algorithm.kStepNeighbor,
- Algorithm.kHop
+ Algorithm.kHop,
+ Algorithm.customPath
].map((algorithm) => (
- <span
- className={
- algorithmWhiteList.includes(algorithm)
- ? ''
- : 'query-tab-content-menu-item-disabled'
- }
- onClick={handleChangeAlgorithm(algorithm)}
- >
+ <span onClick={handleChangeAlgorithm(algorithm)} key={algorithm}>
{t(`data-analyze.algorithm-list.${algorithm}`)}
</span>
))}
</div>
<div className="query-tab-content-menu">
{[
- Algorithm.customPath,
- Algorithm.customIntersectionDetection,
Algorithm.radiographicInspection,
- Algorithm.commonNeighbor,
- Algorithm.weightedShortestPath
+ Algorithm.sameNeighbor,
+ Algorithm.weightedShortestPath,
+ Algorithm.singleSourceWeightedShortestPath,
+ Algorithm.jaccard
].map((algorithm) => (
- <span
- className={
- algorithmWhiteList.includes(algorithm)
- ? ''
- : 'query-tab-content-menu-item-disabled'
- }
- onClick={handleChangeAlgorithm(algorithm)}
- >
+ <span onClick={handleChangeAlgorithm(algorithm)} key={algorithm}>
{t(`data-analyze.algorithm-list.${algorithm}`)}
</span>
))}
</div>
<div className="query-tab-content-menu">
- {[
- Algorithm.singleSourceWeightedPath,
- Algorithm.jaccardSimilarity,
- Algorithm.personalRankRecommendation
- ].map((algorithm) => (
- <span
- className={
- algorithmWhiteList.includes(algorithm)
- ? ''
- : 'query-tab-content-menu-item-disabled'
- }
- onClick={() => {}}
- >
+ {[Algorithm.personalRankRecommendation].map((algorithm) => (
+ <span onClick={handleChangeAlgorithm(algorithm)} key={algorithm}>
{t(`data-analyze.algorithm-list.${algorithm}`)}
</span>
))}
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/AllPath.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/AllPath.tsx
index aab733e..cfc7f6d 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/AllPath.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/AllPath.tsx
@@ -1,23 +1,37 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
+import { Button, Radio, Input, Select } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { GraphManagementStoreContext } from '../../../../stores';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
const AllPath = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(algorithmAnalyzerStore.allPathParams).some(
- (value) => value === ''
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
);
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateAllPathParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.allPathParams.source !== '' &&
+ algorithmAnalyzerStore.allPathParams.target !== '' &&
+ algorithmAnalyzerStore.allPathParams.max_depth !== '';
+
return (
<div className="query-tab-content-form">
<div className="query-tab-content-form-row">
@@ -25,15 +39,15 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t('data-analyze.algorithm-forms.focus-detection.options.source')}
+ {t('data-analyze.algorithm-forms.all-path.options.source')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
@@ -58,7 +72,7 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t('data-analyze.algorithm-forms.focus-detection.options.label')}
+ {t('data-analyze.algorithm-forms.all-path.options.label')}
</span>
</div>
<Select
@@ -66,16 +80,16 @@ const AllPath = observer(() => {
trigger="click"
value={algorithmAnalyzerStore.allPathParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.all-path.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
algorithmAnalyzerStore.mutateAllPathParams('label', value);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.focus-detection.pre-value')}
+ {t('data-analyze.algorithm-forms.all-path.pre-value')}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -90,15 +104,15 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t('data-analyze.algorithm-forms.focus-detection.options.target')}
+ {t('data-analyze.algorithm-forms.all-path.options.target')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-target-id'
)}
errorLocation="layer"
errorMessage={
@@ -123,17 +137,41 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.max_degree'
- )}
+ {t('data-analyze.algorithm-forms.all-path.options.max_degree')}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.all-path.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
@@ -162,9 +200,7 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.direction'
- )}
+ {t('data-analyze.algorithm-forms.all-path.options.direction')}
</span>
</div>
<Radio.Group
@@ -185,17 +221,15 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.all-path.options.capacity')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
@@ -223,9 +257,7 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.max_depth'
- )}
+ {t('data-analyze.algorithm-forms.all-path.options.max_depth')}
</span>
<CustomTooltip
trigger="hover"
@@ -242,7 +274,7 @@ const AllPath = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.focus-detection.hint.max-depth'
+ 'data-analyze.algorithm-forms.all-path.hint.max-depth'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -255,11 +287,11 @@ const AllPath = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
@@ -284,34 +316,32 @@ const AllPath = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.all-path.options.limit')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.all-path.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateAllPathParamsErrorMessage.capacity
+ algorithmAnalyzerStore.validateAllPathParamsErrorMessage.limit
}
- value={algorithmAnalyzerStore.allPathParams.capacity}
+ value={algorithmAnalyzerStore.allPathParams.limit}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateAllPathParams(
- 'capacity',
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateAllPathParams('capacity');
+ algorithmAnalyzerStore.validateAllPathParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateAllPathParams('capacity');
+ algorithmAnalyzerStore.validateAllPathParams('limit');
}
}}
/>
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/CustomPath.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/CustomPath.tsx
new file mode 100644
index 0000000..92c3733
--- /dev/null
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/CustomPath.tsx
@@ -0,0 +1,1098 @@
+import React, { useContext } from 'react';
+import { observer } from 'mobx-react';
+import {
+ size,
+ flatten,
+ flattenDeep,
+ uniq,
+ isEmpty,
+ cloneDeep,
+ fromPairs
+} from 'lodash-es';
+import { Button, Radio, Input, Select } from 'hubble-ui';
+import { useTranslation } from 'react-i18next';
+
+import { styles } from '../QueryAndAlgorithmLibrary';
+import { GraphManagementStoreContext } from '../../../../stores';
+import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { isDataTypeNumeric, calcAlgorithmFormWidth } from '../../../../utils';
+
+const CustomPath = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
+ const dataAnalyzeStore = useContext(DataAnalyzeStore);
+ const { t } = useTranslation();
+ const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 390
+ );
+
+ const formWidthInStep = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 310,
+ 380
+ );
+
+ const formSmallWidthInStep = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 150,
+ 160
+ );
+
+ const sourceType = algorithmAnalyzerStore.customPathParams.method;
+
+ const allowAddNewProperty = !flatten(
+ algorithmAnalyzerStore.customPathParams.vertexProperty
+ ).some((value) => value === '');
+
+ const addNewPropertyClassName =
+ allowAddNewProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !== 'pending'
+ ? 'query-tab-content-internal-expand-manipulation-enable'
+ : 'query-tab-content-internal-expand-manipulation-disabled';
+
+ const allowAddNewRuleProperty = !flattenDeep(
+ algorithmAnalyzerStore.customPathParams.steps.map(
+ ({ properties }) => properties
+ )
+ ).some((value) => value === '');
+
+ const addNewRulePropertyClassName =
+ allowAddNewRuleProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !== 'pending'
+ ? 'query-tab-content-internal-expand-manipulation-enable'
+ : 'query-tab-content-internal-expand-manipulation-disabled';
+
+ const isValidSourceId =
+ algorithmAnalyzerStore.customPathParams.method === 'id' &&
+ algorithmAnalyzerStore.customPathParams.source !== '';
+
+ const isValidProperty =
+ algorithmAnalyzerStore.customPathParams.method === 'property' &&
+ !(
+ isEmpty(algorithmAnalyzerStore.customPathParams.vertexType) &&
+ flatten(
+ algorithmAnalyzerStore.customPathParams.vertexProperty
+ ).every((value) => isEmpty(value))
+ ) &&
+ algorithmAnalyzerStore.customPathParams.vertexProperty.every(
+ ([key, value]) => (!isEmpty(key) ? !isEmpty(value) : true)
+ );
+
+ const isValidateRuleProperties = algorithmAnalyzerStore.customPathParams.steps.every(
+ ({ properties }) => {
+ if (size(properties) === 1) {
+ return (
+ (isEmpty(properties[0][0]) && isEmpty(properties[0][1])) ||
+ (!isEmpty(properties[0][0]) && !isEmpty(properties[0][1]))
+ );
+ } else {
+ return properties.every(([, value]) => !isEmpty(value));
+ }
+ }
+ );
+
+ const isValidRuleWeight = algorithmAnalyzerStore.customPathParams.steps.every(
+ ({ weight_by, default_weight }) =>
+ algorithmAnalyzerStore.customPathParams.sort_by === 'NONE' ||
+ (weight_by === '__CUSTOM_WEIGHT__' && default_weight !== '') ||
+ (weight_by !== '__CUSTOM_WEIGHT__' && !isEmpty(weight_by))
+ );
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateCustomPathParmasErrorMessage
+ ).every((value) => Array.isArray(value) || value === '') &&
+ algorithmAnalyzerStore.validateCustomPathParmasErrorMessage.steps.every(
+ (step) => Object.values(step).every((value) => value === '')
+ ) &&
+ (algorithmAnalyzerStore.customPathParams.method === 'id'
+ ? algorithmAnalyzerStore.customPathParams.source !== ''
+ : true) &&
+ (isValidSourceId || isValidProperty) &&
+ isValidateRuleProperties &&
+ isValidRuleWeight;
+
+ const isValidAddRule = algorithmAnalyzerStore.validateCustomPathParmasErrorMessage.steps.every(
+ (step) => Object.values(step).every((value) => value === '')
+ );
+
+ return (
+ <div style={{ display: 'flex' }}>
+ <div className="query-tab-content-form" style={{ width: '50%' }}>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.custom-path.options.method')}
+ </span>
+ </div>
+ <Radio.Group
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ value={algorithmAnalyzerStore.customPathParams.method}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.switchCustomPathMethod(e.target.value);
+ }}
+ >
+ <Radio value="id">
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.radio-value.specific-id'
+ )}
+ </Radio>
+ <Radio value="property">
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.radio-value.filtered-type-property'
+ )}
+ </Radio>
+ </Radio.Group>
+ </div>
+ </div>
+
+ {sourceType === 'id' && (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.custom-path.options.source')}
+ </span>
+ </div>
+
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-source-id'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateCustomPathParmasErrorMessage
+ .source
+ }
+ value={algorithmAnalyzerStore.customPathParams.source}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'source',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateCustomPathParams('source');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathParams('source');
+ }
+ }}
+ />
+ </div>
+ </div>
+ )}
+
+ {sourceType !== 'id' && (
+ <>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.vertex-type'
+ )}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ selectorName={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.select-vertex-type'
+ )}
+ value={algorithmAnalyzerStore.customPathParams.vertexType}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.no-vertex-type'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ width={formWidth}
+ onChange={(value: string) => {
+ // switch property selections from properties of index to certain properties
+ if (
+ isEmpty(
+ algorithmAnalyzerStore.customPathParams.vertexType
+ )
+ ) {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'vertexProperty',
+ [['', '']]
+ );
+ }
+
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'vertexType',
+ value
+ );
+ }}
+ >
+ {dataAnalyzeStore.vertexTypes.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+ </div>
+
+ <div
+ className="query-tab-content-form-row"
+ style={{ marginBottom: 0 }}
+ >
+ <div
+ className="query-tab-content-form-item"
+ style={{ alignItems: 'start' }}
+ >
+ <div
+ className="query-tab-content-form-item-title large"
+ style={{ lineHeight: '32px' }}
+ >
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.vertex-property'
+ )}
+ </span>
+ </div>
+
+ <div>
+ {algorithmAnalyzerStore.customPathParams.vertexProperty.map(
+ ([key, value], propertyIndex) => {
+ const currentVertexType = dataAnalyzeStore.vertexTypes.find(
+ ({ name }) =>
+ name ===
+ algorithmAnalyzerStore.customPathParams.vertexType
+ );
+
+ return (
+ <div className="query-tab-content-internal-expand-row">
+ <Select
+ width={161}
+ size="medium"
+ trigger="click"
+ selectorName={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.select-vertex-property'
+ )}
+ value={key}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.no-properties'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ onChange={(value: string) => {
+ const vertexProperty = cloneDeep(
+ algorithmAnalyzerStore.customPathParams
+ .vertexProperty
+ );
+
+ vertexProperty[propertyIndex][0] = value;
+
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'vertexProperty',
+ vertexProperty
+ );
+ }}
+ >
+ {!isEmpty(
+ algorithmAnalyzerStore.customPathParams.vertexType
+ )
+ ? flatten(
+ currentVertexType?.property_indexes.map(
+ ({ fields }) => fields
+ )
+ )
+ .concat(currentVertexType!.primary_keys)
+ .filter(
+ (property) =>
+ !algorithmAnalyzerStore.customPathParams.vertexProperty
+ .map(([key]) => key)
+ .includes(property)
+ )
+ .map((property) => (
+ <Select.Option
+ value={property}
+ key={property}
+ >
+ {property}
+ </Select.Option>
+ ))
+ : algorithmAnalyzerStore.allPropertyIndexProperty.map(
+ (property) => (
+ <Select.Option
+ value={property}
+ key={property}
+ >
+ {property}
+ </Select.Option>
+ )
+ )}
+ </Select>
+ <div className="query-tab-content-internal-expand-input">
+ <Input
+ width={161}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-multiple-properties'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateCustomPathParmasErrorMessage
+ .vertexProperty
+ }
+ value={value}
+ onChange={(e: any) => {
+ const vertexProperty = cloneDeep(
+ algorithmAnalyzerStore.customPathParams
+ .vertexProperty
+ );
+
+ vertexProperty[propertyIndex][1] = e.value;
+
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'vertexProperty',
+ vertexProperty
+ );
+
+ algorithmAnalyzerStore.validateCustomPathParams(
+ 'vertexProperty'
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathParams(
+ 'vertexProperty'
+ );
+ }
+ }}
+ />
+ </div>
+ {size(
+ algorithmAnalyzerStore.customPathParams
+ .vertexProperty
+ ) > 1 && (
+ <div
+ style={{
+ fontSize: 14,
+ lineHeight: '32px',
+ color: '#2b65ff',
+ cursor: 'pointer'
+ }}
+ onClick={() => {
+ algorithmAnalyzerStore.removeCustomPathVertexProperty(
+ propertyIndex
+ );
+ }}
+ >
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.delete'
+ )}
+ </div>
+ )}
+ </div>
+ );
+ }
+ )}
+ </div>
+ </div>
+ </div>
+ {algorithmAnalyzerStore.customPathParams.vertexType === '' &&
+ !allowAddNewProperty &&
+ size(algorithmAnalyzerStore.customPathParams.vertexProperty) ===
+ 1 ? (
+ <div
+ className="query-tab-algorithm-hint"
+ style={{ margin: '0 0 16px 172px' }}
+ >
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.hint.vertex_type_or_property'
+ )}
+ </span>
+ </div>
+ ) : (
+ <div className={addNewPropertyClassName}>
+ <span
+ onClick={() => {
+ if (
+ allowAddNewProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !== 'pending'
+ ) {
+ algorithmAnalyzerStore.addCustomPathVertexProperty();
+ }
+ }}
+ >
+ {t('data-analyze.algorithm-forms.custom-path.add')}
+ </span>
+ </div>
+ )}
+ </>
+ )}
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.custom-path.options.sort_by')}
+ </span>
+ </div>
+ <Radio.Group
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ value={algorithmAnalyzerStore.customPathParams.sort_by}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'sort_by',
+ e.target.value
+ );
+
+ if (e.target.value === 'NONE') {
+ algorithmAnalyzerStore.customPathParams.steps.forEach(
+ (_, ruleIndex) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'weight_by',
+ '',
+ ruleIndex
+ );
+
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'default_weight',
+ '',
+ ruleIndex
+ );
+ }
+ );
+ }
+ }}
+ >
+ <Radio value="NONE">
+ {t('data-analyze.algorithm-forms.custom-path.radio-value.none')}
+ </Radio>
+ <Radio value="INCR">
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.radio-value.ascend'
+ )}
+ </Radio>
+ <Radio value="DECR">
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.radio-value.descend'
+ )}
+ </Radio>
+ </Radio.Group>
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t('data-analyze.algorithm-forms.custom-path.options.capacity')}
+ </span>
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-positive-integer-or-negative-one-capacity'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateCustomPathParmasErrorMessage
+ .capacity
+ }
+ value={algorithmAnalyzerStore.customPathParams.capacity}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'capacity',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateCustomPathParams('capacity');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathParams('capacity');
+ }
+ }}
+ />
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t('data-analyze.algorithm-forms.custom-path.options.limit')}
+ </span>
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-positive-integer-or-negative-one-limit'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateCustomPathParmasErrorMessage
+ .limit
+ }
+ value={algorithmAnalyzerStore.customPathParams.limit}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathParams(
+ 'limit',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateCustomPathParams('limit');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathParams('limit');
+ }
+ }}
+ />
+ </div>
+ </div>
+ <div
+ className="query-tab-content-form-row"
+ style={{ marginLeft: 92, justifyContent: 'flex-start' }}
+ >
+ <Button
+ type="primary"
+ style={styles.primaryButton}
+ disabled={
+ !isValidExec ||
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ onClick={async () => {
+ algorithmAnalyzerStore.switchCollapse(true);
+ dataAnalyzeStore.switchGraphLoaded(false);
+
+ const timerId = dataAnalyzeStore.addTempExecLog();
+ await dataAnalyzeStore.fetchGraphs({
+ url: 'customizedpaths',
+ type: Algorithm.customPath
+ });
+ await dataAnalyzeStore.fetchExecutionLogs();
+ window.clearTimeout(timerId);
+ }}
+ >
+ {t('data-analyze.manipulations.execution')}
+ </Button>
+ <Button
+ style={styles.primaryButton}
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ onClick={() => {
+ algorithmAnalyzerStore.resetCustomPathParams();
+ }}
+ >
+ {t('data-analyze.manipulations.reset')}
+ </Button>
+ </div>
+ </div>
+
+ <div
+ className="query-tab-content-form-expand-wrapper"
+ style={{ width: '50%' }}
+ >
+ {algorithmAnalyzerStore.customPathParams.steps.map(
+ (
+ {
+ uuid,
+ direction,
+ labels,
+ degree,
+ sample,
+ properties,
+ weight_by,
+ default_weight
+ },
+ ruleIndex
+ ) => {
+ return (
+ <div className="query-tab-content-form-expand-items" key={uuid}>
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.direction'
+ )}
+ </span>
+ </div>
+ <Radio.Group
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ value={direction}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'direction',
+ e.target.value,
+ ruleIndex
+ );
+ }}
+ >
+ <Radio value="BOTH">both</Radio>
+ <Radio value="OUT">out</Radio>
+ <Radio value="IN">in</Radio>
+ </Radio.Group>
+ {size(algorithmAnalyzerStore.customPathParams.steps) > 1 && (
+ <div
+ style={{
+ marginLeft: 175,
+ fontSize: 14,
+ color: '#2b65ff',
+ cursor: 'pointer',
+ lineHeight: '22px'
+ }}
+ onClick={() => {
+ algorithmAnalyzerStore.removeCustomPathRule(ruleIndex);
+ }}
+ >
+ åˆ é™¤
+ </div>
+ )}
+ </div>
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.labels'
+ )}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ value={labels}
+ mode="multiple"
+ showSearch={false}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.select-edge-type'
+ )}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.no-edge-type'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ width={formWidthInStep}
+ onChange={(value: string[]) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'labels',
+ value,
+ ruleIndex
+ );
+ }}
+ >
+ {dataAnalyzeStore.edgeTypes.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+
+ <div
+ className="query-tab-content-form-expand-item"
+ style={{ alignItems: 'start', marginBottom: 16 }}
+ >
+ <div
+ className="query-tab-content-form-item-title query-tab-content-form-expand-title"
+ style={{ lineHeight: '32px' }}
+ >
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.properties'
+ )}
+ </span>
+ </div>
+ <div>
+ <>
+ {properties.map(([key, value], propertyIndex) => {
+ return (
+ <div
+ style={{ display: 'flex', marginBottom: 16 }}
+ key={key}
+ >
+ <div style={{ marginRight: 8 }}>
+ <Select
+ size="medium"
+ trigger="click"
+ value={key}
+ selectorName={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.select-edge-property'
+ )}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.no-edge-property'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ width={formSmallWidthInStep}
+ onChange={(value: string) => {
+ const clonedRuleProperties = cloneDeep(
+ properties
+ );
+
+ clonedRuleProperties[
+ propertyIndex
+ ][0] = value;
+
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'properties',
+ clonedRuleProperties,
+ ruleIndex
+ );
+ }}
+ >
+ {uniq(
+ flatten(
+ dataAnalyzeStore.edgeTypes
+ .filter(({ name }) =>
+ labels.includes(name)
+ )
+ .map(({ properties }) =>
+ properties.map(({ name }) => name)
+ )
+ )
+ )
+ .filter(
+ (name) =>
+ !Object.keys(
+ fromPairs(properties)
+ ).includes(name)
+ )
+ .map((name) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+
+ <div style={{ marginRight: 8 }}>
+ <Input
+ width={formSmallWidthInStep}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-multiple-properties'
+ )}
+ value={value}
+ onChange={(e: any) => {
+ const clonedRuleProperties = cloneDeep(
+ properties
+ );
+
+ clonedRuleProperties[propertyIndex][1] =
+ e.value;
+
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'properties',
+ clonedRuleProperties,
+ ruleIndex
+ );
+ }}
+ />
+ </div>
+
+ {size(properties) > 1 && (
+ <div
+ style={{
+ fontSize: 14,
+ lineHeight: '32px',
+ color: '#2b65ff',
+ cursor: 'pointer'
+ }}
+ onClick={() => {
+ algorithmAnalyzerStore.removeCustomPathRuleProperty(
+ ruleIndex,
+ propertyIndex
+ );
+ }}
+ >
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.delete'
+ )}
+ </div>
+ )}
+ </div>
+ );
+ })}
+
+ <div
+ className={addNewRulePropertyClassName}
+ style={{
+ marginTop: 8,
+ marginBottom: 0,
+ paddingLeft: 0
+ }}
+ >
+ <span
+ onClick={() => {
+ if (
+ allowAddNewRuleProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !==
+ 'pending'
+ ) {
+ algorithmAnalyzerStore.addCustomPathRuleProperty(
+ ruleIndex
+ );
+ }
+ }}
+ >
+ {t('data-analyze.algorithm-forms.custom-path.add')}
+ </span>
+ </div>
+ </>
+ </div>
+ </div>
+
+ {algorithmAnalyzerStore.customPathParams.sort_by !== 'NONE' && (
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.weight_by'
+ )}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ value={weight_by}
+ selectorName={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.select-property'
+ )}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.no-property'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ width={formWidthInStep}
+ onChange={(value: string) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'weight_by',
+ value,
+ ruleIndex
+ );
+ }}
+ >
+ <Select.Option
+ value="__CUSTOM_WEIGHT__"
+ key="__CUSTOM_WEIGHT__"
+ >
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.custom-weight'
+ )}
+ </Select.Option>
+ {dataAnalyzeStore.allPropertiesFromEdge.map(
+ (property) => (
+ <Select.Option value={property} property={property}>
+ {property}
+ </Select.Option>
+ )
+ )}
+ </Select>
+ </div>
+ )}
+ {algorithmAnalyzerStore.customPathParams.steps[ruleIndex]
+ .weight_by === '__CUSTOM_WEIGHT__' && (
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <span></span>
+ </div>
+ <Input
+ width={formWidthInStep}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-number'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateCustomPathParmasErrorMessage.steps[ruleIndex]
+ .default_weight
+ }
+ value={default_weight}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'default_weight',
+ e.value as string,
+ ruleIndex
+ );
+
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'default_weight',
+ ruleIndex
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'default_weight',
+ ruleIndex
+ );
+ }
+ }}
+ />
+ </div>
+ )}
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.degree'
+ )}
+ </span>
+ </div>
+ <Input
+ width={formWidthInStep}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-positive-integer-or-negative-one-degree'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateCustomPathParmasErrorMessage.steps[ruleIndex]
+ .degree
+ }
+ value={degree}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'degree',
+ e.value as string,
+ ruleIndex
+ );
+
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'degree',
+ ruleIndex
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'degree',
+ ruleIndex
+ );
+ }
+ }}
+ />
+ </div>
+ <div className="query-tab-content-form-expand-item">
+ <div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.custom-path.options.sample'
+ )}
+ </span>
+ </div>
+ <Input
+ width={formWidthInStep}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.custom-path.placeholder.input-integer'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateCustomPathParmasErrorMessage.steps[ruleIndex]
+ .sample
+ }
+ value={sample}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateCustomPathRuleParams(
+ 'sample',
+ e.value as string,
+ ruleIndex
+ );
+
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'sample',
+ ruleIndex
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateCustomPathRules(
+ 'sample',
+ ruleIndex
+ );
+ }
+ }}
+ />
+ </div>
+ </div>
+ );
+ }
+ )}
+ <div
+ style={{
+ width: 'fix-content',
+ fontSize: 14,
+ color: isValidAddRule ? '#2b65ff' : '#999',
+ marginTop: 8
+ }}
+ >
+ <span
+ style={{ cursor: 'pointer' }}
+ onClick={() => {
+ if (isValidAddRule) {
+ algorithmAnalyzerStore.addCustomPathRule();
+ }
+ }}
+ >
+ {t('data-analyze.algorithm-forms.custom-path.add-new-rule')}
+ </span>
+ </div>
+ </div>
+ </div>
+ );
+});
+
+export default CustomPath;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/FocusDetection.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/FocusDetection.tsx
index f73f592..cbf4e57 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/FocusDetection.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/FocusDetection.tsx
@@ -2,16 +2,26 @@ import React, { useContext, createContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { GraphManagementStoreContext } from '../../../../stores';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
+import { calcAlgorithmFormWidth } from '../../../../utils';
const FocusDetection = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
const isValidExec =
Object.values(
@@ -32,7 +42,7 @@ const FocusDetection = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -73,7 +83,7 @@ const FocusDetection = observer(() => {
'data-analyze.algorithm-forms.focus-detection.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
algorithmAnalyzerStore.mutateFocusDetectionParams('label', value);
}}
@@ -98,7 +108,7 @@ const FocusDetection = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -132,13 +142,39 @@ const FocusDetection = observer(() => {
'data-analyze.algorithm-forms.focus-detection.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.focus-detection.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
@@ -192,33 +228,35 @@ const FocusDetection = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t('data-analyze.algorithm-forms.focus-detection.options.limit')}
+ {t(
+ 'data-analyze.algorithm-forms.focus-detection.options.capacity'
+ )}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateFocusDetectionParamsErrorMessage
- .limit
+ .capacity
}
- value={algorithmAnalyzerStore.focusDetectionParams.limit}
+ value={algorithmAnalyzerStore.focusDetectionParams.capacity}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateFocusDetectionParams(
- 'limit',
+ 'capacity',
e.value as string
);
- algorithmAnalyzerStore.validateFocusDetectionParams('limit');
+ algorithmAnalyzerStore.validateFocusDetectionParams('capacity');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateFocusDetectionParams('limit');
+ algorithmAnalyzerStore.validateFocusDetectionParams('capacity');
}
}}
/>
@@ -261,7 +299,7 @@ const FocusDetection = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -293,35 +331,33 @@ const FocusDetection = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.focus-detection.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.focus-detection.options.limit')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.focus-detection.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateFocusDetectionParamsErrorMessage
- .capacity
+ .limit
}
- value={algorithmAnalyzerStore.focusDetectionParams.capacity}
+ value={algorithmAnalyzerStore.focusDetectionParams.limit}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateFocusDetectionParams(
- 'capacity',
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateFocusDetectionParams('capacity');
+ algorithmAnalyzerStore.validateFocusDetectionParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateFocusDetectionParams('capacity');
+ algorithmAnalyzerStore.validateFocusDetectionParams('limit');
}
}}
/>
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/Jaccard.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/Jaccard.tsx
new file mode 100644
index 0000000..12764d5
--- /dev/null
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/Jaccard.tsx
@@ -0,0 +1,261 @@
+import React, { useContext } from 'react';
+import { observer } from 'mobx-react';
+import { Button, Radio, Input, Select } from 'hubble-ui';
+import { useTranslation } from 'react-i18next';
+
+import { styles } from '../QueryAndAlgorithmLibrary';
+import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
+import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
+
+import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
+
+const Jaccard = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
+ const dataAnalyzeStore = useContext(DataAnalyzeStore);
+ const { t } = useTranslation();
+ const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateJaccardParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.jaccardParams.vertex !== '' &&
+ algorithmAnalyzerStore.jaccardParams.other !== '';
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ return (
+ <div className="query-tab-content-form">
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.jaccard.options.vertex')}
+ </span>
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.jaccard.placeholder.input-source-id'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateJaccardParamsErrorMessage.vertex
+ }
+ value={algorithmAnalyzerStore.jaccardParams.vertex}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateJaccardParams(
+ 'vertex',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateJaccardParams('vertex');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateJaccardParams('vertex');
+ }
+ }}
+ />
+ </div>
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>
+ {t('data-analyze.algorithm-forms.jaccard.options.label')}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ value={algorithmAnalyzerStore.jaccardParams.label}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.jaccard.placeholder.no-edge-types'
+ )}
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ width={formWidth}
+ onChange={(value: string) => {
+ algorithmAnalyzerStore.mutateJaccardParams('label', value);
+ }}
+ >
+ <Select.Option value="__all__" key="__all__">
+ {t('data-analyze.algorithm-forms.jaccard.pre-value')}
+ </Select.Option>
+ {dataAnalyzeStore.edgeTypes.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.jaccard.options.other')}
+ </span>
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.jaccard.placeholder.input-other-id'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateJaccardParamsErrorMessage.other
+ }
+ value={algorithmAnalyzerStore.jaccardParams.other}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateJaccardParams(
+ 'other',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateJaccardParams('other');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateJaccardParams('other');
+ }
+ }}
+ />
+ </div>
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>
+ {t('data-analyze.algorithm-forms.jaccard.options.max_degree')}
+ </span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.jaccard.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.jaccard.placeholder.input-positive-integer-or-negative-one-max-degree'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateJaccardParamsErrorMessage
+ .max_degree
+ }
+ value={algorithmAnalyzerStore.jaccardParams.max_degree}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateJaccardParams(
+ 'max_degree',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateJaccardParams('max_degree');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateJaccardParams('max_degree');
+ }
+ }}
+ />
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <i>*</i>
+ <span>
+ {t('data-analyze.algorithm-forms.jaccard.options.direction')}
+ </span>
+ </div>
+ <Radio.Group
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ value={algorithmAnalyzerStore.jaccardParams.direction}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutateJaccardParams(
+ 'direction',
+ e.target.value
+ );
+ }}
+ >
+ <Radio value="BOTH">both</Radio>
+ <Radio value="OUT">out</Radio>
+ <Radio value="IN">in</Radio>
+ </Radio.Group>
+ </div>
+ </div>
+ <div
+ className="query-tab-content-form-row"
+ style={{ marginLeft: 92, justifyContent: 'flex-start' }}
+ >
+ <Button
+ type="primary"
+ style={styles.primaryButton}
+ disabled={
+ !isValidExec ||
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ onClick={async () => {
+ algorithmAnalyzerStore.switchCollapse(true);
+ dataAnalyzeStore.switchGraphLoaded(false);
+
+ const timerId = dataAnalyzeStore.addTempExecLog();
+ await dataAnalyzeStore.fetchGraphs({
+ url: 'jaccardsimilarity',
+ type: Algorithm.jaccard
+ });
+ await dataAnalyzeStore.fetchExecutionLogs();
+ window.clearTimeout(timerId);
+ }}
+ >
+ {t('data-analyze.manipulations.execution')}
+ </Button>
+ <Button
+ style={styles.primaryButton}
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ onClick={() => {
+ algorithmAnalyzerStore.resetJaccardParams();
+ }}
+ >
+ {t('data-analyze.manipulations.reset')}
+ </Button>
+ </div>
+ </div>
+ );
+});
+
+export default Jaccard;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KHop.tsx
similarity index 59%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KHop.tsx
index 82ec79a..20d434e 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KHop.tsx
@@ -1,22 +1,35 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
import { styles } from '../QueryAndAlgorithmLibrary';
+
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const KHop = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ const isValidExec =
+ Object.values(algorithmAnalyzerStore.validateKHopParamsErrorMessage).every(
+ (value) => value === ''
+ ) &&
+ algorithmAnalyzerStore.kHopParams.source !== '' &&
+ algorithmAnalyzerStore.kHopParams.max_depth !== '';
return (
<div className="query-tab-content-form">
@@ -25,65 +38,55 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
- )}
+ {t('data-analyze.algorithm-forms.k-hop.options.source')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.k-hop.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .source
+ algorithmAnalyzerStore.validateKHopParamsErrorMessage.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
+ value={algorithmAnalyzerStore.kHopParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateKHopParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateKHopParams('source');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateKHopParams('source');
}
}}
/>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
- )}
- </span>
+ <span>{t('data-analyze.algorithm-forms.k-hop.options.label')}</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={algorithmAnalyzerStore.kHopParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.k-hop.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'label',
- value
- );
+ algorithmAnalyzerStore.mutateKHopParams('label', value);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
+ {t('data-analyze.algorithm-forms.k-hop.pre-value')}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -98,95 +101,14 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .target
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'target',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_degree
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
- )}
+ {t('data-analyze.algorithm-forms.k-hop.options.direction')}
</span>
</div>
<Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
+ value={algorithmAnalyzerStore.kHopParams.direction}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateKHopParams(
'direction',
e.target.value
);
@@ -200,37 +122,58 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.k-hop.options.max_degree')}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.k-hop.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.k-hop.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore.validateKHopParamsErrorMessage.max_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
+ value={algorithmAnalyzerStore.kHopParams.max_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
+ algorithmAnalyzerStore.mutateKHopParams(
+ 'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
+ algorithmAnalyzerStore.validateKHopParams('max_degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
- );
+ algorithmAnalyzerStore.validateKHopParams('max_degree');
}
}}
/>
@@ -241,9 +184,7 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
- )}
+ {t('data-analyze.algorithm-forms.k-hop.options.max_depth')}
</span>
<CustomTooltip
trigger="hover"
@@ -260,7 +201,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ 'data-analyze.algorithm-forms.k-hop.hint.max-depth'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -273,31 +214,28 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.k-hop.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_depth
+ algorithmAnalyzerStore.validateKHopParamsErrorMessage.max_depth
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
+ value={algorithmAnalyzerStore.kHopParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateKHopParams(
'max_depth',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
+ algorithmAnalyzerStore.validateKHopParams('max_depth');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_depth'
- );
+ algorithmAnalyzerStore.validateKHopParams('max_depth');
}
}}
/>
@@ -305,9 +243,42 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
- )}
+ {t('data-analyze.algorithm-forms.k-hop.options.capacity')}
+ </span>
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.k-hop.placeholder.input-positive-integer-or-negative-one-capacity'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateKHopParamsErrorMessage.capacity
+ }
+ value={algorithmAnalyzerStore.kHopParams.capacity}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateKHopParams(
+ 'capacity',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateKHopParams('capacity');
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateKHopParams('capacity');
+ }
+ }}
+ />
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>
+ {t('data-analyze.algorithm-forms.k-hop.options.nearest')}
</span>
<CustomTooltip
trigger="hover"
@@ -324,7 +295,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
+ 'data-analyze.algorithm-forms.k-hop.hint.shortest-path'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -336,34 +307,42 @@ const ShortestPathAll = observer(() => {
childrenWrapperElement="img"
/>
</div>
+ <Switch
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ checked={algorithmAnalyzerStore.kHopParams.nearest}
+ onChange={(checked: boolean) => {
+ algorithmAnalyzerStore.mutateKHopParams('nearest', checked);
+ }}
+ />
+ </div>
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>{t('data-analyze.algorithm-forms.k-hop.options.limit')}</span>
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.k-hop.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .skip_degree
+ algorithmAnalyzerStore.validateKHopParamsErrorMessage.limit
}
- value={algorithmAnalyzerStore.shortestPathAllParams.skip_degree}
+ value={algorithmAnalyzerStore.kHopParams.limit}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'skip_degree',
+ algorithmAnalyzerStore.mutateKHopParams(
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
+ algorithmAnalyzerStore.validateKHopParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
+ algorithmAnalyzerStore.validateKHopParams('limit');
}
}}
/>
@@ -386,8 +365,8 @@ const ShortestPathAll = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'allshortpath',
- type: Algorithm.shortestPathAll
+ url: 'kout',
+ type: Algorithm.kHop
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -399,7 +378,7 @@ const ShortestPathAll = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetKHopParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -409,4 +388,4 @@ const ShortestPathAll = observer(() => {
);
});
-export default ShortestPathAll;
+export default KHop;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KStepNeighbor.tsx
similarity index 57%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KStepNeighbor.tsx
index 50f62eb..4f22cdb 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/KStepNeighbor.tsx
@@ -1,25 +1,35 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
+import { Button, Radio, Input, Select } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-const LoopDetection = observer(() => {
- const { t } = useTranslation();
+const KStepNeighbor = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
const isValidExec =
Object.values(
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateKStepNeighborParamsErrorMessage
).every((value) => value === '') &&
- algorithmAnalyzerStore.loopDetectionParams.source !== '' &&
- algorithmAnalyzerStore.loopDetectionParams.max_depth !== '';
+ algorithmAnalyzerStore.kStepNeighborParams.source !== '' &&
+ algorithmAnalyzerStore.kStepNeighborParams.max_depth !== '';
return (
<div className="query-tab-content-form">
@@ -28,33 +38,33 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t('data-analyze.algorithm-forms.loop-detection.options.source')}
+ {t('data-analyze.algorithm-forms.k-step-neighbor.options.source')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.k-step-neighbor.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateKStepNeighborParamsErrorMessage
.source
}
- value={algorithmAnalyzerStore.loopDetectionParams.source}
+ value={algorithmAnalyzerStore.kStepNeighborParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('source');
+ algorithmAnalyzerStore.validateKStepNeighborParams('source');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('source');
+ algorithmAnalyzerStore.validateKStepNeighborParams('source');
}
}}
/>
@@ -62,24 +72,24 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t('data-analyze.algorithm-forms.loop-detection.options.label')}
+ {t('data-analyze.algorithm-forms.k-step-neighbor.options.label')}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.loopDetectionParams.label}
+ value={algorithmAnalyzerStore.kStepNeighborParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.k-step-neighbor.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams('label', value);
+ algorithmAnalyzerStore.mutateKStepNeighborParams('label', value);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.loop-detection.pre-value')}
+ {t('data-analyze.algorithm-forms.k-step-neighbor.pre-value')}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -95,15 +105,15 @@ const LoopDetection = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.loop-detection.options.direction'
+ 'data-analyze.algorithm-forms.k-step-neighbor.options.direction'
)}
</span>
</div>
<Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.loopDetectionParams.direction}
+ value={algorithmAnalyzerStore.kStepNeighborParams.direction}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
'direction',
e.target.value
);
@@ -118,34 +128,60 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.loop-detection.options.max_degree'
+ 'data-analyze.algorithm-forms.k-step-neighbor.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.k-step-neighbor.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.k-step-neighbor.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateKStepNeighborParamsErrorMessage
.max_degree
}
- value={algorithmAnalyzerStore.loopDetectionParams.max_degree}
+ value={algorithmAnalyzerStore.kStepNeighborParams.max_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('max_degree');
+ algorithmAnalyzerStore.validateKStepNeighborParams('max_degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams(
+ algorithmAnalyzerStore.validateKStepNeighborParams(
'max_degree'
);
}
@@ -159,7 +195,7 @@ const LoopDetection = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.loop-detection.options.max_depth'
+ 'data-analyze.algorithm-forms.k-step-neighbor.options.max_depth'
)}
</span>
<CustomTooltip
@@ -177,7 +213,7 @@ const LoopDetection = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.loop-detection.hint.max-depth'
+ 'data-analyze.algorithm-forms.k-step-neighbor.hint.max-depth'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -190,29 +226,29 @@ const LoopDetection = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.k-step-neighbor.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateKStepNeighborParamsErrorMessage
.max_depth
}
- value={algorithmAnalyzerStore.loopDetectionParams.max_depth}
+ value={algorithmAnalyzerStore.kStepNeighborParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
'max_depth',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('max_depth');
+ algorithmAnalyzerStore.validateKStepNeighborParams('max_depth');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('max_depth');
+ algorithmAnalyzerStore.validateKStepNeighborParams('max_depth');
}
}}
/>
@@ -220,93 +256,33 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t('data-analyze.algorithm-forms.loop-detection.options.limit')}
+ {t('data-analyze.algorithm-forms.k-step-neighbor.options.limit')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.k-step-neighbor.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateKStepNeighborParamsErrorMessage
.limit
}
- value={algorithmAnalyzerStore.loopDetectionParams.limit}
+ value={algorithmAnalyzerStore.kStepNeighborParams.limit}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
+ algorithmAnalyzerStore.mutateKStepNeighborParams(
'limit',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('limit');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('limit');
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.loop-detection.options.source_in_ring'
- )}
- </span>
- </div>
- <Switch
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- checked={algorithmAnalyzerStore.loopDetectionParams.source_in_ring}
- onChange={(checked: boolean) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'source_in_ring',
- checked
- );
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.loop-detection.options.capacity'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .capacity
- }
- value={algorithmAnalyzerStore.loopDetectionParams.capacity}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'capacity',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateLoopDetectionParams('capacity');
+ algorithmAnalyzerStore.validateKStepNeighborParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('capacity');
+ algorithmAnalyzerStore.validateKStepNeighborParams('limit');
}
}}
/>
@@ -329,8 +305,8 @@ const LoopDetection = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'rings',
- type: Algorithm.loopDetection
+ url: 'kneighbor',
+ type: Algorithm.kStepNeighbor
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -342,7 +318,7 @@ const LoopDetection = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetLoopDetectionParams();
+ algorithmAnalyzerStore.resetKStepNeighborParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -352,4 +328,4 @@ const LoopDetection = observer(() => {
);
});
-export default LoopDetection;
+export default KStepNeighbor;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
index 50f62eb..0e24bd9 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
@@ -1,18 +1,28 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { GraphManagementStoreContext } from '../../../../stores';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
const LoopDetection = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
const isValidExec =
Object.values(
@@ -32,7 +42,7 @@ const LoopDetection = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -73,7 +83,7 @@ const LoopDetection = observer(() => {
'data-analyze.algorithm-forms.loop-detection.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
algorithmAnalyzerStore.mutateLoopDetectionParams('label', value);
}}
@@ -121,13 +131,39 @@ const LoopDetection = observer(() => {
'data-analyze.algorithm-forms.loop-detection.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.loop-detection.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
@@ -190,7 +226,7 @@ const LoopDetection = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -224,11 +260,11 @@ const LoopDetection = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
@@ -263,7 +299,6 @@ const LoopDetection = observer(() => {
</span>
</div>
<Switch
- width={400}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
checked={algorithmAnalyzerStore.loopDetectionParams.source_in_ring}
@@ -284,11 +319,11 @@ const LoopDetection = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ModelSimilarity.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ModelSimilarity.tsx
index af4c7bc..554a456 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ModelSimilarity.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ModelSimilarity.tsx
@@ -1,266 +1,427 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { size } from 'lodash-es';
+import { flatten, cloneDeep, size, isEmpty } from 'lodash-es';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
const ModelSimilarity = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 390
+ );
const sourceType = algorithmAnalyzerStore.modelSimilarityParams.method;
+ const allowAddNewProperty = !flatten(
+ algorithmAnalyzerStore.modelSimilarityParams.vertexProperty
+ ).some((value) => value === '');
+
+ const addNewPropertyClassName =
+ allowAddNewProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !== 'pending'
+ ? 'query-tab-content-internal-expand-manipulation-enable'
+ : 'query-tab-content-internal-expand-manipulation-disabled';
+
+ const isValidSourceId =
+ algorithmAnalyzerStore.modelSimilarityParams.method === 'id' &&
+ algorithmAnalyzerStore.modelSimilarityParams.source !== '';
+
+ const isValidProperty =
+ algorithmAnalyzerStore.modelSimilarityParams.method === 'property' &&
+ !(
+ isEmpty(algorithmAnalyzerStore.modelSimilarityParams.vertexType) &&
+ flatten(
+ algorithmAnalyzerStore.modelSimilarityParams.vertexProperty
+ ).every((value) => isEmpty(value))
+ ) &&
+ algorithmAnalyzerStore.modelSimilarityParams.vertexProperty.every(
+ ([key, value]) => (!isEmpty(key) ? !isEmpty(value) : true)
+ );
+
const isValidExec =
Object.values(
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
).every((value) => value === '') &&
algorithmAnalyzerStore.modelSimilarityParams.least_neighbor !== '' &&
algorithmAnalyzerStore.modelSimilarityParams.similarity !== '' &&
- (algorithmAnalyzerStore.modelSimilarityParams.property_filter !== ''
+ (!isEmpty(algorithmAnalyzerStore.modelSimilarityParams.property_filter)
? algorithmAnalyzerStore.modelSimilarityParams.least_property_number !==
''
: true) &&
- ((algorithmAnalyzerStore.modelSimilarityParams.method === 'id' &&
- algorithmAnalyzerStore.modelSimilarityParams.source !== '') ||
- algorithmAnalyzerStore.modelSimilarityParams.method === 'property');
+ (isValidSourceId || isValidProperty);
return (
- <div className="query-tab-content-form">
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.method'
- )}
- </span>
- </div>
- <Radio.Group
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.modelSimilarityParams.method}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.switchModelSimilarityMethod(
- e.target.value
- );
- }}
- >
- <Radio value="id">
- {t(
- 'data-analyze.algorithm-forms.model-similarity.radio-value.specific-id'
- )}
- </Radio>
- <Radio value="property">
- {t(
- 'data-analyze.algorithm-forms.model-similarity.radio-value.filtered-type-property'
- )}
- </Radio>
- </Radio.Group>
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.property_filter'
- )}
- </span>
- </div>
- <Select
- size="medium"
- trigger="click"
- selectorName={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-filtered-property'
- )}
- value={algorithmAnalyzerStore.modelSimilarityParams.property_filter}
- notFoundContent={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.no-properties'
- )}
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
- onChange={(value: string) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'property_filter',
- value
- );
- }}
- >
- {dataAnalyzeStore.properties.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- </div>
- </div>
-
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- {sourceType === 'id' && <i>*</i>}
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.source'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.vertex-type'
- )}
- </span>
- </div>
- {sourceType === 'id' ? (
- <Input
- width={400}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .source
- }
- value={algorithmAnalyzerStore.modelSimilarityParams.source}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'source',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateModelSimilarityParams('source');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'source'
- );
- }
- }}
- />
- ) : (
- <Select
- size="medium"
- trigger="click"
- selectorName={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-vertex-type'
- )}
- value={algorithmAnalyzerStore.modelSimilarityParams.vertexType}
- notFoundContent={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.no-vertex-type'
- )}
+ <div style={{ display: 'flex' }}>
+ <div className="query-tab-content-form" style={{ width: '50%' }}>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div
+ className="query-tab-content-form-item-title large"
+ style={{ lineHeight: '32px' }}
+ >
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.method'
+ )}
+ </span>
+ </div>
+ <Radio.Group
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- width={400}
- onChange={(value: string) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'vertexType',
- value
+ value={algorithmAnalyzerStore.modelSimilarityParams.method}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.switchModelSimilarityMethod(
+ e.target.value
);
}}
>
- {dataAnalyzeStore.vertexTypes.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- )}
+ <Radio value="id">
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.radio-value.specific-id'
+ )}
+ </Radio>
+ <Radio value="property">
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.radio-value.filtered-type-property'
+ )}
+ </Radio>
+ </Radio.Group>
+ </div>
</div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.least_property_number'
- )}
- </span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
+
+ {sourceType === 'id' && (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.source'
+ )}
+ </span>
+ </div>
+
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.model-similarity.hint.least_property_number'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
+ placeholder={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateModelSimilartiyParamsErrorMessage.source
}
- }}
- childrenWrapperElement="img"
- />
+ value={algorithmAnalyzerStore.modelSimilarityParams.source}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'source',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'source'
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'source'
+ );
+ }
+ }}
+ />
+ </div>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer-gt-1'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .least_property_number
- }
- value={
- algorithmAnalyzerStore.modelSimilarityParams.least_property_number
- }
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'least_property_number',
- e.value as string
- );
+ )}
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_property_number'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_property_number'
- );
- }
- }}
- />
- </div>
- </div>
+ {sourceType !== 'id' && (
+ <>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.vertex-type'
+ )}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ selectorName={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-vertex-type'
+ )}
+ value={
+ algorithmAnalyzerStore.modelSimilarityParams.vertexType
+ }
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.no-vertex-type'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ width={formWidth}
+ onChange={(value: string) => {
+ // switch property selections from properties of index to certain properties
+ if (
+ isEmpty(
+ algorithmAnalyzerStore.modelSimilarityParams.vertexType
+ )
+ ) {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'vertexProperty',
+ [['', '']]
+ );
+ }
+
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'vertexType',
+ value
+ );
+ }}
+ >
+ {dataAnalyzeStore.vertexTypes.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+ </div>
+
+ <div
+ className="query-tab-content-form-row"
+ style={{ marginBottom: 0 }}
+ >
+ <div
+ className="query-tab-content-form-item"
+ style={{ alignItems: 'start' }}
+ >
+ <div
+ className="query-tab-content-form-item-title large"
+ style={{ lineHeight: '32px' }}
+ >
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.vertex-property'
+ )}
+ </span>
+ </div>
+
+ <div>
+ {algorithmAnalyzerStore.modelSimilarityParams.vertexProperty.map(
+ ([key, value], propertyIndex) => {
+ const currentVertexType = dataAnalyzeStore.vertexTypes.find(
+ ({ name }) =>
+ name ===
+ algorithmAnalyzerStore.modelSimilarityParams
+ .vertexType
+ );
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- {sourceType === 'id' && <i>*</i>}
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.direction'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.vertex-property'
+ return (
+ <div className="query-tab-content-internal-expand-row">
+ <Select
+ width={161}
+ size="medium"
+ trigger="click"
+ placeholder={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.select-vertex-property'
+ )}
+ value={key}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.no-properties'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ onChange={(value: string) => {
+ const vertexProperty = cloneDeep(
+ algorithmAnalyzerStore.modelSimilarityParams
+ .vertexProperty
+ );
+
+ vertexProperty[propertyIndex][0] = value;
+
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'vertexProperty',
+ vertexProperty
+ );
+ }}
+ >
+ {!isEmpty(
+ algorithmAnalyzerStore.modelSimilarityParams
+ .vertexType
+ )
+ ? flatten(
+ currentVertexType?.property_indexes.map(
+ ({ fields }) => fields
+ )
+ )
+ .concat(currentVertexType!.primary_keys)
+ .filter(
+ (property) =>
+ !algorithmAnalyzerStore.modelSimilarityParams.vertexProperty
+ .map(([key]) => key)
+ .includes(property)
+ )
+ .map((property) => (
+ <Select.Option
+ value={property}
+ key={property}
+ >
+ {property}
+ </Select.Option>
+ ))
+ : algorithmAnalyzerStore.allPropertyIndexProperty.map(
+ (property) => (
+ <Select.Option
+ value={property}
+ key={property}
+ >
+ {property}
+ </Select.Option>
+ )
+ )}
+ </Select>
+ <div className="query-tab-content-internal-expand-input">
+ <Input
+ width={161}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs ===
+ 'pending'
+ }
+ placeholder={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-vertex-property'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateModelSimilartiyParamsErrorMessage
+ .vertexProperty
+ }
+ value={value}
+ onChange={(e: any) => {
+ const vertexProperty = cloneDeep(
+ algorithmAnalyzerStore.modelSimilarityParams
+ .vertexProperty
+ );
+
+ vertexProperty[propertyIndex][1] = e.value;
+
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'vertexProperty',
+ vertexProperty
+ );
+
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'vertexProperty'
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'vertexProperty'
+ );
+ }
+ }}
+ />
+ </div>
+ {size(
+ algorithmAnalyzerStore.modelSimilarityParams
+ .vertexProperty
+ ) > 1 && (
+ <div
+ style={{
+ fontSize: 14,
+ lineHeight: '32px',
+ color: '#2b65ff',
+ cursor: 'pointer'
+ }}
+ onClick={() => {
+ algorithmAnalyzerStore.removeModelSimilarityVertexProperty(
+ propertyIndex
+ );
+ }}
+ >
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.delete'
+ )}
+ </div>
+ )}
+ </div>
+ );
+ }
)}
- </span>
- </div>
- {sourceType === 'id' ? (
+ </div>
+ </div>
+ </div>
+ {algorithmAnalyzerStore.modelSimilarityParams.vertexType === '' &&
+ !allowAddNewProperty &&
+ size(
+ algorithmAnalyzerStore.modelSimilarityParams.vertexProperty
+ ) === 1 ? (
+ <div
+ className="query-tab-algorithm-hint"
+ style={{ margin: '0 0 16px 172px' }}
+ >
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.hint.vertex_type_or_property'
+ )}
+ </span>
+ </div>
+ ) : (
+ <div className={addNewPropertyClassName}>
+ <span
+ onClick={() => {
+ if (
+ allowAddNewProperty &&
+ dataAnalyzeStore.requestStatus.fetchGraphs !== 'pending'
+ ) {
+ algorithmAnalyzerStore.addModelSimilarityVertexProperty();
+ }
+ }}
+ >
+ {t('data-analyze.algorithm-forms.model-similarity.add')}
+ </span>
+ </div>
+ )}
+ </>
+ )}
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.direction'
+ )}
+ </span>
+ </div>
<Radio.Group
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
@@ -277,101 +438,18 @@ const ModelSimilarity = observer(() => {
<Radio value="OUT">out</Radio>
<Radio value="IN">in</Radio>
</Radio.Group>
- ) : (
- <Select
- width={400}
- mode="multiple"
- size="medium"
- trigger="click"
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-vertex-property'
- )}
- value={
- algorithmAnalyzerStore.modelSimilarityParams.vertexProperty
- }
- notFoundContent={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.no-properties'
- )}
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- onChange={(value: string[]) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'vertexProperty',
- value
- );
- }}
- >
- {dataAnalyzeStore.vertexTypes
- .find(
- ({ name }) =>
- name ===
- algorithmAnalyzerStore.modelSimilarityParams.vertexType
- )
- ?.properties.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.max_degree'
- )}
- </span>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .max_degree
- }
- value={algorithmAnalyzerStore.modelSimilarityParams.max_degree}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'max_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_degree'
- );
- }
- }}
- />
</div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <i>*</i>
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.least_neighbor'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.direction'
- )}
- </span>
- {sourceType === 'id' && (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.least_neighbor'
+ )}
+ </span>
<CustomTooltip
trigger="hover"
placement="bottom-start"
@@ -398,17 +476,15 @@ const ModelSimilarity = observer(() => {
}}
childrenWrapperElement="img"
/>
- )}
- </div>
- {sourceType === 'id' ? (
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
@@ -436,120 +512,54 @@ const ModelSimilarity = observer(() => {
}
}}
/>
- ) : (
- <Radio.Group
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- value={algorithmAnalyzerStore.modelSimilarityParams.direction}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'direction',
- e.target.value
- );
- }}
- >
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.capacity'
- )}
- </span>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .capacity
- }
- value={algorithmAnalyzerStore.modelSimilarityParams.capacity}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'capacity',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateModelSimilarityParams('capacity');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'capacity'
- );
- }
- }}
- />
</div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <i>*</i>
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.similarity'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.least_neighbor'
- )}
- </span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={
- sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.hint.similarity'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.hint.least_neighbor'
- )
- }
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
- </div>
- {sourceType === 'id' ? (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <i>*</i>
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.similarity'
+ )}
+ </span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.model-similarity.hint.similarity'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
+ </div>
+
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.similarity'
)}
errorLocation="layer"
errorMessage={
@@ -575,100 +585,56 @@ const ModelSimilarity = observer(() => {
}
}}
/>
- ) : (
- <Input
- width={400}
+ </div>
+ </div>
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.label'
+ )}
+ </span>
+ </div>
+ <Select
size="medium"
+ trigger="click"
+ value={algorithmAnalyzerStore.modelSimilarityParams.label}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.no-edge-types'
+ )}
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .least_neighbor
- }
- value={
- algorithmAnalyzerStore.modelSimilarityParams.least_neighbor
- }
- onChange={(e: any) => {
+ width={formWidth}
+ onChange={(value: string) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'least_neighbor',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_neighbor'
+ 'label',
+ value
);
}}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_neighbor'
- );
- }
- }}
- />
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.skip_degree'
- )}
- </span>
+ >
+ <Select.Option value="__all__" key="__all__">
+ {t('data-analyze.algorithm-forms.model-similarity.pre-value')}
+ </Select.Option>
+ {dataAnalyzeStore.edgeTypes.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .skip_degree
- }
- value={algorithmAnalyzerStore.modelSimilarityParams.skip_degree}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'skip_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'skip_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'skip_degree'
- );
- }
- }}
- />
</div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- {sourceType !== 'id' && <i>*</i>}
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.label'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.similarity'
- )}
- </span>
- {sourceType !== 'id' && (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.max_similar'
+ )}
+ </span>
<CustomTooltip
trigger="hover"
placement="bottom-start"
@@ -684,7 +650,7 @@ const ModelSimilarity = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.model-similarity.hint.similarity'
+ 'data-analyze.algorithm-forms.model-similarity.hint.max_similar'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -695,122 +661,176 @@ const ModelSimilarity = observer(() => {
}}
childrenWrapperElement="img"
/>
- )}
- </div>
- {sourceType === 'id' ? (
- <Select
+ </div>
+ <Input
+ width={formWidth}
size="medium"
- trigger="click"
- value={algorithmAnalyzerStore.modelSimilarityParams.label}
- notFoundContent={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.no-edge-types'
- )}
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- width={400}
- onChange={(value: string) => {
+ placeholder={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
+ .max_similar
+ }
+ value={algorithmAnalyzerStore.modelSimilarityParams.max_similar}
+ onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'label',
- value
+ 'max_similar',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'max_similar'
);
}}
- >
- <Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.model-similarity.pre-value')}
- </Select.Option>
- {dataAnalyzeStore.edgeTypes.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- ) : (
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateModelSimilarityParams(
+ 'max_similar'
+ );
+ }
+ }}
+ />
+ </div>
+ </div>
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.least_similar'
+ )}
+ </span>
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .similarity
+ .least_similar
}
- value={algorithmAnalyzerStore.modelSimilarityParams.similarity}
+ value={algorithmAnalyzerStore.modelSimilarityParams.least_similar}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'similarity',
+ 'least_similar',
e.value as string
);
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'similarity'
+ 'least_similar'
);
}}
originInputProps={{
onBlur() {
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'similarity'
+ 'least_similar'
);
}
}}
/>
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t('data-analyze.algorithm-forms.model-similarity.options.limit')}
- </span>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .limit
+ </div>
+
+ <div
+ className="query-tab-content-form-row"
+ style={{ marginLeft: 92, justifyContent: 'flex-start' }}
+ >
+ <Button
+ type="primary"
+ style={styles.primaryButton}
+ disabled={
+ !isValidExec ||
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- value={algorithmAnalyzerStore.modelSimilarityParams.limit}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'limit',
- e.value as string
- );
+ onClick={async () => {
+ algorithmAnalyzerStore.switchCollapse(true);
+ dataAnalyzeStore.switchGraphLoaded(false);
- algorithmAnalyzerStore.validateModelSimilarityParams('limit');
+ const timerId = dataAnalyzeStore.addTempExecLog();
+ await dataAnalyzeStore.fetchGraphs({
+ url: 'fsimilarity',
+ type: Algorithm.modelSimilarity
+ });
+ await dataAnalyzeStore.fetchExecutionLogs();
+ window.clearTimeout(timerId);
}}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams('limit');
- }
+ >
+ {t('data-analyze.manipulations.execution')}
+ </Button>
+ <Button
+ style={styles.primaryButton}
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ onClick={() => {
+ algorithmAnalyzerStore.resetModelSimilarityParams();
}}
- />
+ >
+ {t('data-analyze.manipulations.reset')}
+ </Button>
</div>
</div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- {sourceType === 'id' && <i>*</i>}
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.max_similar'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.label'
- )}
- </span>
- {sourceType === 'id' && (
+ <div className="query-tab-content-form" style={{ width: '50%' }}>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.property_filter'
+ )}
+ </span>
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ selectorName={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-filtered-property'
+ )}
+ value={
+ algorithmAnalyzerStore.modelSimilarityParams.property_filter
+ }
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.no-properties'
+ )}
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ width={formWidth}
+ onChange={(value: string) => {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'property_filter',
+ value
+ );
+ }}
+ >
+ {dataAnalyzeStore.properties.map(({ name }) => (
+ <Select.Option value={name} key={name}>
+ {name}
+ </Select.Option>
+ ))}
+ </Select>
+ </div>
+ </div>
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.least_property_number'
+ )}
+ </span>
<CustomTooltip
trigger="hover"
placement="bottom-start"
@@ -826,7 +846,7 @@ const ModelSimilarity = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.model-similarity.hint.max_similar'
+ 'data-analyze.algorithm-forms.model-similarity.hint.least_property_number'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -837,142 +857,54 @@ const ModelSimilarity = observer(() => {
}}
childrenWrapperElement="img"
/>
- )}
- </div>
- {sourceType === 'id' ? (
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer-gt-1'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .max_similar
+ .least_property_number
+ }
+ value={
+ algorithmAnalyzerStore.modelSimilarityParams
+ .least_property_number
}
- value={algorithmAnalyzerStore.modelSimilarityParams.max_similar}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'max_similar',
+ 'least_property_number',
e.value as string
);
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_similar'
+ 'least_property_number'
);
}}
originInputProps={{
onBlur() {
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_similar'
+ 'least_property_number'
);
}
}}
/>
- ) : (
- <Select
- size="medium"
- trigger="click"
- value={algorithmAnalyzerStore.modelSimilarityParams.label}
- notFoundContent={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.no-edge-types'
- )}
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- width={400}
- onChange={(value: string) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'label',
- value
- );
- }}
- >
- <Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.model-similarity.pre-value')}
- </Select.Option>
- {dataAnalyzeStore.edgeTypes.map(({ name }) => (
- <Select.Option value={name} key={name}>
- {name}
- </Select.Option>
- ))}
- </Select>
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.return_common_connection'
- )}
- </span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.model-similarity.hint.return_common_connection'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
- </div>
- <div style={{ width: 400 }}>
- <Switch
- width={40}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- checked={
- algorithmAnalyzerStore.modelSimilarityParams
- .return_common_connection
- }
- onChange={(checked: boolean) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'return_common_connection',
- checked
- );
- }}
- />
</div>
</div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- {sourceType !== 'id' && <i>*</i>}
- <span>
- {sourceType === 'id'
- ? t(
- 'data-analyze.algorithm-forms.model-similarity.options.least_similar'
- )
- : t(
- 'data-analyze.algorithm-forms.model-similarity.options.max_similar'
- )}
- </span>
- {sourceType !== 'id' && (
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.max_degree'
+ )}
+ </span>
<CustomTooltip
trigger="hover"
placement="bottom-start"
@@ -988,7 +920,7 @@ const ModelSimilarity = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.model-similarity.hint.max_similar'
+ 'data-analyze.algorithm-forms.model-similarity.hint.max-degree'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -999,190 +931,216 @@ const ModelSimilarity = observer(() => {
}}
childrenWrapperElement="img"
/>
- )}
- </div>
- {sourceType === 'id' ? (
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .least_similar
+ .max_degree
}
- value={algorithmAnalyzerStore.modelSimilarityParams.least_similar}
+ value={algorithmAnalyzerStore.modelSimilarityParams.max_degree}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'least_similar',
+ 'max_degree',
e.value as string
);
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_similar'
+ 'max_degree'
);
}}
originInputProps={{
onBlur() {
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_similar'
+ 'max_degree'
);
}
}}
/>
- ) : (
+ </div>
+ </div>
+
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.capacity'
+ )}
+ </span>
+ </div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .max_similar
+ .capacity
}
- value={algorithmAnalyzerStore.modelSimilarityParams.max_similar}
+ value={algorithmAnalyzerStore.modelSimilarityParams.capacity}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'max_similar',
+ 'capacity',
e.value as string
);
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_similar'
+ 'capacity'
);
}}
originInputProps={{
onBlur() {
algorithmAnalyzerStore.validateModelSimilarityParams(
- 'max_similar'
+ 'capacity'
);
}
}}
/>
- )}
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title large">
- <span>
- {t(
- 'data-analyze.algorithm-forms.model-similarity.options.return_complete_info'
- )}
- </span>
- </div>
- <div style={{ width: 400 }}>
- <Switch
- width={40}
- size="medium"
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- checked={
- algorithmAnalyzerStore.modelSimilarityParams
- .return_complete_info
- }
- onChange={(checked: boolean) => {
- algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'return_complete_info',
- checked
- );
- }}
- />
</div>
</div>
- </div>
- {sourceType !== 'id' && (
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title large">
<span>
{t(
- 'data-analyze.algorithm-forms.model-similarity.options.least_similar'
+ 'data-analyze.algorithm-forms.model-similarity.options.limit'
)}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.model-similarity.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.model-similarity.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
algorithmAnalyzerStore.validateModelSimilartiyParamsErrorMessage
- .least_similar
+ .limit
}
- value={algorithmAnalyzerStore.modelSimilarityParams.least_similar}
+ value={algorithmAnalyzerStore.modelSimilarityParams.limit}
onChange={(e: any) => {
algorithmAnalyzerStore.mutateModelSimilarityParams(
- 'least_similar',
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_similar'
- );
+ algorithmAnalyzerStore.validateModelSimilarityParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateModelSimilarityParams(
- 'least_similar'
- );
+ algorithmAnalyzerStore.validateModelSimilarityParams('limit');
}
}}
/>
</div>
</div>
- )}
- <div
- className="query-tab-content-form-row"
- style={{ marginLeft: 92, justifyContent: 'flex-start' }}
- >
- <Button
- type="primary"
- style={styles.primaryButton}
- disabled={
- !isValidExec ||
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- onClick={async () => {
- algorithmAnalyzerStore.switchCollapse(true);
- dataAnalyzeStore.switchGraphLoaded(false);
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.return_common_connection'
+ )}
+ </span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.model-similarity.hint.return_common_connection'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
+ </div>
+ <div style={{ width: formWidth }}>
+ <Switch
+ width={40}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ checked={
+ algorithmAnalyzerStore.modelSimilarityParams
+ .return_common_connection
+ }
+ onChange={(checked: boolean) => {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'return_common_connection',
+ checked
+ );
+ }}
+ />
+ </div>
+ </div>
+ </div>
- const timerId = dataAnalyzeStore.addTempExecLog();
- await dataAnalyzeStore.fetchGraphs({
- url: 'fsimilarity',
- type: Algorithm.modelSimilarity
- });
- await dataAnalyzeStore.fetchExecutionLogs();
- window.clearTimeout(timerId);
- }}
- >
- {t('data-analyze.manipulations.execution')}
- </Button>
- <Button
- style={styles.primaryButton}
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
- }}
- >
- {t('data-analyze.manipulations.reset')}
- </Button>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title large">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.model-similarity.options.return_complete_info'
+ )}
+ </span>
+ </div>
+ <div style={{ width: formWidth }}>
+ <Switch
+ width={40}
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
+ }
+ checked={
+ algorithmAnalyzerStore.modelSimilarityParams
+ .return_complete_info
+ }
+ onChange={(checked: boolean) => {
+ algorithmAnalyzerStore.mutateModelSimilarityParams(
+ 'return_complete_info',
+ checked
+ );
+ }}
+ />
+ </div>
+ </div>
+ </div>
</div>
</div>
);
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/NeighborRank.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/NeighborRank.tsx
index 5341571..472919d 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/NeighborRank.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/NeighborRank.tsx
@@ -1,22 +1,35 @@
import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { size, last } from 'lodash-es';
+import { size } from 'lodash-es';
import { useTranslation } from 'react-i18next';
-import classnames from 'classnames';
import { styles } from '../QueryAndAlgorithmLibrary';
import { Button, Radio, Input, Select } from 'hubble-ui';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-import { NeighborRankRule } from '../../../../stores/types/GraphManagementStore/dataAnalyzeStore';
const NeighborRank = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ const formWidthInStep = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 310,
+ 380
+ );
const isValidExec =
Object.values(
@@ -28,17 +41,9 @@ const NeighborRank = observer(() => {
algorithmAnalyzerStore.neighborRankParams.source !== '' &&
algorithmAnalyzerStore.neighborRankParams.alpha !== '';
- const isValidAddRule =
- algorithmAnalyzerStore.validateNeighborRankParamsParamsErrorMessage.steps.every(
- (step) => Object.values(step).every((value) => value === '')
- ) && algorithmAnalyzerStore.duplicateNeighborRankRuleSet.size === 0;
-
- const invalidExtendFormClassname = (flag: boolean) => {
- return classnames({
- 'query-tab-content-form-expand-items': true,
- 'query-tab-content-form-expand-items-invalid': flag
- });
- };
+ const isValidAddRule = algorithmAnalyzerStore.validateNeighborRankParamsParamsErrorMessage.steps.every(
+ (step) => Object.values(step).every((value) => value === '')
+ );
return (
<div style={{ display: 'flex' }}>
@@ -55,7 +60,7 @@ const NeighborRank = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
@@ -97,7 +102,7 @@ const NeighborRank = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
@@ -127,37 +132,6 @@ const NeighborRank = observer(() => {
/>
</div>
</div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div
- className="query-tab-content-form-item-title"
- style={{ width: 105 }}
- >
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.neighbor-rank.options.direction'
- )}
- </span>
- </div>
- <Radio.Group
- disabled={
- dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
- }
- value={algorithmAnalyzerStore.neighborRankParams.direction}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateNeighborRankParams(
- 'direction',
- e.target.value
- );
- }}
- >
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
- </div>
- </div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
<div
@@ -171,13 +145,13 @@ const NeighborRank = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
@@ -219,7 +193,7 @@ const NeighborRank = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
url: 'neighborrank',
- type: Algorithm.neighborRankRecommendation
+ type: Algorithm.neighborRank
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -231,7 +205,7 @@ const NeighborRank = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetNeighborRankParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -244,13 +218,9 @@ const NeighborRank = observer(() => {
style={{ width: '50%' }}
>
{algorithmAnalyzerStore.neighborRankParams.steps.map(
- ({ uuid, direction, label, degree, top }, ruleIndex) => {
+ ({ uuid, direction, labels, degree, top }, ruleIndex) => {
return (
- <div
- className={invalidExtendFormClassname(
- algorithmAnalyzerStore.duplicateNeighborRankRuleSet.has(uuid)
- )}
- >
+ <div className="query-tab-content-form-expand-items">
<div className="query-tab-content-form-expand-item">
<div className="query-tab-content-form-item-title query-tab-content-form-expand-title">
<i>*</i>
@@ -271,10 +241,6 @@ const NeighborRank = observer(() => {
e.target.value,
ruleIndex
);
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- uuid
- );
}}
>
<Radio value="BOTH">both</Radio>
@@ -285,7 +251,7 @@ const NeighborRank = observer(() => {
1 && (
<div
style={{
- marginLeft: 198,
+ marginLeft: 175,
fontSize: 14,
color: '#2b65ff',
cursor: 'pointer',
@@ -295,10 +261,6 @@ const NeighborRank = observer(() => {
algorithmAnalyzerStore.removeNeighborRankRule(
ruleIndex
);
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- uuid
- );
}}
>
{t('addition.common.del')}
@@ -316,24 +278,20 @@ const NeighborRank = observer(() => {
<Select
size="medium"
trigger="click"
- value={label}
+ value={labels[0]}
notFoundContent={t(
'data-analyze.algorithm-forms.neighbor-rank.placeholder.no-edge-types'
)}
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- width={400}
+ width={formWidthInStep}
onChange={(value: string) => {
algorithmAnalyzerStore.mutateNeighborRankRuleParams(
- 'label',
- value,
+ 'labels',
+ [value],
ruleIndex
);
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- uuid
- );
}}
>
<Select.Option value="__all__" key="__all__">
@@ -355,15 +313,41 @@ const NeighborRank = observer(() => {
'data-analyze.algorithm-forms.neighbor-rank.options.degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.neighbor-rank.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidthInStep}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
@@ -384,10 +368,6 @@ const NeighborRank = observer(() => {
'degree',
ruleIndex
);
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- uuid
- );
}}
originInputProps={{
onBlur() {
@@ -434,13 +414,13 @@ const NeighborRank = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidthInStep}
size="medium"
disabled={
dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
placeholder={t(
- 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.neighbor-rank.placeholder.input-integer-lt-1000'
)}
errorLocation="layer"
errorMessage={
@@ -461,10 +441,6 @@ const NeighborRank = observer(() => {
'top',
ruleIndex
);
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- uuid
- );
}}
originInputProps={{
onBlur() {
@@ -488,42 +464,16 @@ const NeighborRank = observer(() => {
marginTop: 8
}}
>
- {algorithmAnalyzerStore.duplicateNeighborRankRuleSet.size === 0 ? (
- <span
- style={{ cursor: 'pointer' }}
- onClick={() => {
- if (isValidAddRule) {
- algorithmAnalyzerStore.addNeighborRankRule();
-
- algorithmAnalyzerStore.validateDuplicateNeighborRankRules(
- (
- last(
- algorithmAnalyzerStore.neighborRankParams.steps
- ) as NeighborRankRule
- ).uuid
- );
- }
- }}
- >
- {t('data-analyze.algorithm-forms.neighbor-rank.add-new-rule')}
- </span>
- ) : (
- <div
- style={{
- width: 150,
- boxShadow: '0 1px 4px 0 rgba(0, 0, 0, 0.15)',
- lineHeight: '18px',
- padding: '16px',
- color: '#e64552',
- fontSize: 14,
- textAlign: 'center'
- }}
- >
- {t(
- 'data-analyze.algorithm-forms.neighbor-rank.validations.input-chars'
- )}
- </div>
- )}
+ <span
+ style={{ cursor: 'pointer' }}
+ onClick={() => {
+ if (isValidAddRule) {
+ algorithmAnalyzerStore.addNeighborRankRule();
+ }
+ }}
+ >
+ {t('data-analyze.algorithm-forms.neighbor-rank.add-new-rule')}
+ </span>
</div>
</div>
</div>
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/PersonalRank.tsx
similarity index 53%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/PersonalRank.tsx
index 82ec79a..a83ba4a 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/PersonalRank.tsx
@@ -1,90 +1,101 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const PersonalRank = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.personalRankParams.source !== '' &&
+ algorithmAnalyzerStore.personalRankParams.alpha !== '' &&
+ algorithmAnalyzerStore.personalRankParams.label !== '' &&
+ algorithmAnalyzerStore.personalRankParams.max_depth !== '';
return (
<div className="query-tab-content-form">
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 112 }}
+ >
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.source')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .source
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
+ value={algorithmAnalyzerStore.personalRankParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutatePersonalRankParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validatePersonalRankParams('source');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validatePersonalRankParams('source');
}
}}
/>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
+ <i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.label')}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={algorithmAnalyzerStore.personalRankParams.label}
+ selectorName={t(
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.select-edge'
+ )}
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'label',
- value
- );
+ algorithmAnalyzerStore.mutatePersonalRankParams('label', value);
}}
>
- <Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
- </Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
{name}
@@ -95,38 +106,38 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 112 }}
+ >
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.alpha')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.alpha'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .target
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage.alpha
}
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
+ value={algorithmAnalyzerStore.personalRankParams.alpha}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'target',
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'alpha',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validatePersonalRankParams('alpha');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validatePersonalRankParams('alpha');
}
}}
/>
@@ -134,39 +145,58 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.degree')}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.personal-rank.hint.degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.input-positive-integer-or-negative-one-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_degree
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage.degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
+ value={algorithmAnalyzerStore.personalRankParams.degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_degree',
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
+ algorithmAnalyzerStore.validatePersonalRankParams('degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
+ algorithmAnalyzerStore.validatePersonalRankParams('degree');
}
}}
/>
@@ -174,63 +204,73 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 112 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
+ 'data-analyze.algorithm-forms.personal-rank.options.max_depth'
)}
</span>
</div>
- <Radio.Group
+ <Input
+ width={formWidth}
+ size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'direction',
- e.target.value
+ placeholder={t(
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.max_depth'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage.max_depth
+ }
+ value={algorithmAnalyzerStore.personalRankParams.max_depth}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'max_depth',
+ e.value as string
);
+
+ algorithmAnalyzerStore.validatePersonalRankParams('max_depth');
}}
- >
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validatePersonalRankParams('max_depth');
+ }
+ }}
+ />
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.limit')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.personal-rank.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore.validatePersonalRankErrorMessage.limit
}
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
+ value={algorithmAnalyzerStore.personalRankParams.limit}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
+ algorithmAnalyzerStore.validatePersonalRankParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
- );
+ algorithmAnalyzerStore.validatePersonalRankParams('limit');
}
}}
/>
@@ -238,11 +278,14 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 112 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
+ 'data-analyze.algorithm-forms.personal-rank.options.with_label'
)}
</span>
<CustomTooltip
@@ -260,7 +303,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ 'data-analyze.algorithm-forms.personal-rank.hint.with-label'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -272,42 +315,37 @@ const ShortestPathAll = observer(() => {
childrenWrapperElement="img"
/>
</div>
- <Input
- width={400}
- size="medium"
+ <Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_depth
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_depth',
- e.value as string
+ value={algorithmAnalyzerStore.personalRankParams.with_label}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'with_label',
+ e.target.value
);
-
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_depth'
- );
- }
}}
- />
+ >
+ <Radio value="SAME_LABEL">
+ {t(
+ 'data-analyze.algorithm-forms.personal-rank.with-label-radio-value.same_label'
+ )}
+ </Radio>
+ <Radio value="OTHER_LABEL">
+ {t(
+ 'data-analyze.algorithm-forms.personal-rank.with-label-radio-value.other_label'
+ )}
+ </Radio>
+ <Radio value="BOTH_LABEL">
+ {t(
+ 'data-analyze.algorithm-forms.personal-rank.with-label-radio-value.both_label'
+ )}
+ </Radio>
+ </Radio.Group>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
- )}
+ {t('data-analyze.algorithm-forms.personal-rank.options.sorted')}
</span>
<CustomTooltip
trigger="hover"
@@ -324,7 +362,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
+ 'data-analyze.algorithm-forms.personal-rank.hint.sorted'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -336,37 +374,21 @@ const ShortestPathAll = observer(() => {
childrenWrapperElement="img"
/>
</div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .skip_degree
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.skip_degree}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'skip_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
+ <div style={{ width: formWidth }}>
+ <Switch
+ size="medium"
+ disabled={
+ dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'
}
- }}
- />
+ checked={algorithmAnalyzerStore.personalRankParams.sorted}
+ onChange={(checked: boolean) => {
+ algorithmAnalyzerStore.mutatePersonalRankParams(
+ 'sorted',
+ checked
+ );
+ }}
+ />
+ </div>
</div>
</div>
<div
@@ -386,8 +408,8 @@ const ShortestPathAll = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'allshortpath',
- type: Algorithm.shortestPathAll
+ url: 'personalrank',
+ type: Algorithm.personalRankRecommendation
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -399,7 +421,7 @@ const ShortestPathAll = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetPersonalRankParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -409,4 +431,4 @@ const ShortestPathAll = observer(() => {
);
});
-export default ShortestPathAll;
+export default PersonalRank;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/RadiographicInspection.tsx
similarity index 61%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/RadiographicInspection.tsx
index 82ec79a..6eec096 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/RadiographicInspection.tsx
@@ -1,22 +1,35 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
+import { Button, Radio, Input, Select } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const RadiographicInspection = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateRadiographicInspectionParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.radiographicInspectionParams.source !== '' &&
+ algorithmAnalyzerStore.radiographicInspectionParams.max_depth !== '';
return (
<div className="query-tab-content-form">
@@ -26,34 +39,38 @@ const ShortestPathAll = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.source'
)}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .source
+ algorithmAnalyzerStore
+ .validateRadiographicInspectionParamsErrorMessage.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
+ value={algorithmAnalyzerStore.radiographicInspectionParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'source'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'source'
+ );
}
}}
/>
@@ -62,28 +79,30 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.label'
)}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={algorithmAnalyzerStore.radiographicInspectionParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
'label',
value
);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
+ {t(
+ 'data-analyze.algorithm-forms.radiographic-inspection.pre-value'
+ )}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -99,94 +118,17 @@ const ShortestPathAll = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .target
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'target',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_degree
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_degree',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.direction'
)}
</span>
</div>
<Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
+ value={
+ algorithmAnalyzerStore.radiographicInspectionParams.direction
+ }
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
'direction',
e.target.value
);
@@ -201,35 +143,65 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.radiographic-inspection.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore
+ .validateRadiographicInspectionParamsErrorMessage.max_degree
+ }
+ value={
+ algorithmAnalyzerStore.radiographicInspectionParams.max_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
+ 'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'max_degree'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'max_degree'
);
}
}}
@@ -242,7 +214,7 @@ const ShortestPathAll = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.max_depth'
)}
</span>
<CustomTooltip
@@ -260,7 +232,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ 'data-analyze.algorithm-forms.radiographic-inspection.hint.max-depth'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -273,29 +245,33 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_depth
+ algorithmAnalyzerStore
+ .validateRadiographicInspectionParamsErrorMessage.max_depth
+ }
+ value={
+ algorithmAnalyzerStore.radiographicInspectionParams.max_depth
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
'max_depth',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'max_depth'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
'max_depth'
);
}
@@ -306,63 +282,80 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.capacity'
)}
</span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
+ </div>
+ <Input
+ width={formWidth}
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ placeholder={t(
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.input-positive-integer-or-negative-one-capacity'
+ )}
+ errorLocation="layer"
+ errorMessage={
+ algorithmAnalyzerStore
+ .validateRadiographicInspectionParamsErrorMessage.capacity
+ }
+ value={algorithmAnalyzerStore.radiographicInspectionParams.capacity}
+ onChange={(e: any) => {
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
+ 'capacity',
+ e.value as string
+ );
+
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'capacity'
+ );
+ }}
+ originInputProps={{
+ onBlur() {
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'capacity'
+ );
+ }
+ }}
+ />
+ </div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item"></div>
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.radiographic-inspection.options.limit'
)}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
+ </span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.radiographic-inspection.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .skip_degree
+ algorithmAnalyzerStore
+ .validateRadiographicInspectionParamsErrorMessage.limit
}
- value={algorithmAnalyzerStore.shortestPathAllParams.skip_degree}
+ value={algorithmAnalyzerStore.radiographicInspectionParams.limit}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'skip_degree',
+ algorithmAnalyzerStore.mutateRadiographicInspectionParams(
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'limit'
);
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
+ algorithmAnalyzerStore.validateRadiographicInspectionParams(
+ 'limit'
);
}
}}
@@ -386,8 +379,8 @@ const ShortestPathAll = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'allshortpath',
- type: Algorithm.shortestPathAll
+ url: 'rays',
+ type: Algorithm.radiographicInspection
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -399,7 +392,7 @@ const ShortestPathAll = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetRadiographicInspectionParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -409,4 +402,4 @@ const ShortestPathAll = observer(() => {
);
});
-export default ShortestPathAll;
+export default RadiographicInspection;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SameNeighbor.tsx
similarity index 54%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SameNeighbor.tsx
index 50f62eb..d7afc70 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/LoopDetection.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SameNeighbor.tsx
@@ -1,25 +1,35 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
+import { Button, Radio, Input, Select } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-const LoopDetection = observer(() => {
- const { t } = useTranslation();
+const SameNeighbor = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
const isValidExec =
Object.values(
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
+ algorithmAnalyzerStore.validateSameNeighborParamsErrorMessage
).every((value) => value === '') &&
- algorithmAnalyzerStore.loopDetectionParams.source !== '' &&
- algorithmAnalyzerStore.loopDetectionParams.max_depth !== '';
+ algorithmAnalyzerStore.sameNeighborParams.vertex !== '' &&
+ algorithmAnalyzerStore.sameNeighborParams.other !== '';
return (
<div className="query-tab-content-form">
@@ -28,33 +38,33 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t('data-analyze.algorithm-forms.loop-detection.options.source')}
+ {t('data-analyze.algorithm-forms.same-neighbor.options.vertex')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.same-neighbor.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .source
+ algorithmAnalyzerStore.validateSameNeighborParamsErrorMessage
+ .vertex
}
- value={algorithmAnalyzerStore.loopDetectionParams.source}
+ value={algorithmAnalyzerStore.sameNeighborParams.vertex}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'source',
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ 'vertex',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('source');
+ algorithmAnalyzerStore.validateSameNeighborParams('vertex');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('source');
+ algorithmAnalyzerStore.validateSameNeighborParams('vertex');
}
}}
/>
@@ -62,24 +72,24 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t('data-analyze.algorithm-forms.loop-detection.options.label')}
+ {t('data-analyze.algorithm-forms.same-neighbor.options.label')}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.loopDetectionParams.label}
+ value={algorithmAnalyzerStore.sameNeighborParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.same-neighbor.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams('label', value);
+ algorithmAnalyzerStore.mutateSameNeighborParams('label', value);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.loop-detection.pre-value')}
+ {t('data-analyze.algorithm-forms.same-neighbor.pre-value')}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -94,72 +104,42 @@ const LoopDetection = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.loop-detection.options.direction'
- )}
- </span>
- </div>
- <Radio.Group
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.loopDetectionParams.direction}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'direction',
- e.target.value
- );
- }}
- >
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t(
- 'data-analyze.algorithm-forms.loop-detection.options.max_degree'
- )}
+ {t('data-analyze.algorithm-forms.same-neighbor.options.other')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.same-neighbor.placeholder.input-other-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .max_degree
+ algorithmAnalyzerStore.validateSameNeighborParamsErrorMessage
+ .other
}
- value={algorithmAnalyzerStore.loopDetectionParams.max_degree}
+ value={algorithmAnalyzerStore.sameNeighborParams.other}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'max_degree',
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ 'other',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('max_degree');
+ algorithmAnalyzerStore.validateSameNeighborParams('other');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams(
- 'max_degree'
- );
+ algorithmAnalyzerStore.validateSameNeighborParams('other');
}
}}
/>
</div>
- </div>
- <div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
- <i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.loop-detection.options.max_depth'
+ 'data-analyze.algorithm-forms.same-neighbor.options.max_degree'
)}
</span>
<CustomTooltip
@@ -177,7 +157,7 @@ const LoopDetection = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.loop-detection.hint.max-depth'
+ 'data-analyze.algorithm-forms.same-neighbor.hint.max-degree'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -190,63 +170,29 @@ const LoopDetection = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.same-neighbor.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .max_depth
- }
- value={algorithmAnalyzerStore.loopDetectionParams.max_depth}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'max_depth',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateLoopDetectionParams('max_depth');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('max_depth');
- }
- }}
- />
- </div>
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <span>
- {t('data-analyze.algorithm-forms.loop-detection.options.limit')}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .limit
+ algorithmAnalyzerStore.validateSameNeighborParamsErrorMessage
+ .max_degree
}
- value={algorithmAnalyzerStore.loopDetectionParams.limit}
+ value={algorithmAnalyzerStore.sameNeighborParams.max_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'limit',
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ 'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('limit');
+ algorithmAnalyzerStore.validateSameNeighborParams('max_degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('limit');
+ algorithmAnalyzerStore.validateSameNeighborParams('max_degree');
}
}}
/>
@@ -258,55 +204,55 @@ const LoopDetection = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.loop-detection.options.source_in_ring'
+ 'data-analyze.algorithm-forms.same-neighbor.options.direction'
)}
</span>
</div>
- <Switch
- width={400}
- size="medium"
+ <Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- checked={algorithmAnalyzerStore.loopDetectionParams.source_in_ring}
- onChange={(checked: boolean) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'source_in_ring',
- checked
+ value={algorithmAnalyzerStore.sameNeighborParams.direction}
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ 'direction',
+ e.target.value
);
}}
- />
+ >
+ <Radio value="BOTH">both</Radio>
+ <Radio value="OUT">out</Radio>
+ <Radio value="IN">in</Radio>
+ </Radio.Group>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.loop-detection.options.capacity'
- )}
+ {t('data-analyze.algorithm-forms.same-neighbor.options.limit')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.loop-detection.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.same-neighbor.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateLoopDetectionParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore.validateSameNeighborParamsErrorMessage
+ .limit
}
- value={algorithmAnalyzerStore.loopDetectionParams.capacity}
+ value={algorithmAnalyzerStore.sameNeighborParams.limit}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateLoopDetectionParams(
- 'capacity',
+ algorithmAnalyzerStore.mutateSameNeighborParams(
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateLoopDetectionParams('capacity');
+ algorithmAnalyzerStore.validateSameNeighborParams('limit');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateLoopDetectionParams('capacity');
+ algorithmAnalyzerStore.validateSameNeighborParams('limit');
}
}}
/>
@@ -329,8 +275,8 @@ const LoopDetection = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'rings',
- type: Algorithm.loopDetection
+ url: 'sameneighbors',
+ type: Algorithm.sameNeighbor
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -342,7 +288,7 @@ const LoopDetection = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetLoopDetectionParams();
+ algorithmAnalyzerStore.resetSameNeighborParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -352,4 +298,4 @@ const LoopDetection = observer(() => {
);
});
-export default LoopDetection;
+export default SameNeighbor;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPath.tsx
similarity index 59%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPath.tsx
index 82ec79a..3e1507b 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPath.tsx
@@ -1,22 +1,36 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
-import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
+import { Button, Radio, Input, Select } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const ShortestPath = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.shortestPathAlgorithmParams.source !== '' &&
+ algorithmAnalyzerStore.shortestPathAlgorithmParams.target !== '' &&
+ algorithmAnalyzerStore.shortestPathAlgorithmParams.max_depth !== '';
return (
<div className="query-tab-content-form">
@@ -25,35 +39,33 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
- )}
+ {t('data-analyze.algorithm-forms.shortest-path.options.source')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateShortestPathParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateShortestPathParams('source');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateShortestPathParams('source');
}
}}
/>
@@ -61,29 +73,24 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
- )}
+ {t('data-analyze.algorithm-forms.shortest-path.options.label')}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'label',
- value
- );
+ algorithmAnalyzerStore.mutateShortestPathParams('label', value);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
+ {t('data-analyze.algorithm-forms.shortest-path.pre-value')}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -98,35 +105,33 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<i>*</i>
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
- )}
+ {t('data-analyze.algorithm-forms.shortest-path.options.target')}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-target-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
.target
}
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.target}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateShortestPathParams(
'target',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validateShortestPathParams('target');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validateShortestPathParams('target');
}
}}
/>
@@ -135,38 +140,62 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
+ 'data-analyze.algorithm-forms.shortest-path.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.shortest-path.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
.max_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
+ value={
+ algorithmAnalyzerStore.shortestPathAlgorithmParams.max_degree
+ }
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateShortestPathParams(
'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
+ algorithmAnalyzerStore.validateShortestPathParams('max_degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_degree'
- );
+ algorithmAnalyzerStore.validateShortestPathParams('max_degree');
}
}}
/>
@@ -178,15 +207,15 @@ const ShortestPathAll = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
+ 'data-analyze.algorithm-forms.shortest-path.options.direction'
)}
</span>
</div>
<Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.direction}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateShortestPathParams(
'direction',
e.target.value
);
@@ -201,35 +230,63 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
+ 'data-analyze.algorithm-forms.shortest-path.options.skip_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.shortest-path.hint.skip-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
+ .skip_degree
+ }
+ value={
+ algorithmAnalyzerStore.shortestPathAlgorithmParams.skip_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
+ algorithmAnalyzerStore.mutateShortestPathParams(
+ 'skip_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
+ algorithmAnalyzerStore.validateShortestPathParams('skip_degree');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
+ algorithmAnalyzerStore.validateShortestPathParams(
+ 'skip_degree'
);
}
}}
@@ -242,7 +299,7 @@ const ShortestPathAll = observer(() => {
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
+ 'data-analyze.algorithm-forms.shortest-path.options.max_depth'
)}
</span>
<CustomTooltip
@@ -260,7 +317,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ 'data-analyze.algorithm-forms.shortest-path.hint.max-depth'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -273,31 +330,29 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
.max_depth
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateShortestPathParams(
'max_depth',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
+ algorithmAnalyzerStore.validateShortestPathParams('max_depth');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_depth'
- );
+ algorithmAnalyzerStore.validateShortestPathParams('max_depth');
}
}}
/>
@@ -305,65 +360,33 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
- )}
+ {t('data-analyze.algorithm-forms.shortest-path.options.capacity')}
</span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.shortest-path.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .skip_degree
+ algorithmAnalyzerStore.validateShortestPathParamsErrorMessage
+ .capacity
}
- value={algorithmAnalyzerStore.shortestPathAllParams.skip_degree}
+ value={algorithmAnalyzerStore.shortestPathAlgorithmParams.capacity}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'skip_degree',
+ algorithmAnalyzerStore.mutateShortestPathParams(
+ 'capacity',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
+ algorithmAnalyzerStore.validateShortestPathParams('capacity');
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
- );
+ algorithmAnalyzerStore.validateShortestPathParams('capacity');
}
}}
/>
@@ -386,8 +409,8 @@ const ShortestPathAll = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'allshortpath',
- type: Algorithm.shortestPathAll
+ url: 'shortpath',
+ type: Algorithm.shortestPath
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -399,7 +422,9 @@ const ShortestPathAll = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetShortestPathParams();
+ // temp solution
+ algorithmAnalyzerStore.mutateShortestPathParams('label', '__all__');
}}
>
{t('data-analyze.manipulations.reset')}
@@ -409,4 +434,4 @@ const ShortestPathAll = observer(() => {
);
});
-export default ShortestPathAll;
+export default ShortestPath;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
index 82ec79a..ff2caed 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
@@ -2,21 +2,35 @@ import React, { useContext, createContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
+
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 400
+ );
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.shortestPathAllParams.source !== '' &&
+ algorithmAnalyzerStore.shortestPathAllParams.target !== '' &&
+ algorithmAnalyzerStore.shortestPathAllParams.max_depth !== '';
return (
<div className="query-tab-content-form">
@@ -31,7 +45,7 @@ const ShortestPathAll = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -74,7 +88,7 @@ const ShortestPathAll = observer(() => {
'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
algorithmAnalyzerStore.mutateShortestPathAllParams(
'label',
@@ -104,11 +118,11 @@ const ShortestPathAll = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-target-id'
)}
errorLocation="layer"
errorMessage={
@@ -138,13 +152,39 @@ const ShortestPathAll = observer(() => {
'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.shortest-path-all.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
@@ -206,11 +246,11 @@ const ShortestPathAll = observer(() => {
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
@@ -273,7 +313,7 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
@@ -337,11 +377,11 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
)}
errorLocation="layer"
errorMessage={
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SingleSourceWeightedShortestPath.tsx
similarity index 51%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SingleSourceWeightedShortestPath.tsx
index 82ec79a..342f951 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/SingleSourceWeightedShortestPath.tsx
@@ -1,59 +1,82 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+
+import { GraphManagementStoreContext } from '../../../../stores';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { isDataTypeNumeric, calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const SingleSourceWeightedShortestPath = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
+
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 340,
+ 380
+ );
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams.source !== '';
return (
<div className="query-tab-content-form">
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.source'
)}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore
+ .validateSingleSourceWeightedShortestPathParamsErrorMessage
+ .source
+ }
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'source'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'source'
+ );
}
}}
/>
@@ -62,28 +85,33 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.label'
)}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .label
+ }
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
'label',
value
);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
+ {t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.pre-value'
+ )}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -95,76 +123,99 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.direction'
)}
</span>
</div>
- <Input
- width={400}
- size="medium"
+ <Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .target
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .direction
}
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'target',
- e.value as string
+ onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'direction',
+ e.target.value
);
-
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
}}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
- }
- }}
- />
+ >
+ <Radio value="BOTH">both</Radio>
+ <Radio value="OUT">out</Radio>
+ <Radio value="IN">in</Radio>
+ </Radio.Group>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
+ algorithmAnalyzerStore
+ .validateSingleSourceWeightedShortestPathParamsErrorMessage
+ .max_degree
+ }
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
.max_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
'max_degree'
);
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
'max_degree'
);
}
@@ -174,62 +225,118 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.weight'
)}
</span>
</div>
- <Radio.Group
+ <Select
+ size="medium"
+ trigger="click"
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .weight
+ }
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.no-edge-types'
+ )}
+ selectorName={t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.no-property'
+ )}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
- onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'direction',
- e.target.value
+ width={formWidth}
+ onChange={(value: string) => {
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'weight',
+ value
);
}}
>
- <Radio value="BOTH">both</Radio>
- <Radio value="OUT">out</Radio>
- <Radio value="IN">in</Radio>
- </Radio.Group>
+ {dataAnalyzeStore.allPropertiesFromEdge
+ .filter((propertyName) =>
+ isDataTypeNumeric(
+ dataAnalyzeStore.properties.find(
+ ({ name }) => name === propertyName
+ )?.data_type
+ )
+ )
+ .map((propertyName) => (
+ <Select.Option value={propertyName} key={propertyName}>
+ {propertyName}
+ </Select.Option>
+ ))}
+ </Select>
</div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.skip_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.hint.skip-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.input-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
+ algorithmAnalyzerStore
+ .validateSingleSourceWeightedShortestPathParamsErrorMessage
+ .skip_degree
+ }
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .skip_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'skip_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'skip_degree'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'skip_degree'
);
}
}}
@@ -238,131 +345,117 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.with_vertex'
)}
</span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ </div>
+ <Switch
+ size="medium"
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ checked={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .with_vertex
+ }
+ onChange={(checked: boolean) => {
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'with_vertex',
+ checked
+ );
+ }}
+ />
+ </div>
+ <div className="query-tab-content-form-item">
+ <div className="query-tab-content-form-item-title">
+ <span>
+ {t(
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.capacity'
)}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
+ </span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.input-positive-integer-or-negative-one-capacity'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_depth
+ algorithmAnalyzerStore
+ .validateSingleSourceWeightedShortestPathParamsErrorMessage
+ .capacity
+ }
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .capacity
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_depth',
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'capacity',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'capacity'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_depth'
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'capacity'
);
}
}}
/>
</div>
+ </div>
+ <div className="query-tab-content-form-row">
+ <div className="query-tab-content-form-item"></div>
<div className="query-tab-content-form-item">
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.options.limit'
)}
</span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
- )}
- childrenProps={{
- src: QuestionMarkIcon,
- alt: 'hint',
- style: {
- marginLeft: 5
- }
- }}
- childrenWrapperElement="img"
- />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.single-source-weighted-shortest-path.placeholder.input-positive-integer-or-negative-one-limit'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .skip_degree
+ algorithmAnalyzerStore
+ .validateSingleSourceWeightedShortestPathParamsErrorMessage
+ .limit
+ }
+ value={
+ algorithmAnalyzerStore.singleSourceWeightedShortestPathParams
+ .limit
}
- value={algorithmAnalyzerStore.shortestPathAllParams.skip_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'skip_degree',
+ algorithmAnalyzerStore.mutateSingleSourceWeightedShortestPathParams(
+ 'limit',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'limit'
);
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'skip_degree'
+ algorithmAnalyzerStore.validateSingleSourceWeightedShortestPathParams(
+ 'limit'
);
}
}}
@@ -386,8 +479,8 @@ const ShortestPathAll = observer(() => {
const timerId = dataAnalyzeStore.addTempExecLog();
await dataAnalyzeStore.fetchGraphs({
- url: 'allshortpath',
- type: Algorithm.shortestPathAll
+ url: 'singleshortpath',
+ type: Algorithm.singleSourceWeightedShortestPath
});
await dataAnalyzeStore.fetchExecutionLogs();
window.clearTimeout(timerId);
@@ -399,7 +492,7 @@ const ShortestPathAll = observer(() => {
style={styles.primaryButton}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
onClick={() => {
- algorithmAnalyzerStore.resetShortestPathAllParams();
+ algorithmAnalyzerStore.resetSingleSourceWeightedShortestPathParams();
}}
>
{t('data-analyze.manipulations.reset')}
@@ -409,4 +502,4 @@ const ShortestPathAll = observer(() => {
);
});
-export default ShortestPathAll;
+export default SingleSourceWeightedShortestPath;
diff --git a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/WeightedShortestPath.tsx
similarity index 53%
copy from hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
copy to hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/WeightedShortestPath.tsx
index 82ec79a..07fcdc2 100644
--- a/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/ShortestPathAll.tsx
+++ b/hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/algorithm/WeightedShortestPath.tsx
@@ -1,59 +1,80 @@
-import React, { useContext, createContext } from 'react';
+import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { Button, Radio, Input, Select, Switch } from 'hubble-ui';
import { useTranslation } from 'react-i18next';
import { styles } from '../QueryAndAlgorithmLibrary';
import { Tooltip as CustomTooltip } from '../../../common';
+
+import { GraphManagementStoreContext } from '../../../../stores';
import DataAnalyzeStore from '../../../../stores/GraphManagementStore/dataAnalyzeStore/dataAnalyzeStore';
+import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
+import { isDataTypeNumeric, calcAlgorithmFormWidth } from '../../../../utils';
import QuestionMarkIcon from '../../../../assets/imgs/ic_question_mark.svg';
-import { Algorithm } from '../../../../stores/factory/dataAnalyzeStore/algorithmStore';
-const ShortestPathAll = observer(() => {
- const { t } = useTranslation();
+const WeightedShortestPath = observer(() => {
+ const graphManagementStore = useContext(GraphManagementStoreContext);
const dataAnalyzeStore = useContext(DataAnalyzeStore);
const algorithmAnalyzerStore = dataAnalyzeStore.algorithmAnalyzerStore;
+ const { t } = useTranslation();
- const isValidExec = !Object.values(
- algorithmAnalyzerStore.shortestPathAllParams
- ).some((value) => value === '');
+ const formWidth = calcAlgorithmFormWidth(
+ graphManagementStore.isExpanded,
+ 320,
+ 390
+ );
+
+ const isValidExec =
+ Object.values(
+ algorithmAnalyzerStore.validateWeightedShortestPathParamsErrorMessage
+ ).every((value) => value === '') &&
+ algorithmAnalyzerStore.weightedShortestPathParams.source !== '' &&
+ algorithmAnalyzerStore.weightedShortestPathParams.target !== '' &&
+ algorithmAnalyzerStore.weightedShortestPathParams.weight !== '';
return (
<div className="query-tab-content-form">
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.source'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.source'
)}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.input-source-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .source
+ algorithmAnalyzerStore
+ .validateWeightedShortestPathParamsErrorMessage.source
}
- value={algorithmAnalyzerStore.shortestPathAllParams.source}
+ value={algorithmAnalyzerStore.weightedShortestPathParams.source}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
'source',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'source'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('source');
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'source'
+ );
}
}}
/>
@@ -62,28 +83,30 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.label'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.label'
)}
</span>
</div>
<Select
size="medium"
trigger="click"
- value={algorithmAnalyzerStore.shortestPathAllParams.label}
+ value={algorithmAnalyzerStore.weightedShortestPathParams.label}
notFoundContent={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.no-edge-types'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.no-edge-types'
)}
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- width={400}
+ width={formWidth}
onChange={(value: string) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
'label',
value
);
}}
>
<Select.Option value="__all__" key="__all__">
- {t('data-analyze.algorithm-forms.shortest-path-all.pre-value')}
+ {t(
+ 'data-analyze.algorithm-forms.weighted-shortest-path.pre-value'
+ )}
</Select.Option>
{dataAnalyzeStore.edgeTypes.map(({ name }) => (
<Select.Option value={name} key={name}>
@@ -95,38 +118,45 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.target'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.target'
)}
</span>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-source-id'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.input-target-id'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .target
+ algorithmAnalyzerStore
+ .validateWeightedShortestPathParamsErrorMessage.target
}
- value={algorithmAnalyzerStore.shortestPathAllParams.target}
+ value={algorithmAnalyzerStore.weightedShortestPathParams.target}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
'target',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'target'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams('target');
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'target'
+ );
}
}}
/>
@@ -135,36 +165,62 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_degree'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.max_degree'
)}
</span>
+ <CustomTooltip
+ trigger="hover"
+ placement="bottom-start"
+ modifiers={{
+ offset: {
+ offset: '0, 8'
+ }
+ }}
+ tooltipWrapperProps={{
+ className: 'tooltips-dark',
+ style: {
+ zIndex: 7
+ }
+ }}
+ tooltipWrapper={t(
+ 'data-analyze.algorithm-forms.weighted-shortest-path.hint.max-degree'
+ )}
+ childrenProps={{
+ src: QuestionMarkIcon,
+ alt: 'hint',
+ style: {
+ marginLeft: 5
+ }
+ }}
+ childrenWrapperElement="img"
+ />
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-integer'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.input-positive-integer-or-negative-one-max-degree'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_degree
+ algorithmAnalyzerStore
+ .validateWeightedShortestPathParamsErrorMessage.max_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_degree}
+ value={algorithmAnalyzerStore.weightedShortestPathParams.max_degree}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
'max_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams(
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
'max_degree'
);
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
'max_degree'
);
}
@@ -174,19 +230,22 @@ const ShortestPathAll = observer(() => {
</div>
<div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
<i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.direction'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.direction'
)}
</span>
</div>
<Radio.Group
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- value={algorithmAnalyzerStore.shortestPathAllParams.direction}
+ value={algorithmAnalyzerStore.weightedShortestPathParams.direction}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
'direction',
e.target.value
);
@@ -201,48 +260,7 @@ const ShortestPathAll = observer(() => {
<div className="query-tab-content-form-item-title">
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.capacity'
- )}
- </span>
- </div>
- <Input
- width={400}
- size="medium"
- disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
- placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
- )}
- errorLocation="layer"
- errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .capacity
- }
- value={algorithmAnalyzerStore.shortestPathAllParams.capacity}
- onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'capacity',
- e.value as string
- );
-
- algorithmAnalyzerStore.validateShortestPathAllParams('capacity');
- }}
- originInputProps={{
- onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'capacity'
- );
- }
- }}
- />
- </div>
- </div>
- <div className="query-tab-content-form-row">
- <div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
- <i>*</i>
- <span>
- {t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.max_depth'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.skip_degree'
)}
</span>
<CustomTooltip
@@ -260,7 +278,7 @@ const ShortestPathAll = observer(() => {
}
}}
tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.max-depth'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.hint.skip-degree'
)}
childrenProps={{
src: QuestionMarkIcon,
@@ -273,102 +291,155 @@ const ShortestPathAll = observer(() => {
/>
</div>
<Input
- width={400}
+ width={formWidth}
size="medium"
disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
placeholder={t(
- 'data-analyze.algorithm-forms.shortest-path-all.placeholder.input-positive-integer'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.input-integer'
)}
errorLocation="layer"
errorMessage={
- algorithmAnalyzerStore.validateShortestPathAllParamsErrorMessage
- .max_depth
+ algorithmAnalyzerStore
+ .validateWeightedShortestPathParamsErrorMessage.skip_degree
+ }
+ value={
+ algorithmAnalyzerStore.weightedShortestPathParams.skip_degree
}
- value={algorithmAnalyzerStore.shortestPathAllParams.max_depth}
onChange={(e: any) => {
- algorithmAnalyzerStore.mutateShortestPathAllParams(
- 'max_depth',
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
+ 'skip_degree',
e.value as string
);
- algorithmAnalyzerStore.validateShortestPathAllParams('max_depth');
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'skip_degree'
+ );
}}
originInputProps={{
onBlur() {
- algorithmAnalyzerStore.validateShortestPathAllParams(
- 'max_depth'
+ algorithmAnalyzerStore.validateWeightedShortestPathParams(
+ 'skip_degree'
);
}
}}
/>
</div>
+ </div>
+ <div className="query-tab-content-form-row">
<div className="query-tab-content-form-item">
- <div className="query-tab-content-form-item-title">
+ <div
+ className="query-tab-content-form-item-title"
+ style={{ minWidth: 118 }}
+ >
+ <i>*</i>
<span>
{t(
- 'data-analyze.algorithm-forms.shortest-path-all.options.skip_degree'
+ 'data-analyze.algorithm-forms.weighted-shortest-path.options.weight'
)}
</span>
- <CustomTooltip
- trigger="hover"
- placement="bottom-start"
- modifiers={{
- offset: {
- offset: '0, 8'
- }
- }}
- tooltipWrapperProps={{
- className: 'tooltips-dark',
- style: {
- zIndex: 7
- }
- }}
- tooltipWrapper={t(
- 'data-analyze.algorithm-forms.shortest-path-all.hint.skip-degree'
+ </div>
+ <Select
+ size="medium"
+ trigger="click"
+ value={algorithmAnalyzerStore.weightedShortestPathParams.weight}
+ notFoundContent={t(
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.no-property'
+ )}
+ selectorName={t(
+ 'data-analyze.algorithm-forms.weighted-shortest-path.placeholder.select-property'
+ )}
+ disabled={dataAnalyzeStore.requestStatus.fetchGraphs === 'pending'}
+ width={formWidth}
+ onChange={(value: string) => {
+ algorithmAnalyzerStore.mutateWeightedShortestPathParams(
+ 'weight',
... 7832 lines suppressed ...