diff --git a/.github/workflows/deployment.dev.yml b/.github/workflows/deployment.dev.yml
index e2a1401d..40f0ba2f 100644
--- a/.github/workflows/deployment.dev.yml
+++ b/.github/workflows/deployment.dev.yml
@@ -36,5 +36,5 @@ jobs:
yarn install
yarn start:prod
cd ../server
- echo ${{ secrets.PASSWORD }} | sudo -S sh run_docker.sh local
+ echo ${{ secrets.PASSWORD }} | sudo -S sh run_docker.sh prod
diff --git a/README.md b/README.md
index 58e5a7a8..750c9aa9 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,47 @@
# Dicom Service Management Project
+
## :dart: Objective
Dicom 의료 영상 데이터를 저장, 관리하며 시각화 기능과 머신러닝 개발을 지원하는 SW개발
## :bar_chart: Success metrics
의료데이터 관리 및 시각화 지원 기능을 구현하여 v1.0 배포를 목표로 한다.(option 제외)
+## Usage
+### Prerequirement
+1. 최신 버전의 도커를 설치해주세요. (docker-compose는 v2 버전으로 설치되어야 합니다, 리눅스의 경우 간혹 v1으로 설치되므로 업데이트가 필요합니다.)
+2. java SDK (version. 17.0.1)을 설치합니다. (설치하지 않을 경우 spring 프로젝트 파일이 정상적으로 실행되지 않습니다.)
+3. Node.js 가 설치되어 있지 않다면 v16.6.1버전으로 설치해야 합니다.
+4. 최신 버전의 [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable)을 설치해주세요.
+
+### Install Project
+설치의 경우 프로젝트를 다운로드 한 후, 한번만 실행하면 됩니다. 프로젝트 코드가 갱신될 경우, 코드를 반영하기 위해서 다시 실행해야 합니다.
+#### Common
+1. 코드 다운로드
+```sh
+#clone all project with submodules
+git clone --recurse-submodules https://github.com/BEOKS/DicomProject.git
+cd DicomProject
+```
+2. 현재 프로젝트는 구글 로그인을 사용하고 있으므로 구글 API clientId와 secrect id가 필요합니다. 이를 발급받아 [application-oauth.yml.example](https://github.com/BEOKS/DicomProject/blob/main/server/DSMP/src/main/resources/application-oauth.yml.example)과 같은 형식을 작성하여 같은 파일 위치에 application-oauth.yml 파일을 생성해야 합니다.
+#### Window
+```sh
+.\install_project.sh
+```
+#### Mac, Linux
+```sh
+sudo sh install_project.sh
+```
+### Run Project
+#### Window
+```sh
+run_project.sh local # run project for development
+#localhost:3000에서 서비스 이용가능
+run_project.sh prod # run project for deploy
+```
+#### Mac, Linux
+```sh
+sudo sh run_project.sh local # run project for development
+#localhost:3000에서 서비스 이용가능
+sudo sh run_project.sh prod # run project for deploy
+```
## 📓 Requirements
### 1. 의료 데이터 관리
Requirement | User Story | Notes | Priority
diff --git a/Viewers b/Viewers
index 460fdeb5..4e489ddd 160000
--- a/Viewers
+++ b/Viewers
@@ -1 +1 @@
-Subproject commit 460fdeb534cd94bff55892c8e3d7100ccf8957de
+Subproject commit 4e489ddddae2969f055acc1dacc60efb6b106425
diff --git a/client/README.md b/client/README.md
index 2961e4f5..cf1b19f1 100644
--- a/client/README.md
+++ b/client/README.md
@@ -1,6 +1,6 @@
# Usage
> 이 클라이언트는 Viewer 클라이언트를 참조하기 때문에 우선 Viewer클라이언트를 실행해야한다.
-0. Node.js 가 설치되어 있지 않다면 [최신버전](https://nodejs.org/ko/download/)으로 설치해야 합니다.
+0. Node.js 가 설치되어 있지 않다면 v16.6.1버전으로 ode.js를 설치해야 합니다.
1. 클라이언트 시작 전 [server/README.md](../server/README.md)를 참조하여 서버를 실행합니다.
2. Viewer 서브 모듈을 업데이트 합니다.
```
diff --git a/client/package-lock.json b/client/package-lock.json
index 763b9562..26f6a6ee 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -18,11 +18,18 @@
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.24.0",
+ "convert-csv-to-json": "^1.3.3",
"cross-env": "^7.0.3",
+ "csv": "^6.0.5",
+ "csv-parse": "^5.0.4",
"dicom-parser": "^1.8.11",
+ "fastq": "^1.13.0",
"http-proxy-middleware": "^2.0.1",
+ "json2csv": "^5.0.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-router": "^6.2.1",
+ "react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
@@ -6740,6 +6747,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/convert-csv-to-json": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/convert-csv-to-json/-/convert-csv-to-json-1.3.3.tgz",
+ "integrity": "sha512-lIQrCmEw0GCywtVWeJ/AGv5hhSTPsMFdqOf9GcMtActqO2Gt8z1RZgfw9NBOll479cIPM6BqDOFC8R3W7bSwtA=="
+ },
"node_modules/convert-source-map": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -7369,6 +7381,35 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
"integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
},
+ "node_modules/csv": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/csv/-/csv-6.0.5.tgz",
+ "integrity": "sha512-VyII851P4BvzMsXenhtR7g3mARmZ3HvBX16PD85E8IOoxyvNT9e74egbfdkYBj5SGHh1LphCWXeQvskijH+kfg==",
+ "dependencies": {
+ "csv-generate": "^4.0.4",
+ "csv-parse": "^5.0.4",
+ "csv-stringify": "^6.0.5",
+ "stream-transform": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.1.90"
+ }
+ },
+ "node_modules/csv-generate": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.0.4.tgz",
+ "integrity": "sha512-6/0FOBbF4O+EBSAYsfOXBjIFhyPpfeeeuWEM4XJQhc/6TvDDL9AGFQNPh2SKlFx7VYERBDmZAWnITgaa+z4BJA=="
+ },
+ "node_modules/csv-parse": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.0.4.tgz",
+ "integrity": "sha512-5AIdl8l6n3iYQYxan5djB5eKDa+vBnhfWZtRpJTcrETWfVLYN0WSj3L9RwvgYt+psoO77juUr8TG8qpfGZifVQ=="
+ },
+ "node_modules/csv-stringify": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.0.5.tgz",
+ "integrity": "sha512-7xpV3uweJCFF/Ssn56l3xsR/k2r3UqszwjEhej9qEn2cCPzyK1WyHCgoUVzBA792x8HbwonNX7CU9XM2K5s5yw=="
+ },
"node_modules/customize-cra": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/customize-cra/-/customize-cra-1.0.0.tgz",
@@ -10533,6 +10574,14 @@
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
+ "node_modules/history": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
+ "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
+ "dependencies": {
+ "@babel/runtime": "^7.7.6"
+ }
+ },
"node_modules/hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -14575,6 +14624,31 @@
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
},
+ "node_modules/json2csv": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.6.tgz",
+ "integrity": "sha512-0/4Lv6IenJV0qj2oBdgPIAmFiKKnh8qh7bmLFJ+/ZZHLjSeiL3fKKGX3UryvKPbxFbhV+JcYo9KUC19GJ/Z/4A==",
+ "dependencies": {
+ "commander": "^6.1.0",
+ "jsonparse": "^1.3.1",
+ "lodash.get": "^4.4.2"
+ },
+ "bin": {
+ "json2csv": "bin/json2csv.js"
+ },
+ "engines": {
+ "node": ">= 10",
+ "npm": ">= 6.13.0"
+ }
+ },
+ "node_modules/json2csv/node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@@ -14605,6 +14679,14 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "engines": [
+ "node >= 0.2.0"
+ ]
+ },
"node_modules/jsx-ast-utils": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
@@ -14746,6 +14828,11 @@
"integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=",
"dev": true
},
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -18037,6 +18124,30 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
+ "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
+ "dependencies": {
+ "history": "^5.2.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
+ "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
+ "dependencies": {
+ "history": "^5.2.0",
+ "react-router": "6.2.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz",
@@ -20144,6 +20255,11 @@
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
},
+ "node_modules/stream-transform": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.0.4.tgz",
+ "integrity": "sha512-g2jbk1hs3GiF3oHZLbR7Fph/PXh/3xHoz/D8aR2oHySE4xVUvNeTGqihhb1vxFjYyu4inqiTfT42g2MHBjjx0g=="
+ },
"node_modules/strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
@@ -28319,6 +28435,11 @@
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
+ "convert-csv-to-json": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/convert-csv-to-json/-/convert-csv-to-json-1.3.3.tgz",
+ "integrity": "sha512-lIQrCmEw0GCywtVWeJ/AGv5hhSTPsMFdqOf9GcMtActqO2Gt8z1RZgfw9NBOll479cIPM6BqDOFC8R3W7bSwtA=="
+ },
"convert-source-map": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -28806,6 +28927,32 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
"integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
},
+ "csv": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/csv/-/csv-6.0.5.tgz",
+ "integrity": "sha512-VyII851P4BvzMsXenhtR7g3mARmZ3HvBX16PD85E8IOoxyvNT9e74egbfdkYBj5SGHh1LphCWXeQvskijH+kfg==",
+ "requires": {
+ "csv-generate": "^4.0.4",
+ "csv-parse": "^5.0.4",
+ "csv-stringify": "^6.0.5",
+ "stream-transform": "^3.0.4"
+ }
+ },
+ "csv-generate": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.0.4.tgz",
+ "integrity": "sha512-6/0FOBbF4O+EBSAYsfOXBjIFhyPpfeeeuWEM4XJQhc/6TvDDL9AGFQNPh2SKlFx7VYERBDmZAWnITgaa+z4BJA=="
+ },
+ "csv-parse": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.0.4.tgz",
+ "integrity": "sha512-5AIdl8l6n3iYQYxan5djB5eKDa+vBnhfWZtRpJTcrETWfVLYN0WSj3L9RwvgYt+psoO77juUr8TG8qpfGZifVQ=="
+ },
+ "csv-stringify": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.0.5.tgz",
+ "integrity": "sha512-7xpV3uweJCFF/Ssn56l3xsR/k2r3UqszwjEhej9qEn2cCPzyK1WyHCgoUVzBA792x8HbwonNX7CU9XM2K5s5yw=="
+ },
"customize-cra": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/customize-cra/-/customize-cra-1.0.0.tgz",
@@ -31191,6 +31338,14 @@
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
+ "history": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
+ "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
+ "requires": {
+ "@babel/runtime": "^7.7.6"
+ }
+ },
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -34206,6 +34361,23 @@
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
},
+ "json2csv": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.6.tgz",
+ "integrity": "sha512-0/4Lv6IenJV0qj2oBdgPIAmFiKKnh8qh7bmLFJ+/ZZHLjSeiL3fKKGX3UryvKPbxFbhV+JcYo9KUC19GJ/Z/4A==",
+ "requires": {
+ "commander": "^6.1.0",
+ "jsonparse": "^1.3.1",
+ "lodash.get": "^4.4.2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
+ }
+ }
+ },
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@@ -34228,6 +34400,11 @@
"universalify": "^2.0.0"
}
},
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+ },
"jsx-ast-utils": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
@@ -34342,6 +34519,11 @@
"integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=",
"dev": true
},
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+ },
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -36958,6 +37140,23 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
},
+ "react-router": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
+ "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
+ "requires": {
+ "history": "^5.2.0"
+ }
+ },
+ "react-router-dom": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
+ "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
+ "requires": {
+ "history": "^5.2.0",
+ "react-router": "6.2.1"
+ }
+ },
"react-scripts": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz",
@@ -38662,6 +38861,11 @@
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
},
+ "stream-transform": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.0.4.tgz",
+ "integrity": "sha512-g2jbk1hs3GiF3oHZLbR7Fph/PXh/3xHoz/D8aR2oHySE4xVUvNeTGqihhb1vxFjYyu4inqiTfT42g2MHBjjx0g=="
+ },
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
diff --git a/client/package.json b/client/package.json
index 9c027ea4..5bf2b94c 100644
--- a/client/package.json
+++ b/client/package.json
@@ -13,18 +13,25 @@
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.24.0",
+ "convert-csv-to-json": "^1.3.3",
"cross-env": "^7.0.3",
+ "csv": "^6.0.5",
+ "csv-parse": "^5.0.4",
"dicom-parser": "^1.8.11",
+ "fastq": "^1.13.0",
"http-proxy-middleware": "^2.0.1",
+ "json2csv": "^5.0.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-router": "^6.2.1",
+ "react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
"scripts": {
- "start": "cross-env SERVER_HOST=localhost react-scripts start --max_old_space_size=8192",
- "start:local" : "cross-env SERVER_HOST=localhost react-scripts start --max_old_space_size=8192",
- "start:prod" : "cross-env SERVER_HOST=imdc.hopto.org react-scripts start --max_old_space_size=8192",
+ "start": "cross-env REACT_APP_SERVER_HOST=localhost react-scripts start --max_old_space_size=8192",
+ "start:local": "cross-env REACT_APP_SERVER_HOST=localhost react-scripts start --max_old_space_size=8192",
+ "start:prod": "cross-env REACT_APP_SERVER_HOST=imdc.hopto.org react-scripts start --max_old_space_size=8192",
"build": "react-scripts build --max_old_space_size=4096",
"test": "react-scripts test --max_old_space_size=4096",
"eject": "react-scripts eject --max_old_space_size=4096"
diff --git a/client/src/App.js b/client/src/App.js
index 579da3ac..f1517449 100644
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -1,103 +1,24 @@
-import * as React from 'react';
-import Box from '@mui/material/Box';
-import CssBaseline from '@mui/material/CssBaseline';
-import DicomTable from "./component/Table/DicomTable";
-import UpDownloadToolbar from "./component/Toolbar/UpDownloadToolbar";
-import { DrawerHeader } from './component/Drawer/ProjectDrawer';
-import ProjectDrawer from './component/Drawer/ProjectDrawer'
-import BaseAppBar from './component/AppBar/BaseAppBar';
-import axios from 'axios';
-
-axios.defaults.maxRedirects=0;
-export default function Page() {
- const [open, setOpen] = React.useState(false);
- const [projects, setProjects] = React.useState([]);
- const [presentProject, setPresentProject] = React.useState({ projectName: 'Dicom' });
- const [metaData, setMetaData] = React.useState([]);
- const [metaDataUpdated, setMetaDataUpdated] = React.useState(false);
- const [checkFirst, setCheckFirst] = React.useState(true);
-
- const getProjects = () => {
- axios.get('api/Project',{maxRedirects:0})
- .then(response => {
- if (response.data.length !== 0) {
- setProjects(response.data);
- if (checkFirst) {
- setPresentProject(response.data[0]);
- setCheckFirst(false);
- }
- }
- }).catch(error => {
- alert('서버가 응답하지 않습니다.')
- console.log(error);
- });
- };
-
- const getMetaData = (projectId) => {
- const url = `api/MetaData/${projectId}`;
- axios.get(url)
- .then(response => {
- setMetaData(response.data);
- }).catch(error => {
- console.log(error);
- });
- };
-
- const getNonReferenced = () => {
- const url = 'api/Patient/nonReferenced'
- axios.get(url)
- .then(response => {
- setMetaData(response.data);
- }).catch(error => {
- console.log(error);
- });
- };
-
- React.useEffect(() => {
- getProjects();
- }, [open]);
-
- React.useEffect(() => {
- presentProject.projectId
- ? getMetaData(presentProject.projectId)
- : getNonReferenced();
- }, [presentProject, metaDataUpdated]);
-
-
- const handleDrawerOpen = () => {
- setOpen(true);
- };
-
- const handleDrawerClose = () => {
- setOpen(false);
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
- );
+import * as React from 'react'
+import {useState} from 'react';
+import Page from './Page'
+import LoadingPage from './component/Login/Loading';
+import { chcekLoginStatusAsync } from './component/Login/Login';
+export default function App(){
+ const [loginStatus,setLoginStatus]=useState();
+ if(loginStatus===undefined){
+ chcekLoginStatusAsync(setLoginStatus);
+ return(
+
+ )
+ }
+ else if(loginStatus===false){
+ window.location.href='/oauth2/authorization/google'
+ return(
)
+ }
+ else if(loginStatus){
+ return()
+ }
+ else{
+ alert("로그인 확인 중 오류가 발생했습니다.")
+ }
}
\ No newline at end of file
diff --git a/client/src/Page.js b/client/src/Page.js
new file mode 100644
index 00000000..61f0db39
--- /dev/null
+++ b/client/src/Page.js
@@ -0,0 +1,163 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import CssBaseline from '@mui/material/CssBaseline';
+import { CircularProgress,Stack,Typography } from '@mui/material';
+import DicomTable from "./component/Table/DicomTable";
+import UpDownloadToolbar from "./component/Toolbar/UpDownloadToolbar";
+import { DrawerHeader } from './component/Drawer/ProjectDrawer';
+import ProjectDrawer from './component/Drawer/ProjectDrawer'
+import BaseAppBar from './component/AppBar/BaseAppBar';
+import LoadingPage from './component/Login/Loading';
+import axios from 'axios';
+axios.defaults.maxRedirects=0;
+export default function Page() {
+ const [open, setOpen] = React.useState(false);
+ const [projects, setProjects] = React.useState([]);
+ const [invitedProjects, setInvitedProjects] = React.useState([]);
+ const [isInvitedProject, setIsInvitedProject] = React.useState(false);
+ const [presentProject, setPresentProject] = React.useState({ projectName: '현재 선택된 프로젝트가 없습니다.' });
+ const [metaData, setMetaData] = React.useState([]);
+ const [metaDataUpdated, setMetaDataUpdated] = React.useState(false);
+ const [checkFirst, setCheckFirst] = React.useState(true);
+ const [loading,setLoading] =React.useState(true);
+
+ const getProjects = () => {
+ axios.get('api/Project',{maxRedirects:0})
+ .then(response => {
+ if (response.data.body.length !== 0) {
+ setProjects(response.data.body);
+ if (checkFirst) {
+ setPresentProject(response.data.body[0]);
+ setCheckFirst(false);
+ }
+ }
+ setLoading(false)
+ }).catch(error => {
+ if (error.response) {
+ alert(error.response.data.message);
+ console.log(error.response.data);
+ } else {
+ alert('서버가 응답하지 않습니다.');
+ console.log(error);
+ }
+ });
+ };
+
+ const getInvitedProjects = () => {
+ axios.get('api/Project/invited',{maxRedirects:0})
+ .then(response => {
+ if (response.data.body.length !== 0) {
+ setInvitedProjects(response.data.body);
+ }
+ setLoading(false)
+ }).catch(error => {
+ if (error.response) {
+ alert(error.response.data.message);
+ console.log(error.response.data);
+ } else {
+ alert('서버가 응답하지 않습니다.');
+ console.log(error);
+ }
+ });
+ };
+
+ const getMetaData = () => {
+ const url = `api/MetaData/${presentProject.projectId}`;
+ setMetaData('loading')
+ axios.get(url)
+ .then(response => {
+ setMetaData(response.data.body);
+ }).catch(error => {
+ if (error.response) {
+ alert(error.response.data.message);
+ console.log(error.response.data);
+ } else {
+ alert(error.message);
+ console.log(error);
+ }
+ });
+ };
+
+ // const getNonReferenced = () => {
+ // const url = 'api/Patient/nonReferenced'
+ // axios.get(url)
+ // .then(response => {
+ // setMetaData(response.data);
+ // }).catch(error => {
+ // console.log(error);
+ // });
+ // };
+
+ React.useEffect(() => {
+ getProjects();
+ getInvitedProjects();
+ }, [open]);
+
+ React.useEffect(() => {
+ if(presentProject.projectId ){
+ getMetaData()
+ }
+ //: getNonReferenced();
+ }, [presentProject, metaDataUpdated]);
+
+
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
+
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
+ if(loading){
+ return
+ }
+ return (
+
+
+
+
+
+
+
+ {
+ presentProject.projectId ?
+
+
+ {
+ metaData==='loading'?
+
+
+
+ {'Loading Metadata...'}
+
+
+ :
+ }
+
+ :
+ }
+
+
+ );
+}
\ No newline at end of file
diff --git a/client/src/component/AppBar/BaseAppBar.js b/client/src/component/AppBar/BaseAppBar.js
index cd91dd0d..00804f2f 100644
--- a/client/src/component/AppBar/BaseAppBar.js
+++ b/client/src/component/AppBar/BaseAppBar.js
@@ -46,9 +46,9 @@ export default function BaseAppBar(props) {
diff --git a/client/src/component/Drawer/ProjectDrawer.css b/client/src/component/Drawer/ProjectDrawer.css
new file mode 100644
index 00000000..44184c0a
--- /dev/null
+++ b/client/src/component/Drawer/ProjectDrawer.css
@@ -0,0 +1,9 @@
+.category {
+ padding: 8px 16px;
+ background-color:rgb(134, 154, 172);
+ color: rgb(249, 251, 253);
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ -ms-user-select:none;
+ user-select:none
+}
\ No newline at end of file
diff --git a/client/src/component/Drawer/ProjectDrawer.js b/client/src/component/Drawer/ProjectDrawer.js
index 77129aed..860822b0 100644
--- a/client/src/component/Drawer/ProjectDrawer.js
+++ b/client/src/component/Drawer/ProjectDrawer.js
@@ -8,14 +8,15 @@ import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import FolderOpenIcon from '@mui/icons-material/FolderOpen';
-import MoreIcon from '@mui/icons-material/More';
+// import MoreIcon from '@mui/icons-material/More';
import AddCircleIcon from '@mui/icons-material/AddCircle';
import IconButton from '@mui/material/IconButton';
import { useTheme } from '@mui/material/styles';
import { Grid } from '@mui/material';
-import { Dialog,DialogTitle,DialogContent,DialogContentText,DialogActions,TextField,Button } from '@mui/material';
-import { useState } from 'react';
+import { Dialog,DialogTitle,DialogContent,DialogContentText,DialogActions,TextField,Button,Typography } from '@mui/material';
+import React, { useState } from 'react';
import { createProject } from './Utils/ProjectUtils';
+import './ProjectDrawer.css';
const SUCCESS=1,FAIL=0;
@@ -69,17 +70,21 @@ export const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !==
);
-export default function ProjectDrawer({open,handleDrawerClose,projects,others,setPresentProject,setMetaData}) {
+export default function ProjectDrawer({open,setOpen,projects,invitedProjects,setIsInvitedProject,others,presentProject,setPresentProject,setMetaData,openCreateProjectDialog}) {
const theme = useTheme();
- const [dialogOpen,setDialogOpen]=useState(false);
+ const [dialogOpen,setDialogOpen]=useState(openCreateProjectDialog);
const [projectName,setProjectName]=useState();
-
+ React.useEffect(()=>{
+ setDialogOpen(openCreateProjectDialog)
+ },[openCreateProjectDialog])
const handleProjectCreateRequset=(status,message='')=>{
if(status===FAIL){
alert(message)
}
if(status===SUCCESS){
setDialogOpen(false)
+ setOpen(false)
+ setOpen(true)
}
}
@@ -87,17 +92,25 @@ export default function ProjectDrawer({open,handleDrawerClose,projects,others,se
-
+ setOpen(false)}>
{theme.direction === 'rtl' ? : }
-
+ {open && projects.length > 0 && (
+ Created Projects
+ )}
+
+
{projects.map((project) => (
setPresentProject(project)}>
+ onClick={()=>{
+ setPresentProject(project);
+ setIsInvitedProject(false);
+ }}>
@@ -106,6 +119,27 @@ export default function ProjectDrawer({open,handleDrawerClose,projects,others,se
))}
+ {open && invitedProjects.length > 0 && (
+ Invited Projects
+ )}
+
+ {invitedProjects.map((project) => (
+ {
+ setPresentProject(project);
+ setIsInvitedProject(true);
+ }}>
+
+
+
+
+
+ ))}
+
+ {/*
{others.map((text) => (
))}
-
+
*/}