Skip to content

Commit

Permalink
Merge pull request #1496 from MahtabBukhari/add_dropdown_on_graph_nod…
Browse files Browse the repository at this point in the history
…e_for_merge_and_add_edge

Add dropdown to graph of merge and add edge
  • Loading branch information
Rassl authored May 26, 2024
2 parents 0733d3f + f29cf6c commit a312983
Show file tree
Hide file tree
Showing 8 changed files with 508 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const Body = () => {
</Flex>
) : (
<TitleEditor
from={topicEdge ? topicEdge?.search_value : selectedNode?.name || ''}
from={topicEdge ?? selectedNode}
isSwapped={isSwapped}
onSelect={setSelectedToNode}
selectedToNode={selectedToNode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,40 @@ import { FetchEdgesResponse, TEdge } from '~/types'
type Props = {
onSelect: (topic: TEdge | null) => void
selectedValue: TEdge | null
topicId: string
}

export const ToNode: FC<Props> = ({ onSelect, selectedValue }) => {
export const ToNode: FC<Props> = ({ onSelect, selectedValue, topicId }) => {
const [options, setOptions] = useState<TEdge[]>([])
const [optionsIsLoading, setOptionsIsLoading] = useState(false)

const handleSearch = async (val: string) => {
const filters = {
is_muted: 'False',
sort_by: ALPHABETICALLY,
search: val,
skip: '0',
limit: '1000',
}
const debouncedSearch = useMemo(() => {
const handleSearch = async (val: string) => {
const filters = {
is_muted: 'False',
sort_by: ALPHABETICALLY,
search: val,
skip: '0',
limit: '1000',
}

setOptionsIsLoading(true)
setOptionsIsLoading(true)

try {
const responseData: FetchEdgesResponse = await getEdges(filters.search)
try {
const responseData: FetchEdgesResponse = await getEdges(filters.search)

setOptions(responseData.data)
} catch (error) {
setOptions([])
} finally {
setOptionsIsLoading(false)
const filteredData = responseData.data.filter((item) => item?.ref_id !== topicId)

setOptions(filteredData)
} catch (error) {
setOptions([])
} finally {
setOptionsIsLoading(false)
}
}
}

const debouncedSearch = useMemo(() => debounce(handleSearch, 300), [])
return debounce(handleSearch, 300)
}, [topicId])

const handleChange = (e: string) => {
if (!e) {
Expand Down
14 changes: 8 additions & 6 deletions src/components/ModalsContainer/AddNodeEdgeModal/Title/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import FlipIcon from '~/components/Icons/FlipIcon'
import NodeCircleIcon from '~/components/Icons/NodeCircleIcon'
import { Flex } from '~/components/common/Flex'
import { Text } from '~/components/common/Text'
import { TEdge } from '~/types'
import { NodeExtended, TEdge } from '~/types'
import { ConnectionType } from './ConnectionType'
import { ToNode } from './ToNode'

type Props = {
from: string
from: TEdge | NodeExtended | null
onSelect: (edge: TEdge | null) => void
selectedType: string
setSelectedType: (type: string) => void
Expand All @@ -37,6 +37,8 @@ export const TitleEditor: FC<Props> = ({
setIsSwapped()
}

const nodeName: string | null = from && ('search_value' in from ? from.search_value : from.name)

return (
<Flex mb={20}>
<Flex align="center" direction="row" justify="space-between" mb={18}>
Expand All @@ -47,18 +49,18 @@ export const TitleEditor: FC<Props> = ({

<Div swap={isSwapped}>
<Flex>
<FromSection disabled label={!isSwapped ? 'From' : 'To'} swap={isSwapped} value={from} />
<FromSection disabled label={!isSwapped ? 'From' : 'To'} swap={isSwapped} value={nodeName} />
</Flex>

<Flex my={16}>
<StyledLabel>Type</StyledLabel>
<StyledLabels>Type</StyledLabels>
<ConnectionType selectedType={selectedType} setSelectedType={setSelectedType} />
</Flex>

<Flex>
<ToSection>
<ToLabel>{!isSwapped ? 'To' : 'From'}</ToLabel>
<ToNode onSelect={onSelect} selectedValue={selectedToNode} />
<ToNode onSelect={onSelect} selectedValue={selectedToNode} topicId={from?.ref_id as string} />
</ToSection>
</Flex>

Expand Down Expand Up @@ -128,7 +130,7 @@ const ToSection = styled.div`
align-items: center;
`

const StyledLabel = styled.label`
const StyledLabels = styled.label`
color: #bac1c6;
font-size: 13px;
font-weight: 400;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { IconButton } from '@mui/material'
import { debounce } from 'lodash'
import { FC, useMemo, useState } from 'react'
import { OPTIONS } from '~/components/AddItemModal/SourceTypeStep/constants'
import ClearIcon from '~/components/Icons/ClearIcon'
import { ALPHABETICALLY } from '~/components/SourcesTableModal/SourcesView/constants'
import { AutoComplete, TAutocompleteOption } from '~/components/common/AutoComplete'
import { Flex } from '~/components/common/Flex'
import { getEdges } from '~/network/fetchSourcesData'
import { FetchEdgesResponse, TEdge } from '~/types'

type Props = {
topicId: string
onSelect: (topic: TEdge | null) => void
selectedValue: TEdge | null
}

export const ToNode: FC<Props> = ({ topicId, onSelect, selectedValue }) => {
const [options, setOptions] = useState<TEdge[]>([])
const [optionsIsLoading, setOptionsIsLoading] = useState(false)

const debouncedSearch = useMemo(() => {
const handleSearch = async (val: string) => {
const filters = {
is_muted: 'False',
sort_by: ALPHABETICALLY,
search: val,
skip: '0',
limit: '1000',
}

setOptionsIsLoading(true)

try {
const responseData: FetchEdgesResponse = await getEdges(filters.search)

const filteredData = responseData.data.filter((item) => item?.ref_id !== topicId)

setOptions(filteredData)
} catch (error) {
setOptions([])
} finally {
setOptionsIsLoading(false)
}
}

return debounce(handleSearch, 300)
}, [topicId])

const handleChange = (e: string) => {
if (!e) {
setOptions([])

return
}

if (e.length > 2) {
debouncedSearch(e)
}
}

const handleSelect = (val: TAutocompleteOption | null) => {
const option = val ? options.find((i) => i.ref_id === val.value) : null

onSelect(option || null)
}

const resolveOption = (i: TEdge) => ({ label: i.search_value, value: i.ref_id, type: i.node_type })

const resolveOptions = (values: TEdge[]) => values.map(resolveOption)

return selectedValue ? (
<Flex align="center" basis="100%" direction="row" grow={1} shrink={1}>
<span>{selectedValue.search_value}</span>
<IconButton onClick={() => onSelect(null)} size="small">
<ClearIcon />
</IconButton>
</Flex>
) : (
<AutoComplete
handleInputChange={handleChange}
isLoading={optionsIsLoading}
onSelect={handleSelect}
options={resolveOptions(options) || OPTIONS}
selectedValue={selectedValue ? resolveOption(selectedValue) : null}
/>
)
}
172 changes: 172 additions & 0 deletions src/components/ModalsContainer/MergeTopicModal/Title/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { TextField } from '@mui/material'
import { FC } from 'react'
import styled from 'styled-components'
import ArrowRight from '~/components/Icons/ArrowRight'
import FlipIcon from '~/components/Icons/FlipIcon'
import NodeCircleIcon from '~/components/Icons/NodeCircleIcon'
import { Flex } from '~/components/common/Flex'
import { Text } from '~/components/common/Text'
import { TEdge, Topic } from '~/types'
import { ToNode } from './ToNode'

type Props = {
from: Topic
onSelect: (edge: TEdge | null) => void
isSwapped: boolean
setIsSwapped: () => void
selectedToNode: TEdge | null
}

interface SectionProps {
swap: boolean
}

export const TitleEditor: FC<Props> = ({ from, onSelect, selectedToNode, isSwapped, setIsSwapped }) => (
<Flex mb={20}>
<Flex align="center" direction="row" justify="space-between" mb={18}>
<Flex align="center" direction="row">
<StyledText>Merge topic</StyledText>
</Flex>
</Flex>
<Div swap={isSwapped}>
<SectionWrapper>
<FromSection disabled label={!isSwapped ? 'From' : 'To'} swap={isSwapped} value={from?.name} />
</SectionWrapper>

<Flex my={16}>
<StyledLabel>Type</StyledLabel>
<Text>IS ALIAS</Text>
</Flex>

<Flex>
<ToSection>
<ToLabel>{!isSwapped ? 'To' : 'From'}</ToLabel>
<ToNode onSelect={onSelect} selectedValue={selectedToNode} topicId={from?.ref_id as string} />
</ToSection>
</Flex>

<NodeConnectorDiv>
<IconTopContainer>
<NodeCircleIcon />
</IconTopContainer>
<IconMidContainer onClick={setIsSwapped}>
<FlipIcon />
</IconMidContainer>
<IconBottomContainer>
<ArrowRight />
</IconBottomContainer>
</NodeConnectorDiv>
</Div>
</Flex>
)

const StyledText = styled(Text)`
font-size: 22px;
font-weight: 600;
font-family: 'Barlow';
`

const SectionWrapper = styled(Flex)`
flex: 1 1 100%;
`

const NodeConnectorDiv = styled.div`
position: absolute;
top: 26px;
bottom: 26px;
left: 4px;
width: 35px;
border-left: 1.5px solid #6b7a8d4d;
border-top: 1.5px solid #6b7a8d4d;
border-bottom: 1.5px solid #6b7a8d4d;
border-radius: 12px 0 0 12px;
`

const Div = styled.div<SectionProps>`
position: relative;
color: white;
font-family: 'Barlow';
display: flex;
flex-direction: ${(props) => (props.swap ? 'column-reverse' : 'column')};
margin-bottom: 10px;
padding-left: 38px;
`

const FromSection = styled(TextField)<SectionProps>`
position: relative;
width: 100%;
padding: 16px;
gap: 10px;
border-radius: 6px;
border: 1px solid #6b7a8d4d;
opacity: 0px;
display: flex;
`

const ToSection = styled.div`
position: relative;
width: 100%;
padding: 15px;
gap: 10px;
border-radius: 6px;
border: 1.4px solid #6b7a8d4d;
opacity: 0px;
display: flex;
align-items: center;
`

const StyledLabel = styled.label`
color: #bac1c6;
font-size: 13px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0.01em;
text-align: left;
margin-bottom: 6px;
`

const ToLabel = styled.label`
color: #bac1c6;
background-color: #23252f;
font-size: 13px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0.01em;
text-align: left;
position: absolute;
left: 15px;
top: -10px;
`

const IconTopContainer = styled.div`
position: absolute;
top: 0;
right: 0;
transform: translateY(-50%) translateX(50%);
color: #23252f;
`

const IconMidContainer = styled.div`
position: absolute;
color: transparent;
top: 50%;
left: 0;
transform: translateY(-50%) translateX(-50%);
cursor: pointer;
width: 32px;
height: 32px;
background-color: #303342;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
`

const IconBottomContainer = styled.div`
position: absolute;
bottom: 0;
right: 0;
transform: translateY(10px) translateX(3px);
color: #6b7a8d;
line-height: 1;
`
Loading

0 comments on commit a312983

Please sign in to comment.