diff --git a/apps/client/src/components/NCloud/NetworksBar/SubnetSelect.tsx b/apps/client/src/components/NCloud/NetworksBar/SubnetSelect.tsx
index be0c913b..defe6cd4 100644
--- a/apps/client/src/components/NCloud/NetworksBar/SubnetSelect.tsx
+++ b/apps/client/src/components/NCloud/NetworksBar/SubnetSelect.tsx
@@ -83,6 +83,7 @@ export default ({
variant="text"
disabled={disabled}
disableRipple
+ sx={{ whiteSpace: 'nowrap' }}
>
{subnet ? subnet.value : }
diff --git a/apps/client/src/components/NCloud/NetworksBar/VpcSelect.tsx b/apps/client/src/components/NCloud/NetworksBar/VpcSelect.tsx
index a352bda7..fcafbb00 100644
--- a/apps/client/src/components/NCloud/NetworksBar/VpcSelect.tsx
+++ b/apps/client/src/components/NCloud/NetworksBar/VpcSelect.tsx
@@ -88,6 +88,7 @@ export default ({
type="submit"
disabled={disabled}
disableRipple
+ sx={{ whiteSpace: 'nowrap' }}
>
{vpc ? vpc.value : }
diff --git a/apps/client/src/components/SaveDialog.tsx b/apps/client/src/components/SaveDialog.tsx
index ed928d53..6d28d251 100644
--- a/apps/client/src/components/SaveDialog.tsx
+++ b/apps/client/src/components/SaveDialog.tsx
@@ -12,6 +12,8 @@ import TextField from '@mui/material/TextField';
import { useNavigate, useParams } from 'react-router-dom';
import { urls } from '../apis';
import { useCloudGraph } from './CloudGraphProvider';
+import { useDimensionContext } from '@contexts/DimensionContext';
+import useGraph from '@hooks/useGraph';
type Props = {
open: boolean;
onClose: () => void;
@@ -27,7 +29,9 @@ export default ({ open, onClose }: Props) => {
const {
state: { edges },
} = useEdgeContext();
+ const { updatePointForDimension } = useGraph();
const { data: graphData, setData: setGraphData } = useCloudGraph();
+ const { dimension } = useDimensionContext();
const navigate = useNavigate();
const params = useParams();
@@ -47,12 +51,22 @@ export default ({ open, onClose }: Props) => {
const title = (e.target as any).title.value;
+ let updatedNodes = nodes;
+ let updatedEdges = edges;
+ // 서버에 저장시 2d로 변환
+ if (dimension === '3d') {
+ const { updatedNodes: _updatedNodes, updatedEdges: _updatedEdges } =
+ updatePointForDimension(nodes, edges, '2d');
+
+ updatedNodes = _updatedNodes;
+ updatedEdges = _updatedEdges;
+ }
const resp = await saveArchitecture({
cost: 0,
architecture: {
- nodes,
+ nodes: updatedNodes,
+ edges: updatedEdges,
groups,
- edges,
},
title,
});
diff --git a/apps/client/src/components/ShareDialog.tsx b/apps/client/src/components/ShareDialog.tsx
index ef5b0c4c..30302a24 100644
--- a/apps/client/src/components/ShareDialog.tsx
+++ b/apps/client/src/components/ShareDialog.tsx
@@ -1,26 +1,92 @@
+import { useDimensionContext } from '@contexts/DimensionContext';
+import { useEdgeContext } from '@contexts/EdgeContext';
+import { useGroupContext } from '@contexts/GroupContext';
+import { useNodeContext } from '@contexts/NodeContext';
+import { useSvgContext } from '@contexts/SvgContext';
+import { calculateNodeBoundingBox } from '@helpers/node';
+import useFetch from '@hooks/useFetch';
+import { FormControl, Stack, useColorScheme, useTheme } from '@mui/material';
import Button from '@mui/material/Button';
-import TextField from '@mui/material/TextField';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
-import Select, { OnChangeValue } from 'react-select';
+import TextField from '@mui/material/TextField';
import { useState } from 'react';
-import Creatable, { useCreatable } from 'react-select/creatable';
-import { Stack, FormControl } from '@mui/material';
-import { useEdgeContext } from '@contexts/EdgeContext';
-import { useGroupContext } from '@contexts/GroupContext';
-import { useNodeContext } from '@contexts/NodeContext';
-import useFetch from '@hooks/useFetch';
+import { OnChangeValue } from 'react-select';
+import Creatable from 'react-select/creatable';
import { urls } from '../apis';
-import { useSvgContext } from '@contexts/SvgContext';
-import { calculateNodeBoundingBox } from '@helpers/node';
-import { useDimensionContext } from '@contexts/DimensionContext';
+import useGraph from '@hooks/useGraph';
+
type Props = {
open: boolean;
onClose: () => void;
};
+const reactSelectStyles = (mode: string, theme: any) => ({
+ control: (provided: any) => ({
+ ...provided,
+ backgroundColor:
+ mode === 'dark' ? '#393939' : theme.palette.background.paper,
+ borderColor:
+ mode === 'dark' ? theme.palette.grey[700] : theme.palette.divider,
+ minHeight: '40px',
+ height: '40px',
+ boxShadow: 'none',
+ '&:hover': {
+ borderColor: mode === 'dark' ? '#fff' : theme.palette.text.primary,
+ },
+ '&:focus-within': {
+ borderColor:
+ mode === 'dark'
+ ? theme.palette.primary.main
+ : theme.palette.text.primary,
+ },
+ }),
+ input: (provided: any) => ({
+ ...provided,
+ color:
+ mode === 'dark'
+ ? theme.palette.text.primary
+ : theme.palette.text.secondary,
+ }),
+ menu: (provided: any) => ({
+ ...provided,
+ display: 'none',
+ }),
+ dropdownIndicator: () => ({ display: 'none' }),
+ indicatorSeparator: () => ({ display: 'none' }),
+ multiValue: (provided: any) => ({
+ ...provided,
+ backgroundColor:
+ mode === 'dark' ? theme.palette.grey[700] : theme.palette.grey[300],
+ }),
+ multiValueLabel: (provided: any) => ({
+ ...provided,
+ color:
+ mode === 'dark'
+ ? theme.palette.common.white
+ : theme.palette.text.primary,
+ }),
+ multiValueRemove: (provided: any) => ({
+ ...provided,
+ color:
+ mode === 'dark'
+ ? theme.palette.common.white
+ : theme.palette.text.primary,
+ ':hover': {
+ backgroundColor:
+ mode === 'dark'
+ ? theme.palette.grey[600]
+ : theme.palette.grey[400],
+ color:
+ mode === 'dark'
+ ? theme.palette.common.white
+ : theme.palette.text.primary,
+ },
+ }),
+});
+
export default ({ open, onClose }: Props) => {
const {
state: { nodes },
@@ -31,8 +97,12 @@ export default ({ open, onClose }: Props) => {
const {
state: { edges },
} = useEdgeContext();
+ const { updatePointForDimension } = useGraph();
+
const { svgRef } = useSvgContext();
const { dimension } = useDimensionContext();
+ const { mode } = useColorScheme();
+ const theme = useTheme();
const [tags, setTags] = useState<{ label: string; value: string }[]>([]);
@@ -40,6 +110,25 @@ export default ({ open, onClose }: Props) => {
method: 'POST',
});
+ const getCloneSvg = (svg: SVGSVGElement) => {
+ const allNodeBoundsBox = calculateNodeBoundingBox(
+ Object.values(nodes),
+ dimension,
+ );
+ const padding = 90 * 8;
+
+ const viewBox = `${allNodeBoundsBox.minX - padding} ${
+ allNodeBoundsBox.minY - padding
+ } ${allNodeBoundsBox.width + padding * 2} ${
+ allNodeBoundsBox.height + padding * 2
+ }`;
+
+ const svgClone = svg.cloneNode(true) as SVGSVGElement;
+ svgClone.setAttribute('viewBox', viewBox);
+
+ return svgClone;
+ };
+
const handleClose = () => {
onClose();
};
@@ -62,27 +151,26 @@ export default ({ open, onClose }: Props) => {
return;
}
- const allNodeBoundsBox = calculateNodeBoundingBox(
- Object.values(nodes),
- dimension,
- );
- const padding = 90 * 4;
+ const svgClone = getCloneSvg(svgRef.current);
- const viewBox = `${allNodeBoundsBox.minX - padding} ${
- allNodeBoundsBox.minY - padding
- } ${allNodeBoundsBox.width + padding * 2} ${
- allNodeBoundsBox.height + padding * 2
- }`;
+ let updatedNodes = nodes;
+ let updatedEdges = edges;
+ // 서버에 저장시 2d로 변환
+ if (dimension === '3d') {
+ const { updatedNodes: _updatedNodes, updatedEdges: _updatedEdges } =
+ updatePointForDimension(nodes, edges, '2d');
+
+ updatedNodes = _updatedNodes;
+ updatedEdges = _updatedEdges;
+ }
- const svgClone = svgRef.current.cloneNode(true) as SVGSVGElement;
- svgClone.setAttribute('viewBox', viewBox);
await shareArchitecture({
cost: 0,
tags: cloudTags,
architecture: {
- nodes,
+ nodes: updatedNodes,
+ edges: updatedEdges,
groups,
- edges,
svg: svgClone.outerHTML,
},
title,
@@ -133,14 +221,7 @@ export default ({ open, onClose }: Props) => {
name="tags"
value={tags}
onChange={handleChange}
- styles={{
- menu: (provided) => ({
- ...provided,
- display: 'none',
- }),
- dropdownIndicator: () => ({ display: 'none' }),
- indicatorSeparator: () => ({ display: 'none' }),
- }}
+ styles={reactSelectStyles(mode!, theme)}
/>
diff --git a/apps/client/src/hooks/useGraph.ts b/apps/client/src/hooks/useGraph.ts
index 31f0855a..da76218d 100644
--- a/apps/client/src/hooks/useGraph.ts
+++ b/apps/client/src/hooks/useGraph.ts
@@ -125,9 +125,15 @@ export default () => {
clearSelection();
};
- //TODO: Refactoring필요
- const updateNodePointForDimension = (dimension: Dimension) => {
- //INFO: update node
+ const updatePointForDimension = (
+ nodes: Record,
+ edges: Record,
+ dimension: Dimension,
+ ): {
+ updatedNodes: Record;
+ updatedEdges: Record;
+ } => {
+ // INFO: Update nodes
const updatedNodes: Record = Object.entries(nodes).reduce(
(acc, [id, node]) => {
const adjustedPoint = adjustNodePointForDimension(
@@ -153,26 +159,96 @@ export default () => {
{},
);
- //INFO:update edge
- let updatedEdges = Object.entries(edges).reduce((acc, [id, edge]) => {
- const adjustedBendingPoints = edge.bendingPoints.map((point) => {
- if (dimension === '3d') {
- const grid = screenToGrid2d(point);
- return gridToScreen3d({ col: grid.col + 1, row: grid.row });
- } else {
- const grid = screenToGrid3d(point);
- return gridToScreen2d({ col: grid.col - 1, row: grid.row });
- }
- });
+ // INFO: Update edges
+ const updatedEdges: Record = Object.entries(edges).reduce(
+ (acc, [id, edge]) => {
+ const adjustedBendingPoints = edge.bendingPoints.map(
+ (point) => {
+ if (dimension === '3d') {
+ const grid = screenToGrid2d(point);
+ return gridToScreen3d({
+ col: grid.col + 1,
+ row: grid.row,
+ });
+ } else {
+ const grid = screenToGrid3d(point);
+ return gridToScreen2d({
+ col: grid.col - 1,
+ row: grid.row,
+ });
+ }
+ },
+ );
- return {
- ...acc,
- [id]: {
- ...edge,
- bendingPoints: adjustedBendingPoints,
- },
- };
- }, {});
+ return {
+ ...acc,
+ [id]: {
+ ...edge,
+ bendingPoints: adjustedBendingPoints,
+ },
+ };
+ },
+ {},
+ );
+
+ // Return the updated nodes and edges
+ return { updatedNodes, updatedEdges };
+ };
+
+ //TODO: Refactoring필요
+ const updateNodePointForDimension = (dimension: Dimension) => {
+ //INFO: update node
+ // const updatedNodes: Record = Object.entries(nodes).reduce(
+ // (acc, [id, node]) => {
+ // const adjustedPoint = adjustNodePointForDimension(
+ // node.point,
+ // node.size['3d'],
+ // dimension,
+ // );
+ //
+ // const connectors = getConnectorPoints(
+ // { ...node, point: adjustedPoint },
+ // dimension,
+ // );
+ //
+ // return {
+ // ...acc,
+ // [id]: {
+ // ...node,
+ // point: adjustedPoint,
+ // connectors,
+ // },
+ // };
+ // },
+ // {},
+ // );
+ //
+ // //INFO:update edge
+ // let updatedEdges = Object.entries(edges).reduce((acc, [id, edge]) => {
+ // const adjustedBendingPoints = edge.bendingPoints.map((point) => {
+ // if (dimension === '3d') {
+ // const grid = screenToGrid2d(point);
+ // return gridToScreen3d({ col: grid.col + 1, row: grid.row });
+ // } else {
+ // const grid = screenToGrid3d(point);
+ // return gridToScreen2d({ col: grid.col - 1, row: grid.row });
+ // }
+ // });
+ //
+ // return {
+ // ...acc,
+ // [id]: {
+ // ...edge,
+ // bendingPoints: adjustedBendingPoints,
+ // },
+ // };
+ // }, {});
+
+ const { updatedNodes, updatedEdges } = updatePointForDimension(
+ nodes,
+ edges,
+ dimension,
+ );
//INFO: update ViewBox
if (Object.keys(updatedNodes).length === 0 || !svgRef.current) return;
@@ -457,6 +533,7 @@ export default () => {
addEdge,
removeEdge,
splitEdge,
+ updatePointForDimension,
updateNodePointForDimension,
moveBendingPointer,
addGroup,