Skip to content

Commit

Permalink
Merge pull request #186 from boostcampwm-2024/feat/client/#180
Browse files Browse the repository at this point in the history
Feat/client/#180
  • Loading branch information
SeoGeonhyuk authored Dec 4, 2024
2 parents 4cb96b9 + 577754b commit 64b91af
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 95 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ jobs:
tags: |
cloud-canvas.kr.ncr.ntruss.com/front:dev
cloud-canvas.kr.ncr.ntruss.com/front:${{ github.sha }}
build-args: |
VITE_API_URL=${{ secrets.VITE_API_URL }}
- name: Docker front-hub image build and push
uses: docker/build-push-action@v3
Expand Down
9 changes: 6 additions & 3 deletions apps/client/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ FROM node:20 AS build
WORKDIR /build

COPY . .

RUN npm install -g pnpm && pnpm install && pnpm build

ARG VITE_API_URL
ENV VITE_API_URL=${VITE_API_URL}

RUN npm install -g pnpm && pnpm install && pnpm build:prod

FROM nginx:alpine AS production
COPY --from=build /build/apps/client/dist /usr/share/nginx/html
COPY ./apps/nginx/nginx.conf /etc/nginx/conf.d/default.conf

ENV PORT=5000
EXPOSE 5000
CMD ["nginx", "-g", "daemon off;"]
CMD ["nginx", "-g", "daemon off;"]
5 changes: 5 additions & 0 deletions apps/client/assets/upload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 1 addition & 8 deletions apps/client/src/apis/loaders.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from 'react-router-dom';
import { urls } from '.';
import { undefinedReviver } from '@utils';

export const rootLoader = async ({ params }: LoaderFunctionArgs) => {
const loginResponse = await fetch(urls('login'), {
Expand Down Expand Up @@ -31,13 +30,7 @@ export const rootLoader = async ({ params }: LoaderFunctionArgs) => {
});
}

const text = await archiResponse.text();
let data;
try {
data = JSON.parse(text, undefinedReviver);
} catch (error) {
throw new Response('Invalid JSON response', { status: 500 });
}
const data = await archiResponse.json();

return { data };
};
6 changes: 2 additions & 4 deletions apps/client/src/components/Graph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ export default ({ children }: PropsWithChildren) => {
return;
}

const newWidth = viewBox.width * zoomFactor;
const newHeight = viewBox.height * zoomFactor;
dispatch({
type: 'SET_VIEWBOX',
payload: {
Expand All @@ -50,8 +48,8 @@ export default ({ children }: PropsWithChildren) => {
y:
viewBox.y +
(cursorSvgPoint.y - viewBox.y) * (1 - zoomFactor),
width: newWidth,
height: newHeight,
width: viewBox.width * zoomFactor,
height: viewBox.height * zoomFactor,
},
});
};
Expand Down
4 changes: 2 additions & 2 deletions apps/client/src/components/Layout/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import List from '@mui/material/List';

import Service from '@components/Layout/Sidebar/Service';
import SelectPlatform from '@components/Layout/Sidebar/SelectPlatform';
import { NCLOUD_SERVICES } from '@constants';
import { SIDEBAR_RESOURCES } from '@constants';

const CLOUD_PLATFORMS = [
{
Expand Down Expand Up @@ -55,7 +55,7 @@ export default () => {
overflow: 'auto',
}}
>
{NCLOUD_SERVICES.map((service) => (
{SIDEBAR_RESOURCES.map((service) => (
<Service
key={service.title}
title={service.title}
Expand Down
157 changes: 157 additions & 0 deletions apps/client/src/components/Node/common/ImageBlockNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { useDimensionContext } from '@contexts/DimensionContext';
import { useColorScheme, useTheme } from '@mui/material';
import { calcIsoMatrixPoint, readFile } from '@utils';
import { DragEvent, useEffect, useState } from 'react';

type Props = {
isInnerDropZone: boolean;
imgSrc: string;
onDrop: (e: DragEvent) => void;
onDragLeave: (e: DragEvent) => void;
onDragOver: (e: DragEvent) => void;
};
const ImageBlock3D = ({
isInnerDropZone,
imgSrc,
onDrop: handleDrop,
onDragLeave: handleDragLeave,
onDragOver: handleDragOver,
}: Props) => {
const matrix = calcIsoMatrixPoint({ x: 0, y: 0 });
const theme = useTheme();
return (
<>
<svg
width="128"
height="111"
fillRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit="1.414"
>
<path fill="#b8b8bb" d="M64 74v37l64-37V37L64 74Z"></path>
<path fill="#d2d2d4" d="M0 37v37l64 37V74L0 37Z"></path>
<path
fill={
isInnerDropZone ? theme.palette.primary.main : '#ececed'
}
d="M0 37 64 0l64 37-64 37L0 37Z"
></path>
<path
fill="#83838a"
d="m64 73.407 62.111-35.86.514.889-62.487 36.078h-.276L.743 38.072l.514-.89L64 73.407Z"
></path>
<path fill="#83838a" d="M63.486 74h1.027v36h-1.027z"></path>
<path
fill="#000000"
d="M128 37v37l-64 37L0 74V37L64 0l64 37ZM2.054 38.185v34.63L64 108.627l61.946-35.812v-34.63L64 2.373 2.054 38.185Z"
></path>
</svg>
<svg
x="0"
y="0"
width="128"
height="74"
overflow="visible"
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
style={{ cursor: 'pointer' }}
>
<image
href={imgSrc}
x="37"
y="-37"
width="74"
height="74"
preserveAspectRatio="xMidYMid meet"
transform={matrix.toString()}
/>
</svg>
</>
);
};

const ImageBlock2D = ({
isInnerDropZone,
imgSrc,
onDrop: handleDrop,
onDragLeave: handleDragLeave,
onDragOver: handleDragOver,
}: Props) => {
const theme = useTheme();
return (
<svg
width="90"
height="90"
overflow="visible"
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
>
<rect
width="90"
height="90"
fill={
isInnerDropZone
? theme.palette.primary.light
: 'transparent'
}
></rect>
<image
href={imgSrc}
x="0"
y="0"
width="90"
height="90"
preserveAspectRatio="xMidYMid meet"
/>
</svg>
);
};

export default () => {
const { dimension } = useDimensionContext();
const [imgSrc, setImgSrc] = useState<string>('assets/upload.svg');
const [isInnerDropZone, setIsInnerDropZone] = useState(false);

const handleDrop = async (e: any) => {
e.preventDefault();
const files = e.dataTransfer.files;
if (files && files[0]) {
try {
const src = await readFile(files[0]);
setImgSrc(src);
} catch (error) {
console.error(error);
}
}
setIsInnerDropZone(false);
};

const handleDragOver = (e: DragEvent) => {
e.preventDefault();
setIsInnerDropZone(true);
};

const handleDragLeave = (e: DragEvent) => {
e.preventDefault();
setIsInnerDropZone(false);
};
return dimension === '2d' ? (
<ImageBlock2D
isInnerDropZone={isInnerDropZone}
imgSrc={imgSrc}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
/>
) : (
<ImageBlock3D
isInnerDropZone={isInnerDropZone}
imgSrc={imgSrc}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
/>
);
};
5 changes: 4 additions & 1 deletion apps/client/src/components/Node/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import MySQLDBNode from '@components/Node/ncloud/MySQLDBNode';
import ObjectStorageNode from '@components/Node/ncloud/ObjectStorageNode';
import ServerNode from '@components/Node/ncloud/ServerNode';
import useDrag from '@hooks/useDrag';
import useGraph from '@hooks/useGraph';
import { Node, Point } from '@types';
import { useEffect } from 'react';
import ImageBlockNode from './common/ImageBlockNode';
import LoadBalancerNode from './ncloud/LoadBalancer';
import NatGatewayNode from './ncloud/NatGateway';
import useGraph from '@hooks/useGraph';

const nodeFactory = (node: Node) => {
switch (node.type) {
Expand All @@ -26,6 +27,8 @@ const nodeFactory = (node: Node) => {
return <ContainerRegistryNode {...node} />;
case 'nat-gateway':
return <NatGatewayNode {...node} />;
case 'image-block':
return <ImageBlockNode />;
default:
null;
}
Expand Down
38 changes: 0 additions & 38 deletions apps/client/src/components/Node/ncloud/ServerNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,7 @@ import { Node } from '@types';

type Props = Partial<Node>;

const convertToIsoMatrix = (x: number, y: number) => {
const isoMatrix = new DOMMatrix()
.rotate(30)
.skewX(-30)
.scale(1, 0.8602)
.translate(x, y);

return isoMatrix; // 결과 행렬 반환
};
const Node3D = ({ properties }: Props) => {
const matrix = convertToIsoMatrix(0, 0);

return (
<>
<svg
Expand All @@ -37,22 +26,6 @@ const Node3D = ({ properties }: Props) => {
d="M128 37v37l-64 37L0 74V37L64 0l64 37ZM2.054 38.185v34.63L64 108.627l61.946-35.812v-34.63L64 2.373 2.054 38.185Z"
></path>
</svg>

{/* <g */}
{/* x="58" */}
{/* y="19" */}
{/* transform={`matrix(${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, ${matrix.e}, ${matrix.f})`} */}
{/* > */}
{/* <svg></svg> */}
{/* <path */}
{/* d="M15.948,2h.065a10.418,10.418,0,0,1,.972.528Q22.414,5.65,27.843,8.774a.792.792,0,0,1,.414.788c-.008,4.389,0,8.777-.005,13.164a.813.813,0,0,1-.356.507q-5.773,3.324-11.547,6.644a.587.587,0,0,1-.657.037Q9.912,26.6,4.143,23.274a.7.7,0,0,1-.4-.666q0-6.582,0-13.163a.693.693,0,0,1,.387-.67Q9.552,5.657,14.974,2.535c.322-.184.638-.379.974-.535" */}
{/* style={{ fill: '#009639' }} */}
{/* /> */}
{/* <path */}
{/* d="M8.767,10.538q0,5.429,0,10.859a1.509,1.509,0,0,0,.427,1.087,1.647,1.647,0,0,0,2.06.206,1.564,1.564,0,0,0,.685-1.293c0-2.62-.005-5.24,0-7.86q3.583,4.29,7.181,8.568a2.833,2.833,0,0,0,2.6.782,1.561,1.561,0,0,0,1.251-1.371q.008-5.541,0-11.081a1.582,1.582,0,0,0-3.152,0c0,2.662-.016,5.321,0,7.982-2.346-2.766-4.663-5.556-7-8.332A2.817,2.817,0,0,0,10.17,9.033,1.579,1.579,0,0,0,8.767,10.538Z" */}
{/* style={{ fill: '#fff' }} */}
{/* /> */}
{/* </g> */}
<svg x="49" y="14" width="80" height="36" overflow="visible">
<rect
transform="matrix(0.707 0.409 -0.707 0.409 0 0)"
Expand Down Expand Up @@ -98,17 +71,6 @@ const Node2D = ({ properties }: Props) => {
opacity=".05"
></path>
</svg>
{/* <svg xmlns="http://www.w3.org/2000/svg" x="30" y="27"> */}
{/* <title>file_type_nginx</title> */}
{/* <path */}
{/* d="M15.948,2h.065a10.418,10.418,0,0,1,.972.528Q22.414,5.65,27.843,8.774a.792.792,0,0,1,.414.788c-.008,4.389,0,8.777-.005,13.164a.813.813,0,0,1-.356.507q-5.773,3.324-11.547,6.644a.587.587,0,0,1-.657.037Q9.912,26.6,4.143,23.274a.7.7,0,0,1-.4-.666q0-6.582,0-13.163a.693.693,0,0,1,.387-.67Q9.552,5.657,14.974,2.535c.322-.184.638-.379.974-.535" */}
{/* style={{ fill: '#009639' }} */}
{/* /> */}
{/* <path */}
{/* d="M8.767,10.538q0,5.429,0,10.859a1.509,1.509,0,0,0,.427,1.087,1.647,1.647,0,0,0,2.06.206,1.564,1.564,0,0,0,.685-1.293c0-2.62-.005-5.24,0-7.86q3.583,4.29,7.181,8.568a2.833,2.833,0,0,0,2.6.782,1.561,1.561,0,0,0,1.251-1.371q.008-5.541,0-11.081a1.582,1.582,0,0,0-3.152,0c0,2.662-.016,5.321,0,7.982-2.346-2.766-4.663-5.556-7-8.332A2.817,2.817,0,0,0,10.17,9.033,1.579,1.579,0,0,0,8.767,10.538Z" */}
{/* style={{ fill: '#fff' }} */}
{/* /> */}
{/* </svg> */}
<svg x="18" y="27" width="54" height="36">
<text
x="50%"
Expand Down
8 changes: 7 additions & 1 deletion apps/client/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ export const NODE_BASE_SIZE = {
'3d': { width: 128, height: 111 },
};

export const NCLOUD_SERVICES = [
export const SIDEBAR_RESOURCES = [
{
title: 'Common',
items: [
{ title: 'Image Block', desc: 'Image Block', type: 'image-block' },
],
},
{
title: 'compute',
items: [
Expand Down
5 changes: 2 additions & 3 deletions apps/client/src/hooks/useFetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { undefinedReplacer } from '@utils';
import { useState, useEffect } from 'react';

type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
Expand Down Expand Up @@ -40,9 +39,9 @@ function useFetch<T = any>(
...headers,
},
body: executeBody
? JSON.stringify(executeBody, undefinedReplacer)
? JSON.stringify(executeBody)
: body
? JSON.stringify(body, undefinedReplacer)
? JSON.stringify(body)
: null,
credentials: credentials ?? 'include',
});
Expand Down
15 changes: 15 additions & 0 deletions apps/client/src/models/ncloud/ImageBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GraphNode } from '@helpers/node';
import { Node } from '@types';
import { Networks, NetworksProp } from './Networks';

export const ImageBlock: Node = {
...GraphNode,
type: 'image-block',
size: {
'2d': { width: 90, height: 90 },
'3d': { width: 128, height: 111, offset: 0 },
},
properties: {
...Networks,
},
};
3 changes: 3 additions & 0 deletions apps/client/src/models/ncloud/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ImageBlock } from './ImageBlock';
import { CloudFunctionNode } from './CloudFunction';
import { ContainerRegistryNode } from './ContainerRegistry';
import { LoadBalancerNode } from './LoadBalancer';
Expand Down Expand Up @@ -26,6 +27,8 @@ export const NcloudNodeFactory = (type: string) => {
return ObjectStorageNode;
case 'nat-gateway':
return NatGatewayNode;
case 'image-block':
return ImageBlock;
default: {
throw new Error(`Unknown type: ${type}`);
}
Expand Down
Loading

0 comments on commit 64b91af

Please sign in to comment.