hugegraph-hubble/hubble-fe/src/components/graph-management/data-analyze/DynamicAddEdge.tsx (317 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ import React, { useContext, useCallback, useRef, useEffect } from 'react'; import { observer } from 'mobx-react'; import { Drawer, Select, Input, Button, Message } from 'hubble-ui'; import { DataAnalyzeStoreContext } from '../../../stores'; import { addGraphNodes, addGraphEdges } from '../../../stores/utils'; import { isUndefined, isEmpty } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import i18next from '../../../i18n'; const IDStrategyMappings: Record<string, string> = { PRIMARY_KEY: i18next.t('addition.constant.primary-key-id'), AUTOMATIC: i18next.t('addition.constant.automatic-generation'), CUSTOMIZE_STRING: i18next.t('addition.constant.custom-string'), CUSTOMIZE_NUMBER: i18next.t('addition.constant.custom-number'), CUSTOMIZE_UUID: i18next.t('addition.constant.custom-uuid') }; const DataAnalyzeAddEdge: React.FC = observer(() => { const dataAnalyzeStore = useContext(DataAnalyzeStoreContext); const { t } = useTranslation(); const title = dataAnalyzeStore.dynamicAddGraphDataStatus === 'inEdge' ? t('addition.common.in-edge') : t('addition.common.out-edge'); const selectedEdgeLabel = dataAnalyzeStore.edgeTypes.find( ({ name }) => name === dataAnalyzeStore.newGraphEdgeConfigs.label )!; const nonNullableProperties = [ ...dataAnalyzeStore.newGraphEdgeConfigs.properties.nonNullable.keys() ]; const nullableProperties = [ ...dataAnalyzeStore.newGraphEdgeConfigs.properties.nullable.keys() ]; const premitAddGraphEdge = !isEmpty(dataAnalyzeStore.newGraphEdgeConfigs.label) && !isEmpty(dataAnalyzeStore.newGraphEdgeConfigs.id) && ![ ...dataAnalyzeStore.newGraphEdgeConfigs.properties.nonNullable.values() ].includes('') && [ ...dataAnalyzeStore.validateAddGraphEdgeErrorMessage!.properties.nonNullable.values() ].every((value) => value === '') && [ ...dataAnalyzeStore.validateAddGraphEdgeErrorMessage!.properties.nullable.values() ].every((value) => value === ''); const handleDrawerClose = useCallback(() => { dataAnalyzeStore.setDynamicAddGraphDataStatus(''); dataAnalyzeStore.resetNewGraphData('edge'); }, [dataAnalyzeStore]); useEffect(() => { const handleOutSideClick = (e: MouseEvent) => { const drawerWrapper = document.querySelector( '.new-fc-one-drawer-content-wrapper' ); if ( dataAnalyzeStore.isShowGraphInfo && !dataAnalyzeStore.isClickOnNodeOrEdge && drawerWrapper && !drawerWrapper.contains(e.target as Element) ) { dataAnalyzeStore.setDynamicAddGraphDataStatus(''); } }; document.addEventListener('click', handleOutSideClick, false); return () => { document.removeEventListener('click', handleOutSideClick, false); }; }, [dataAnalyzeStore]); return ( <Drawer width={580} title={`${t('addition.common.add')}${title}`} visible={dataAnalyzeStore.dynamicAddGraphDataStatus.includes('Edge')} onClose={handleDrawerClose} maskClosable={false} footer={[ <Button type="primary" size="medium" style={{ width: 60 }} disabled={!premitAddGraphEdge} onClick={async () => { const graphViewData = await dataAnalyzeStore.addGraphEdge(); if (!isUndefined(graphViewData)) { const { vertices, originalVertices, edges } = graphViewData; addGraphNodes( vertices, dataAnalyzeStore.visDataSet?.nodes, dataAnalyzeStore.vertexSizeMappings, dataAnalyzeStore.colorMappings, dataAnalyzeStore.vertexWritingMappings ); addGraphEdges( edges, dataAnalyzeStore.visDataSet?.edges, dataAnalyzeStore.edgeColorMappings, dataAnalyzeStore.edgeThicknessMappings, dataAnalyzeStore.edgeWithArrowMappings, dataAnalyzeStore.edgeWritingMappings ); dataAnalyzeStore.visNetwork?.selectNodes( originalVertices.map(({ id }) => id) ); dataAnalyzeStore.visNetwork?.selectEdges( edges.map(({ id }) => id) ); Message.success({ content: t('addition.common.add-success'), size: 'medium', showCloseIcon: false }); } else { Message.error({ content: t('addition.common.add-fail'), size: 'medium', showCloseIcon: false }); } handleDrawerClose(); }} > {t('addition.common.add')} </Button>, <Button size="medium" style={{ width: 60 }} onClick={handleDrawerClose}> {t('addition.common.cancel')} </Button> ]} > <div className="data-analyze-dynamic-add-options"> <div className="data-analyze-dynamic-add-option" style={{ marginBottom: 24 }} > <div> {title === t('addition.common.out-edge') ? t('addition.common.source') : t('addition.common.target')} : </div> <span>{dataAnalyzeStore.rightClickedGraphData.id}</span> </div> <div className="data-analyze-dynamic-add-option"> <div>{t('addition.common.edge-type')}:</div> <Select size="medium" trigger="click" selectorName={t('addition.common.edge-type-select-desc')} value={dataAnalyzeStore.newGraphEdgeConfigs.label} width={420} onChange={(value: string) => { dataAnalyzeStore.setNewGraphDataConfig('edge', 'label', value); dataAnalyzeStore.syncNewGraphDataProperties('edge'); dataAnalyzeStore.initValidateAddGraphDataErrorMessage('edge'); }} dropdownClassName="data-analyze-sidebar-select" > {dataAnalyzeStore.relatedGraphEdges.map((label) => ( <Select.Option value={label} key={label}> {label} </Select.Option> ))} </Select> </div> {!isUndefined(selectedEdgeLabel) && ( <> <div className="data-analyze-dynamic-add-option" // override style bugs in index.less style={{ alignItems: 'normal' }} > <div style={{ lineHeight: '32px' }}> {title === t('addition.common.out-edge') ? t('addition.common.target') : t('addition.common.source')} : </div> <div> <Input size="medium" width={420} placeholder={`${t('addition.common.please-input')}${ title === t('addition.common.out-edge') ? t('addition.common.target') : t('addition.common.source') }ID`} errorLocation="layer" errorMessage={ dataAnalyzeStore.validateAddGraphEdgeErrorMessage!.id } value={dataAnalyzeStore.newGraphEdgeConfigs.id} onChange={(e: any) => { dataAnalyzeStore.setNewGraphDataConfig( 'edge', 'id', e.value ); dataAnalyzeStore.validateAddGraphEdge('id', false); }} onBlur={() => { dataAnalyzeStore.validateAddGraphEdge('id', false); }} /> </div> </div> {dataAnalyzeStore.newGraphEdgeConfigs.properties.nonNullable .size !== 0 && ( <div className="data-analyze-dynamic-add-option data-analyze-dynamic-add-option-with-expand"> <div>{t('addition.common.required-property')}:</div> <div className="data-analyze-dynamic-add-option-expands"> <div className="data-analyze-dynamic-add-option-expand"> <div>{t('addition.common.property')}</div> <div>{t('addition.common.property-value')}</div> </div> {nonNullableProperties.map((property) => ( <div className="data-analyze-dynamic-add-option-expand" key={property} > <div>{property}</div> <div> <Input size="medium" width={190} placeholder={t('addition.common.property-input-desc')} errorLocation="layer" errorMessage={dataAnalyzeStore.validateAddGraphEdgeErrorMessage?.properties.nonNullable.get( property )} value={dataAnalyzeStore.newGraphEdgeConfigs.properties.nonNullable.get( property )} onChange={(e: any) => { dataAnalyzeStore.setNewGraphDataConfigProperties( 'edge', 'nonNullable', property, e.value ); dataAnalyzeStore.validateAddGraphEdge( 'nonNullable', false, property ); }} onBlur={() => { dataAnalyzeStore.validateAddGraphEdge( 'nonNullable', false, property ); }} /> </div> </div> ))} </div> </div> )} {dataAnalyzeStore.newGraphEdgeConfigs.properties.nullable.size !== 0 && ( <div className="data-analyze-dynamic-add-option data-analyze-dynamic-add-option-with-expand"> <div>{t('addition.common.nullable-property')}:</div> <div className="data-analyze-dynamic-add-option-expands"> <div className="data-analyze-dynamic-add-option-expand"> <div>{t('addition.common.property')}</div> <div>{t('addition.common.property-value')}</div> </div> {nullableProperties.map((property) => ( <div className="data-analyze-dynamic-add-option-expand" key={property} > <div>{property}</div> <div> <Input size="medium" width={190} placeholder={t('addition.common.property-input-desc')} errorLocation="layer" errorMessage={dataAnalyzeStore.validateAddGraphEdgeErrorMessage!.properties.nullable.get( property )} value={dataAnalyzeStore.newGraphEdgeConfigs.properties.nullable.get( property )} onChange={(e: any) => { dataAnalyzeStore.setNewGraphDataConfigProperties( 'edge', 'nullable', property, e.value ); dataAnalyzeStore.validateAddGraphEdge( 'nullable', false, property ); }} onBlur={() => { dataAnalyzeStore.validateAddGraphEdge( 'nullable', false, property ); }} /> </div> </div> ))} </div> </div> )} </> )} </div> </Drawer> ); }); export default DataAnalyzeAddEdge;