232 Commits

Author SHA1 Message Date
1ebf2f2f9d Merge pull request 'fix/harbor-connection-port' (#15) from fix/harbor-connection-port into main
Reviewed-on: #15
2026-03-10 10:42:58 +03:00
abdelbari
4ddffb6fff chore: update harbor registry to 10.150.1.166:8085
Some checks failed
sgeUpdated CI/CD / deploy (pull_request) Failing after 5m7s
2026-03-10 07:38:21 +00:00
abdelbari
59b37a64f5 Update Harbor registry IP and port for the pipeline 2026-03-10 07:29:31 +00:00
a0041afce9 Merge pull request 'harbor test v' (#14) from testv into main
Reviewed-on: #14
2026-03-09 14:07:36 +03:00
d4ffcb9438 harbor test v
Some checks failed
sgeUpdated CI/CD / deploy (pull_request) Failing after 10m33s
2026-03-09 14:06:23 +03:00
7a948f3b7e harbor+ 2025-12-17 18:17:53 +03:00
a7ba6fe3e4 Merge pull request 'test' (#13) from test into main
Reviewed-on: #13
2025-10-30 20:23:54 +03:00
7976d56552 Update sge-backend/src/main/java/com/sgs/SgsApplication.java
All checks were successful
sgeUpdated CI/CD / deploy (pull_request) Successful in 42s
2025-10-30 20:23:13 +03:00
e3536ea6a3 Update sge-backend/pom.xml 2025-10-30 20:20:53 +03:00
66aeed7fda Merge pull request 'Update sge-frontend/package.json' (#12) from test into main
Reviewed-on: #12
2025-10-30 20:12:13 +03:00
fcc5edcbe2 Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (pull_request) Successful in 3m23s
2025-10-30 20:11:53 +03:00
8f41ce3d51 Merge pull request 'Test branch' (#11) from test into main
Reviewed-on: #11
2025-10-30 20:11:09 +03:00
abdelbari
4ea1cfa9b4 Test branch
All checks were successful
sgeUpdated CI/CD / deploy (pull_request) Successful in 7s
2025-10-30 17:08:40 +00:00
68835f5919 Update sge-frontend/package.json 2025-10-30 19:46:20 +03:00
ee29ecd766 Update .gitea/workflows/sgeupdated.yml 2025-10-30 19:35:34 +03:00
f4dd4a9dce Merge pull request 'Update sge-frontend/package.json' (#4) from test into main
Reviewed-on: #4
2025-10-30 19:31:36 +03:00
853230e742 Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (pull_request) Successful in 3m20s
2025-10-30 19:30:40 +03:00
0a4462923e Update .gitea/workflows/sgeupdated.yml 2025-10-30 19:29:17 +03:00
7f56158c02 Merge pull request 'Test branch' (#3) from test into main
Reviewed-on: #3
2025-10-30 19:23:16 +03:00
1174707918 Update sge-frontend/src/views/DataSet/EmissionSource.js
All checks were successful
sgeUpdated CI/CD / deploy (pull_request) Successful in 3m4s
2025-10-30 19:21:22 +03:00
93cad886d6 Update .gitea/workflows/sgeupdated.yml 2025-10-30 19:20:19 +03:00
a15f249016 Test branch
Some checks failed
sgeUpdated CI/CD / deploy (pull_request) Failing after 45s
2025-10-30 16:05:38 +00:00
5c1f255c3f Merge pull request 'Update sge-backend/pom.xml' (#2) from omar/sgeUpdated:main into main
Reviewed-on: #2
2025-10-30 18:56:54 +03:00
453d35702c Update .gitea/workflows/sgeupdated.yml 2025-10-30 18:55:20 +03:00
cf08be1ddc Update sge-backend/pom.xml
Some checks failed
sgeUpdated CI/CD / deploy (pull_request) Failing after 5s
2025-10-30 18:54:48 +03:00
4a9b65cc30 Update .gitea/workflows/sgeupdated.yml
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-30 18:46:25 +03:00
472a5daf09 Update sge-frontend/src/views/Communication.js
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 2m51s
2025-10-28 19:00:41 +03:00
dcdc1bf43a Update sge-frontend/src/views/Areas/Areas.js 2025-10-28 18:59:54 +03:00
c9b5ebf80e Update sge-backend/pom.xml
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 58s
2025-10-28 18:56:54 +03:00
caa0549983 Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 1m31s
2025-10-28 18:46:42 +03:00
4400572a45 Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 2m54s
2025-10-28 18:41:04 +03:00
04ee05a96b Update sge-frontend/package.json
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 13s
2025-10-28 18:20:22 +03:00
7580bf7cdb Update sge-frontend/README.md
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-28 18:06:28 +03:00
0d017c0a4b Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 2m46s
2025-10-28 18:02:59 +03:00
1eeb91c91c Update sge-backend/README.md 2025-10-28 18:02:18 +03:00
cd18444b08 Update sge-backend/pom.xml 2025-10-28 18:01:05 +03:00
1354d01878 Update sge-frontend/README.md 2025-10-28 17:14:39 +03:00
9856c1f9aa Update sge-frontend/package.json 2025-10-28 17:03:05 +03:00
b1ea7bf736 Update sge-frontend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-28 16:42:50 +03:00
8b82b44591 Update sge-backend/pom.xml
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-28 16:41:26 +03:00
5c534314df Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-28 16:40:53 +03:00
dde5fece3b Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 38s
2025-10-28 16:31:43 +03:00
f3b893f05c Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 38s
2025-10-28 16:19:26 +03:00
08e8badae2 Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 7s
2025-10-28 16:02:04 +03:00
dd1083db82 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 12s
2025-10-28 15:33:14 +03:00
fad8037371 Update sgeupdated pipeline v25+
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 7s
2025-10-28 15:04:50 +03:00
61faf1bf46 Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 7s
2025-10-27 18:39:50 +03:00
230c4bcb6e Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-27 17:53:46 +03:00
cbe2660080 Update sgeupdated pipeline v25
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 9s
New script to call the deploy.sh file in the server
2025-10-27 17:29:31 +03:00
cf38f431a8 Update sge-frontend/src/views/Communication.js
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-25 23:53:46 +03:00
f585763563 Update .gitea/workflows/sgeupdated.yml
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-25 23:52:38 +03:00
7bee15a901 Update sge-frontend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 9s
2025-10-24 18:04:13 +03:00
1ae3d76781 Update sgeupdated pipeline v22-+
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 6s
2025-10-24 18:03:14 +03:00
53d5bf2e77 Update sge-frontend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 3m1s
2025-10-24 17:57:15 +03:00
60e50dc9e8 Update .gitea/workflows/sgeupdated.yml
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-24 17:50:36 +03:00
aaf116ca71 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-10-24 17:47:44 +03:00
061c0cb376 Update sgeupdated pipeline v22-
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 9s
2025-10-24 17:46:55 +03:00
bd155fadb2 Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 42s
2025-10-24 17:32:23 +03:00
11541714f5 Update sge-frontend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 3m56s
2025-10-24 17:07:27 +03:00
91559134cd Update sge-backend/README.md
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 49s
2025-10-24 17:03:16 +03:00
d26ca12e0c Update sgeupdated pipeline v22-
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-24 15:35:57 +03:00
18c8c49a3d Update sge-frontend/README.md
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-24 15:28:43 +03:00
97253a54eb Update sge-backend/README.md
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 8s
2025-10-24 15:26:53 +03:00
f411f44006 Update sgeupdated pipeline v22
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 8s
2025-10-24 15:21:53 +03:00
f4f4fb976b Update sgeupdated pipeline v22+
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 16s
2025-10-24 15:19:57 +03:00
385eda2132 Update sgeupdated pipeline v22
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 6s
2025-10-24 15:13:23 +03:00
23a3d8252e Update sge-backend/pom.xml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 26s
2025-10-24 15:11:40 +03:00
eeda227698 Update sgeupdated pipeline v24
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 26s
2025-10-24 15:09:18 +03:00
871bcf9651 Update sgeupdated pipeline v23++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-23 13:04:06 +03:00
614cbe8b04 Update sgeupdated pipeline v23+++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 9s
2025-10-23 13:01:17 +03:00
ce19adb1a0 Update sgeupdated pipeline v23++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 15s
2025-10-23 12:56:52 +03:00
5471db463f Update sgeupdated pipeline v23+
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-23 12:47:17 +03:00
845417ee49 Update sgeupdated pipeline v23
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 20s
2025-10-23 12:41:49 +03:00
1c12ac1e16 Update sge-frontend/package.json
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-23 12:08:16 +03:00
eb2ec01d28 Update sgeupdated pipeline v22
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
new script for gitea
2025-10-23 12:06:40 +03:00
4d40015fd1 Update sge-frontend/package.json
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 19:24:33 +03:00
c55f5ce7d1 Update sge-frontend/package.json
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 19:17:57 +03:00
07a8973b92 Update for pipeline testing Back-end +
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 19:07:18 +03:00
54b47eee05 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:46:53 +03:00
3f0550f9f2 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:45:08 +03:00
6499c9471e Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:42:07 +03:00
71e507c21b Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:39:28 +03:00
737fd6da53 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 18:34:24 +03:00
490f3b539e Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:32:24 +03:00
9c0c4c4828 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:29:51 +03:00
b28a73b4ff Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 18:27:20 +03:00
f087b6eb88 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 18:23:55 +03:00
d07932cc1e Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 18:21:17 +03:00
76d37d6038 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 18:11:36 +03:00
50abcab358 Update sgeupdated pipeline v21++++++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
Commented the backend section
2025-10-22 17:55:10 +03:00
445f9256a1 Update sgeupdated pipeline v21+++++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 23s
Commented the backend section
2025-10-22 17:53:16 +03:00
4d1a82fe92 Update for pipeline testing Front-end v099
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 2m33s
2025-10-22 17:12:00 +03:00
6d6e935b52 Update sgeupdated pipeline v21++++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
commenting the frontend dependencies installation
2025-10-22 17:10:24 +03:00
a51a81ce7c Update sgeupdated pipeline v21+++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 2m30s
Paused the concurrency check temporally
2025-10-22 16:05:33 +03:00
3b6000bc40 Update sgeupdated pipeline v21++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-10-22 15:52:38 +03:00
78ed73acc6 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 2m29s
2025-10-22 15:47:39 +03:00
7f8a7b1bf8 Update sgeupdated pipeline v21++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 2m31s
2025-10-22 15:39:57 +03:00
8c6e37ad72 Update sgeupdated pipeline v21+++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 15:38:04 +03:00
85151e536d Update sgeupdated pipeline v21++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 15:08:02 +03:00
573db7fee9 Update sgeupdated pipeline v21+
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-10-22 14:49:07 +03:00
a11f9614ed Update sgeupdated pipeline v21
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 20s
new condition to be added
2025-10-22 14:29:27 +03:00
02bd570573 Update sge-backend/pom.xml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 3m19s
2025-10-21 16:12:15 +03:00
5da26152a9 update to sgeupdated pipeline v20++++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 23s
2025-09-05 23:07:35 +03:00
4f4c2e2ce5 Update .gitea/workflows/sgeupdated.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 1m5s
2025-09-05 23:01:04 +03:00
79ddbf2207 Update docker-compose.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 45s
2025-09-05 22:59:28 +03:00
23d9e65a7f update to sgeupdated pipeline v20+++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 51s
2025-09-05 22:55:07 +03:00
c8f9abe5e9 update to sgeupdated pipeline v20+++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 56s
changing in npm installation
2025-09-05 22:49:34 +03:00
fa96969bc7 update to sgeupdated pipeline v20++++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 16s
2025-09-05 22:37:40 +03:00
dc67f75027 Update sge-frontend/nginx.conf
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 9m42s
2025-09-05 22:01:33 +03:00
e22c880673 Update sge-backend/Dockerfile
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 16s
2025-09-05 21:57:44 +03:00
b37ed8797b update to sgeupdated pipeline v20+++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 10m22s
2025-09-01 05:14:58 +03:00
04ed88e45e Update for pipeline testing Back-end
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-09-01 05:11:10 +03:00
5f8de8105b update to sgeupdated pipeline v21
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-09-01 05:09:20 +03:00
8fb923a4db Update for pipeline testing Back-end
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-09-01 05:01:57 +03:00
a088889a67 update to sgeupdated pipeline v20+++
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 10m21s
2025-09-01 04:50:38 +03:00
b3de688265 update to sgeupdated pipeline v20++
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-09-01 04:41:12 +03:00
080924f788 update to sgeupdated pipeline v20+
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-09-01 03:57:59 +03:00
e43199f086 Update sge-frontend/nginx.conf
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-09-01 03:52:57 +03:00
49e2020455 update to sgeupdated pipeline v20
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 21s
2025-09-01 03:33:42 +03:00
876227286c Update for pipeline testing Front-end v00
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-09-01 03:28:59 +03:00
af518cef20 Update for pipeline testing Back-end
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 23s
2025-09-01 03:27:48 +03:00
2e5bf41ed9 update to sgeupdated pipeline v19
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
changes the concept of rebuilding
2025-09-01 03:26:26 +03:00
f61199cedb Update for pipeline testing Front-end
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-09-01 03:06:55 +03:00
5001a44406 Update for pipeline testing
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 2m15s
2025-09-01 03:03:47 +03:00
87487510ce update to sgeupdated pipeline v18
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 23s
added some feature to avoid failing when nothing is changed
2025-09-01 03:02:23 +03:00
547ade53ae update to sgeupdated pipeline v17
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 22s
2025-09-01 02:57:34 +03:00
95afe7b877 Back to sgeupdated pipeline v16
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-09-01 02:46:07 +03:00
ae0e112572 Delete smoke file
All checks were successful
SgeUpdated Deploy / deploy-frontend (push) Has been skipped
SgeUpdated Deploy / deploy-backend (push) Has been skipped
2025-09-01 02:41:02 +03:00
b35eac74a1 Update sgeupdated pipeline v17
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
SgeUpdated Deploy / deploy-frontend (push) Has been skipped
SgeUpdated Deploy / deploy-backend (push) Has been skipped
a clone of the aypos yml file to test it
2025-09-01 02:40:20 +03:00
20aabd605c Update for pipeline testing Front-end
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 20s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 21:12:44 +03:00
517d4d499b Update for pipeline testing
Some checks failed
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-30 21:12:22 +03:00
1aa745ebf5 Update sgeupdated pipeline v16
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-30 21:11:03 +03:00
88a312d37c Update sgeupdated pipeline v15
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 23s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
forgot to add the dependencies installation
2025-08-30 21:04:54 +03:00
b1019b21cf Update for pipeline testing Front-end
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 20s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 21:02:37 +03:00
57c28e4a90 Update for pipeline testing
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-30 21:02:19 +03:00
b1cf711420 Update sgeupdated pipeline v14
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 21s
multiple changes applied to make the workflows works over ssh
2025-08-30 20:58:45 +03:00
1d6b026710 Update for pipeline testing
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-30 20:21:33 +03:00
02e4993c2c Update for pipeline testing Front-end
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-30 20:20:37 +03:00
be71b59a3e Update for pipeline testing Front-end
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 20:11:43 +03:00
7e5761993b Update for pipeline testing Front-end
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Successful in 20s
2025-08-30 04:20:34 +03:00
66bd7b5a68 Update for pipeline testing
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 21s
sgeUpdated CI/CD / deploy (push) Successful in 23s
2025-08-30 04:20:16 +03:00
206d8a2bbf Update sgeupdated pipeline v13
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 23s
2025-08-30 04:14:36 +03:00
6fbca1c29a Update for pipeline testing Front-end
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 10s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-30 03:41:56 +03:00
1f6b06260c Update for pipeline testing
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 29s
2025-08-30 03:38:28 +03:00
b00a8e1bf1 Update Front-End after pipeline v10
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 9s
2025-08-30 03:11:38 +03:00
0f01ddefe9 Update Back-End after pipeline v12
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-30 03:11:13 +03:00
2116b0f28a Update Front-End after pipeline v9
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-30 03:02:45 +03:00
5161286279 Update Back-End after pipeline v11
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-30 03:02:19 +03:00
29963d5388 Update sgeupdated pipeline v12
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 7s
sgeUpdated CI/CD / deploy (push) Successful in 27s
2025-08-30 03:00:47 +03:00
990b98c171 Update sgeupdated pipeline v12
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 8s
2025-08-30 02:58:54 +03:00
f2d5182215 Update sgeupdated pipeline v12
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 02:57:42 +03:00
e9a361489e Update sgeupdated pipeline v12
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
a new update that fixed the docker files problem, it deletes the old ones then builds the new accordingly
2025-08-30 02:56:08 +03:00
37873ad091 Update Dockerfile
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-30 01:58:28 +03:00
cac67b815c Update Front-End after pipeline v8
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:38:03 +03:00
28fc21e9f2 Update Back-End after pipeline v10
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-30 01:37:40 +03:00
98a2515735 Update sgeupdated pipeline v11
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 23s
2025-08-30 01:36:21 +03:00
4503d7c319 Update sgeupdated pipeline v11
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:33:48 +03:00
e2a1b6f940 Update sgeupdated pipeline v11
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:33:02 +03:00
d25a7975c7 Update sgeupdated pipeline v11
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:29:50 +03:00
926c6b0b66 Update sgeupdated pipeline v11
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:28:12 +03:00
986bec559b Update Front-End after pipeline v7
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:14:28 +03:00
77d5c94cf7 Update Back-End after pipeline v9
Some checks failed
sgeUpdated CI/CD / deploy (push) Successful in 23s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-30 01:14:02 +03:00
75c2f7ff19 Update sgeupdated pipeline v10
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 23s
new code updated changes in fornt-end and back-end structure
2025-08-30 01:09:38 +03:00
55577469de Update Front-End after pipeline v6
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-30 01:02:15 +03:00
f50803f469 Update Back-End after pipeline v8
Some checks failed
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-30 01:01:47 +03:00
adce8cddd8 Update sgeupdated pipeline v9
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-29 20:17:14 +03:00
c2ddc08802 Update Front-End after pipeline v5
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-29 20:11:39 +03:00
2c79300663 Update Back-End after pipeline v7
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-29 20:11:17 +03:00
a6bb799caa Update sgeupdated pipeline v8
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-29 20:05:03 +03:00
a4791d6a57 Update Front-End after pipeline v4
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 20s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-29 19:40:12 +03:00
168cfaa8a7 Update Back-End after pipeline v6
Some checks failed
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-29 19:39:45 +03:00
710655c1fd Update docker-compose.yml
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-29 19:37:41 +03:00
6f445f205a Update sgeupdated pipeline v7
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-29 19:35:49 +03:00
32b9533a33 Update docker-compose.yml
Some checks failed
sgeUpdated CI/CD / deploy (push) Has been cancelled
sgeUpdated Smoke Test / smoke-test (push) Successful in 7s
2025-08-29 19:27:28 +03:00
62829194e2 Update Front-End after pipeline v3
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-29 19:24:43 +03:00
87a80f63ed Update Back-End after pipeline v5
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 16s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-29 19:24:21 +03:00
f12c5cb8d4 Update sgeupdated pipeline v6
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 29s
Some mistakes in directory
2025-08-29 19:20:39 +03:00
7148bdf834 Update Front-End after pipeline v2
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
2025-08-29 19:12:06 +03:00
9eb903a450 Update Back-End after pipeline v4
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 16s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-29 19:11:38 +03:00
991aef0417 Update sgeupdated pipeline v5
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 22s
working on updating the docker
2025-08-29 19:09:11 +03:00
a1c0f71fbf Update Front-End after pipeline
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
2025-08-29 00:21:02 +03:00
64c36cb617 Update Back-End after pipeline v3
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-29 00:20:41 +03:00
0f2bf5a800 Update Front-End after pipeline
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
2025-08-29 00:17:33 +03:00
d6375c320a Update Back-End after pipeline v3
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-29 00:17:07 +03:00
3d440798e3 Update sgeupdated pipeline v4
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
Made a force for rebuilding the docker
2025-08-29 00:16:07 +03:00
8cdc00f921 Update sgeupdated pipeline v3
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Successful in 21s
2025-08-29 00:11:13 +03:00
593e5ceb6a Update Front-End after pipeline
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
problem with dockerizing
2025-08-29 00:07:10 +03:00
b2eebfce64 Update Back-End after pipeline v2
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
problem with not dockerizing
2025-08-29 00:06:18 +03:00
c3ed359103 Update sgeupdated pipeline v3
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
a typo in docker names for front-end and back-end
2025-08-29 00:02:27 +03:00
7b4143ba52 Update sgeupdated pipeline v3
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 21s
problem in restarting docker
2025-08-28 23:56:54 +03:00
0322235404 Update Back-End after pipeline
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 22s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-28 23:48:21 +03:00
95a344a7a6 Update Front-End after CI/CD
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 21s
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
2025-08-28 23:45:33 +03:00
c477143b30 Update sgeupdated pipeline v2
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Failing after 16s
2025-08-28 23:42:13 +03:00
6202f7ec26 Update sgeupdated pipeline
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Successful in 5s
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-28 23:28:23 +03:00
8eb9835e13 Update sgeupdated pipeline
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
sgeUpdated CI/CD / deploy (push) Successful in 22s
2025-08-28 19:09:57 +03:00
08941cc7d5 Update sgeupdated pipeline
Some checks failed
sgeUpdated CI/CD / deploy (push) Failing after 35s
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
2025-08-28 19:01:37 +03:00
994e81b1fb Add sgeupdated pipeline
Some checks failed
sgeUpdated Smoke Test / smoke-test (push) Has been cancelled
sgeUpdated CI/CD / deploy (push) Has been cancelled
2025-08-28 18:47:24 +03:00
0c03a110e5 DELETE
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-28 17:56:30 +03:00
7c5eb3a210 Delete .gitea/workflows/deploy.yml
All checks were successful
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-28 17:55:52 +03:00
a943925325 Add a Smoke test workflow
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 43s
sgeUpdated Smoke Test / smoke-test (push) Successful in 6s
2025-08-28 17:53:33 +03:00
5bd98fb09d update a Smoke test workflow
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 40s
2025-08-27 03:42:02 +03:00
cdb6d98ae7 Add a Smoke test workflow
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 15s
2025-08-27 03:40:09 +03:00
243f89457f Add test workflow
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 40s
2025-08-27 03:34:14 +03:00
03875dde53 Add test workflow updated name
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 16s
2025-08-27 03:32:21 +03:00
e695d06f5b Add CI/CD deploy workflows
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 56s
2025-08-27 03:04:15 +03:00
837353bc45 Add test workflow
Some checks failed
CI/CD Pipeline / deploy_production (push) Failing after 16s
CI/CD Pipeline / deploy_testing (push) Has been skipped
2025-08-27 03:02:45 +03:00
2459ba092b Add CI/CD deploy workflow update
Some checks failed
CI/CD Pipeline / deploy_testing (push) Has been skipped
CI/CD Pipeline / deploy_production (push) Failing after 1m48s
2025-08-27 03:00:10 +03:00
4bfd2ee1f8 Add CI/CD deploy workflow 2025-08-27 02:45:09 +03:00
95fbbc340e Add .gitea/workflows/deploy.yml 2025-08-27 02:43:00 +03:00
78ffa4fe7e Merge pull request 'multi-emission-feature' (#14) from multi-emission-feature into main
Reviewed-on: BLC/sgeUpdated#14
2025-08-19 09:26:46 +03:00
a14bc4e73a Add cityID in creation and update and edit some graphics in the map 2025-08-19 09:24:29 +03:00
50c6a2ef5b cloudsystem column added 2025-08-19 07:36:45 +03:00
d4e40f5a6b just pushing this to resolve merge conflict i have no changes made in this commit 2025-08-19 07:33:53 +03:00
bbb0976aa1 added the cloudsystem column 2025-08-19 07:16:17 +03:00
085a417016 Fix dropdown selection overflow while scrolling 2025-08-19 06:51:50 +03:00
edd8feb4d2 Add optimization to show data faster using Memo 2025-08-19 06:43:22 +03:00
2d39883b7f filtering raw data page 2025-08-19 06:17:37 +03:00
21b757cf77 Fix small translation in Map 2025-08-19 05:39:16 +03:00
8bd6d94174 Fix the DataCenterOverview tab display by removing project relation 2025-08-19 05:39:02 +03:00
Ali Sadeghi
b5901a049c Merge: Add city to datacenter, cloudsystem to summary, fix listener 2025-08-19 04:43:53 +03:00
82f86a62ca Fix issue in updating datacenter
Found a hibernate cascade issue and was fixed by reuse the existing collection instaed of creating a new one in updating the datacenter entity
2025-08-19 00:15:51 +03:00
47959fb35f Make the datacenter creation modal mobile friendly 2025-08-19 00:08:42 +03:00
2257ec79f6 Make creation of default area nested in city initialization 2025-08-19 00:08:01 +03:00
17d77fcda7 Fix message queue data misnaming 2025-08-19 00:07:20 +03:00
3245040274 Merge pull request 'Multi Emission Sources Feature' (#10) from multi-emission-feature into main
Reviewed-on: BLC/sgeUpdated#10
2025-08-18 08:09:49 +03:00
92d88df213 Fix Backend error:
Error loading data: Exception while fetching data (/vmEmissionSummary) : org.hibernate.exception.SQLGrammarException: could not extract ResultSet
2025-08-18 08:03:40 +03:00
a66b01334d Small bug fix 2025-08-18 08:02:34 +03:00
c7e60c25eb Add datacenter with multiple emission source and inputs 2025-08-18 06:12:19 +03:00
ebd997a33d Fix the datacenter query according to the changes in backend 2025-08-18 05:38:51 +03:00
dd04a057b1 Comment not needed orgnization code 2025-08-18 05:38:39 +03:00
d224905ba0 Make the Datacenter module structure following the whole code structure 2025-08-18 05:38:20 +03:00
b5ceb1591e Merge Backend Updates 2025-08-18 04:28:45 +03:00
63 changed files with 6487 additions and 4922 deletions

View File

@@ -0,0 +1,29 @@
name: sgeUpdated CI/CD
on:
pull_request:
types:
- closed # Fires when a PR is closed (either merged or manually closed)
branches:
- main # Only when PR targets main
jobs:
deploy:
if: github.event.pull_request.merged == true # Run only if the PR was merged (not just closed)
runs-on: ubuntu-latest
steps:
- name: Setup SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
- name: Run deploy script on server
run: |
ssh ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'EOF'
echo "✅ PR merged into main — running deploy script.."
cd /home/ubuntu/Bgreen/sgeUpdated
./deploy.sh
EOF

24
config.conf Normal file
View File

@@ -0,0 +1,24 @@
# SGE Application Configuration
# This file contains configuration for both backend and frontend
# Database Configuration
SPRING_DATASOURCE_URL=jdbc:postgresql://bgreen-database:5432/sge
SPRING_DATASOURCE_USERNAME=sge
SPRING_DATASOURCE_PASSWORD=147
# Server Configuration
SERVER_PORT=8080
# Mail Configuration
MAIL_HOSTNAME=mail.spacemail.com
MAIL_SMTP_PORT=465
MAIL_ADDRESS=info@blc-css.com
MAIL_PASSWORD=123456Bb@
# React Application Configuration
# API Configuration
API_PROTOCOL=http
API_HOST=bgreen-backend
# Application URLs
APP_SURVEY_BASE_URL=https://bgreen.blc-css.com

110
deploy.sh Executable file
View File

@@ -0,0 +1,110 @@
#!/bin/bash
set -euo pipefail
cd /home/ubuntu/Bgreen/sgeUpdated
# -----------------------
# Harbor settings
# -----------------------
HARBOR_REGISTRY="10.150.1.166:8085"
HARBOR_PROJECT="bgreen"
BACKEND_IMAGE_REPO="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/bgreen-backend"
FRONTEND_IMAGE_REPO="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/bgreen-frontend"
# Tag images within git commit (better than latest; enables rollback)
VERSION="$(git rev-parse --short HEAD)"
echo "📦 Fetching latest changes from origin/main..."
git fetch myfork main
# Detect which files changed between local HEAD and the latest remote version
CHANGED_FILES=$(git diff --name-only HEAD myfork/main || true)
if [ -z "$CHANGED_FILES" ]; then
echo "✅ No file changes detected between HEAD and origin/main."
else
echo "🪶 Changed files:"
echo "$CHANGED_FILES"
fi
# Update to the latest version
git reset --hard myfork/main
BACKEND_CHANGED=false
FRONTEND_CHANGED=false
# Check if backend folder changed (excluding README.md)
if echo "$CHANGED_FILES" | grep "^sge-backend/" | grep -qv "README.md$"; then
BACKEND_CHANGED=true
fi
# Check if frontend folder changed (excluding README.md)
if echo "$CHANGED_FILES" | grep "^sge-frontend/" | grep -qv "README.md$"; then
FRONTEND_CHANGED=true
fi
# -----------------------
# Backend section
# -----------------------
if [ "$BACKEND_CHANGED" = true ]; then
echo "⚡ Backend changes detected."
cd sge-backend
echo "Running Maven build..."
/opt/apache-maven-3.9.11/bin/mvn clean install -DskipTests
echo "🐳 Building backend Docker image..."
docker build -t "${BACKEND_IMAGE_REPO}:${VERSION}" .
echo "📤 Pushing backend image to Harbor..."
docker push "${BACKEND_IMAGE_REPO}:${VERSION}"
echo "📥 Pulling backend image from Harbor (to ensure registry is source of truth)..."
docker pull "${BACKEND_IMAGE_REPO}:${VERSION}"
cd ..
echo "🚀 Recreating backend container using Harbor image..."
VERSION="$VERSION" docker compose up -d bgreen-backend
else
echo "✅ No backend changes."
fi
# -----------------------
# Frontend section
# -----------------------
if [ "$FRONTEND_CHANGED" = true ]; then
echo "⚡ Frontend changes detected."
cd sge-frontend
# Check if package.json or package-lock.json changed
if echo "$CHANGED_FILES" | grep -qE "^sge-frontend/(package\.json|package-lock\.json)$"; then
echo "📦 package.json changed. Running 'npm install' and 'npm run build'..."
npm install
npm run build
else
echo "📦 only code changes. Running 'npm run build'..."
npm run build
fi
echo "🐳 Building frontend Docker image..."
docker build -t "${FRONTEND_IMAGE_REPO}:${VERSION}" .
echo "📤 Pushing frontend image to Harbor..."
docker push "${FRONTEND_IMAGE_REPO}:${VERSION}"
echo "📥 Pulling frontend image from Harbor (to ensure registry is source of truth)..."
docker pull "${FRONTEND_IMAGE_REPO}:${VERSION}"
cd ..
echo "🚀 Recreating frontend container using Harbor image..."
VERSION="$VERSION" docker compose up -d bgreen-frontend
else
echo "✅ No frontend changes."
fi
echo "✅ Deployment complete."

69
deploy.sh.save Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -euo pipefail
export GIT_SSH_COMMAND="ssh -i ~/.ssh/deploy_id_rsa -o StrictHostKeyC
cd /home/ubuntu/Bgreen/sgeUpdated
echo "📦 Fetching latest changes from origin/main..."
git fetch origin main
# Detect which files changed between local HEAD and the latest remote version
CHANGED_FILES=$(git diff --name-only HEAD origin/main || true)
if [ -z "$CHANGED_FILES" ]; then
echo "✅ No file changes detected between HEAD and origin/main."
else
echo "🪶 Changed files:"
echo "$CHANGED_FILES"
fi
# Update to the latest version
git reset --hard origin/main
BACKEND_CHANGED=false
FRONTEND_CHANGED=false
# Check if backend folder changed
if echo "$CHANGED_FILES" | grep -q "^sge-backend/"; then
BACKEND_CHANGED=true
fi
# Check if frontend folder changed
if echo "$CHANGED_FILES" | grep -q "^sge-frontend/"; then
FRONTEND_CHANGED=true
fi
# -----------------------
# Backend section
# -----------------------
if [ "$BACKEND_CHANGED" = true ]; then
echo "⚡ Backend changes detected."
cd sge-backend
echo "Running Maven build..."
/opt/apache-maven-3.9.11/bin/mvn clean install -DskipTests
cd ..
echo "Rebuilding backend Docker container..."
docker compose up -d --build bgreen-backend
else
echo "✅ No backend changes."
fi
# -----------------------
# Frontend section
# -----------------------
if [ "$FRONTEND_CHANGED" = true ]; then
echo "⚡ Frontend changes detected."
cd sge-frontend
echo "Running npm build..."
npm install
npm run build
cd ..
echo "Rebuilding frontend Docker container..."
docker compose up -d --build bgreen-frontend
else
echo "✅ No frontend changes."
fi
echo "✅ Deployment complete."

39
docker-compose.yml Normal file
View File

@@ -0,0 +1,39 @@
services:
bgreen-backend:
build:
context: ./sge-backend
dockerfile: Dockerfile
ports:
- "8080:8080"
env_file:
- ./config.conf
environment:
SPRING_PROFILES_ACTIVE: docker
depends_on:
- database
restart: unless-stopped
bgreen-frontend:
build:
context: ./sge-frontend
dockerfile: Dockerfile
ports:
- "80:80"
env_file:
- ./config.conf
restart: unless-stopped
database:
image: postgres:15
environment:
POSTGRES_DB: sge
POSTGRES_USER: sge
POSTGRES_PASSWORD: 147
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:

1
sge-backend/README.md Normal file
View File

@@ -0,0 +1 @@
## CI/CD Pipeline Check v23

File diff suppressed because it is too large Load Diff

View File

@@ -6,12 +6,12 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version> <version>2.5.5</version>
<relativePath /> <relativePath />
</parent> </parent>
<groupId>com.sgs</groupId> <groupId>com.sgs</groupId>
<artifactId>sgs</artifactId> <artifactId>sgs</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.2-SNAPSHOT</version>
<name>sgs</name> <name>sgs</name>
<description>SGS project for Spring Boot</description> <description>SGS project for Spring Boot</description>
<properties> <properties>

View File

@@ -2,6 +2,8 @@ package com.sgs;
import com.sgs.graphql.activitySubUnit.domain.ActivitySubUnit; import com.sgs.graphql.activitySubUnit.domain.ActivitySubUnit;
import com.sgs.graphql.activitySubUnit.service.ActivitySubUnitService; import com.sgs.graphql.activitySubUnit.service.ActivitySubUnitService;
import com.sgs.graphql.area.domain.Area;
import com.sgs.graphql.area.service.AreaService;
import com.sgs.graphql.city.domain.City; import com.sgs.graphql.city.domain.City;
import com.sgs.graphql.city.repo.CityRepo; import com.sgs.graphql.city.repo.CityRepo;
import com.sgs.graphql.city.service.CityService; import com.sgs.graphql.city.service.CityService;
@@ -73,6 +75,7 @@ public class SgsApplication implements CommandLineRunner {
private final PermissionService permissionService; private final PermissionService permissionService;
private final RoleService roleService; private final RoleService roleService;
private final RoleRepo roleRepo; private final RoleRepo roleRepo;
private final AreaService areaService;
private final NeighborhoodRepo neighborhoodRepo; private final NeighborhoodRepo neighborhoodRepo;
private final NeighborhoodService neighborhoodService; private final NeighborhoodService neighborhoodService;
private final CityService cityService; private final CityService cityService;
@@ -118,7 +121,8 @@ public class SgsApplication implements CommandLineRunner {
@Autowired @Autowired
public SgsApplication(RoleService roleService, PermissionService permissionService, RoleRepo roleRepo, public SgsApplication(RoleService roleService, PermissionService permissionService, RoleRepo roleRepo,
NeighborhoodRepo neighborhoodRepo, NeighborhoodService neighborhoodService, CityService cityService, AreaService areaService, NeighborhoodRepo neighborhoodRepo, NeighborhoodService neighborhoodService,
CityService cityService,
CityRepo cityRepo, DistrictRepo districtRepo, DistrictService districtService, CountryRepo countryRepo, CityRepo cityRepo, DistrictRepo districtRepo, DistrictService districtService, CountryRepo countryRepo,
CountryService countryService, OrganizationService organizationService, UserService userService, CountryService countryService, OrganizationService organizationService, UserService userService,
PasswordEncoder passwordEncoder, SectorService sectorService, SubSectorService subSectorService, PasswordEncoder passwordEncoder, SectorService sectorService, SubSectorService subSectorService,
@@ -133,6 +137,7 @@ public class SgsApplication implements CommandLineRunner {
this.roleService = roleService; this.roleService = roleService;
this.permissionService = permissionService; this.permissionService = permissionService;
this.roleRepo = roleRepo; this.roleRepo = roleRepo;
this.areaService = areaService;
this.neighborhoodRepo = neighborhoodRepo; this.neighborhoodRepo = neighborhoodRepo;
this.neighborhoodService = neighborhoodService; this.neighborhoodService = neighborhoodService;
this.cityService = cityService; this.cityService = cityService;
@@ -182,7 +187,7 @@ public class SgsApplication implements CommandLineRunner {
admin.setFirstName("Seda"); admin.setFirstName("Seda");
admin.setLastName("Kemikli"); admin.setLastName("Kemikli");
admin.setEmail("seda.kemikli@blc-css.com"); admin.setEmail("seda.kemikli@blc-css.com");
admin.setPhoneNumber("11111111"); admin.setPhoneNumber("11111511");
admin.setPassword(passwordEncoder.encode("admin")); admin.setPassword(passwordEncoder.encode("admin"));
// if (organizations.size() == 1) { // if (organizations.size() == 1) {
// admin.setOrganizations(organizations); // admin.setOrganizations(organizations);
@@ -426,6 +431,10 @@ public class SgsApplication implements CommandLineRunner {
data_center_read.setTag(PermissionName.DATA_CENTER_READ); data_center_read.setTag(PermissionName.DATA_CENTER_READ);
data_center_read.setDescription(PermissionDescription.DATA_CENTER_READ); data_center_read.setDescription(PermissionDescription.DATA_CENTER_READ);
Permission paginate_datacenters_get = new Permission();
paginate_datacenters_get.setTag(PermissionName.PAGINATE_DATACENTERS_GET);
paginate_datacenters_get.setDescription(PermissionDescription.PAGINATE_DATACENTERS_GET);
permissionService.saveAll(List.of( permissionService.saveAll(List.of(
show_graphics, activities_get, paginate_user_histories, activity_sub_units_get, sub_sectors_get, show_graphics, activities_get, paginate_user_histories, activity_sub_units_get, sub_sectors_get,
sectors_get, deleted_items, undelete_items, user_create, user_update, user_delete, paginate_users_get, sectors_get, deleted_items, undelete_items, user_create, user_update, user_delete, paginate_users_get,
@@ -442,7 +451,7 @@ public class SgsApplication implements CommandLineRunner {
question_create, question_delete, question_update, paginate_questions_get, question_create, question_delete, question_update, paginate_questions_get,
published_survey_create, surveys_get, paginate_surveys_get, published_survey_create, surveys_get, paginate_surveys_get,
survey_add, survey_delete, survey_update, settings_access, data_center_create, data_center_delete, survey_add, survey_delete, survey_update, settings_access, data_center_create, data_center_delete,
data_center_update, data_center_read)); data_center_update, data_center_read, paginate_datacenters_get));
} }
public void createDefaultRole() { public void createDefaultRole() {
@@ -771,6 +780,27 @@ public class SgsApplication implements CommandLineRunner {
mailInfoService.save(mailInfo); mailInfoService.save(mailInfo);
} }
public void ensureMissingPermissions() {
// Check if paginate_datacenters_get permission exists
Optional<Permission> datacenterPermission = permissionService.findByTag("paginate_datacenters_get");
if (!datacenterPermission.isPresent()) {
// Create the missing permission
Permission paginate_datacenters_get = new Permission();
paginate_datacenters_get.setTag(PermissionName.PAGINATE_DATACENTERS_GET);
paginate_datacenters_get.setDescription(PermissionDescription.PAGINATE_DATACENTERS_GET);
permissionService.save(paginate_datacenters_get);
}
// Ensure SUPER_ADMIN has all permissions
Optional<Role> superAdminRole = roleRepo.findByTag("SUPER_ADMIN");
if (superAdminRole.isPresent()) {
Role role = superAdminRole.get();
List<Permission> allPermissions = permissionService.findAll();
role.setPermissions(allPermissions);
roleService.save(role);
}
}
@Override @Override
public void run(String... args) throws Exception { public void run(String... args) throws Exception {
if (mailInfoService.findAll().isEmpty()) { if (mailInfoService.findAll().isEmpty()) {
@@ -816,6 +846,8 @@ public class SgsApplication implements CommandLineRunner {
if (roleService.findAll().isEmpty()) { if (roleService.findAll().isEmpty()) {
createDefaultRole(); createDefaultRole();
} }
// Ensure all permissions are created and assigned to SUPER_ADMIN
ensureMissingPermissions();
if (organizationService.findAll().isEmpty()) { if (organizationService.findAll().isEmpty()) {
createDefaultOrganization(); createDefaultOrganization();
} }
@@ -827,6 +859,7 @@ public class SgsApplication implements CommandLineRunner {
} }
if (cityService.findAll().isEmpty()) { if (cityService.findAll().isEmpty()) {
createCitiesFromJson(); createCitiesFromJson();
createDefaultArea();
} }
if (districtService.findAll().isEmpty()) { if (districtService.findAll().isEmpty()) {
createDistrictFromJson(); createDistrictFromJson();
@@ -834,18 +867,31 @@ public class SgsApplication implements CommandLineRunner {
if (neighborhoodService.findAll().isEmpty()) { if (neighborhoodService.findAll().isEmpty()) {
createNeighborhoodsFromJson(); createNeighborhoodsFromJson();
} }
// Add new permission if it doesn't exist }
// [Remove Later]
if (permissionService.findAll().stream().noneMatch(p -> PermissionName.SETTINGS_ACCESS.equals(p.getTag()))) { void createDefaultArea() {
Permission settingsAccess = new Permission(); // Check if default area already exists
settingsAccess.setTag(PermissionName.SETTINGS_ACCESS); List<Area> existingAreas = areaService.findAll();
settingsAccess.setDescription(PermissionDescription.SETTINGS_ACCESS); boolean defaultAreaExists = existingAreas.stream()
settingsAccess.setDefault_permission(false); .anyMatch(area -> "Turkiye".equals(area.getTag()) && area.isDefaultArea());
settingsAccess.setDeleted(false);
permissionService.save(settingsAccess); if (!defaultAreaExists) {
Area defaultArea = new Area();
defaultArea.setTag("Turkiye");
defaultArea.setDefaultArea(true);
defaultArea.setDeleted(false);
// Get all cities to add to the default area
List<City> allCities = cityService.findAll();
defaultArea.setCities(allCities);
// Get the Turkey country to add to the default area
List<Country> countries = countryService.findAll();
if (!countries.isEmpty()) {
defaultArea.setCountries(countries);
}
areaService.save(defaultArea);
} }
Permission settings_access = new Permission();
settings_access.setTag(PermissionName.SETTINGS_ACCESS);
settings_access.setDescription(PermissionDescription.SETTINGS_ACCESS);
} }
} }

View File

@@ -1,12 +1,12 @@
package com.sgs.graphql.dataCenter.domain; package com.sgs.graphql.dataCenter.domain;
import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference; import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.sgs.graphql.area.domain.Area; import com.sgs.graphql.area.domain.Area;
import com.sgs.graphql.city.domain.City;
import com.sgs.graphql.sector.domain.Sector; import com.sgs.graphql.sector.domain.Sector;
import com.sgs.graphql.subSector.domain.SubSector; import com.sgs.graphql.subSector.domain.SubSector;
import com.sgs.graphql.emissionSource.domain.EmissionSource;
import com.sgs.graphql.emissionScope.domain.EmissionScope; import com.sgs.graphql.emissionScope.domain.EmissionScope;
import com.sgs.graphql.consuptionUnit.domain.ConsuptionUnit;
import com.sgs.graphql.activitySubUnit.domain.ActivitySubUnit; import com.sgs.graphql.activitySubUnit.domain.ActivitySubUnit;
import com.sgs.lib.dao.domain.BaseDomain; import com.sgs.lib.dao.domain.BaseDomain;
@@ -14,7 +14,8 @@ import javax.persistence.*;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.transaction.annotation.Transactional; import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -29,14 +30,14 @@ public class DataCenter extends BaseDomain {
private Integer number; private Integer number;
private Area area; private Area area;
private City city;
private List<Project> projects = new ArrayList<>(); private List<PhysicalMachine> physicalMachines = new ArrayList<>();
private List<DataCenterEmissionSource> dataCenterEmissionSources = new ArrayList<>();
private Sector sector; private Sector sector;
private SubSector subSector; private SubSector subSector;
private EmissionSource emissionSource;
private EmissionScope emissionScope; private EmissionScope emissionScope;
private Double consuptionAmount; private Double consuptionAmount;
private ConsuptionUnit consuptionUnit;
private ActivitySubUnit activitySubUnit; private ActivitySubUnit activitySubUnit;
// New attributes // New attributes
@@ -45,9 +46,7 @@ public class DataCenter extends BaseDomain {
private Double latitude; private Double latitude;
private Double longitude; private Double longitude;
@Column(name = "data_center_name") @Column(name = "data_center_name")
@Transactional
public String getDataCenter() { public String getDataCenter() {
return dataCenter; return dataCenter;
} }
@@ -63,12 +62,23 @@ public class DataCenter extends BaseDomain {
@OneToMany(mappedBy = "dataCenter", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @OneToMany(mappedBy = "dataCenter", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JsonManagedReference @JsonManagedReference
public List<Project> getProjects() { public List<PhysicalMachine> getPhysicalMachines() {
return projects; return physicalMachines;
} }
public void setProjects(List<Project> projects) { public void setPhysicalMachines(List<PhysicalMachine> physicalMachines) {
this.projects = projects; this.physicalMachines = physicalMachines;
}
@OneToMany(mappedBy = "dataCenter", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@Fetch(FetchMode.SUBSELECT)
@JsonManagedReference
public List<DataCenterEmissionSource> getDataCenterEmissionSources() {
return dataCenterEmissionSources;
}
public void setDataCenterEmissionSources(List<DataCenterEmissionSource> dataCenterEmissionSources) {
this.dataCenterEmissionSources = dataCenterEmissionSources;
} }
public void setExternalId(Integer externalId) { public void setExternalId(Integer externalId) {
@@ -84,7 +94,6 @@ public class DataCenter extends BaseDomain {
this.number = number; this.number = number;
} }
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "sector_id") @JoinColumn(name = "sector_id")
public Sector getSector() { public Sector getSector() {
@@ -114,16 +123,6 @@ public class DataCenter extends BaseDomain {
this.consuptionAmount = consuptionAmount; this.consuptionAmount = consuptionAmount;
} }
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "consuption_unit_id")
public ConsuptionUnit getConsuptionUnit() {
return consuptionUnit;
}
public void setConsuptionUnit(ConsuptionUnit consuptionUnit) {
this.consuptionUnit = consuptionUnit;
}
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "area_id") @JoinColumn(name = "area_id")
public Area getArea() { public Area getArea() {
@@ -134,6 +133,16 @@ public class DataCenter extends BaseDomain {
this.area = area; this.area = area;
} }
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "city_id")
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "sub_sector_id") @JoinColumn(name = "sub_sector_id")
public SubSector getSubSector() { public SubSector getSubSector() {
@@ -144,16 +153,6 @@ public class DataCenter extends BaseDomain {
this.subSector = subSector; this.subSector = subSector;
} }
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "emission_source_id")
public EmissionSource getEmissionSource() {
return emissionSource;
}
public void setEmissionSource(EmissionSource emissionSource) {
this.emissionSource = emissionSource;
}
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "activity_sub_unit_id") @JoinColumn(name = "activity_sub_unit_id")
public ActivitySubUnit getActivitySubUnit() { public ActivitySubUnit getActivitySubUnit() {

View File

@@ -0,0 +1,68 @@
package com.sgs.graphql.dataCenter.domain;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.sgs.graphql.emissionSource.domain.EmissionSource;
import com.sgs.graphql.consuptionUnit.domain.ConsuptionUnit;
import com.sgs.lib.dao.domain.BaseDomain;
import javax.persistence.*;
@Entity
@Table(name = "data_center_emission_source")
public class DataCenterEmissionSource extends BaseDomain {
private DataCenter dataCenter;
private EmissionSource emissionSource;
private ConsuptionUnit consuptionUnit;
private Boolean isDefault = false; // To mark which one is the default emission source
private Double percentage; // Percentage allocation for this emission source (optional)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "data_center_id", nullable = false)
@JsonBackReference
public DataCenter getDataCenter() {
return dataCenter;
}
public void setDataCenter(DataCenter dataCenter) {
this.dataCenter = dataCenter;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "emission_source_id", nullable = false)
public EmissionSource getEmissionSource() {
return emissionSource;
}
public void setEmissionSource(EmissionSource emissionSource) {
this.emissionSource = emissionSource;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "consuption_unit_id", nullable = false)
public ConsuptionUnit getConsuptionUnit() {
return consuptionUnit;
}
public void setConsuptionUnit(ConsuptionUnit consuptionUnit) {
this.consuptionUnit = consuptionUnit;
}
@Column(name = "is_default")
public Boolean getIsDefault() {
return isDefault;
}
public void setIsDefault(Boolean isDefault) {
this.isDefault = isDefault;
}
@Column(name = "percentage")
public Double getPercentage() {
return percentage;
}
public void setPercentage(Double percentage) {
this.percentage = percentage;
}
}

View File

@@ -14,9 +14,10 @@ public class PhysicalMachine extends BaseDomain {
private String name; private String name;
private String ip; private String ip;
private String tag; private String tag;
private String cloudSystem;
private Double power; private Double power;
private List<VM> vms = new ArrayList<>(); private List<VM> vms = new ArrayList<>();
private Project project; private DataCenter dataCenter;
@Column(name = "name") @Column(name = "name")
public String getName() { public String getName() {
@@ -45,6 +46,15 @@ public class PhysicalMachine extends BaseDomain {
this.tag = tag; this.tag = tag;
} }
@Column(name = "cloud_system")
public String getCloudSystem() {
return cloudSystem;
}
public void setCloudSystem(String cloudSystem) {
this.cloudSystem = cloudSystem;
}
@Column(name = "power") @Column(name = "power")
public Double getPower() { public Double getPower() {
return power; return power;
@@ -65,13 +75,13 @@ public class PhysicalMachine extends BaseDomain {
} }
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "project_id") @JoinColumn(name = "data_center_id")
@JsonBackReference @JsonBackReference
public Project getProject() { public DataCenter getDataCenter() {
return project; return dataCenter;
} }
public void setProject(Project project) { public void setDataCenter(DataCenter dataCenter) {
this.project = project; this.dataCenter = dataCenter;
} }
} }

View File

@@ -1,50 +0,0 @@
package com.sgs.graphql.dataCenter.domain;
import java.util.List;
import javax.persistence.*;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.sgs.lib.dao.domain.BaseDomain;
@Entity
@Table(name = "project")
public class Project extends BaseDomain{
private String name;
private List<PhysicalMachine> physicalMachines;
@OneToMany(mappedBy = "project", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
public List<PhysicalMachine> getPhysicalMachines() {
return physicalMachines;
}
public void setPhysicalMachines(List<PhysicalMachine> physicalMachines) {
this.physicalMachines = physicalMachines;
}
// This creates a foreign key in the `project` table
private DataCenter dataCenter;
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne
@JoinColumn(name = "data_center_id")
@JsonBackReference
public DataCenter getDataCenter() {
return dataCenter;
}
public void setDataCenter(DataCenter dataCenter) {
this.dataCenter = dataCenter;
}
}

View File

@@ -23,6 +23,7 @@ public class VM extends BaseDomain {
private String host; private String host;
private String flavorName; private String flavorName;
private String tag; private String tag;
private String project; // UUID of the project this VM belongs to
private String emissionSourceData; // JSON string to store emission source map private String emissionSourceData; // JSON string to store emission source map
private Config config; private Config config;
private PhysicalMachine physicalMachine; private PhysicalMachine physicalMachine;
@@ -100,6 +101,15 @@ public class VM extends BaseDomain {
this.tag = tag; this.tag = tag;
} }
@Column(name = "project")
public String getProject() {
return project;
}
public void setProject(String project) {
this.project = project;
}
@Column(name = "ip") @Column(name = "ip")
public String getIp() { public String getIp() {
return ip; return ip;

View File

@@ -17,7 +17,9 @@ public class DataCenterDto {
private Integer externalId; private Integer externalId;
private Integer number; private Integer number;
private AreaDto area; private AreaDto area;
private Map<String, ProjectDto> projects;
@JsonProperty("physical_machines")
private Map<String, PhysicalMachineDto> physicalMachine;
// Emission calculation fields // Emission calculation fields
private SectorDto sector; private SectorDto sector;
@@ -68,12 +70,12 @@ public class DataCenterDto {
this.area = area; this.area = area;
} }
public Map<String, ProjectDto> getProjects() { public Map<String, PhysicalMachineDto> getPhysicalMachine() {
return projects; return physicalMachine;
} }
public void setProjects(Map<String, ProjectDto> projects) { public void setPhysicalMachine(Map<String, PhysicalMachineDto> physicalMachine) {
this.projects = projects; this.physicalMachine = physicalMachine;
} }
public SectorDto getSector() { public SectorDto getSector() {

View File

@@ -0,0 +1,50 @@
package com.sgs.graphql.dataCenter.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DataCenterEmissionSourceDto {
@JsonProperty("emission_source_id")
private String emissionSourceId;
@JsonProperty("consuption_unit_id")
private String consuptionUnitId;
@JsonProperty("is_default")
private Boolean isDefault = false;
@JsonProperty("percentage")
private Double percentage;
public String getEmissionSourceId() {
return emissionSourceId;
}
public void setEmissionSourceId(String emissionSourceId) {
this.emissionSourceId = emissionSourceId;
}
public String getConsuptionUnitId() {
return consuptionUnitId;
}
public void setConsuptionUnitId(String consuptionUnitId) {
this.consuptionUnitId = consuptionUnitId;
}
public Boolean getIsDefault() {
return isDefault;
}
public void setIsDefault(Boolean isDefault) {
this.isDefault = isDefault;
}
public Double getPercentage() {
return percentage;
}
public void setPercentage(Double percentage) {
this.percentage = percentage;
}
}

View File

@@ -1,24 +0,0 @@
package com.sgs.graphql.dataCenter.dto;
import java.util.Map;
public class MainOptimizationSpaceDto {
private Map<String, VMDto> vms;
private Map<String, PhysicalMachineDto> pms;
public Map<String, VMDto> getVms() {
return vms;
}
public void setVms(Map<String, VMDto> vms) {
this.vms = vms;
}
public Map<String, PhysicalMachineDto> getPms() {
return pms;
}
public void setPms(Map<String, PhysicalMachineDto> pms) {
this.pms = pms;
}
}

View File

@@ -2,6 +2,7 @@ package com.sgs.graphql.dataCenter.dto;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List; import java.util.List;
import java.util.Map;
public class PhysicalMachineDto { public class PhysicalMachineDto {
@JsonProperty("name") @JsonProperty("name")
@@ -10,12 +11,18 @@ public class PhysicalMachineDto {
@JsonProperty("tag") @JsonProperty("tag")
private String tag; private String tag;
@JsonProperty("cloud_system")
private String cloudSystem;
@JsonProperty("power") @JsonProperty("power")
private double power; private double power;
@JsonProperty("confg") // Note: keeping the typo from JSON @JsonProperty("confg") // Note: keeping the typo from JSON
private List<Object> confg; private List<Object> confg;
@JsonProperty("vms")
private Map<String, VMDto> vms;
private String ip; // IP address from the message key private String ip; // IP address from the message key
public String getName() { public String getName() {
@@ -34,6 +41,14 @@ public class PhysicalMachineDto {
this.tag = tag; this.tag = tag;
} }
public String getCloudSystem() {
return cloudSystem;
}
public void setCloudSystem(String cloudSystem) {
this.cloudSystem = cloudSystem;
}
public double getPower() { public double getPower() {
return power; return power;
} }
@@ -57,4 +72,12 @@ public class PhysicalMachineDto {
public void setIp(String ip) { public void setIp(String ip) {
this.ip = ip; this.ip = ip;
} }
public Map<String, VMDto> getVms() {
return vms;
}
public void setVms(Map<String, VMDto> vms) {
this.vms = vms;
}
} }

View File

@@ -1,61 +0,0 @@
package com.sgs.graphql.dataCenter.dto;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ProjectDto {
@JsonProperty("main_optimization_space")
private MainOptimizationSpaceDto mainOptimizationSpace;
@JsonProperty("sub_optimization_space")
private SubOptimizationSpaceDto subOptimizationSpace;
// Legacy field - kept for backward compatibility with older message formats
@JsonProperty("physical_machines")
private List<PhysicalMachineDto> physicalMachines;
// These fields are derived from the map key and entity relationships, not from the message
private String id; // This will be set from the map key
private String name; // This will be derived or set separately
public MainOptimizationSpaceDto getMainOptimizationSpace() {
return mainOptimizationSpace;
}
public void setMainOptimizationSpace(MainOptimizationSpaceDto mainOptimizationSpace) {
this.mainOptimizationSpace = mainOptimizationSpace;
}
public SubOptimizationSpaceDto getSubOptimizationSpace() {
return subOptimizationSpace;
}
public void setSubOptimizationSpace(SubOptimizationSpaceDto subOptimizationSpace) {
this.subOptimizationSpace = subOptimizationSpace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<PhysicalMachineDto> getPhysicalMachines() {
return physicalMachines;
}
public void setPhysicalMachines(List<PhysicalMachineDto> physicalMachines) {
this.physicalMachines = physicalMachines;
}
}

View File

@@ -1,24 +0,0 @@
package com.sgs.graphql.dataCenter.dto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* DTO for sub_optimization_space in the message format.
* Currently appears to be empty in the message structure.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SubOptimizationSpaceDto {
// Currently empty based on the message format
// Can be extended if needed in the future
// Add a placeholder field to make Jackson happy
private boolean isEmpty = true;
public boolean isEmpty() {
return isEmpty;
}
public void setEmpty(boolean empty) {
this.isEmpty = empty;
}
}

View File

@@ -26,6 +26,9 @@ public class VMDto {
@JsonProperty("tag") @JsonProperty("tag")
private String tag; private String tag;
@JsonProperty("project")
private String project;
@JsonProperty("confg") // Note: keeping the typo from JSON @JsonProperty("confg") // Note: keeping the typo from JSON
private List<Object> confg; private List<Object> confg;
@@ -101,6 +104,14 @@ public class VMDto {
this.tag = tag; this.tag = tag;
} }
public String getProject() {
return project;
}
public void setProject(String project) {
this.project = project;
}
public List<Object> getConfg() { public List<Object> getConfg() {
return confg; return confg;
} }

View File

@@ -1,18 +1,26 @@
package com.sgs.graphql.dataCenter.mutation; package com.sgs.graphql.dataCenter.mutation;
import com.sgs.exception.GraphQLCustomException;
import com.sgs.graphql.dataCenter.mutation.mapper.DataCenterMapper; import com.sgs.graphql.dataCenter.mutation.mapper.DataCenterMapper;
import com.sgs.graphql.dataCenter.service.DataCenterService; import com.sgs.graphql.dataCenter.service.DataCenterService;
import com.sgs.graphql.dataCenter.domain.DataCenter; import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterCreateInput; import com.sgs.graphql.dataCenter.mutation.input.DataCenterCreateInput;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterUpdateInput; import com.sgs.graphql.dataCenter.mutation.input.DataCenterUpdateInput;
import com.sgs.graphql.permission.domain.PermissionName; import com.sgs.graphql.permission.domain.PermissionName;
import com.sgs.graphql.systemHistory.enums.LogType;
import com.sgs.graphql.systemHistory.mutation.SystemLogger;
import com.sgs.graphql.userHistory.mutation.UserLogger;
import com.sgs.graphql.userNotification.mutation.UserNotificationMutation;
import graphql.kickstart.tools.GraphQLMutationResolver; import graphql.kickstart.tools.GraphQLMutationResolver;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.transaction.Transactional;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.NoSuchElementException;
import java.util.UUID; import java.util.UUID;
@Validated @Validated
@@ -21,57 +29,128 @@ public class DataCenterMutation implements GraphQLMutationResolver {
private final DataCenterService dataCenterService; private final DataCenterService dataCenterService;
private final DataCenterMapper dataCenterMapper; private final DataCenterMapper dataCenterMapper;
private final SystemLogger systemLogger;
private final UserLogger userLogger;
private final UserNotificationMutation notificationMutation;
@Autowired @Autowired
public DataCenterMutation(DataCenterService dataCenterService, DataCenterMapper dataCenterMapper) { public DataCenterMutation(DataCenterService dataCenterService, DataCenterMapper dataCenterMapper,
SystemLogger systemLogger, UserLogger userLogger,
UserNotificationMutation notificationMutation) {
this.dataCenterService = dataCenterService; this.dataCenterService = dataCenterService;
this.dataCenterMapper = dataCenterMapper; this.dataCenterMapper = dataCenterMapper;
this.systemLogger = systemLogger;
this.userLogger = userLogger;
this.notificationMutation = notificationMutation;
} }
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_CREATE + "')") @PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_CREATE + "')")
public DataCenter createDataCenter(@Valid DataCenterCreateInput input) { @Transactional
// Check for duplicate externalId public DataCenter createDataCenter(@Valid DataCenterCreateInput input, DataFetchingEnvironment environment) {
if (input.getExternalId() != null && dataCenterService.existsByExternalId(input.getExternalId())) { try {
throw new RuntimeException("This external id already exists: " + input.getExternalId()); // Check for duplicate externalId
if (input.getExternalId() != null && dataCenterService.existsByExternalId(input.getExternalId())) {
throw new GraphQLCustomException("2010", input.getExternalId().toString());
}
DataCenter dataCenter = dataCenterMapper.toEntity(input);
// Set auto-generated number if not provided
if (dataCenter.getNumber() == null) {
Integer maxNumber = dataCenterService.findMaxNumber();
dataCenter.setNumber((maxNumber == null) ? 1 : maxNumber + 1);
}
DataCenter savedDataCenter = dataCenterService.save(dataCenter);
// Log and notify
String dataCenterName = savedDataCenter.getDataCenter() != null ? savedDataCenter.getDataCenter()
: "DataCenter #" + savedDataCenter.getNumber();
systemLogger.createSystemLog(LogType.INFO, dataCenterName + " adlı veri merkezi oluşturuldu");
userLogger.createUserLog(LogType.INFO, dataCenterName + " adlı veri merkezi oluşturuldu", environment);
notificationMutation.createNotification(environment, "Veri Merkezi",
dataCenterName + " adlı veri merkezi oluşturuldu", "Yeni kayıt");
return savedDataCenter;
} catch (GraphQLCustomException e) {
throw e;
} catch (Exception e) {
systemLogger.createSystemLog(LogType.ERROR,
"Yeni veri merkezi oluşturulurken hata oluştu: " + e.getMessage());
throw e;
} }
DataCenter dataCenter = dataCenterMapper.toEntity(input);
// Set auto-generated number if not provided
if (dataCenter.getNumber() == null) {
Integer maxNumber = dataCenterService.getRepository().findMaxNumber();
dataCenter.setNumber((maxNumber == null) ? 1 : maxNumber + 1);
}
return dataCenterService.save(dataCenter);
} }
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_UPDATE + "')") @PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_UPDATE + "')")
public DataCenter updateDataCenter(UUID id, @Valid DataCenterUpdateInput input) { @Transactional
return dataCenterService.findById(id) public DataCenter updateDataCenter(UUID id, @Valid DataCenterUpdateInput input,
.map(dataCenter -> { DataFetchingEnvironment environment) {
// Check for duplicate externalId if it's being updated try {
if (input.getExternalId() != null && DataCenter dataCenter = dataCenterService.findById(id)
!input.getExternalId().equals(dataCenter.getExternalId()) && .orElseThrow(() -> new NoSuchElementException("Data center not found with ID: " + id));
dataCenterService.existsByExternalId(input.getExternalId())) {
throw new RuntimeException("This external id already exists: " + input.getExternalId()); // Check for duplicate externalId if it's being updated
} if (input.getExternalId() != null &&
return dataCenterService.update(dataCenterMapper.updateEntity(dataCenter, input)); !input.getExternalId().equals(dataCenter.getExternalId()) &&
}) dataCenterService.existsByExternalId(input.getExternalId())) {
.orElseThrow(() -> new RuntimeException("Data center not found with ID: " + id)); throw new GraphQLCustomException("2010", input.getExternalId().toString());
}
DataCenter updatedDataCenter = dataCenterService.update(dataCenterMapper.updateEntity(dataCenter, input));
// Log and notify
String dataCenterName = updatedDataCenter.getDataCenter() != null ? updatedDataCenter.getDataCenter()
: "DataCenter #" + updatedDataCenter.getNumber();
systemLogger.createSystemLog(LogType.INFO, dataCenterName + " adlı veri merkezi güncellendi");
userLogger.createUserLog(LogType.INFO, dataCenterName + " adlı veri merkezi güncellendi", environment);
notificationMutation.createNotification(environment, "Veri Merkezi",
dataCenterName + " adlı veri merkezi güncellendi", "Güncelleme");
return updatedDataCenter;
} catch (GraphQLCustomException e) {
throw e;
} catch (NoSuchElementException e) {
systemLogger.createSystemLog(LogType.ERROR, "Veri merkezi bulunamadı: " + id);
throw e;
} catch (Exception e) {
systemLogger.createSystemLog(LogType.ERROR, "Veri merkezi güncellenirken hata oluştu: " + e.getMessage());
throw e;
}
} }
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_DELETE + "')") @PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_DELETE + "')")
public Boolean deleteDataCenter(UUID id) { @Transactional
public String deleteDataCenter(UUID id, DataFetchingEnvironment environment) {
String dataCenterName = "";
try { try {
DataCenter dataCenter = dataCenterService.findById(id) DataCenter dataCenter = dataCenterService.findById(id)
.orElseThrow(() -> new RuntimeException("Data center not found with ID: " + id)); .orElseThrow(() -> new NoSuchElementException("Data center not found with ID: " + id));
dataCenterName = dataCenter.getDataCenter() != null ? dataCenter.getDataCenter()
: "DataCenter #" + dataCenter.getNumber();
// Check if data center has physical machines or other dependencies
if (dataCenter.getPhysicalMachines() != null && !dataCenter.getPhysicalMachines().isEmpty()) {
String message = "Silinmeye çalışılan veri merkezinin fiziksel makineleri olduğu için silinememektedir";
systemLogger.createSystemLog(LogType.WARN, dataCenterName + ": " + message);
return message;
}
dataCenterService.delete(dataCenter); dataCenterService.delete(dataCenter);
return true;
// Log and notify
systemLogger.createSystemLog(LogType.INFO, dataCenterName + " adlı veri merkezi silindi");
userLogger.createUserLog(LogType.INFO, dataCenterName + " adlı veri merkezi silindi", environment);
notificationMutation.createNotification(environment, "Veri Merkezi",
dataCenterName + " adlı veri merkezi silindi", "Silme");
return "true";
} catch (NoSuchElementException e) {
systemLogger.createSystemLog(LogType.ERROR, "Veri merkezi bulunamadı: " + id);
return "false";
} catch (Exception e) { } catch (Exception e) {
System.out.println("DataCenter deletion error: " + e.getMessage()); systemLogger.createSystemLog(LogType.ERROR, "Veri merkezi silinirken hata oluştu: " + e.getMessage());
return false; return "false";
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Min; import javax.validation.constraints.Min;
import java.util.UUID; import java.util.UUID;
import java.util.List;
public class DataCenterCreateInput extends BaseCreateInput { public class DataCenterCreateInput extends BaseCreateInput {
@NotBlank(message = "Data center adı gereklidir") @NotBlank(message = "Data center adı gereklidir")
@@ -17,15 +18,18 @@ public class DataCenterCreateInput extends BaseCreateInput {
private UUID areaId; private UUID areaId;
private UUID cityId;
@NotNull(message = "Sektör ID gereklidir") @NotNull(message = "Sektör ID gereklidir")
private UUID sectorId; private UUID sectorId;
private UUID subSectorId; private UUID subSectorId;
private UUID emissionSourceId;
private UUID emissionScopeId; private UUID emissionScopeId;
private UUID consuptionUnitId;
private UUID activitySubUnitId; private UUID activitySubUnitId;
// Multiple emission sources support - each with exactly one unit
private List<DataCenterEmissionSourceInput> dataCenterEmissionSources;
// New attributes // New attributes
private String ayposURL; private String ayposURL;
private String address; private String address;
@@ -48,24 +52,24 @@ public class DataCenterCreateInput extends BaseCreateInput {
public UUID getAreaId() { return areaId; } public UUID getAreaId() { return areaId; }
public void setAreaId(UUID areaId) { this.areaId = areaId; } public void setAreaId(UUID areaId) { this.areaId = areaId; }
public UUID getCityId() { return cityId; }
public void setCityId(UUID cityId) { this.cityId = cityId; }
public UUID getSectorId() { return sectorId; } public UUID getSectorId() { return sectorId; }
public void setSectorId(UUID sectorId) { this.sectorId = sectorId; } public void setSectorId(UUID sectorId) { this.sectorId = sectorId; }
public UUID getSubSectorId() { return subSectorId; } public UUID getSubSectorId() { return subSectorId; }
public void setSubSectorId(UUID subSectorId) { this.subSectorId = subSectorId; } public void setSubSectorId(UUID subSectorId) { this.subSectorId = subSectorId; }
public UUID getEmissionSourceId() { return emissionSourceId; }
public void setEmissionSourceId(UUID emissionSourceId) { this.emissionSourceId = emissionSourceId; }
public UUID getEmissionScopeId() { return emissionScopeId; } public UUID getEmissionScopeId() { return emissionScopeId; }
public void setEmissionScopeId(UUID emissionScopeId) { this.emissionScopeId = emissionScopeId; } public void setEmissionScopeId(UUID emissionScopeId) { this.emissionScopeId = emissionScopeId; }
public UUID getConsuptionUnitId() { return consuptionUnitId; }
public void setConsuptionUnitId(UUID consuptionUnitId) { this.consuptionUnitId = consuptionUnitId; }
public UUID getActivitySubUnitId() { return activitySubUnitId; } public UUID getActivitySubUnitId() { return activitySubUnitId; }
public void setActivitySubUnitId(UUID activitySubUnitId) { this.activitySubUnitId = activitySubUnitId; } public void setActivitySubUnitId(UUID activitySubUnitId) { this.activitySubUnitId = activitySubUnitId; }
public List<DataCenterEmissionSourceInput> getDataCenterEmissionSources() { return dataCenterEmissionSources; }
public void setDataCenterEmissionSources(List<DataCenterEmissionSourceInput> dataCenterEmissionSources) { this.dataCenterEmissionSources = dataCenterEmissionSources; }
// New attribute getters and setters // New attribute getters and setters
public String getAyposURL() { return ayposURL; } public String getAyposURL() { return ayposURL; }
public void setAyposURL(String ayposURL) { this.ayposURL = ayposURL; } public void setAyposURL(String ayposURL) { this.ayposURL = ayposURL; }

View File

@@ -0,0 +1,40 @@
package com.sgs.graphql.dataCenter.mutation.input;
public class DataCenterEmissionSourceInput {
private String emissionSourceId;
private String consuptionUnitId;
private Boolean isDefault = false;
private Double percentage;
public String getEmissionSourceId() {
return emissionSourceId;
}
public void setEmissionSourceId(String emissionSourceId) {
this.emissionSourceId = emissionSourceId;
}
public String getConsuptionUnitId() {
return consuptionUnitId;
}
public void setConsuptionUnitId(String consuptionUnitId) {
this.consuptionUnitId = consuptionUnitId;
}
public Boolean getIsDefault() {
return isDefault;
}
public void setIsDefault(Boolean isDefault) {
this.isDefault = isDefault;
}
public Double getPercentage() {
return percentage;
}
public void setPercentage(Double percentage) {
this.percentage = percentage;
}
}

View File

@@ -1,9 +1,11 @@
package com.sgs.graphql.dataCenter.mutation.input; package com.sgs.graphql.dataCenter.mutation.input;
import com.sgs.lib.dao.mutation.input.BaseUpdateInput; import com.sgs.lib.dao.mutation.input.BaseUpdateInput;
import javax.validation.constraints.NotNull; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.validation.constraints.NotNull;
public class DataCenterUpdateInput extends BaseUpdateInput { public class DataCenterUpdateInput extends BaseUpdateInput {
private String dataCenter; private String dataCenter;
private Integer externalId; private Integer externalId;
@@ -11,14 +13,16 @@ public class DataCenterUpdateInput extends BaseUpdateInput {
private Double consuptionAmount; private Double consuptionAmount;
private UUID areaId; private UUID areaId;
private UUID cityId;
@NotNull(message = "Sektör ID gereklidir") @NotNull(message = "Sektör ID gereklidir")
private UUID sectorId; private UUID sectorId;
private UUID subSectorId; private UUID subSectorId;
private UUID emissionSourceId;
private UUID emissionScopeId; private UUID emissionScopeId;
private UUID consuptionUnitId;
private UUID activitySubUnitId; private UUID activitySubUnitId;
// Multiple emission sources with units
private List<DataCenterEmissionSourceInput> dataCenterEmissionSources;
// New attributes // New attributes
private String ayposURL; private String ayposURL;
private String address; private String address;
@@ -41,24 +45,28 @@ public class DataCenterUpdateInput extends BaseUpdateInput {
public UUID getAreaId() { return areaId; } public UUID getAreaId() { return areaId; }
public void setAreaId(UUID areaId) { this.areaId = areaId; } public void setAreaId(UUID areaId) { this.areaId = areaId; }
public UUID getCityId() { return cityId; }
public void setCityId(UUID cityId) { this.cityId = cityId; }
public UUID getSectorId() { return sectorId; } public UUID getSectorId() { return sectorId; }
public void setSectorId(UUID sectorId) { this.sectorId = sectorId; } public void setSectorId(UUID sectorId) { this.sectorId = sectorId; }
public UUID getSubSectorId() { return subSectorId; } public UUID getSubSectorId() { return subSectorId; }
public void setSubSectorId(UUID subSectorId) { this.subSectorId = subSectorId; } public void setSubSectorId(UUID subSectorId) { this.subSectorId = subSectorId; }
public UUID getEmissionSourceId() { return emissionSourceId; }
public void setEmissionSourceId(UUID emissionSourceId) { this.emissionSourceId = emissionSourceId; }
public UUID getEmissionScopeId() { return emissionScopeId; } public UUID getEmissionScopeId() { return emissionScopeId; }
public void setEmissionScopeId(UUID emissionScopeId) { this.emissionScopeId = emissionScopeId; } public void setEmissionScopeId(UUID emissionScopeId) { this.emissionScopeId = emissionScopeId; }
public UUID getConsuptionUnitId() { return consuptionUnitId; }
public void setConsuptionUnitId(UUID consuptionUnitId) { this.consuptionUnitId = consuptionUnitId; }
public UUID getActivitySubUnitId() { return activitySubUnitId; } public UUID getActivitySubUnitId() { return activitySubUnitId; }
public void setActivitySubUnitId(UUID activitySubUnitId) { this.activitySubUnitId = activitySubUnitId; } public void setActivitySubUnitId(UUID activitySubUnitId) { this.activitySubUnitId = activitySubUnitId; }
public List<DataCenterEmissionSourceInput> getDataCenterEmissionSources() {
return dataCenterEmissionSources;
}
public void setDataCenterEmissionSources(List<DataCenterEmissionSourceInput> dataCenterEmissionSources) {
this.dataCenterEmissionSources = dataCenterEmissionSources;
}
// New attribute getters and setters // New attribute getters and setters
public String getAyposURL() { return ayposURL; } public String getAyposURL() { return ayposURL; }
public void setAyposURL(String ayposURL) { this.ayposURL = ayposURL; } public void setAyposURL(String ayposURL) { this.ayposURL = ayposURL; }

View File

@@ -1,8 +1,10 @@
package com.sgs.graphql.dataCenter.mutation.mapper; package com.sgs.graphql.dataCenter.mutation.mapper;
import com.sgs.graphql.dataCenter.domain.DataCenter; import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.domain.DataCenterEmissionSource;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterCreateInput; import com.sgs.graphql.dataCenter.mutation.input.DataCenterCreateInput;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterUpdateInput; import com.sgs.graphql.dataCenter.mutation.input.DataCenterUpdateInput;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterEmissionSourceInput;
import com.sgs.graphql.area.service.AreaService; import com.sgs.graphql.area.service.AreaService;
import com.sgs.graphql.sector.service.SectorService; import com.sgs.graphql.sector.service.SectorService;
import com.sgs.graphql.subSector.service.SubSectorService; import com.sgs.graphql.subSector.service.SubSectorService;
@@ -10,9 +12,13 @@ import com.sgs.graphql.emissionSource.service.EmissionSourceService;
import com.sgs.graphql.emissionScope.service.EmissionScopeService; import com.sgs.graphql.emissionScope.service.EmissionScopeService;
import com.sgs.graphql.consuptionUnit.service.ConsuptionUnitService; import com.sgs.graphql.consuptionUnit.service.ConsuptionUnitService;
import com.sgs.graphql.activitySubUnit.service.ActivitySubUnitService; import com.sgs.graphql.activitySubUnit.service.ActivitySubUnitService;
import com.sgs.graphql.city.service.CityService;
import com.sgs.lib.dao.mutation.mapper.BaseCreateUpdateMapper; import com.sgs.lib.dao.mutation.mapper.BaseCreateUpdateMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
import java.util.ArrayList;
import java.util.UUID;
@Component @Component
public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCenterCreateInput, DataCenterUpdateInput> { public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCenterCreateInput, DataCenterUpdateInput> {
@@ -24,12 +30,13 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
private final EmissionScopeService emissionScopeService; private final EmissionScopeService emissionScopeService;
private final ConsuptionUnitService consuptionUnitService; private final ConsuptionUnitService consuptionUnitService;
private final ActivitySubUnitService activitySubUnitService; private final ActivitySubUnitService activitySubUnitService;
private final CityService cityService;
@Autowired @Autowired
public DataCenterMapper(AreaService areaService, SectorService sectorService, public DataCenterMapper(AreaService areaService, SectorService sectorService,
SubSectorService subSectorService, EmissionSourceService emissionSourceService, SubSectorService subSectorService, EmissionSourceService emissionSourceService,
EmissionScopeService emissionScopeService, ConsuptionUnitService consuptionUnitService, EmissionScopeService emissionScopeService, ConsuptionUnitService consuptionUnitService,
ActivitySubUnitService activitySubUnitService) { ActivitySubUnitService activitySubUnitService, CityService cityService) {
this.areaService = areaService; this.areaService = areaService;
this.sectorService = sectorService; this.sectorService = sectorService;
this.subSectorService = subSectorService; this.subSectorService = subSectorService;
@@ -37,6 +44,7 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
this.emissionScopeService = emissionScopeService; this.emissionScopeService = emissionScopeService;
this.consuptionUnitService = consuptionUnitService; this.consuptionUnitService = consuptionUnitService;
this.activitySubUnitService = activitySubUnitService; this.activitySubUnitService = activitySubUnitService;
this.cityService = cityService;
} }
@Override @Override
@@ -53,6 +61,9 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
if (input.getAreaId() != null) { if (input.getAreaId() != null) {
entity.setArea(areaService.findById(input.getAreaId()).orElse(null)); entity.setArea(areaService.findById(input.getAreaId()).orElse(null));
} }
if (input.getCityId() != null) {
entity.setCity(cityService.findById(input.getCityId()).orElse(null));
}
if (input.getSectorId() != null) { if (input.getSectorId() != null) {
entity.setSector(sectorService.findById(input.getSectorId()).orElse(null)); entity.setSector(sectorService.findById(input.getSectorId()).orElse(null));
@@ -62,18 +73,10 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
entity.setSubSector(subSectorService.findById(input.getSubSectorId()).orElse(null)); entity.setSubSector(subSectorService.findById(input.getSubSectorId()).orElse(null));
} }
if (input.getEmissionSourceId() != null) {
entity.setEmissionSource(emissionSourceService.findById(input.getEmissionSourceId()).orElse(null));
}
if (input.getEmissionScopeId() != null) { if (input.getEmissionScopeId() != null) {
entity.setEmissionScope(emissionScopeService.findById(input.getEmissionScopeId()).orElse(null)); entity.setEmissionScope(emissionScopeService.findById(input.getEmissionScopeId()).orElse(null));
} }
if (input.getConsuptionUnitId() != null) {
entity.setConsuptionUnit(consuptionUnitService.findById(input.getConsuptionUnitId()).orElse(null));
}
if (input.getActivitySubUnitId() != null) { if (input.getActivitySubUnitId() != null) {
entity.setActivitySubUnit(activitySubUnitService.findById(input.getActivitySubUnitId()).orElse(null)); entity.setActivitySubUnit(activitySubUnitService.findById(input.getActivitySubUnitId()).orElse(null));
} }
@@ -84,6 +87,37 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
entity.setLatitude(input.getLatitude()); entity.setLatitude(input.getLatitude());
entity.setLongitude(input.getLongitude()); entity.setLongitude(input.getLongitude());
// Handle multiple emission sources if provided
if (input.getDataCenterEmissionSources() != null && !input.getDataCenterEmissionSources().isEmpty()) {
List<DataCenterEmissionSource> dataCenterEmissionSources = new ArrayList<>();
for (DataCenterEmissionSourceInput emissionSourceInput : input.getDataCenterEmissionSources()) {
DataCenterEmissionSource dcEmissionSource = new DataCenterEmissionSource();
dcEmissionSource.setDataCenter(entity);
// Set EmissionSource
if (emissionSourceInput.getEmissionSourceId() != null) {
dcEmissionSource.setEmissionSource(emissionSourceService
.findById(UUID.fromString(emissionSourceInput.getEmissionSourceId())).orElse(null));
}
// Set ConsuptionUnit
if (emissionSourceInput.getConsuptionUnitId() != null) {
dcEmissionSource.setConsuptionUnit(consuptionUnitService
.findById(UUID.fromString(emissionSourceInput.getConsuptionUnitId())).orElse(null));
}
// Set optional fields
dcEmissionSource.setIsDefault(
emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setPercentage(emissionSourceInput.getPercentage());
dataCenterEmissionSources.add(dcEmissionSource);
}
entity.setDataCenterEmissionSources(dataCenterEmissionSources);
}
return entity; return entity;
} }
@@ -110,6 +144,9 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
if (input.getAreaId() != null) { if (input.getAreaId() != null) {
entity.setArea(areaService.findById(input.getAreaId()).orElse(null)); entity.setArea(areaService.findById(input.getAreaId()).orElse(null));
} }
if (input.getCityId() != null) {
entity.setCity(cityService.findById(input.getCityId()).orElse(null));
}
if (input.getSectorId() != null) { if (input.getSectorId() != null) {
entity.setSector(sectorService.findById(input.getSectorId()).orElse(null)); entity.setSector(sectorService.findById(input.getSectorId()).orElse(null));
@@ -119,22 +156,43 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
entity.setSubSector(subSectorService.findById(input.getSubSectorId()).orElse(null)); entity.setSubSector(subSectorService.findById(input.getSubSectorId()).orElse(null));
} }
if (input.getEmissionSourceId() != null) {
entity.setEmissionSource(emissionSourceService.findById(input.getEmissionSourceId()).orElse(null));
}
if (input.getEmissionScopeId() != null) { if (input.getEmissionScopeId() != null) {
entity.setEmissionScope(emissionScopeService.findById(input.getEmissionScopeId()).orElse(null)); entity.setEmissionScope(emissionScopeService.findById(input.getEmissionScopeId()).orElse(null));
} }
if (input.getConsuptionUnitId() != null) {
entity.setConsuptionUnit(consuptionUnitService.findById(input.getConsuptionUnitId()).orElse(null));
}
if (input.getActivitySubUnitId() != null) { if (input.getActivitySubUnitId() != null) {
entity.setActivitySubUnit(activitySubUnitService.findById(input.getActivitySubUnitId()).orElse(null)); entity.setActivitySubUnit(activitySubUnitService.findById(input.getActivitySubUnitId()).orElse(null));
} }
// Handle multiple emission sources update if provided
if (input.getDataCenterEmissionSources() != null) {
// Clear existing emission sources from the managed collection
entity.getDataCenterEmissionSources().clear();
// Add new emission sources to the same managed collection
for (DataCenterEmissionSourceInput emissionSourceInput : input.getDataCenterEmissionSources()) {
DataCenterEmissionSource dcEmissionSource = new DataCenterEmissionSource();
dcEmissionSource.setDataCenter(entity);
if (emissionSourceInput.getEmissionSourceId() != null) {
dcEmissionSource.setEmissionSource(emissionSourceService
.findById(UUID.fromString(emissionSourceInput.getEmissionSourceId())).orElse(null));
}
if (emissionSourceInput.getConsuptionUnitId() != null) {
dcEmissionSource.setConsuptionUnit(consuptionUnitService
.findById(UUID.fromString(emissionSourceInput.getConsuptionUnitId())).orElse(null));
}
dcEmissionSource.setIsDefault(
emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setPercentage(emissionSourceInput.getPercentage());
// Add to the existing managed collection instead of creating a new one
entity.getDataCenterEmissionSources().add(dcEmissionSource);
}
}
// New attributes (partial update - only if provided) // New attributes (partial update - only if provided)
if (input.getAyposURL() != null) { if (input.getAyposURL() != null) {
entity.setAyposURL(input.getAyposURL()); entity.setAyposURL(input.getAyposURL());

View File

@@ -11,15 +11,16 @@ import javax.transaction.Transactional;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.sgs.graphql.auth.service.AuthorizationService;
import com.sgs.graphql.dataCenter.domain.DataCenter; import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.domain.PhysicalMachine;
import com.sgs.graphql.dataCenter.query.pagination.DataCenterPageable; import com.sgs.graphql.dataCenter.query.pagination.DataCenterPageable;
import com.sgs.graphql.dataCenter.repo.DataCenterRepo;
import com.sgs.graphql.dataCenter.repo.criteria.DataCenterCriteria; import com.sgs.graphql.dataCenter.repo.criteria.DataCenterCriteria;
import com.sgs.graphql.dataCenter.service.DataCenterService; import com.sgs.graphql.dataCenter.service.DataCenterService;
import com.sgs.graphql.systemHistory.mutation.SystemLogger; import com.sgs.graphql.dataCenter.service.PhysicalMachineService;
import com.sgs.graphql.permission.domain.PermissionName;
import com.sgs.lib.dao.query.pagination.Pagination; import com.sgs.lib.dao.query.pagination.Pagination;
import com.sgs.lib.dao.query.sort.SortBy; import com.sgs.lib.dao.query.sort.SortBy;
@@ -28,42 +29,46 @@ import graphql.kickstart.tools.GraphQLQueryResolver;
@Component @Component
public class DataCenterQueryResolver implements GraphQLQueryResolver { public class DataCenterQueryResolver implements GraphQLQueryResolver {
private final DataCenterService DataCenterService; private final DataCenterService dataCenterService;
private final DataCenterRepo dataCenterRepo; private final PhysicalMachineService physicalMachineService;
private final AuthorizationService authorizationService;
private final SystemLogger systemLogger;
@Autowired @Autowired
public DataCenterQueryResolver(AuthorizationService authorizationService, SystemLogger systemLogger, DataCenterService DataCenterService, DataCenterRepo dataCenterRepo) { public DataCenterQueryResolver(DataCenterService dataCenterService, PhysicalMachineService physicalMachineService) {
this.DataCenterService = DataCenterService; this.dataCenterService = dataCenterService;
this.dataCenterRepo = dataCenterRepo; this.physicalMachineService = physicalMachineService;
this.authorizationService = authorizationService;
this.systemLogger = systemLogger;
} }
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_READ + "')")
public DataCenter dataCenter(UUID id) { public DataCenter dataCenter(UUID id) {
return DataCenterService.findById(id).orElse(null); return dataCenterService.findById(id).orElse(null);
} }
@Transactional @Transactional
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_READ + "')")
public List<DataCenter> dataCenters(DataCenterCriteria criteria, List<SortBy> sortBy) { public List<DataCenter> dataCenters(DataCenterCriteria criteria, List<SortBy> sortBy) {
List<DataCenter> dataCenters = DataCenterService.filterWithSort(ObjectUtils.defaultIfNull(criteria, new DataCenterCriteria()), return dataCenterService.filterWithSort(ObjectUtils.defaultIfNull(criteria, new DataCenterCriteria()),
Sort.by(ObjectUtils.defaultIfNull(sortBy, new ArrayList<SortBy>()) Sort.by(ObjectUtils.defaultIfNull(sortBy, new ArrayList<SortBy>())
.stream() .stream()
.map(SortBy::toOrder) .map(SortBy::toOrder)
.collect(Collectors.toList()))); .collect(Collectors.toList())));
return dataCenters;
} }
public DataCenterPageable paginateDataCenters(Pagination pagination, DataCenterCriteria criteria, List<SortBy> sortBy) { @PreAuthorize("hasAuthority('" + PermissionName.PAGINATE_DATACENTERS_GET + "')")
return new DataCenterPageable(DataCenterService.filterWithPaginate(ObjectUtils.defaultIfNull(criteria, new DataCenterCriteria()), public DataCenterPageable paginateDataCenters(Pagination pagination, DataCenterCriteria criteria,
Pagination.toPageRequest(pagination, sortBy))); List<SortBy> sortBy) {
return new DataCenterPageable(
dataCenterService.filterWithPaginate(ObjectUtils.defaultIfNull(criteria, new DataCenterCriteria()),
Pagination.toPageRequest(pagination, sortBy)));
} }
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_READ + "')")
public Optional<DataCenter> getByNumber(Integer number) {
return dataCenterService.findByNumber(number);
}
public Optional<DataCenter> getByNumber(Integer id) { @PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_READ + "')")
return dataCenterRepo.findByNumber(id).stream().findFirst(); public List<PhysicalMachine> physicalMachines(UUID datacenterId) {
return physicalMachineService.findByDatacenterId(datacenterId);
} }
} }

View File

@@ -0,0 +1,25 @@
package com.sgs.graphql.dataCenter.repo;
import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.domain.DataCenterEmissionSource;
import com.sgs.lib.dao.repo.BaseRepo;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface DataCenterEmissionSourceRepo extends BaseRepo<DataCenterEmissionSource> {
List<DataCenterEmissionSource> findByDataCenter(DataCenter dataCenter);
Optional<DataCenterEmissionSource> findByDataCenterAndIsDefaultTrue(DataCenter dataCenter);
@Query("SELECT dces FROM DataCenterEmissionSource dces WHERE dces.dataCenter.id = :dataCenterId")
List<DataCenterEmissionSource> findByDataCenterId(@Param("dataCenterId") String dataCenterId);
void deleteByDataCenter(DataCenter dataCenter);
}

View File

@@ -0,0 +1,22 @@
package com.sgs.graphql.dataCenter.repo;
import com.sgs.graphql.dataCenter.domain.PhysicalMachine;
import com.sgs.lib.dao.repo.BaseRepo;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface PhysicalMachineRepo extends BaseRepo<PhysicalMachine> {
/**
* Find all physical machines by datacenter ID
* @param datacenterId Datacenter ID
* @return List of physical machines
*/
@Query("SELECT pm FROM PhysicalMachine pm WHERE pm.dataCenter.id = :datacenterId")
List<PhysicalMachine> findByDatacenterId(@Param("datacenterId") UUID datacenterId);
}

View File

@@ -0,0 +1,6 @@
package com.sgs.graphql.dataCenter.repo.criteria;
import com.sgs.lib.dao.repo.criteria.BaseCriteria;
public class DataCenterEmissionSourceCriteria extends BaseCriteria {
}

View File

@@ -0,0 +1,6 @@
package com.sgs.graphql.dataCenter.repo.criteria;
import com.sgs.lib.dao.repo.criteria.BaseCriteria;
public class PhysicalMachineCriteria extends BaseCriteria {
}

View File

@@ -0,0 +1,6 @@
package com.sgs.graphql.dataCenter.repo.criteria;
import com.sgs.lib.dao.repo.criteria.BaseCriteria;
public class VMCriteria extends BaseCriteria {
}

View File

@@ -0,0 +1,17 @@
package com.sgs.graphql.dataCenter.repo.criteria.spec;
import com.sgs.graphql.dataCenter.domain.DataCenterEmissionSource;
import com.sgs.graphql.dataCenter.repo.criteria.DataCenterEmissionSourceCriteria;
import com.sgs.lib.dao.repo.criteria.spec.BaseCriteriaSpec;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
@Component
public class DataCenterEmissionSourceCriteriaSpec
extends BaseCriteriaSpec<DataCenterEmissionSource, DataCenterEmissionSourceCriteria> {
@Override
public Specification<DataCenterEmissionSource> createForAll(DataCenterEmissionSourceCriteria criteria) {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package com.sgs.graphql.dataCenter.repo.criteria.spec;
import com.sgs.graphql.dataCenter.domain.PhysicalMachine;
import com.sgs.graphql.dataCenter.repo.criteria.PhysicalMachineCriteria;
import com.sgs.lib.dao.repo.criteria.spec.BaseCriteriaSpec;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
@Component
public class PhysicalMachineCriteriaSpec extends BaseCriteriaSpec<PhysicalMachine, PhysicalMachineCriteria> {
@Override
public Specification<PhysicalMachine> createForAll(PhysicalMachineCriteria criteria) {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package com.sgs.graphql.dataCenter.repo.criteria.spec;
import com.sgs.graphql.dataCenter.domain.VM;
import com.sgs.graphql.dataCenter.repo.criteria.VMCriteria;
import com.sgs.lib.dao.repo.criteria.spec.BaseCriteriaSpec;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
@Component
public class VMCriteriaSpec extends BaseCriteriaSpec<VM, VMCriteria> {
@Override
public Specification<VM> createForAll(VMCriteria criteria) {
return null;
}
}

View File

@@ -0,0 +1,40 @@
package com.sgs.graphql.dataCenter.service;
import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.domain.DataCenterEmissionSource;
import com.sgs.graphql.dataCenter.repo.DataCenterEmissionSourceRepo;
import com.sgs.graphql.dataCenter.repo.criteria.DataCenterEmissionSourceCriteria;
import com.sgs.graphql.dataCenter.repo.criteria.spec.DataCenterEmissionSourceCriteriaSpec;
import com.sgs.lib.dao.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class DataCenterEmissionSourceService extends
BaseService<DataCenterEmissionSource, DataCenterEmissionSourceRepo, DataCenterEmissionSourceCriteria, DataCenterEmissionSourceCriteriaSpec> {
@Autowired
public DataCenterEmissionSourceService(DataCenterEmissionSourceRepo repository,
DataCenterEmissionSourceCriteriaSpec criteriaSpec) {
super(repository, criteriaSpec);
}
public List<DataCenterEmissionSource> findByDataCenter(DataCenter dataCenter) {
return getRepository().findByDataCenter(dataCenter);
}
public Optional<DataCenterEmissionSource> findByDataCenterAndIsDefaultTrue(DataCenter dataCenter) {
return getRepository().findByDataCenterAndIsDefaultTrue(dataCenter);
}
public List<DataCenterEmissionSource> findByDataCenterId(String dataCenterId) {
return getRepository().findByDataCenterId(dataCenterId);
}
public void deleteByDataCenter(DataCenter dataCenter) {
getRepository().deleteByDataCenter(dataCenter);
}
}

View File

@@ -8,8 +8,11 @@ import com.sgs.lib.dao.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Optional;
@Service @Service
public class DataCenterService extends BaseService<DataCenter, DataCenterRepo, DataCenterCriteria, DataCenterCriteriaSpec> { public class DataCenterService
extends BaseService<DataCenter, DataCenterRepo, DataCenterCriteria, DataCenterCriteriaSpec> {
@Autowired @Autowired
public DataCenterService(DataCenterRepo repository, DataCenterCriteriaSpec criteriaSpec) { public DataCenterService(DataCenterRepo repository, DataCenterCriteriaSpec criteriaSpec) {
@@ -19,4 +22,12 @@ public class DataCenterService extends BaseService<DataCenter, DataCenterRepo, D
public boolean existsByExternalId(Integer externalId) { public boolean existsByExternalId(Integer externalId) {
return getRepository().existsByExternalId(externalId); return getRepository().existsByExternalId(externalId);
} }
public Optional<DataCenter> findByNumber(Integer number) {
return getRepository().findByNumber(number);
}
public Integer findMaxNumber() {
return getRepository().findMaxNumber();
}
} }

View File

@@ -0,0 +1,26 @@
package com.sgs.graphql.dataCenter.service;
import com.sgs.graphql.dataCenter.domain.PhysicalMachine;
import com.sgs.graphql.dataCenter.repo.PhysicalMachineRepo;
import com.sgs.graphql.dataCenter.repo.criteria.PhysicalMachineCriteria;
import com.sgs.graphql.dataCenter.repo.criteria.spec.PhysicalMachineCriteriaSpec;
import com.sgs.lib.dao.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
public class PhysicalMachineService extends
BaseService<PhysicalMachine, PhysicalMachineRepo, PhysicalMachineCriteria, PhysicalMachineCriteriaSpec> {
@Autowired
public PhysicalMachineService(PhysicalMachineRepo repository, PhysicalMachineCriteriaSpec criteriaSpec) {
super(repository, criteriaSpec);
}
public List<PhysicalMachine> findByDatacenterId(UUID datacenterId) {
return getRepository().findByDatacenterId(datacenterId);
}
}

View File

@@ -0,0 +1,29 @@
package com.sgs.graphql.dataCenter.service;
import com.sgs.graphql.dataCenter.domain.VM;
import com.sgs.graphql.dataCenter.repo.VMRepo;
import com.sgs.graphql.dataCenter.repo.criteria.VMCriteria;
import com.sgs.graphql.dataCenter.repo.criteria.spec.VMCriteriaSpec;
import com.sgs.lib.dao.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class VMService extends BaseService<VM, VMRepo, VMCriteria, VMCriteriaSpec> {
@Autowired
public VMService(VMRepo repository, VMCriteriaSpec criteriaSpec) {
super(repository, criteriaSpec);
}
public List<VM> findAllByVmName(String vmName) {
return getRepository().findAllByVmName(vmName);
}
public Optional<VM> findFirstByVmNameOrderByIdDesc(String vmName) {
return getRepository().findFirstByVmNameOrderByIdDesc(vmName);
}
}

View File

@@ -15,7 +15,7 @@ public class VMEmissionSummary {
private Double totalEmission; // Individual record's total emission private Double totalEmission; // Individual record's total emission
private LocalDateTime createdDate; // When this specific record was created private LocalDateTime createdDate; // When this specific record was created
private String physicalMachine; private String physicalMachine;
private String project; private String cloudSystem; // From physical machine
private String dataCenter; private String dataCenter;
// Individual emission values for this specific record // Individual emission values for this specific record
@@ -31,7 +31,7 @@ public class VMEmissionSummary {
public VMEmissionSummary(UUID vmId, String vmName, Double vmPower, String vmStatus, public VMEmissionSummary(UUID vmId, String vmName, Double vmPower, String vmStatus,
Double totalEmission, LocalDateTime createdDate, Double totalEmission, LocalDateTime createdDate,
String physicalMachine, String project, String dataCenter, String physicalMachine, String cloudSystem, String dataCenter,
Double co2, Double ch4, Double n2o) { Double co2, Double ch4, Double n2o) {
this.vmId = vmId; this.vmId = vmId;
this.vmName = vmName; this.vmName = vmName;
@@ -40,7 +40,7 @@ public class VMEmissionSummary {
this.totalEmission = totalEmission; this.totalEmission = totalEmission;
this.createdDate = createdDate; this.createdDate = createdDate;
this.physicalMachine = physicalMachine; this.physicalMachine = physicalMachine;
this.project = project; this.cloudSystem = cloudSystem;
this.dataCenter = dataCenter; this.dataCenter = dataCenter;
this.co2 = co2; this.co2 = co2;
this.ch4 = ch4; this.ch4 = ch4;
@@ -70,8 +70,8 @@ public class VMEmissionSummary {
public String getPhysicalMachine() { return physicalMachine; } public String getPhysicalMachine() { return physicalMachine; }
public void setPhysicalMachine(String physicalMachine) { this.physicalMachine = physicalMachine; } public void setPhysicalMachine(String physicalMachine) { this.physicalMachine = physicalMachine; }
public String getProject() { return project; } public String getCloudSystem() { return cloudSystem; }
public void setProject(String project) { this.project = project; } public void setCloudSystem(String cloudSystem) { this.cloudSystem = cloudSystem; }
public String getDataCenter() { return dataCenter; } public String getDataCenter() { return dataCenter; }
public void setDataCenter(String dataCenter) { this.dataCenter = dataCenter; } public void setDataCenter(String dataCenter) { this.dataCenter = dataCenter; }

View File

@@ -51,9 +51,11 @@ public class MainDataTableQueryResolver implements GraphQLQueryResolver {
/** /**
* GraphQL query to get VM emission summaries with hierarchy information * GraphQL query to get VM emission summaries with hierarchy information
* @param datacenterId Optional datacenter ID to filter VMs by datacenter
* @param projectId Optional project ID to filter VMs by project
* @return List of VM emission summaries including datacenter, project, aggregate, and physical machine info * @return List of VM emission summaries including datacenter, project, aggregate, and physical machine info
*/ */
public List<VMEmissionSummary> vmEmissionSummary() { public List<VMEmissionSummary> vmEmissionSummary(UUID datacenterId) {
return mainDataTableService.getVMEmissionSummaries(); return mainDataTableService.getVMEmissionSummaries(datacenterId);
} }
} }

View File

@@ -9,6 +9,7 @@ import com.sgs.lib.dao.service.BaseService;
import com.sgs.graphql.mainDataTable.dto.VMEmissionSummary; import com.sgs.graphql.mainDataTable.dto.VMEmissionSummary;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -21,7 +22,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class MainDataTableService extends BaseService<MainDataTable, MainDataTableRepo, MainDataTableCriteria, MainDataTableCriteriaSpec> { public class MainDataTableService
extends BaseService<MainDataTable, MainDataTableRepo, MainDataTableCriteria, MainDataTableCriteriaSpec> {
@PersistenceContext @PersistenceContext
private EntityManager entityManager; private EntityManager entityManager;
@@ -32,31 +34,48 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
} }
public List<VMEmissionSummary> getVMEmissionSummaries() { public List<VMEmissionSummary> getVMEmissionSummaries() {
return getVMEmissionSummaries(null);
}
public List<VMEmissionSummary> getVMEmissionSummaries(UUID datacenterId) {
List<String> whereConditions = new ArrayList<>();
if (datacenterId != null) {
whereConditions.add("dc.id = decode(replace(:datacenterId, '-', ''), 'hex')");
}
String whereClause = whereConditions.isEmpty() ? "" :
"WHERE " + String.join(" AND ", whereConditions) + " ";
String sql = """ String sql = """
SELECT SELECT
CAST(v.id AS VARCHAR) as vm_id, CAST(v.id AS VARCHAR) as vm_id,
v.name as vm_name, v.vm_name as vm_name,
v.power as vm_power, v.power as vm_power,
v.status as vm_status, v.state as vm_status,
mdt.total_emission, mdt.total_emission,
mdt.created_date, mdt.created_date,
pm.name as physical_machine_name, pm.name as physical_machine_name,
p.name as project_name, pm.cloud_system as cloud_system,
dc.data_center_name as datacenter_name, dc.data_center_name as datacenter_name,
mdt.co2, mdt.co2,
mdt.ch4, mdt.ch4,
mdt.n2o mdt.n2o
FROM main_data_table mdt FROM main_data_table mdt
JOIN vm v ON mdt.vm_id = v.id JOIN vm v ON mdt.vm_id = v.id
LEFT JOIN vms vms_active ON v.active_vms_id = vms_active.id LEFT JOIN physical_machine pm ON v.physical_machine_id = pm.id
LEFT JOIN vms vms_inactive ON v.inactive_vms_id = vms_inactive.id LEFT JOIN data_center dc ON pm.data_center_id = dc.id
LEFT JOIN physical_machine pm ON (pm.vms_id = vms_active.id OR pm.vms_id = vms_inactive.id) """ + whereClause + """
LEFT JOIN project p ON pm.project_id = p.id ORDER BY mdt.created_date DESC, v.vm_name
LEFT JOIN data_center dc ON p.data_center_id = dc.id
ORDER BY mdt.created_date DESC, v.name
"""; """;
Query query = entityManager.createNativeQuery(sql); Query query = entityManager.createNativeQuery(sql);
// Add parameters if provided
if (datacenterId != null) {
query.setParameter("datacenterId", datacenterId.toString());
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Object[]> results = query.getResultList(); List<Object[]> results = query.getResultList();
@@ -80,7 +99,7 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
} }
summary.setPhysicalMachine((String) row[6]); summary.setPhysicalMachine((String) row[6]);
summary.setProject((String) row[7]); summary.setCloudSystem((String) row[7]);
summary.setDataCenter((String) row[8]); summary.setDataCenter((String) row[8]);
// Individual emission values // Individual emission values
@@ -94,6 +113,7 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
/** /**
* Converts PostgreSQL hex format UUID to proper UUID format * Converts PostgreSQL hex format UUID to proper UUID format
*
* @param hexUuid UUID in hex format (e.g., \x6205c18b8d1e4f0fa5154212fb44050b) * @param hexUuid UUID in hex format (e.g., \x6205c18b8d1e4f0fa5154212fb44050b)
* @return UUID object * @return UUID object
*/ */
@@ -104,10 +124,10 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
// Insert hyphens to make it a proper UUID format // Insert hyphens to make it a proper UUID format
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
String formatted = hex.substring(0, 8) + "-" + String formatted = hex.substring(0, 8) + "-" +
hex.substring(8, 12) + "-" + hex.substring(8, 12) + "-" +
hex.substring(12, 16) + "-" + hex.substring(12, 16) + "-" +
hex.substring(16, 20) + "-" + hex.substring(16, 20) + "-" +
hex.substring(20); hex.substring(20);
return UUID.fromString(formatted); return UUID.fromString(formatted);
} else { } else {
// If it's already in proper format, parse directly // If it's already in proper format, parse directly

View File

@@ -74,4 +74,5 @@ public class PermissionDescription {
public static final String DATA_CENTER_DELETE = "Veri Merkezi Silme"; public static final String DATA_CENTER_DELETE = "Veri Merkezi Silme";
public static final String DATA_CENTER_UPDATE = "Veri Merkezi Güncelleme"; public static final String DATA_CENTER_UPDATE = "Veri Merkezi Güncelleme";
public static final String DATA_CENTER_READ = "Veri Merkezi Görüntüleme"; public static final String DATA_CENTER_READ = "Veri Merkezi Görüntüleme";
public static final String PAGINATE_DATACENTERS_GET = "Veri Merkezleri Listesi Görüntüleme";
} }

View File

@@ -84,5 +84,6 @@ public class PermissionName {
public static final String DATA_CENTER_DELETE = "data_center_delete"; public static final String DATA_CENTER_DELETE = "data_center_delete";
public static final String DATA_CENTER_UPDATE = "data_center_update"; public static final String DATA_CENTER_UPDATE = "data_center_update";
public static final String DATA_CENTER_READ = "data_center_read"; public static final String DATA_CENTER_READ = "data_center_read";
public static final String PAGINATE_DATACENTERS_GET = "paginate_datacenters_get";
} }

View File

@@ -9,6 +9,8 @@ import com.sgs.lib.dao.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Optional;
@Service @Service
public class PermissionService extends BaseService<Permission, PermissionRepo, PermissionCriteria, PermissionCriteriaSpec> { public class PermissionService extends BaseService<Permission, PermissionRepo, PermissionCriteria, PermissionCriteriaSpec> {
@@ -16,4 +18,8 @@ public class PermissionService extends BaseService<Permission, PermissionRepo, P
public PermissionService(PermissionRepo repository, PermissionCriteriaSpec criteriaSpec) { public PermissionService(PermissionRepo repository, PermissionCriteriaSpec criteriaSpec) {
super(repository, criteriaSpec); super(repository, criteriaSpec);
} }
public Optional<Permission> findByTag(String tag) {
return getRepository().findByTag(tag);
}
} }

View File

@@ -74,19 +74,16 @@ public class MessageListener {
System.out.println(" External ID: " + dto.getId()); System.out.println(" External ID: " + dto.getId());
System.out.println(" Number: " + dto.getNumber()); System.out.println(" Number: " + dto.getNumber());
System.out.println(" Consumption Amount: " + dto.getConsuptionAmount()); System.out.println(" Consumption Amount: " + dto.getConsuptionAmount());
System.out.println(" Projects Count: " + (dto.getProjects() != null ? dto.getProjects().size() : 0)); System.out.println(" Physical Machines Count: " + (dto.getPhysicalMachine() != null ? dto.getPhysicalMachine().size() : 0));
// Log MainOptimizationSpace info for each project // Log Physical Machine info
if (dto.getProjects() != null) { if (dto.getPhysicalMachine() != null) {
for (Map.Entry<String, ProjectDto> projectEntry : dto.getProjects().entrySet()) { for (Map.Entry<String, PhysicalMachineDto> pmEntry : dto.getPhysicalMachine().entrySet()) {
String projectId = projectEntry.getKey(); String pmIp = pmEntry.getKey();
ProjectDto project = projectEntry.getValue(); PhysicalMachineDto pm = pmEntry.getValue();
if (project.getMainOptimizationSpace() != null) { System.out.println(" Physical Machine " + pm.getName() + " (IP: " + pmIp + "):");
MainOptimizationSpaceDto mainOpt = project.getMainOptimizationSpace(); System.out.println(" Power: " + pm.getPower());
System.out.println(" Project " + projectId + ":"); System.out.println(" VMs: " + (pm.getVms() != null ? pm.getVms().size() : 0));
System.out.println(" PMs: " + (mainOpt.getPms() != null ? mainOpt.getPms().size() : 0));
System.out.println(" VMs: " + (mainOpt.getVms() != null ? mainOpt.getVms().size() : 0));
}
} }
} }
@@ -103,18 +100,18 @@ public class MessageListener {
// System.out.println(entity.toString()); // System.out.println(entity.toString());
System.out.println("✅ Raw JSON message:\n" + message); System.out.println("✅ Raw JSON message:\n" + message);
System.out.println("✅ DTO parsed:\n" + objectMapper.writeValueAsString(dto)); //System.out.println("✅ DTO parsed:\n" + objectMapper.writeValueAsString(dto));
//System.out.println("✅ Entity:\n" + objectMapper.writeValueAsString(entity)); //System.out.println("✅ Entity:\n" + objectMapper.writeValueAsString(entity));
System.out.println("🚨 DataCenter name: " + dataCenter.getDataCenter()); System.out.println("🚨 DataCenter name: " + dataCenter.getDataCenter());
System.out.println("🚨 External ID: " + dataCenter.getExternalId()); System.out.println("🚨 External ID: " + dataCenter.getExternalId());
System.out.println("🚨 Projects count: " + (dataCenter.getProjects() != null ? dataCenter.getProjects().size() : 0)); System.out.println("🚨 Physical Machines count: " + (dataCenter.getPhysicalMachines() != null ? dataCenter.getPhysicalMachines().size() : 0));
if (dataCenter.getProjects() != null && !dataCenter.getProjects().isEmpty()) { if (dataCenter.getPhysicalMachines() != null && !dataCenter.getPhysicalMachines().isEmpty()) {
Project firstProject = dataCenter.getProjects().get(0); PhysicalMachine firstPM = dataCenter.getPhysicalMachines().get(0);
System.out.println("🚨 PMs in first project: " + firstProject.getPhysicalMachines().size()); System.out.println("🚨 VMs in first PM: " + firstPM.getVms().size());
// Show VM assignment summary // Show VM assignment summary
int totalVMs = 0; int totalVMs = 0;
for (PhysicalMachine pm : firstProject.getPhysicalMachines()) { for (PhysicalMachine pm : dataCenter.getPhysicalMachines()) {
int vmCount = pm.getVms() != null ? pm.getVms().size() : 0; int vmCount = pm.getVms() != null ? pm.getVms().size() : 0;
totalVMs += vmCount; totalVMs += vmCount;
System.out.println(" PM " + pm.getName() + " (IP: " + pm.getIp() + "): " + vmCount + " VMs"); System.out.println(" PM " + pm.getName() + " (IP: " + pm.getIp() + "): " + vmCount + " VMs");
@@ -157,6 +154,7 @@ public class MessageListener {
entity.setHost(dto.getHost()); entity.setHost(dto.getHost());
entity.setFlavorName(dto.getFlavorName()); entity.setFlavorName(dto.getFlavorName());
entity.setTag(dto.getTag()); entity.setTag(dto.getTag());
entity.setProject(dto.getProject());
// Set calcOn - you may want to derive this from state or other logic // Set calcOn - you may want to derive this from state or other logic
entity.setCalcOn(dto.isCalcOn()); entity.setCalcOn(dto.isCalcOn());
@@ -168,7 +166,7 @@ public class MessageListener {
entity.setEmissionSource(dto.getEmissionSource()); entity.setEmissionSource(dto.getEmissionSource());
// Debug logging // Debug logging
System.out.println("🔍 VM Entity Created: " + dto.getVmName() + " - state = " + dto.getState() + " - calcOn = " + dto.isCalcOn()); System.out.println("🔍 VM Entity Created: " + dto.getVmName() + " - state = " + dto.getState() + " - calcOn = " + dto.isCalcOn() + " - project = " + dto.getProject());
if (dto.getEmissionSource() != null && !dto.getEmissionSource().isEmpty()) { if (dto.getEmissionSource() != null && !dto.getEmissionSource().isEmpty()) {
System.out.println(" Emission Sources: " + dto.getEmissionSource()); System.out.println(" Emission Sources: " + dto.getEmissionSource());
} }
@@ -184,6 +182,7 @@ public class MessageListener {
entity.setName(dto.getName()); entity.setName(dto.getName());
entity.setIp(dto.getIp()); entity.setIp(dto.getIp());
entity.setTag(dto.getTag()); entity.setTag(dto.getTag());
entity.setCloudSystem(dto.getCloudSystem());
entity.setPower(dto.getPower()); entity.setPower(dto.getPower());
// VMs are now processed separately from the new message format // VMs are now processed separately from the new message format
@@ -207,113 +206,44 @@ public class MessageListener {
// ConsuptionUnit, and ActivitySubUnit are no longer received in the message // ConsuptionUnit, and ActivitySubUnit are no longer received in the message
// These will need to be set via the DataCenter CRUD operations // These will need to be set via the DataCenter CRUD operations
// Convert Projects // Convert Physical Machines directly
if (dto.getProjects() != null) { if (dto.getPhysicalMachine() != null) {
List<Project> projects = new ArrayList<>(); List<PhysicalMachine> physicalMachines = new ArrayList<>();
for (Map.Entry<String, ProjectDto> projectEntry : dto.getProjects().entrySet()) { for (Map.Entry<String, PhysicalMachineDto> pmEntry : dto.getPhysicalMachine().entrySet()) {
String projectId = projectEntry.getKey(); String pmIp = pmEntry.getKey();
ProjectDto projectDto = projectEntry.getValue(); PhysicalMachineDto pmDto = pmEntry.getValue();
// Set the project ID and a default name if not provided PhysicalMachine pm = new PhysicalMachine();
projectDto.setId(projectId); pm.setName(pmDto.getName());
if (projectDto.getName() == null || projectDto.getName().isEmpty()) { pm.setIp(pmIp); // Use the IP from the map key
projectDto.setName("Project-" + projectId.substring(0, 8)); // Use first 8 chars of ID as name pm.setTag(pmDto.getTag());
pm.setCloudSystem(pmDto.getCloudSystem());
pm.setPower(pmDto.getPower());
pm.setDataCenter(entity);
// Process VMs for this PM
if (pmDto.getVms() != null) {
List<VM> vms = new ArrayList<>();
for (Map.Entry<String, VMDto> vmEntry : pmDto.getVms().entrySet()) {
String vmIp = vmEntry.getKey();
VMDto vmDto = vmEntry.getValue();
VM vm = toVMEntity(vmDto);
vm.setIp(vmIp); // Use the IP from the map key
vm.setPhysicalMachine(pm);
vms.add(vm);
}
pm.setVms(vms);
} }
Project project = toProjectEntity(projectDto); physicalMachines.add(pm);
project.setDataCenter(entity);
projects.add(project);
} }
entity.setProjects(projects);
}
return entity;
}
public Project toProjectEntity(ProjectDto dto){
if (dto == null)
return null;
Project entity = new Project();
entity.setName(dto.getName());
// Process MainOptimizationSpace instead of physical machines list
if (dto.getMainOptimizationSpace() != null) {
List<PhysicalMachine> physicalMachines = processMainOptimizationSpace(dto.getMainOptimizationSpace());
// Set project reference for each PM
physicalMachines.forEach(pm -> pm.setProject(entity));
entity.setPhysicalMachines(physicalMachines); entity.setPhysicalMachines(physicalMachines);
} }
return entity; return entity;
} }
/**
* Process MainOptimizationSpaceDto and assign VMs to their hosting PMs
*/
private List<PhysicalMachine> processMainOptimizationSpace(MainOptimizationSpaceDto mainOptSpace) {
List<PhysicalMachine> physicalMachines = new ArrayList<>();
if (mainOptSpace.getPms() == null || mainOptSpace.getVms() == null) {
System.out.println("⚠️ MainOptimizationSpace has null PMs or VMs");
return physicalMachines;
}
System.out.println("🔍 Processing MainOptimizationSpace with " +
mainOptSpace.getPms().size() + " PMs and " +
mainOptSpace.getVms().size() + " VMs");
// Convert PMs from DTO to Entity
for (Map.Entry<String, PhysicalMachineDto> pmEntry : mainOptSpace.getPms().entrySet()) {
String pmIp = pmEntry.getKey();
PhysicalMachineDto pmDto = pmEntry.getValue();
// Set the IP from the map key
pmDto.setIp(pmIp);
PhysicalMachine pm = toPhysicalMachineEntity(pmDto);
physicalMachines.add(pm);
System.out.println("✅ Created PM: " + pm.getName() + " (IP: " + pm.getIp() + ")");
}
// Assign VMs to their hosting PMs
for (Map.Entry<String, VMDto> vmEntry : mainOptSpace.getVms().entrySet()) {
String vmIp = vmEntry.getKey();
VMDto vmDto = vmEntry.getValue();
// Set the IP from the map key
vmDto.setIp(vmIp);
VM vm = toVMEntity(vmDto);
// Find the hosting PM by IP
String hostingPmIp = vmDto.getHostingPm();
PhysicalMachine hostingPm = physicalMachines.stream()
.filter(pm -> pm.getIp().equals(hostingPmIp))
.findFirst()
.orElse(null);
if (hostingPm != null) {
// Assign VM to PM
vm.setPhysicalMachine(hostingPm);
if (hostingPm.getVms() == null) {
hostingPm.setVms(new ArrayList<>());
}
hostingPm.getVms().add(vm);
System.out.println("✅ Assigned VM: " + vm.getVmName() + " (IP: " + vm.getIp() +
") to PM: " + hostingPm.getName() + " (IP: " + hostingPm.getIp() + ")");
} else {
System.err.println("❌ Could not find hosting PM with IP: " + hostingPmIp +
" for VM: " + vm.getVmName());
}
}
return physicalMachines;
}
@Transactional @Transactional
public DataCenter createDataCenter(DataCenter newDc) { public DataCenter createDataCenter(DataCenter newDc) {
try { try {
@@ -335,123 +265,117 @@ public class MessageListener {
// Note: DataCenter name and emission-related fields are no longer updated from the message // Note: DataCenter name and emission-related fields are no longer updated from the message
// These are now managed via DataCenter CRUD operations // These are now managed via DataCenter CRUD operations
for (Project newProject : newDc.getProjects()) { // Ensure datacenter has initialized physical machines list
Optional<Project> existingProjOpt = dc.getProjects().stream() if (dc.getPhysicalMachines() == null) {
.filter(p -> p.getName().equalsIgnoreCase(newProject.getName())) dc.setPhysicalMachines(new ArrayList<>());
.findFirst(); }
Project project; // Process Physical Machines directly from the message structure
if (existingProjOpt.isPresent()) { for (PhysicalMachine newPm : newDc.getPhysicalMachines()) {
project = existingProjOpt.get(); Optional<PhysicalMachine> existingPmOpt = dc.getPhysicalMachines().stream()
project.setName(newProject.getName()); .filter(pm -> pm.getIp().equals(newPm.getIp())) // Match by IP instead of name
System.out.println("✅ Updated existing project: " + project.getName()); .findFirst();
} else {
project = newProject; PhysicalMachine pm;
project.setDataCenter(dc); if (existingPmOpt.isPresent()) {
dc.getProjects().add(project); // Update existing PM
System.out.println("✅ Created new project: " + project.getName()); pm = existingPmOpt.get();
pm.setName(newPm.getName());
pm.setIp(newPm.getIp());
pm.setTag(newPm.getTag());
pm.setCloudSystem(newPm.getCloudSystem());
pm.setPower(newPm.getPower());
System.out.println("✅ Updated existing PM: " + pm.getName() + " (IP: " + pm.getIp() + ") - CloudSystem: " + pm.getCloudSystem());
} else {
// Create new PM
pm = newPm;
pm.setDataCenter(dc);
dc.getPhysicalMachines().add(pm);
System.out.println("✅ Created new PM: " + pm.getName() + " (IP: " + pm.getIp() + ") - CloudSystem: " + pm.getCloudSystem());
}
// Process VMs that are already assigned to this PM
if (newPm.getVms() != null && !newPm.getVms().isEmpty()) {
System.out.println("🔍 Processing " + newPm.getVms().size() + " VMs for PM: " + newPm.getName());
// Ensure PM has VM list initialized
if (pm.getVms() == null) {
pm.setVms(new ArrayList<>());
} }
// Ensure project has initialized physical machines list // Clear existing VMs to replace with new ones
if (project.getPhysicalMachines() == null) { pm.getVms().clear();
project.setPhysicalMachines(new ArrayList<>());
}
// Process Physical Machines (VMs are already assigned to PMs from MainOptimizationSpace) // Process each VM that's already assigned to this PM
for (PhysicalMachine newPm : newProject.getPhysicalMachines()) { for (VM newVm : newPm.getVms()) {
Optional<PhysicalMachine> existingPmOpt = project.getPhysicalMachines().stream() if (newVm == null) continue;
.filter(pm -> pm.getIp().equals(newPm.getIp())) // Match by IP instead of name
.findFirst();
PhysicalMachine pm; // Find existing VM by vmName
if (existingPmOpt.isPresent()) { Optional<VM> existingVmOpt = Optional.empty();
// Update existing PM String vmLookupName = newVm.getVmName();
pm = existingPmOpt.get(); if (vmLookupName != null) {
pm.setName(newPm.getName()); existingVmOpt = vmRepo.findFirstByVmNameOrderByIdDesc(vmLookupName);
pm.setIp(newPm.getIp());
pm.setTag(newPm.getTag());
pm.setPower(newPm.getPower());
System.out.println("✅ Updated existing PM: " + pm.getName() + " (IP: " + pm.getIp() + ")");
} else {
// Create new PM
pm = newPm;
pm.setProject(project);
project.getPhysicalMachines().add(pm);
System.out.println("✅ Created new PM: " + pm.getName() + " (IP: " + pm.getIp() + ")");
} }
// Process VMs that are already assigned to this PM VM vm;
if (newPm.getVms() != null && !newPm.getVms().isEmpty()) { if (existingVmOpt.isPresent()) {
System.out.println("🔍 Processing " + newPm.getVms().size() + " VMs for PM: " + newPm.getName()); // Update existing VM
vm = existingVmOpt.get();
// Ensure PM has VM list initialized // IMPORTANT: Remove VM from its current Physical Machine first
if (pm.getVms() == null) { if (vm.getPhysicalMachine() != null) {
pm.setVms(new ArrayList<>()); PhysicalMachine currentPM = vm.getPhysicalMachine();
if (currentPM.getVms() != null) {
currentPM.getVms().remove(vm);
System.out.println("🔄 Removed VM " + vm.getVmName() + " from previous PM: " + currentPM.getName());
}
} }
// Clear existing VMs to replace with new ones vm.setState(newVm.getState());
pm.getVms().clear(); vm.setVmName(newVm.getVmName());
vm.setIp(newVm.getIp());
vm.setPower(newVm.getPower());
vm.setCalcOn(newVm.getCalcOn());
vm.setHostingPm(newVm.getHostingPm());
vm.setHost(newVm.getHost());
vm.setFlavorName(newVm.getFlavorName());
vm.setTag(newVm.getTag());
vm.setEmissionSource(newVm.getEmissionSource());
vm.setProject(newVm.getProject());
// Process each VM that's already assigned to this PM System.out.println("✅ Updated existing VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn());
for (VM newVm : newPm.getVms()) { } else {
if (newVm == null) continue; // Use new VM
vm = newVm;
// Find existing VM by vmName System.out.println("✅ Created new VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn());
Optional<VM> existingVmOpt = Optional.empty(); }
String vmLookupName = newVm.getVmName();
if (vmLookupName != null) {
existingVmOpt = vmRepo.findFirstByVmNameOrderByIdDesc(vmLookupName);
}
VM vm; // Set physical machine relationship
if (existingVmOpt.isPresent()) { vm.setPhysicalMachine(pm);
// Update existing VM pm.getVms().add(vm);
vm = existingVmOpt.get();
vm.setState(newVm.getState());
vm.setVmName(newVm.getVmName());
vm.setIp(newVm.getIp());
vm.setPower(newVm.getPower());
vm.setCalcOn(newVm.getCalcOn());
vm.setHostingPm(newVm.getHostingPm());
vm.setHost(newVm.getHost());
vm.setFlavorName(newVm.getFlavorName());
vm.setTag(newVm.getTag());
vm.setEmissionSource(newVm.getEmissionSource());
System.out.println("✅ Updated existing VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn()); // Update config
} else { if (newVm.getConfig() != null) {
// Use new VM if (vm.getConfig() == null) {
vm = newVm; vm.setConfig(newVm.getConfig());
vm.getConfig().setVm(vm);
System.out.println("✅ Created new VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn()); } else {
} vm.getConfig().setCpu(newVm.getConfig().getCpu());
vm.getConfig().setRam(newVm.getConfig().getRam());
// Set physical machine relationship vm.getConfig().setDisk(newVm.getConfig().getDisk());
vm.setPhysicalMachine(pm);
pm.getVms().add(vm);
// Update config
if (newVm.getConfig() != null) {
if (vm.getConfig() == null) {
vm.setConfig(newVm.getConfig());
vm.getConfig().setVm(vm);
} else {
vm.getConfig().setCpu(newVm.getConfig().getCpu());
vm.getConfig().setRam(newVm.getConfig().getRam());
vm.getConfig().setDisk(newVm.getConfig().getDisk());
}
}
} }
} }
} }
} }
}
System.out.println("Before Save: DataCenter=" + dc.getDataCenter()); System.out.println("Before Save: DataCenter=" + dc.getDataCenter());
System.out.println("External ID=" + dc.getExternalId()); System.out.println("External ID=" + dc.getExternalId());
System.out.println("Number=" + dc.getNumber()); System.out.println("Number=" + dc.getNumber());
System.out.println("Projects=" + (dc.getProjects() != null ? dc.getProjects().size() : 0)); System.out.println("Physical Machines=" + (dc.getPhysicalMachines() != null ? dc.getPhysicalMachines().size() : 0));
DataCenter saved = dataCenterService.save(dc); DataCenter saved = dataCenterService.save(dc);
System.out.println("✅ Saved: ID=" + saved.getId()); System.out.println("✅ Saved: ID=" + saved.getId());
@@ -525,41 +449,29 @@ public class MessageListener {
int failedCalculations = 0; int failedCalculations = 0;
int totalEmissionSources = 0; int totalEmissionSources = 0;
for (Project project : dataCenter.getProjects()) { for (PhysicalMachine pm : dataCenter.getPhysicalMachines()) {
for (PhysicalMachine pm : project.getPhysicalMachines()) { if (pm.getVms() != null) {
if (pm.getVms() != null) { // Calculate for all VMs (only those with calcOn = true)
// Calculate for all VMs (only those with calcOn = true) for (VM vm : pm.getVms()) {
for (VM vm : pm.getVms()) { totalVMs++;
totalVMs++; if (vm.getCalcOn() != null && vm.getCalcOn()) {
if (vm.getCalcOn() != null && vm.getCalcOn()) { eligibleVMs++;
eligibleVMs++; if (vm.getPower() != null && vm.getPower() > 0) {
if (vm.getPower() != null && vm.getPower() > 0) { System.out.println("✅ Processing VM " + vm.getVmName() + " (calcOn = true)");
System.out.println("✅ Processing VM " + vm.getVmName() + " (calcOn = true)"); processedVMs++;
processedVMs++;
// Check if VM has emission sources // Check if VM has emission sources
Map<String, Integer> emissionSources = vm.getEmissionSource(); Map<String, Integer> emissionSources = vm.getEmissionSource();
if (emissionSources != null && !emissionSources.isEmpty()) { if (emissionSources != null && !emissionSources.isEmpty()) {
// Create separate emission record for each emission source // Create separate emission record for each emission source
System.out.println("🔍 VM has " + emissionSources.size() + " emission sources"); System.out.println("🔍 VM has " + emissionSources.size() + " emission sources");
totalEmissionSources += emissionSources.size(); totalEmissionSources += emissionSources.size();
for (Map.Entry<String, Integer> sourceEntry : emissionSources.entrySet()) { for (Map.Entry<String, Integer> sourceEntry : emissionSources.entrySet()) {
String sourceName = sourceEntry.getKey(); String sourceName = sourceEntry.getKey();
Integer percentage = sourceEntry.getValue(); Integer percentage = sourceEntry.getValue();
System.out.println(" - " + sourceName + ": " + percentage + "%"); System.out.println(" - " + sourceName + ": " + percentage + "%");
boolean success = createVMEmissionRecordForSource(dataCenter, vm, project, pm, sourceName, percentage); boolean success = createVMEmissionRecordForSource(dataCenter, vm, pm, sourceName, percentage);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
}
} else {
// Fallback to default emission source if VM has no emission sources
System.out.println("⚠️ VM has no emission sources, using default");
totalEmissionSources++;
boolean success = createVMEmissionRecord(dataCenter, vm, project, pm);
if (success) { if (success) {
successfulCalculations++; successfulCalculations++;
} else { } else {
@@ -567,11 +479,21 @@ public class MessageListener {
} }
} }
} else { } else {
System.out.println("⚠️ Skipping VM " + vm.getVmName() + " (calcOn = true) - no power consumption data"); // Fallback to default emission source if VM has no emission sources
System.out.println("⚠️ VM has no emission sources, using default");
totalEmissionSources++;
boolean success = createVMEmissionRecord(dataCenter, vm, pm);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
} }
} else { } else {
System.out.println(" Skipping VM " + vm.getVmName() + " - calcOn = " + vm.getCalcOn()); System.out.println(" Skipping VM " + vm.getVmName() + " (calcOn = true) - no power consumption data");
} }
} else {
System.out.println("⏭️ Skipping VM " + vm.getVmName() + " - calcOn = " + vm.getCalcOn());
} }
} }
} }
@@ -587,7 +509,7 @@ public class MessageListener {
System.out.println(" Failed emission calculations: " + failedCalculations); System.out.println(" Failed emission calculations: " + failedCalculations);
} }
private boolean createVMEmissionRecord(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) { private boolean createVMEmissionRecord(DataCenter dataCenter, VM vm, PhysicalMachine pm) {
try { try {
// Check if VM has an ID (is persisted) // Check if VM has an ID (is persisted)
if (vm.getId() == null) { if (vm.getId() == null) {
@@ -595,7 +517,7 @@ public class MessageListener {
return false; return false;
} }
MainDataTableCreateInput input = createVMMainDataTableInput(dataCenter, vm, project, pm); MainDataTableCreateInput input = createVMMainDataTableInput(dataCenter, vm, pm);
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + " (Power: " + vm.getPower() + "W)"); System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + " (Power: " + vm.getPower() + "W)");
MainDataTable result = callMainDataTableMutation(input); MainDataTable result = callMainDataTableMutation(input);
@@ -619,7 +541,7 @@ public class MessageListener {
} }
} }
private boolean createVMEmissionRecordForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, String emissionSourceName, Integer percentage) { private boolean createVMEmissionRecordForSource(DataCenter dataCenter, VM vm, PhysicalMachine pm, String emissionSourceName, Integer percentage) {
try { try {
// Check if VM has an ID (is persisted) // Check if VM has an ID (is persisted)
if (vm.getId() == null) { if (vm.getId() == null) {
@@ -627,19 +549,56 @@ public class MessageListener {
return false; return false;
} }
// Find the emission source by name/tag // Find the emission source by name/tag from datacenter's configured emission sources
List<EmissionSource> emissionSources = emissionSourceRepo.findByTag(emissionSourceName); EmissionSource emissionSource = null;
if (emissionSources.isEmpty()) {
// First, try to find the emission source from datacenter's configured sources
if (dataCenter.getDataCenterEmissionSources() != null && !dataCenter.getDataCenterEmissionSources().isEmpty()) {
for (DataCenterEmissionSource dces : dataCenter.getDataCenterEmissionSources()) {
if (dces.getEmissionSource() != null &&
emissionSourceName.equalsIgnoreCase(dces.getEmissionSource().getTag())) {
emissionSource = dces.getEmissionSource();
System.out.println("✅ Found emission source '" + emissionSourceName +
"' in datacenter's configured sources (ID: " + emissionSource.getId() + ")");
break;
}
}
}
// If not found in datacenter's sources, fall back to subsector-specific search
if (emissionSource == null && dataCenter.getSubSector() != null) {
emissionSource = emissionSourceRepo.findByTagAndSubSectorIgnoreCase(emissionSourceName, dataCenter.getSubSector());
if (emissionSource != null) {
System.out.println("⚠️ Using subsector fallback for emission source '" + emissionSourceName +
"' (ID: " + emissionSource.getId() + ") - Consider configuring it for datacenter");
}
}
// Last resort: global search
if (emissionSource == null) {
List<EmissionSource> emissionSources = emissionSourceRepo.findByTag(emissionSourceName);
if (!emissionSources.isEmpty()) {
emissionSource = emissionSources.get(0);
System.out.println("⚠️ Using global fallback for emission source '" + emissionSourceName +
"' (ID: " + emissionSource.getId() + ") - This may cause incorrect calculations!");
}
}
if (emissionSource == null) {
System.err.println("❌ Could not find emission source: " + emissionSourceName); System.err.println("❌ Could not find emission source: " + emissionSourceName);
return false; return false;
} }
EmissionSource emissionSource = emissionSources.get(0);
// Calculate power consumption for this emission source (percentage of total VM power) // Calculate power consumption for this emission source (percentage of total VM power)
double sourceSpecificPower = vm.getPower() * (percentage / 100.0); double sourceSpecificPower = vm.getPower() * (percentage / 100.0);
MainDataTableCreateInput input = createVMMainDataTableInputForSource(dataCenter, vm, project, pm, emissionSource, sourceSpecificPower, percentage); MainDataTableCreateInput input = createVMMainDataTableInputForSource(dataCenter, vm, pm, emissionSource, sourceSpecificPower, percentage);
if (input == null) {
System.err.println("❌ Failed to create input for VM emission calculation - skipping");
return false;
}
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() +
" - Source: " + emissionSourceName + " (" + percentage + "%) - Power: " + sourceSpecificPower + "W"); " - Source: " + emissionSourceName + " (" + percentage + "%) - Power: " + sourceSpecificPower + "W");
@@ -665,7 +624,7 @@ public class MessageListener {
} }
} }
private MainDataTableCreateInput createVMMainDataTableInput(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) { private MainDataTableCreateInput createVMMainDataTableInput(DataCenter dataCenter, VM vm, PhysicalMachine pm) {
MainDataTableCreateInput input = new MainDataTableCreateInput(); MainDataTableCreateInput input = new MainDataTableCreateInput();
// Copy datacenter-level information (if available) // Copy datacenter-level information (if available)
@@ -692,8 +651,15 @@ public class MessageListener {
input.setSubSector(dataCenter.getSubSector().getId()); input.setSubSector(dataCenter.getSubSector().getId());
} }
if (dataCenter.getEmissionSource() != null) { // Handle multiple emission sources - use the default one for emission calculations
input.setEmissionSource(dataCenter.getEmissionSource().getId()); if (dataCenter.getDataCenterEmissionSources() != null && !dataCenter.getDataCenterEmissionSources().isEmpty()) {
// Find the default emission source or use the first one
DataCenterEmissionSource defaultEmissionSource = dataCenter.getDataCenterEmissionSources().stream()
.filter(DataCenterEmissionSource::getIsDefault)
.findFirst()
.orElse(dataCenter.getDataCenterEmissionSources().get(0));
input.setEmissionSource(defaultEmissionSource.getEmissionSource().getId());
} else { } else {
// Fallback to default emission source for electricity // Fallback to default emission source for electricity
try { try {
@@ -711,8 +677,16 @@ public class MessageListener {
input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId()); input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId());
} }
if (dataCenter.getConsuptionUnit() != null) { // Handle consumption unit from emission sources - use the default one for VM calculations
input.setConsuptionUnit(dataCenter.getConsuptionUnit().getId()); if (dataCenter.getDataCenterEmissionSources() != null && !dataCenter.getDataCenterEmissionSources().isEmpty()) {
DataCenterEmissionSource defaultEmissionSource = dataCenter.getDataCenterEmissionSources().stream()
.filter(DataCenterEmissionSource::getIsDefault)
.findFirst()
.orElse(dataCenter.getDataCenterEmissionSources().get(0));
if (defaultEmissionSource.getConsuptionUnit() != null) {
input.setConsuptionUnit(defaultEmissionSource.getConsuptionUnit().getId());
}
} }
// Default to Kapsam-3 if no emission scope is set // Default to Kapsam-3 if no emission scope is set
@@ -739,68 +713,143 @@ public class MessageListener {
System.out.println(" VM Name: " + vm.getVmName()); System.out.println(" VM Name: " + vm.getVmName());
System.out.println(" Power: " + vm.getPower() + "W"); System.out.println(" Power: " + vm.getPower() + "W");
System.out.println(" Physical Machine: " + pm.getName()); System.out.println(" Physical Machine: " + pm.getName());
System.out.println(" Project: " + project.getName());
System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET")); System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET"));
return input; return input;
} }
private MainDataTableCreateInput createVMMainDataTableInputForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, EmissionSource emissionSource, double sourceSpecificPower, Integer percentage) { private MainDataTableCreateInput createVMMainDataTableInputForSource(DataCenter dataCenter, VM vm, PhysicalMachine pm, EmissionSource emissionSource, double sourceSpecificPower, Integer percentage) {
MainDataTableCreateInput input = new MainDataTableCreateInput(); MainDataTableCreateInput input = new MainDataTableCreateInput();
// Copy datacenter-level information (if available) // Copy datacenter-level information (if available)
input.setYear("2025"); input.setYear("2025");
input.setMonth("07"); input.setMonth("07");
// Validate required fields
if (dataCenter == null) {
System.err.println("❌ DataCenter is null - cannot create emission record");
return null;
}
if (vm == null) {
System.err.println("❌ VM is null - cannot create emission record");
return null;
}
if (emissionSource == null) {
System.err.println("❌ EmissionSource is null - cannot create emission record");
return null;
}
// Note: These fields are no longer received in the message // Note: These fields are no longer received in the message
// They need to be set via DataCenter CRUD operations first // They need to be set via DataCenter CRUD operations first
if (dataCenter.getArea() != null && !dataCenter.getArea().getCities().isEmpty()) { if (dataCenter.getArea() != null && !dataCenter.getArea().getCities().isEmpty()) {
input.setCity(dataCenter.getArea().getCities().get(0).getId()); input.setCity(dataCenter.getArea().getCities().get(0).getId());
System.out.println("🔍 Setting City: " + dataCenter.getArea().getCities().get(0).getId());
} else {
System.out.println("⚠️ Warning: No city available for DataCenter");
} }
if (dataCenter.getArea() != null && !dataCenter.getArea().getDistricts().isEmpty()) { if (dataCenter.getArea() != null && !dataCenter.getArea().getDistricts().isEmpty()) {
input.setDistrict(dataCenter.getArea().getDistricts().get(0).getId()); input.setDistrict(dataCenter.getArea().getDistricts().get(0).getId());
System.out.println("🔍 Setting District: " + dataCenter.getArea().getDistricts().get(0).getId());
} else {
System.out.println("⚠️ Warning: No district available for DataCenter");
} }
if (dataCenter.getSector() != null) { if (dataCenter.getSector() != null) {
input.setSector(dataCenter.getSector().getId()); input.setSector(dataCenter.getSector().getId());
System.out.println("🔍 Setting Sector: " + dataCenter.getSector().getId() + " (" + dataCenter.getSector().getTag() + ")");
} else { } else {
System.out.println("⚠️ Warning: DataCenter has no sector set - emission calculation may fail"); System.err.println("❌ Error: DataCenter has no sector set - this is required for emission calculation");
return null;
} }
if (dataCenter.getSubSector() != null) { if (dataCenter.getSubSector() != null) {
input.setSubSector(dataCenter.getSubSector().getId()); input.setSubSector(dataCenter.getSubSector().getId());
System.out.println("🔍 Setting SubSector: " + dataCenter.getSubSector().getId());
} else {
System.out.println("⚠️ Warning: DataCenter has no subsector set");
} }
// Use the specific emission source for this calculation // Use the specific emission source for this calculation
input.setEmissionSource(emissionSource.getId()); input.setEmissionSource(emissionSource.getId());
System.out.println("🔍 Setting EmissionSource: " + emissionSource.getId() + " (" + emissionSource.getTag() + ")");
if (dataCenter.getActivitySubUnit() != null) { if (dataCenter.getActivitySubUnit() != null) {
input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId()); input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId());
System.out.println("🔍 Setting ActivitySubUnit: " + dataCenter.getActivitySubUnit().getId());
} else {
System.out.println("⚠️ Warning: DataCenter has no activity sub unit set");
} }
if (dataCenter.getConsuptionUnit() != null) { // Handle consumption unit from emission sources - use the emission source's unit
input.setConsuptionUnit(dataCenter.getConsuptionUnit().getId()); if (emissionSource != null) {
// Find the DataCenterEmissionSource that matches this emissionSource
System.out.println("🔍 Looking for consumption unit for emission source: " + emissionSource.getTag());
if (dataCenter.getDataCenterEmissionSources() == null || dataCenter.getDataCenterEmissionSources().isEmpty()) {
System.err.println("❌ Error: DataCenter has no emission sources configured - cannot find consumption unit");
return null;
}
boolean foundUnit = false;
for (DataCenterEmissionSource dces : dataCenter.getDataCenterEmissionSources()) {
if (dces.getEmissionSource() != null && dces.getEmissionSource().getId().equals(emissionSource.getId())) {
if (dces.getConsuptionUnit() != null) {
input.setConsuptionUnit(dces.getConsuptionUnit().getId());
System.out.println("🔍 Setting ConsumptionUnit: " + dces.getConsuptionUnit().getId() + " (" + dces.getConsuptionUnit().getTag() + ")");
foundUnit = true;
break;
} else {
System.err.println("❌ Error: DataCenterEmissionSource has no consumption unit set for emission source: " + emissionSource.getTag());
return null;
}
}
}
if (!foundUnit) {
System.err.println("❌ Error: Could not find matching DataCenterEmissionSource for emission source: " + emissionSource.getTag());
return null;
}
} }
// Default to Kapsam-3 if no emission scope is set // Default to Kapsam-3 if no emission scope is set
input.setScope(dataCenter.getEmissionScope() != null ? input.setScope(dataCenter.getEmissionScope() != null ?
dataCenter.getEmissionScope().getTag().equals("Kapsam-3") : true); dataCenter.getEmissionScope().getTag().equals("Kapsam-3") : true);
System.out.println("🔍 Setting Scope: " + (dataCenter.getEmissionScope() != null ?
dataCenter.getEmissionScope().getTag() : "Kapsam-3 (default)"));
try { try {
List<Organization> organizations = organizationRepo.findAll(); List<Organization> organizations = organizationRepo.findAll();
if (!organizations.isEmpty()) { if (!organizations.isEmpty()) {
input.setOrganization(organizations.get(0).getId()); input.setOrganization(organizations.get(0).getId());
System.out.println("🔍 Setting Organization: " + organizations.get(0).getId());
} else {
System.err.println("❌ Error: No organizations found in database - this is required");
return null;
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println("❌ Error finding organization: " + e.getMessage()); System.err.println("❌ Error finding organization: " + e.getMessage());
return null;
} }
// Set VM-specific fields // Set VM-specific fields
input.setVmId(vm.getId()); input.setVmId(vm.getId());
System.out.println("🔍 Setting VM ID: " + vm.getId());
// Use the source-specific power consumption (percentage of total VM power) // Use the source-specific power consumption (percentage of total VM power)
input.setConsuptionAmount(String.valueOf(sourceSpecificPower)); // Format to 6 decimal places to avoid very long strings
String formattedPower = String.format("%.6f", sourceSpecificPower);
input.setConsuptionAmount(formattedPower);
System.out.println("🔍 Setting Consumption Amount: " + formattedPower + "W");
// Validate field lengths to prevent database errors
System.out.println("🔍 Field length validation:");
System.out.println(" Year: " + (input.getYear() != null ? input.getYear().length() : "null"));
System.out.println(" Month: " + (input.getMonth() != null ? input.getMonth().length() : "null"));
System.out.println(" ConsuptionAmount: " + (input.getConsuptionAmount() != null ? input.getConsuptionAmount().length() : "null"));
System.out.println("🔍 VM Emission Input for Source:"); System.out.println("🔍 VM Emission Input for Source:");
System.out.println(" VM ID: " + vm.getId()); System.out.println(" VM ID: " + vm.getId());
@@ -809,7 +858,6 @@ public class MessageListener {
System.out.println(" Percentage: " + percentage + "%"); System.out.println(" Percentage: " + percentage + "%");
System.out.println(" Source Power: " + sourceSpecificPower + "W"); System.out.println(" Source Power: " + sourceSpecificPower + "W");
System.out.println(" Physical Machine: " + pm.getName()); System.out.println(" Physical Machine: " + pm.getName());
System.out.println(" Project: " + project.getName());
System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET")); System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET"));
return input; return input;
@@ -828,6 +876,34 @@ public class MessageListener {
try { try {
System.out.println("🔄 Calling mainDataTableMutation.createMainDataTable..."); System.out.println("🔄 Calling mainDataTableMutation.createMainDataTable...");
// Validate input fields before making the call
if (input.getSector() == null) {
System.err.println("❌ Sector is null - cannot create emission record");
return null;
}
if (input.getEmissionSource() == null) {
System.err.println("❌ EmissionSource is null - cannot create emission record");
return null;
}
if (input.getConsuptionUnit() == null) {
System.err.println("❌ ConsumptionUnit is null - cannot create emission record");
return null;
}
if (input.getOrganization() == null) {
System.err.println("❌ Organization is null - cannot create emission record");
return null;
}
if (input.getVmId() == null) {
System.err.println("❌ VM ID is null - cannot create emission record");
return null;
}
System.out.println("🔍 Input validation passed - proceeding with mutation call");
// Call the mutation method - pass null environment since we've already patched the logging // Call the mutation method - pass null environment since we've already patched the logging
MainDataTable result = mainDataTableMutation.createMainDataTable(input, null); MainDataTable result = mainDataTableMutation.createMainDataTable(input, null);

View File

@@ -5,10 +5,13 @@ input DataCenterCreateInput {
sectorId: ID sectorId: ID
subSectorId: ID subSectorId: ID
activitySubUnitId: ID activitySubUnitId: ID
emissionSourceId: ID
consuptionUnitId: ID # Multiple emission sources support - each with exactly one unit
dataCenterEmissionSources: [DataCenterEmissionSourceInput!]
consuptionAmount: Float consuptionAmount: Float
areaId: ID areaId: ID
cityId: ID
number: Int number: Int
ayposURL: String ayposURL: String
address: String address: String
@@ -23,13 +26,23 @@ input DataCenterUpdateInput {
sectorId: ID sectorId: ID
subSectorId: ID subSectorId: ID
activitySubUnitId: ID activitySubUnitId: ID
emissionSourceId: ID
consuptionUnitId: ID # Multiple emission sources support - each with exactly one unit
dataCenterEmissionSources: [DataCenterEmissionSourceInput!]
consuptionAmount: Float consuptionAmount: Float
areaId: ID areaId: ID
cityId: ID
number: Int number: Int
ayposURL: String ayposURL: String
address: String address: String
latitude: Float latitude: Float
longitude: Float longitude: Float
} }
input DataCenterEmissionSourceInput {
emissionSourceId: ID!
consuptionUnitId: ID!
isDefault: Boolean
percentage: Float
}

View File

@@ -3,4 +3,5 @@ extend type Query{
dataCenters(criteria: DataCenterCriteria, sortBy: [SortBy!]): [DataCenter!] dataCenters(criteria: DataCenterCriteria, sortBy: [SortBy!]): [DataCenter!]
paginateDataCenters(pagination : Pagination!, criteria: DataCenterCriteria, sortBy:[SortBy!] ) : DataCenterPageable! paginateDataCenters(pagination : Pagination!, criteria: DataCenterCriteria, sortBy:[SortBy!] ) : DataCenterPageable!
getByNumber(number: Int!): DataCenter getByNumber(number: Int!): DataCenter
physicalMachines(datacenterId: ID!): [PhysicalMachine!]!
} }

View File

@@ -7,12 +7,15 @@ type DataCenter {
sector: Sector sector: Sector
subSector: SubSector subSector: SubSector
activitySubUnit: ActivitySubUnit activitySubUnit: ActivitySubUnit
emissionSource: EmissionSource
consuptionUnit: ConsuptionUnit # Multiple emission sources support - each with exactly one unit
dataCenterEmissionSources: [DataCenterEmissionSource]
consuptionAmount: Float consuptionAmount: Float
projects: [Project] physicalMachines: [PhysicalMachine]
area: Area area: Area
city: City
number: Int number: Int
ayposURL: String ayposURL: String
@@ -21,10 +24,12 @@ type DataCenter {
longitude: Float longitude: Float
} }
type Project { type DataCenterEmissionSource {
id: ID id: ID
name: String emissionSource: EmissionSource
physicalMachines: [PhysicalMachine] consuptionUnit: ConsuptionUnit
isDefault: Boolean
percentage: Float
} }
type PhysicalMachine { type PhysicalMachine {
@@ -32,11 +37,13 @@ type PhysicalMachine {
name: String name: String
ip: String ip: String
tag: String tag: String
cloudSystem: String
power: Float power: Float
vms: [Vm] vms: [VM]
dataCenter: DataCenter
} }
type Vm { type VM {
id: ID id: ID
state: String state: String
vmName: String vmName: String
@@ -47,8 +54,10 @@ type Vm {
host: String host: String
flavorName: String flavorName: String
tag: String tag: String
project: String
emissionSource: EmissionSourceMap emissionSource: EmissionSourceMap
config: Config config: Config
physicalMachine: PhysicalMachine
} }
scalar EmissionSourceMap scalar EmissionSourceMap

View File

@@ -2,5 +2,5 @@ extend type Query{
mainDataTable(id: ID!): MainDataTable! mainDataTable(id: ID!): MainDataTable!
mainDataTables(criteria: MainDataTableCriteria, sortBy: [SortBy!]): [MainDataTable!] mainDataTables(criteria: MainDataTableCriteria, sortBy: [SortBy!]): [MainDataTable!]
paginateMainDataTables(pagination : Pagination!, criteria: MainDataTableCriteria, sortBy:[SortBy!] ) : MainDataTablePageable! paginateMainDataTables(pagination : Pagination!, criteria: MainDataTableCriteria, sortBy:[SortBy!] ) : MainDataTablePageable!
vmEmissionSummary: [VMEmissionSummary!]! vmEmissionSummary(datacenterId: ID): [VMEmissionSummary!]!
} }

View File

@@ -26,11 +26,11 @@ type MainDataTable {
proteinAmount:Float proteinAmount:Float
burnOrOpenBurn:Boolean burnOrOpenBurn:Boolean
scopeCheck:Boolean scopeCheck:Boolean
vm: Vm vm: VM
} }
type Vm { type VM {
id: ID id: ID
state: String state: String
vmName: String vmName: String
@@ -41,6 +41,7 @@ type Vm {
host: String host: String
flavorName: String flavorName: String
tag: String tag: String
project: String
config: Config config: Config
} }
@@ -51,22 +52,22 @@ type Config {
disk: Int disk: Int
} }
type VMEmissionSummary { type VMEmissionSummary {
vmId: ID! vmId: ID!
vmName: String! vmName: String
vmPower: Float vmPower: Float
vmStatus: String vmStatus: String
totalEmission: Float! totalEmission: Float!
createdDate: LocalDateTime! createdDate: LocalDateTime!
physicalMachine: String physicalMachine: String
project: String cloudSystem: String
dataCenter: String dataCenter: String
# Individual emission values per record # Individual emission values per record
co2: Float! co2: Float!
ch4: Float! ch4: Float!
n2o: Float! n2o: Float!
reportGeneratedTime: LocalDateTime reportGeneratedTime: LocalDateTime
} }
type SolidWasteSupplement { type SolidWasteSupplement {
id: ID! id: ID!

View File

@@ -102,3 +102,7 @@ Ensure both services are configured consistently.
## License ## License
[Insert your license information here] [Insert your license information here]
## CI/CD Testing v20

View File

@@ -1,35 +1,28 @@
server { server {
listen 80; listen 80;
server_name bgreen.blc-css.com; server_name bgreen.blc-css.com;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html index.htm; index index.html index.htm;
location / { location / {
try_files $uri /index.html; try_files $uri /index.html;
} }
location /api/v1/graphql { location /api/v1/graphql {
proxy_pass http://bgreen-backend:8080/api/v1/graphql; proxy_pass http://bgreen-backend:8080/api/v1/graphql;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
} }
location /api/v1/upload { location /api/v1/upload {
proxy_pass http://bgreen-backend:8080/upload; proxy_pass http://bgreen-backend:8080/upload;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
} }
# location /api/v1/datacenter { # location /api/v1/datacenter {
# proxy_pass http://backend:8080/api/v1/datacenter; # proxy_pass http://backend:8080/api/v1/datacenter;
# proxy_set_header Host $host; # proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Real-IP $remote_addr;
# } # }
# Hata durumlarında da index.html'i sun # Hata durumlarında da index.html'i sun
error_page 404 /index.html; error_page 404 /index.html;
gzip on; gzip on;
gzip_vary on; gzip_vary on;
gzip_min_length 10240; gzip_min_length 10240;

View File

@@ -1,6 +1,6 @@
{ {
"name": "sgs-web", "name": "sgs-web",
"version": "1.0.0", "version": "1.0.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@apollo/client": "^3.13.8", "@apollo/client": "^3.13.8",

View File

@@ -45,6 +45,10 @@ export const getDataCenters = () => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -58,41 +62,42 @@ export const getDataCenters = () => {
id id
tag tag
} }
emissionSource { dataCenterEmissionSources {
id id
tag emissionSource {
} id
consuptionUnit { tag
id }
description consuptionUnit {
id
description
}
isDefault
percentage
} }
activitySubUnit { activitySubUnit {
id id
tag tag
} }
projects { physicalMachines {
id id
name name
physicalMachines { vms {
id id
name vmName
vms { state
id power
vmName calcOn
state hostingPm
power host
calcOn flavorName
hostingPm tag
host config {
flavorName id
tag cpu
config { ram
id disk
cpu }
ram
disk
}
}
} }
} }
} }
@@ -111,7 +116,7 @@ export const getDataCenters = () => {
console.log("GraphQL Response:", { console.log("GraphQL Response:", {
status: response.status, status: response.status,
data: response.data, data: response.data,
errors: response.data?.errors errors: response.data?.errors,
}); });
// Check for GraphQL errors // Check for GraphQL errors
@@ -144,7 +149,7 @@ export const getDataCenters = () => {
message: error.message, message: error.message,
response: error.response?.data, response: error.response?.data,
status: error.response?.status, status: error.response?.status,
stack: error.stack stack: error.stack,
}); });
// Check for specific error types // Check for specific error types
@@ -200,6 +205,10 @@ export const createDataCenter = (dataCenterData) => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -213,13 +222,18 @@ export const createDataCenter = (dataCenterData) => {
id id
tag tag
} }
emissionSource { dataCenterEmissionSources {
id id
tag emissionSource {
} id
consuptionUnit { tag
id }
description consuptionUnit {
id
description
}
isDefault
percentage
} }
activitySubUnit { activitySubUnit {
id id
@@ -235,17 +249,22 @@ export const createDataCenter = (dataCenterData) => {
ayposURL: dataCenterData.ayposURL || "", ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1, number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId || null, areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "", address: dataCenterData.address || "",
latitude: dataCenterData.latitude ? parseFloat(dataCenterData.latitude) : null, latitude: dataCenterData.latitude
longitude: dataCenterData.longitude ? parseFloat(dataCenterData.longitude) : null, ? parseFloat(dataCenterData.latitude)
: null,
longitude: dataCenterData.longitude
? parseFloat(dataCenterData.longitude)
: null,
emissionScopeId: dataCenterData.emissionScopeId || null, emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null, sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null, subSectorId: dataCenterData.subSectorId || null,
emissionSourceId: dataCenterData.emissionSourceId || null, dataCenterEmissionSources:
consuptionUnitId: dataCenterData.consuptionUnitId || null, dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null activitySubUnitId: dataCenterData.activitySubUnitId || null,
} },
} },
}, },
{ {
headers: { headers: {
@@ -258,7 +277,7 @@ export const createDataCenter = (dataCenterData) => {
console.log("Create Response:", { console.log("Create Response:", {
status: response.status, status: response.status,
data: response.data, data: response.data,
errors: response.data?.errors errors: response.data?.errors,
}); });
if (response.data?.errors) { if (response.data?.errors) {
@@ -321,6 +340,10 @@ export const updateDataCenter = (id, dataCenterData) => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -334,13 +357,18 @@ export const updateDataCenter = (id, dataCenterData) => {
id id
tag tag
} }
emissionSource { dataCenterEmissionSources {
id id
tag emissionSource {
} id
consuptionUnit { tag
id }
description consuptionUnit {
id
description
}
isDefault
percentage
} }
activitySubUnit { activitySubUnit {
id id
@@ -357,17 +385,22 @@ export const updateDataCenter = (id, dataCenterData) => {
ayposURL: dataCenterData.ayposURL || "", ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1, number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId || null, areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "", address: dataCenterData.address || "",
latitude: dataCenterData.latitude ? parseFloat(dataCenterData.latitude) : null, latitude: dataCenterData.latitude
longitude: dataCenterData.longitude ? parseFloat(dataCenterData.longitude) : null, ? parseFloat(dataCenterData.latitude)
: null,
longitude: dataCenterData.longitude
? parseFloat(dataCenterData.longitude)
: null,
emissionScopeId: dataCenterData.emissionScopeId || null, emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null, sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null, subSectorId: dataCenterData.subSectorId || null,
emissionSourceId: dataCenterData.emissionSourceId || null, dataCenterEmissionSources:
consuptionUnitId: dataCenterData.consuptionUnitId || null, dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null activitySubUnitId: dataCenterData.activitySubUnitId || null,
} },
} },
}, },
{ {
headers: { headers: {
@@ -382,7 +415,7 @@ export const updateDataCenter = (id, dataCenterData) => {
dispatch({ dispatch({
type: "UPDATE_DATA_CENTER_SUCCESS", type: "UPDATE_DATA_CENTER_SUCCESS",
payload: response.data.data.updateDataCenter payload: response.data.data.updateDataCenter,
}); });
return response.data.data.updateDataCenter; return response.data.data.updateDataCenter;
@@ -415,8 +448,8 @@ export const deleteDataCenter = (id) => {
} }
`, `,
variables: { variables: {
id: id id: id,
} },
}, },
{ {
headers: { headers: {
@@ -431,7 +464,7 @@ export const deleteDataCenter = (id) => {
dispatch({ dispatch({
type: "DELETE_DATA_CENTER_SUCCESS", type: "DELETE_DATA_CENTER_SUCCESS",
payload: id payload: id,
}); });
return true; return true;
@@ -466,7 +499,7 @@ export const getEmissionScopes = () => {
description description
} }
} }
` `,
}, },
{ {
headers: { headers: {
@@ -481,7 +514,7 @@ export const getEmissionScopes = () => {
dispatch({ dispatch({
type: "GET_EMISSION_SCOPES_SUCCESS", type: "GET_EMISSION_SCOPES_SUCCESS",
payload: response.data.data.emissionScopes payload: response.data.data.emissionScopes,
}); });
return response.data.data.emissionScopes; return response.data.data.emissionScopes;
@@ -502,65 +535,59 @@ export const getDataCenterVMs = (dataCenterId) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
// Don't make the request if dataCenterId is undefined, null, or empty // Don't make the request if dataCenterId is undefined, null, or empty
if (!dataCenterId || dataCenterId === "undefined") { if (!dataCenterId || dataCenterId === "undefined") {
console.log('getDataCenterVMs: No dataCenterId provided'); console.log("getDataCenterVMs: No dataCenterId provided");
resolve([]); resolve([]);
return; return;
} }
try { try {
console.log('getDataCenterVMs: Fetching VMs for data center:', dataCenterId); console.log(
const response = await ApplicationService.http() "getDataCenterVMs: Fetching VMs for data center:",
.post( dataCenterId
"/graphql", );
{ const response = await ApplicationService.http().post(
query: ` "/graphql",
{
query: `
{ {
dataCenter(id: "${dataCenterId}") { dataCenter(id: "${dataCenterId}") {
id id
dataCenter dataCenter
projects { physicalMachines {
id id
name name
physicalMachines { vms {
id id
name vmName
vms { state
id power
name
status
power
}
} }
} }
} }
} }
`, `,
},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("accessToken"),
}, },
{ }
headers: { );
Authorization: "Bearer " + localStorage.getItem("accessToken"),
},
}
);
const dataCenter = response?.data?.data?.dataCenter; const dataCenter = response?.data?.data?.dataCenter;
console.log('getDataCenterVMs: Data center response:', dataCenter); console.log("getDataCenterVMs: Data center response:", dataCenter);
let allVMs = []; let allVMs = [];
if (dataCenter && dataCenter.projects) { if (dataCenter && dataCenter.physicalMachines) {
dataCenter.projects.forEach(project => { dataCenter.physicalMachines.forEach((pm) => {
if (project.physicalMachines) { if (pm.vms) {
project.physicalMachines.forEach(pm => { allVMs = allVMs.concat(pm.vms);
if (pm.vms) {
allVMs = allVMs.concat(pm.vms);
}
});
} }
}); });
} }
console.log('getDataCenterVMs: Found VMs:', allVMs); console.log("getDataCenterVMs: Found VMs:", allVMs);
resolve(allVMs); resolve(allVMs);
} catch (error) { } catch (error) {
console.error("Error fetching VMs by data center:", error); console.error("Error fetching VMs by data center:", error);

View File

@@ -1,6 +1,6 @@
import ApplicationService from "../../../services/ApplicationService"; import ApplicationService from "../../../services/ApplicationService";
export const getVMEmissionSummary = () => { export const getVMEmissionSummary = (datacenterId) => {
return async (dispatch) => { return async (dispatch) => {
try { try {
const response = await ApplicationService.http() const response = await ApplicationService.http()
@@ -8,8 +8,8 @@ export const getVMEmissionSummary = () => {
"/graphql", "/graphql",
{ {
query: ` query: `
{ query GetVMEmissions($datacenterId: ID) {
vmEmissionSummary { vmEmissionSummary(datacenterId: $datacenterId) {
vmId vmId
vmName vmName
vmPower vmPower
@@ -17,7 +17,7 @@ export const getVMEmissionSummary = () => {
totalEmission totalEmission
createdDate createdDate
physicalMachine physicalMachine
project cloudSystem
dataCenter dataCenter
co2 co2
ch4 ch4
@@ -25,7 +25,10 @@ export const getVMEmissionSummary = () => {
reportGeneratedTime reportGeneratedTime
} }
} }
` `,
variables: {
datacenterId: datacenterId
}
}, },
{ {
headers: { headers: {

View File

@@ -75,7 +75,7 @@ const Areas = () => {
}, },
{ {
name: t("Areas.areas"), name: t("Areas.areas"),
selector: (row) => row.areas, // Bura boştu "". selector: (row) => row.areas, // Bura boştu "".
sortable: true, sortable: true,
minWidth: "350px", minWidth: "350px",
cell: (row) => { cell: (row) => {

View File

@@ -9,7 +9,7 @@ import {
ModalBody, ModalBody,
ModalHeader, ModalHeader,
Row, Row,
UncontrolledTooltip, // Add UncontrolledTooltip import UncontrolledTooltip, // Add UncontrolledTooltip import
} from "reactstrap"; } from "reactstrap";
import { Edit, Mail, Phone, MapPin } from "react-feather"; // Import Mail, Phone, MapPin import { Edit, Mail, Phone, MapPin } from "react-feather"; // Import Mail, Phone, MapPin
@@ -187,7 +187,7 @@ function Communication() {
{/* Add MapPin icon */} {/* Add MapPin icon */}
<address> <address>
Central Office: 4995 sokak no:3, Alacaatlı Mahallesi, Central Office: 4995 sokak no:3, Alacaatlı Mahallesi,
Daire No: A2 06810 Çankaya/Ankara Daire No: A2 06820 Çankaya/Ankara
</address> </address>
</div> </div>
</Col> </Col>

View File

@@ -18,17 +18,16 @@ const DataCenter = () => {
const [refreshInterval, setRefreshInterval] = useState(null); const [refreshInterval, setRefreshInterval] = useState(null);
const getAllPhysicalMachines = (dataCenter) => { const getAllPhysicalMachines = (dataCenter) => {
if (!dataCenter.projects) return []; // Physical machines are directly in the dataCenter object, not in projects
return dataCenter.projects.flatMap(project => const pms = dataCenter.physicalMachines || [];
project.physicalMachines || [] return pms;
);
}; };
// Table columns following your pattern // Table columns following your pattern
const initialColumns = [ const initialColumns = [
{ {
name: "Number", name: "External ID",
selector: (row) => row.number, selector: (row) => row.externalId,
sortable: true, sortable: true,
minWidth: "100px", minWidth: "100px",
}, },
@@ -38,28 +37,33 @@ const DataCenter = () => {
sortable: true, sortable: true,
minWidth: "200px", minWidth: "200px",
}, },
// Projects // Projects - Based on API response, this field might not exist or be structured differently
{ // {
name: "Projects", // name: "Projects",
selector: (row) => (row.projects || []).length, // selector: (row) => row.projects?.length || 0,
sortable: true, // sortable: true,
minWidth: "200px", // minWidth: "200px",
cell: (row) => ( // cell: (row) => (
<div> // <div>
{(row.projects || []).length > 0 ? ( // {row.projects && row.projects.length > 0 ? (
<div className="d-flex flex-column"> // <div className="d-flex flex-column">
{row.projects.map((project, index) => ( // {row.projects.map((project, index) => (
<div key={project.id} className={`badge badge-light-primary ${index > 0 ? 'mt-1' : ''}`}> // <div
{project.name} // key={project.id}
</div> // className={`badge badge-light-primary ${
))} // index > 0 ? "mt-1" : ""
</div> // }`}
) : ( // >
<span className="text-muted">-</span> // {project.name}
)} // </div>
</div> // ))}
), // </div>
}, // ) : (
// <span className="text-muted">-</span>
// )}
// </div>
// ),
// },
// Physical Machines // Physical Machines
{ {
name: "Physical Machines", name: "Physical Machines",
@@ -80,26 +84,38 @@ const DataCenter = () => {
name: "Virtual Machines", name: "Virtual Machines",
selector: (row) => { selector: (row) => {
const pms = getAllPhysicalMachines(row); const pms = getAllPhysicalMachines(row);
const vms = pms.reduce((acc, pm) => { const vms = pms.reduce(
if (!pm.vms) return acc; (acc, pm) => {
return { if (!pm.vms) return acc;
active: acc.active + pm.vms.filter(vm => vm.state?.toLowerCase() === "active").length, return {
total: acc.total + pm.vms.length active:
}; acc.active +
}, { active: 0, total: 0 }); pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return vms.total; return vms.total;
}, },
sortable: true, sortable: true,
minWidth: "200px", minWidth: "200px",
cell: (row) => { cell: (row) => {
const pms = getAllPhysicalMachines(row); const pms = getAllPhysicalMachines(row);
const vms = pms.reduce((acc, pm) => { const vms = pms.reduce(
if (!pm.vms) return acc; (acc, pm) => {
return { if (!pm.vms) return acc;
active: acc.active + pm.vms.filter(vm => vm.state?.toLowerCase() === "active").length, return {
total: acc.total + pm.vms.length active:
}; acc.active +
}, { active: 0, total: 0 }); pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return ( return (
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
@@ -109,7 +125,9 @@ const DataCenter = () => {
<div className="small"> <div className="small">
<span className="text-success">{vms.active} Active</span> <span className="text-success">{vms.active} Active</span>
<span className="text-muted mx-1"></span> <span className="text-muted mx-1"></span>
<span className="text-warning">{vms.total - vms.active} Inactive</span> <span className="text-warning">
{vms.total - vms.active} Inactive
</span>
</div> </div>
</div> </div>
</div> </div>
@@ -183,14 +201,23 @@ const DataCenter = () => {
</thead> </thead>
<tbody> <tbody>
{pm.vms.map((vm) => { {pm.vms.map((vm) => {
const isActive = vm.state && ["ACTIVE", "active"].includes(vm.state); const isActive =
vm.state && ["ACTIVE", "active"].includes(vm.state);
return ( return (
<tr key={vm.id}> <tr key={vm.id}>
<td> <td>
<span className="font-weight-bold">{vm.vmName || vm.vm_name}</span> <span className="font-weight-bold">
{vm.vmName || vm.vm_name}
</span>
</td> </td>
<td> <td>
<div className={`d-inline-block px-2 py-1 rounded-pill ${isActive ? 'bg-light-success text-success' : 'bg-light-warning text-warning'}`}> <div
className={`d-inline-block px-2 py-1 rounded-pill ${
isActive
? "bg-light-success text-success"
: "bg-light-warning text-warning"
}`}
>
{vm.state} {vm.state}
</div> </div>
</td> </td>
@@ -204,23 +231,48 @@ const DataCenter = () => {
<td> <td>
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<div className="mr-3"> <div className="mr-3">
<small className="text-muted d-block">CPU</small> <small className="text-muted d-block">
<span>{(vm.config?.cpu || (vm.confg && vm.confg[1])) || '-'}</span> CPU
</small>
<span>
{vm.config?.cpu ||
(vm.confg && vm.confg[1]) ||
"-"}
</span>
</div> </div>
<div className="mr-3"> <div className="mr-3">
<small className="text-muted d-block">RAM</small> <small className="text-muted d-block">
<span>{(vm.config?.ram || (vm.confg && vm.confg[2])) || '-'} GB</span> RAM
</small>
<span>
{vm.config?.ram ||
(vm.confg && vm.confg[2]) ||
"-"}{" "}
GB
</span>
</div> </div>
<div> <div>
<small className="text-muted d-block">Disk</small> <small className="text-muted d-block">
<span>{(vm.config?.disk || (vm.confg && vm.confg[3])) || '-'} GB</span> Disk
</small>
<span>
{vm.config?.disk ||
(vm.confg && vm.confg[3]) ||
"-"}{" "}
GB
</span>
</div> </div>
</div> </div>
</td> </td>
<td> <td>
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<Server size={14} className="mr-1" /> <Server size={14} className="mr-1" />
<span>{vm.host || vm.hostingPm || (vm.confg && vm.confg[4]) || '-'}</span> <span>
{vm.host ||
vm.hostingPm ||
(vm.confg && vm.confg[4]) ||
"-"}
</span>
</div> </div>
</td> </td>
</tr> </tr>
@@ -241,8 +293,6 @@ const DataCenter = () => {
); );
}; };
return ( return (
<div style={{ marginTop: "2%" }}> <div style={{ marginTop: "2%" }}>
<Card> <Card>

View File

@@ -28,26 +28,37 @@ import { Edit } from "@mui/icons-material";
import { useSnackbar } from "notistack"; import { useSnackbar } from "notistack";
import { default as SweetAlert } from "sweetalert2"; import { default as SweetAlert } from "sweetalert2";
import withReactContent from "sweetalert2-react-content"; import withReactContent from "sweetalert2-react-content";
import { getDataCenters, createDataCenter, updateDataCenter, deleteDataCenter, getEmissionScopes } from "../redux/actions/dataCenter"; import {
getDataCenters,
createDataCenter,
updateDataCenter,
deleteDataCenter,
getEmissionScopes,
} from "../redux/actions/dataCenter";
import { getAreas, getAreasWithCriteria } from "../redux/actions/areas"; import { getAreas, getAreasWithCriteria } from "../redux/actions/areas";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { getSectors, getSectorById, getSubSectorById, getConsuptionUnits } from "../redux/actions/datas"; import {
getSectors,
getSectorById,
getSubSectorById,
getConsuptionUnits,
} from "../redux/actions/datas";
import { getAllEmissionSources } from "../redux/actions/emissionSources"; import { getAllEmissionSources } from "../redux/actions/emissionSources";
import { permissionCheck } from "../components/permission-check"; import { permissionCheck } from "../components/permission-check";
import { customFilterForSelect } from "../utility/Utils"; import { customFilterForSelect } from "../utility/Utils";
import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet'; import { MapContainer, TileLayer, Marker, useMapEvents } from "react-leaflet";
import 'leaflet/dist/leaflet.css'; import "leaflet/dist/leaflet.css";
import L from 'leaflet'; import L from "leaflet";
import axios from 'axios'; import axios from "axios";
import { debounce } from 'lodash'; import { debounce } from "lodash";
// Add Nominatim service configuration // Add Nominatim service configuration
const NOMINATIM_BASE_URL = 'https://nominatim.openstreetmap.org'; const NOMINATIM_BASE_URL = "https://nominatim.openstreetmap.org";
const nominatimAxios = axios.create({ const nominatimAxios = axios.create({
baseURL: NOMINATIM_BASE_URL, baseURL: NOMINATIM_BASE_URL,
headers: { headers: {
'User-Agent': 'SGE-DataCenter-Management' // Required by Nominatim's usage policy "User-Agent": "SGE-DataCenter-Management", // Required by Nominatim's usage policy
} },
}); });
const Swal = withReactContent(SweetAlert); const Swal = withReactContent(SweetAlert);
@@ -55,9 +66,9 @@ const Swal = withReactContent(SweetAlert);
// Fix Leaflet marker icon issue // Fix Leaflet marker icon issue
delete L.Icon.Default.prototype._getIconUrl; delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({ L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"),
iconUrl: require('leaflet/dist/images/marker-icon.png'), iconUrl: require("leaflet/dist/images/marker-icon.png"),
shadowUrl: require('leaflet/dist/images/marker-shadow.png') shadowUrl: require("leaflet/dist/images/marker-shadow.png"),
}); });
// Map marker component that handles clicks // Map marker component that handles clicks
@@ -66,30 +77,33 @@ const MapMarker = ({ position, setPosition, setSelectedDataCenter }) => {
click(e) { click(e) {
setPosition([e.latlng.lat, e.latlng.lng]); setPosition([e.latlng.lat, e.latlng.lng]);
// Use Nominatim reverse geocoding directly // Use Nominatim reverse geocoding directly
nominatimAxios.get(`/reverse?format=json&lat=${e.latlng.lat}&lon=${e.latlng.lng}`) nominatimAxios
.then(response => { .get(`/reverse?format=json&lat=${e.latlng.lat}&lon=${e.latlng.lng}`)
.then((response) => {
const address = response.data.display_name; const address = response.data.display_name;
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
address, address,
latitude: e.latlng.lat, latitude: e.latlng.lat,
longitude: e.latlng.lng longitude: e.latlng.lng,
})); }));
}) })
.catch(error => { .catch((error) => {
console.error('Error getting address:', error); console.error("Error getting address:", error);
// Still update coordinates even if address lookup fails // Still update coordinates even if address lookup fails
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: e.latlng.lat, latitude: e.latlng.lat,
longitude: e.latlng.lng longitude: e.latlng.lng,
})); }));
}); });
} },
}); });
// Only render marker if position exists and has valid coordinates // Only render marker if position exists and has valid coordinates
return position && position[0] && position[1] ? <Marker position={position} /> : null; return position && position[0] && position[1] ? (
<Marker position={position} />
) : null;
}; };
const DataCenterManagement = () => { const DataCenterManagement = () => {
@@ -115,15 +129,14 @@ const DataCenterManagement = () => {
emissionScopeId: null, emissionScopeId: null,
sectorId: null, sectorId: null,
subSectorId: null, subSectorId: null,
emissionSourceId: null, dataCenterEmissionSources: [], // Array of emission sources with consumption units
consuptionUnitId: null, activitySubUnitId: null,
activitySubUnitId: null
}); });
const [mapPosition, setMapPosition] = useState(null); const [mapPosition, setMapPosition] = useState(null);
const dataCenterStore = useSelector((state) => { const dataCenterStore = useSelector((state) => {
console.log('DataCenter Store:', state.dataCenter); console.log("DataCenter Store:", state.dataCenter);
return state.dataCenter; return state.dataCenter;
}); });
const emissionScopeStore = useSelector((state) => state.emissionScope); const emissionScopeStore = useSelector((state) => state.emissionScope);
@@ -170,7 +183,7 @@ const DataCenterManagement = () => {
<Button <Button
color="primary" color="primary"
size="sm" size="sm"
onClick={() => window.open(row.ayposURL, '_blank')} onClick={() => window.open(row.ayposURL, "_blank")}
> >
Dashboard Dashboard
</Button> </Button>
@@ -200,7 +213,9 @@ const DataCenterManagement = () => {
onClick={() => handleEditDataCenter(row)} onClick={() => handleEditDataCenter(row)}
> >
<Edit size={15} /> <Edit size={15} />
<span className="align-middle ml-50">{t("Cruds.edit")}</span> <span className="align-middle ml-50">
{t("Cruds.edit")}
</span>
</DropdownItem> </DropdownItem>
)} )}
{permissionCheck("data_center_delete") && ( {permissionCheck("data_center_delete") && (
@@ -210,7 +225,9 @@ const DataCenterManagement = () => {
onClick={() => handleDeleteDataCenter(row)} onClick={() => handleDeleteDataCenter(row)}
> >
<Trash size={15} /> <Trash size={15} />
<span className="align-middle ml-50">{t("Cruds.delete")}</span> <span className="align-middle ml-50">
{t("Cruds.delete")}
</span>
</DropdownItem> </DropdownItem>
)} )}
</DropdownMenu> </DropdownMenu>
@@ -269,16 +286,41 @@ const DataCenterManagement = () => {
); );
}, [emissionSourceStore?.emissionSources]); }, [emissionSourceStore?.emissionSources]);
// Remove the old emission source effect since we now handle it in the emission sources component
// useEffect(() => {
// if (selectedDataCenter?.emissionSourceId) {
// dispatch(
// getConsuptionUnits({
// id: selectedDataCenter?.emissionSourceId,
// sector: selectedDataCenter?.sectorId,
// })
// );
// }
// }, [selectedDataCenter?.emissionSourceId]);
// Ensure there's always at least one emission source entry for new data centers
useEffect(() => { useEffect(() => {
if (selectedDataCenter?.emissionSourceId) { if (
dispatch( showAddModal &&
getConsuptionUnits({ !editingDataCenter &&
id: selectedDataCenter?.emissionSourceId, selectedDataCenter.dataCenterEmissionSources.length === 0
sector: selectedDataCenter?.sectorId, ) {
}) setSelectedDataCenter((prev) => ({
); ...prev,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
}));
} }
}, [selectedDataCenter?.emissionSourceId]); }, [
showAddModal,
editingDataCenter,
selectedDataCenter.dataCenterEmissionSources.length,
]);
useEffect(() => { useEffect(() => {
if (selectedSubSector != null) { if (selectedSubSector != null) {
@@ -352,33 +394,63 @@ const DataCenterManagement = () => {
}, [selectedDataCenter.areaId, areasStore?.areas]); }, [selectedDataCenter.areaId, areasStore?.areas]);
const handleEditDataCenter = (row) => { const handleEditDataCenter = (row) => {
console.log('Editing data center:', row); console.log("Editing data center:", row);
setEditingDataCenter(row); setEditingDataCenter(row);
// Convert dataCenterEmissionSources to the format expected by the form
const emissionSources = row.dataCenterEmissionSources
? row.dataCenterEmissionSources.map((dces) => ({
emissionSourceId: dces.emissionSource?.id,
consuptionUnitId: dces.consuptionUnit?.id,
isDefault: dces.isDefault || false,
}))
: [];
setSelectedDataCenter({ setSelectedDataCenter({
name: row.dataCenter, name: row.dataCenter,
externalId: row.externalId?.toString(), externalId: row.externalId?.toString(),
number: row.number?.toString(), number: row.number?.toString(),
address: row.address || "", address: row.address || "",
areaId: row.area?.id || null, areaId: row.area?.id || null,
cityId: null, cityId: row.city?.id || null,
latitude: row.latitude, latitude: row.latitude,
longitude: row.longitude, longitude: row.longitude,
ayposURL: row.ayposURL || "", ayposURL: row.ayposURL || "",
city: row.city || "", city: row.city?.name || "",
emissionScopeId: row.emissionScope?.id || null, emissionScopeId: row.emissionScope?.id || null,
sectorId: row.sector?.id || null, sectorId: row.sector?.id || null,
subSectorId: row.subSector?.id || null, subSectorId: row.subSector?.id || null,
emissionSourceId: row.emissionSource?.id || null, dataCenterEmissionSources: emissionSources,
consuptionUnitId: row.consuptionUnit?.id || null, activitySubUnitId: row.activitySubUnit?.id || null,
activitySubUnitId: row.activitySubUnit?.id || null
}); });
// Set the selected sector and sub sector for cascading dropdowns // Set the selected sector and sub sector for cascading dropdowns
setSelectedSector(row.sector?.id); setSelectedSector(row.sector?.id);
setSelectedSubSector(row.subSector?.id); setSelectedSubSector(row.subSector?.id);
// If there are existing emission sources, fetch consumption units for each
if (
row.dataCenterEmissionSources &&
row.dataCenterEmissionSources.length > 0
) {
row.dataCenterEmissionSources.forEach((dces) => {
if (dces.emissionSource && dces.emissionSource.id) {
dispatch(
getConsuptionUnits({
id: dces.emissionSource.id,
sector: row.sector?.id,
})
);
}
});
}
// Only set map position if we have both address and valid coordinates // Only set map position if we have both address and valid coordinates
setMapPosition(row.address && row.latitude && row.longitude ? [row.latitude, row.longitude] : null); setMapPosition(
row.address && row.latitude && row.longitude
? [row.latitude, row.longitude]
: null
);
setShowAddModal(true); setShowAddModal(true);
}; };
@@ -403,10 +475,9 @@ const DataCenterManagement = () => {
enqueueSnackbar(t("DataCenter.deleteSuccess"), { variant: "success" }); enqueueSnackbar(t("DataCenter.deleteSuccess"), { variant: "success" });
} catch (error) { } catch (error) {
console.error("Delete error:", error); console.error("Delete error:", error);
enqueueSnackbar( enqueueSnackbar(error?.message || t("DataCenter.deleteError"), {
error?.message || t("DataCenter.deleteError"), variant: "error",
{ variant: "error" } });
);
} }
} }
}; };
@@ -473,23 +544,60 @@ const DataCenterManagement = () => {
if (selectedDataCenter.subSectorId && !selectedDataCenter.sectorId) { if (selectedDataCenter.subSectorId && !selectedDataCenter.sectorId) {
errors.push(t("DataCenter.sectorRequired")); errors.push(t("DataCenter.sectorRequired"));
} }
if (selectedDataCenter.emissionSourceId && !selectedDataCenter.subSectorId) { if (
errors.push(t("DataCenter.subSectorRequired")); selectedDataCenter.activitySubUnitId &&
} !selectedDataCenter.subSectorId
if (selectedDataCenter.consuptionUnitId && !selectedDataCenter.emissionSourceId) { ) {
errors.push(t("DataCenter.emissionSourceRequired"));
}
if (selectedDataCenter.activitySubUnitId && !selectedDataCenter.subSectorId) {
errors.push(t("DataCenter.subSectorRequiredForActivity")); errors.push(t("DataCenter.subSectorRequiredForActivity"));
} }
// Emission sources validations
if (selectedDataCenter.dataCenterEmissionSources.length > 0) {
const validSources = selectedDataCenter.dataCenterEmissionSources.filter(
(source) => source.emissionSourceId && source.consuptionUnitId
);
if (validSources.length === 0) {
errors.push(t("DataCenter.atLeastOneEmissionSource"));
}
// Check for incomplete emission sources
selectedDataCenter.dataCenterEmissionSources.forEach((source, index) => {
if (
(source.emissionSourceId && !source.consuptionUnitId) ||
(!source.emissionSourceId && source.consuptionUnitId)
) {
errors.push(
t("DataCenter.incompleteEmissionSource", { index: index + 1 })
);
}
});
// Check for duplicate emission sources
const sourceIds = validSources.map((s) => s.emissionSourceId);
const duplicates = sourceIds.filter(
(id, index) => sourceIds.indexOf(id) !== index
);
if (duplicates.length > 0) {
errors.push(t("DataCenter.duplicateEmissionSources"));
}
// Ensure exactly one default emission source
const defaultSources = validSources.filter((s) => s.isDefault);
if (defaultSources.length === 0) {
errors.push(t("DataCenter.oneDefaultEmissionSourceRequired"));
} else if (defaultSources.length > 1) {
errors.push(t("DataCenter.onlyOneDefaultEmissionSourceAllowed"));
}
}
return errors; return errors;
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
const validationErrors = validateForm(); const validationErrors = validateForm();
if (validationErrors.length > 0) { if (validationErrors.length > 0) {
validationErrors.forEach(error => { validationErrors.forEach((error) => {
enqueueSnackbar(error, { variant: "error" }); enqueueSnackbar(error, { variant: "error" });
}); });
return; return;
@@ -498,20 +606,27 @@ const DataCenterManagement = () => {
try { try {
// Format data according to GraphQL input type // Format data according to GraphQL input type
const dataToSubmit = { const dataToSubmit = {
dataCenter: selectedDataCenter.name, name: selectedDataCenter.name,
externalId: parseInt(selectedDataCenter.externalId), externalId: parseInt(selectedDataCenter.externalId),
number: parseInt(selectedDataCenter.number || "1"), number: parseInt(selectedDataCenter.number || "1"),
address: selectedDataCenter.address, address: selectedDataCenter.address,
areaId: selectedDataCenter.areaId, areaId: selectedDataCenter.areaId,
latitude: selectedDataCenter.latitude ? parseFloat(selectedDataCenter.latitude) : null, cityId: selectedDataCenter.cityId,
longitude: selectedDataCenter.longitude ? parseFloat(selectedDataCenter.longitude) : null, latitude: selectedDataCenter.latitude
? parseFloat(selectedDataCenter.latitude)
: null,
longitude: selectedDataCenter.longitude
? parseFloat(selectedDataCenter.longitude)
: null,
ayposURL: selectedDataCenter.ayposURL, ayposURL: selectedDataCenter.ayposURL,
emissionScopeId: selectedDataCenter.emissionScopeId, emissionScopeId: selectedDataCenter.emissionScopeId,
sectorId: selectedDataCenter.sectorId, sectorId: selectedDataCenter.sectorId,
subSectorId: selectedDataCenter.subSectorId, subSectorId: selectedDataCenter.subSectorId,
emissionSourceId: selectedDataCenter.emissionSourceId, dataCenterEmissionSources:
consuptionUnitId: selectedDataCenter.consuptionUnitId, selectedDataCenter.dataCenterEmissionSources.filter(
activitySubUnitId: selectedDataCenter.activitySubUnitId (source) => source.emissionSourceId && source.consuptionUnitId
),
activitySubUnitId: selectedDataCenter.activitySubUnitId,
}; };
if (editingDataCenter) { if (editingDataCenter) {
@@ -533,16 +648,17 @@ const DataCenterManagement = () => {
// Handle specific error cases // Handle specific error cases
if (error.message?.includes("duplicate")) { if (error.message?.includes("duplicate")) {
enqueueSnackbar(t("DataCenter.duplicateExternalId"), { variant: "error" }); enqueueSnackbar(t("DataCenter.duplicateExternalId"), {
variant: "error",
});
} else if (error.message?.includes("permission")) { } else if (error.message?.includes("permission")) {
enqueueSnackbar(t("Common.noPermission"), { variant: "error" }); enqueueSnackbar(t("Common.noPermission"), { variant: "error" });
} else if (error.message?.includes("not found")) { } else if (error.message?.includes("not found")) {
enqueueSnackbar(t("DataCenter.resourceNotFound"), { variant: "error" }); enqueueSnackbar(t("DataCenter.resourceNotFound"), { variant: "error" });
} else { } else {
enqueueSnackbar( enqueueSnackbar(error?.message || t("DataCenter.submitError"), {
error?.message || t("DataCenter.submitError"), variant: "error",
{ variant: "error" } });
);
} }
} }
}; };
@@ -554,13 +670,28 @@ const DataCenterManagement = () => {
externalId: "", externalId: "",
number: "", number: "",
address: "", address: "",
areaId: null,
cityId: null,
latitude: null, latitude: null,
longitude: null, longitude: null,
ayposURL: "", ayposURL: "",
city: "" city: "",
emissionScopeId: null,
sectorId: null,
subSectorId: null,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null,
}); });
setMapPosition(null); setMapPosition(null);
setEditingDataCenter(null); setEditingDataCenter(null);
setSelectedSector(null);
setSelectedSubSector(null);
}; };
const handleFilter = (e) => { const handleFilter = (e) => {
@@ -594,45 +725,47 @@ const DataCenterManagement = () => {
const geocodeAddress = useCallback(async (address) => { const geocodeAddress = useCallback(async (address) => {
if (!address || !address.trim()) { if (!address || !address.trim()) {
setMapPosition(null); setMapPosition(null);
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: null, latitude: null,
longitude: null longitude: null,
})); }));
return false; return false;
} }
try { try {
const response = await nominatimAxios.get(`/search?format=json&q=${encodeURIComponent(address)}`); const response = await nominatimAxios.get(
`/search?format=json&q=${encodeURIComponent(address)}`
);
if (response.data && response.data[0]) { if (response.data && response.data[0]) {
const { lat, lon } = response.data[0]; const { lat, lon } = response.data[0];
const newPosition = [parseFloat(lat), parseFloat(lon)]; const newPosition = [parseFloat(lat), parseFloat(lon)];
setMapPosition(newPosition); setMapPosition(newPosition);
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: parseFloat(lat), latitude: parseFloat(lat),
longitude: parseFloat(lon) longitude: parseFloat(lon),
})); }));
return true; return true;
} }
// If no results found, clear the coordinates // If no results found, clear the coordinates
setMapPosition(null); setMapPosition(null);
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: null, latitude: null,
longitude: null longitude: null,
})); }));
return false; return false;
} catch (error) { } catch (error) {
console.error('Error geocoding address:', error); console.error("Error geocoding address:", error);
// On error, clear the coordinates // On error, clear the coordinates
setMapPosition(null); setMapPosition(null);
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: null, latitude: null,
longitude: null longitude: null,
})); }));
return false; return false;
} }
@@ -641,18 +774,18 @@ const DataCenterManagement = () => {
// Update the address input handler // Update the address input handler
const handleAddressChange = (e) => { const handleAddressChange = (e) => {
const newAddress = e.target.value; const newAddress = e.target.value;
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
address: newAddress address: newAddress,
})); }));
// If address is empty, clear the coordinates // If address is empty, clear the coordinates
if (!newAddress.trim()) { if (!newAddress.trim()) {
setMapPosition(null); setMapPosition(null);
setSelectedDataCenter(prev => ({ setSelectedDataCenter((prev) => ({
...prev, ...prev,
latitude: null, latitude: null,
longitude: null longitude: null,
})); }));
} else { } else {
// If address is not empty, try to geocode it after a delay // If address is not empty, try to geocode it after a delay
@@ -675,9 +808,7 @@ const DataCenterManagement = () => {
size="lg" size="lg"
> >
<ModalHeader toggle={handleCloseModal}> <ModalHeader toggle={handleCloseModal}>
{editingDataCenter {editingDataCenter ? t("DataCenter.edit") : t("DataCenter.add")}
? t("DataCenter.edit")
: t("DataCenter.add")}
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
<Form> <Form>
@@ -685,7 +816,8 @@ const DataCenterManagement = () => {
<Col sm="12"> <Col sm="12">
<FormGroup> <FormGroup>
<Label for="name"> <Label for="name">
{t("DataCenter.name")} <span className="text-danger">*</span> {t("DataCenter.name")}{" "}
<span className="text-danger">*</span>
</Label> </Label>
<Input <Input
type="text" type="text"
@@ -705,7 +837,8 @@ const DataCenterManagement = () => {
<Col sm="6"> <Col sm="6">
<FormGroup> <FormGroup>
<Label for="externalId"> <Label for="externalId">
{t("DataCenter.externalId")} <span className="text-danger">*</span> {t("DataCenter.externalId")}{" "}
<span className="text-danger">*</span>
</Label> </Label>
<Input <Input
type="text" type="text"
@@ -817,7 +950,9 @@ const DataCenterManagement = () => {
{/* Emission Scope Section */} {/* Emission Scope Section */}
<Col sm="12"> <Col sm="12">
<h5 className="mt-3 mb-2 text-primary">Emission Scope Configuration</h5> <h5 className="mt-3 mb-2 text-primary">
Emission Scope Configuration
</h5>
</Col> </Col>
<Col sm="6"> <Col sm="6">
<FormGroup> <FormGroup>
@@ -828,7 +963,8 @@ const DataCenterManagement = () => {
placeholder="Select emission scope" placeholder="Select emission scope"
options={emissionScopesOptions} options={emissionScopesOptions}
value={emissionScopesOptions?.find( value={emissionScopesOptions?.find(
(option) => option.value === selectedDataCenter.emissionScopeId (option) =>
option.value === selectedDataCenter.emissionScopeId
)} )}
onChange={(option) => onChange={(option) =>
setSelectedDataCenter({ setSelectedDataCenter({
@@ -843,7 +979,9 @@ const DataCenterManagement = () => {
</Col> </Col>
<Col sm="6"> <Col sm="6">
<FormGroup> <FormGroup>
<Label for="sector">Sector <span className="text-danger">*</span></Label> <Label for="sector">
Sector <span className="text-danger">*</span>
</Label>
<Select <Select
id="sector" id="sector"
name="sector" name="sector"
@@ -858,8 +996,13 @@ const DataCenterManagement = () => {
...selectedDataCenter, ...selectedDataCenter,
sectorId: option?.value, sectorId: option?.value,
subSectorId: null, subSectorId: null,
emissionSourceId: null, dataCenterEmissionSources: [
consuptionUnitId: null, {
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null, activitySubUnitId: null,
}); });
}} }}
@@ -877,15 +1020,21 @@ const DataCenterManagement = () => {
placeholder="Select sub sector" placeholder="Select sub sector"
options={subSectorsOptions} options={subSectorsOptions}
value={subSectorsOptions?.find( value={subSectorsOptions?.find(
(option) => option.value === selectedDataCenter.subSectorId (option) =>
option.value === selectedDataCenter.subSectorId
)} )}
onChange={(option) => { onChange={(option) => {
setSelectedSubSector(option?.value); setSelectedSubSector(option?.value);
setSelectedDataCenter({ setSelectedDataCenter({
...selectedDataCenter, ...selectedDataCenter,
subSectorId: option?.value, subSectorId: option?.value,
emissionSourceId: null, dataCenterEmissionSources: [
consuptionUnitId: null, {
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null, activitySubUnitId: null,
}); });
}} }}
@@ -895,51 +1044,236 @@ const DataCenterManagement = () => {
/> />
</FormGroup> </FormGroup>
</Col> </Col>
<Col sm="6"> <Col sm="12">
<FormGroup> <FormGroup>
<Label for="emissionSource">Emission Source</Label> <Label>Emission Sources & Consumption Units</Label>
<Select <div className="border rounded p-3 bg-light">
id="emissionSource" <div className="d-flex justify-content-between align-items-center mb-3">
name="emissionSource" <small className="text-muted">
placeholder="Select emission source" Configure emission sources for this data center. At
options={emissionSourcesOptions} least one emission source with consumption unit is
value={emissionSourcesOptions?.find( required.
(option) => option.value === selectedDataCenter.emissionSourceId </small>
<Button
color="primary"
size="sm"
onClick={() => {
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: [
...selectedDataCenter.dataCenterEmissionSources,
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: false,
},
],
});
}}
disabled={!selectedDataCenter.subSectorId}
className="d-none d-sm-flex"
>
<Plus size={14} className="me-1" />
Add Source
</Button>
</div>
{selectedDataCenter.dataCenterEmissionSources.map(
(source, index) => (
<div
key={index}
className="border rounded p-3 mb-3 bg-white"
>
<Row className="g-3">
<Col xs="12" md="6">
<Label
for={`emissionSource-${index}`}
className="form-label fw-bold"
>
Emission Source *
</Label>
<Select
id={`emissionSource-${index}`}
placeholder="Select emission source..."
options={emissionSourcesOptions}
value={emissionSourcesOptions?.find(
(option) =>
option.value === source.emissionSourceId
)}
onChange={(option) => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
updatedSources[index] = {
...updatedSources[index],
emissionSourceId: option?.value,
consuptionUnitId: null, // Reset consumption unit when emission source changes
};
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: updatedSources,
});
// Fetch consumption units for the selected emission source
if (option?.value) {
dispatch(
getConsuptionUnits({
id: option.value,
sector: selectedDataCenter?.sectorId,
})
);
}
}}
isClearable
filterOption={customFilterForSelect}
isDisabled={!selectedDataCenter.subSectorId}
styles={{
placeholder: (provided) => ({
...provided,
color: "#6e6b7b",
}),
}}
menuPlacement="auto"
/>
</Col>
<Col xs="12" md="6">
<Label
for={`consuptionUnit-${index}`}
className="form-label fw-bold"
>
Consumption Unit *
</Label>
<Select
id={`consuptionUnit-${index}`}
placeholder="Select consumption unit..."
options={consuptionUnitsOptions}
value={consuptionUnitsOptions?.find(
(option) =>
option.value === source.consuptionUnitId
)}
onChange={(option) => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
updatedSources[index] = {
...updatedSources[index],
consuptionUnitId: option?.value,
};
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: updatedSources,
});
}}
isClearable
filterOption={customFilterForSelect}
isDisabled={!source.emissionSourceId}
styles={{
placeholder: (provided) => ({
...provided,
color: "#6e6b7b",
}),
}}
menuPlacement="auto"
/>
</Col>
</Row>
<Row className="mt-3">
<Col xs="12">
<div className="d-flex flex-column flex-sm-row gap-2 justify-content-between align-items-start align-items-sm-center">
<div className="d-flex gap-2 flex-wrap">
<Button
color={
source.isDefault
? "primary"
: "outline-secondary"
}
size="sm"
onClick={() => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
// First, set all sources to not default
updatedSources.forEach(
(s) => (s.isDefault = false)
);
// Then set the selected one as default
updatedSources[index].isDefault = true;
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources:
updatedSources,
});
}}
title="Set as default emission source"
>
{source.isDefault
? "★ Default"
: "☆ Set Default"}
</Button>
{source.isDefault && (
<span className="badge bg-success align-self-center">
Default Source
</span>
)}
</div>
<Button
color="outline-danger"
size="sm"
onClick={() => {
const updatedSources =
selectedDataCenter.dataCenterEmissionSources.filter(
(_, i) => i !== index
);
// If we're removing the default source and there are other sources, make the first one default
if (
source.isDefault &&
updatedSources.length > 0
) {
updatedSources[0].isDefault = true;
}
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: updatedSources,
});
}}
disabled={
selectedDataCenter.dataCenterEmissionSources
.length === 1
}
title="Remove emission source"
>
<Trash size={14} className="me-1" />
Remove
</Button>
</div>
</Col>
</Row>
</div>
)
)} )}
onChange={(option) => { <div className="text-center mt-3">
setSelectedDataCenter({ <Button
...selectedDataCenter, color="primary"
emissionSourceId: option?.value, size="sm"
consuptionUnitId: null, onClick={() => {
}); setSelectedDataCenter({
}} ...selectedDataCenter,
isClearable dataCenterEmissionSources: [
filterOption={customFilterForSelect} ...selectedDataCenter.dataCenterEmissionSources,
isDisabled={!selectedDataCenter.subSectorId} {
/> emissionSourceId: null,
</FormGroup> consuptionUnitId: null,
</Col> isDefault: false,
<Col sm="6"> },
<FormGroup> ],
<Label for="consuptionUnit">Consumption Unit</Label> });
<Select }}
id="consuptionUnit" disabled={!selectedDataCenter.subSectorId}
name="consuptionUnit" className="w-100 d-sm-none"
placeholder="Select consumption unit" >
options={consuptionUnitsOptions} <Plus size={14} className="me-1" />
value={consuptionUnitsOptions?.find( Add Another Emission Source
(option) => option.value === selectedDataCenter.consuptionUnitId </Button>
)} </div>
onChange={(option) => { </div>
setSelectedDataCenter({
...selectedDataCenter,
consuptionUnitId: option?.value,
});
}}
isClearable
filterOption={customFilterForSelect}
isDisabled={!selectedDataCenter.emissionSourceId}
/>
</FormGroup> </FormGroup>
</Col> </Col>
<Col sm="12"> <Col sm="12">
@@ -948,10 +1282,11 @@ const DataCenterManagement = () => {
<Select <Select
id="activitySubUnit" id="activitySubUnit"
name="activitySubUnit" name="activitySubUnit"
placeholder="Select activity sub unit" placeholder="Select activity sub unit..."
options={activitySubUnitsOptions} options={activitySubUnitsOptions}
value={activitySubUnitsOptions?.find( value={activitySubUnitsOptions?.find(
(option) => option.value === selectedDataCenter.activitySubUnitId (option) =>
option.value === selectedDataCenter.activitySubUnitId
)} )}
onChange={(option) => { onChange={(option) => {
setSelectedDataCenter({ setSelectedDataCenter({
@@ -962,6 +1297,7 @@ const DataCenterManagement = () => {
isClearable isClearable
filterOption={customFilterForSelect} filterOption={customFilterForSelect}
isDisabled={!selectedDataCenter.subSectorId} isDisabled={!selectedDataCenter.subSectorId}
menuPlacement="top"
/> />
</FormGroup> </FormGroup>
</Col> </Col>
@@ -986,7 +1322,7 @@ const DataCenterManagement = () => {
setSelectedDataCenter({ setSelectedDataCenter({
...selectedDataCenter, ...selectedDataCenter,
latitude: pos[0], latitude: pos[0],
longitude: pos[1] longitude: pos[1],
}); });
}} }}
setSelectedDataCenter={setSelectedDataCenter} setSelectedDataCenter={setSelectedDataCenter}
@@ -1002,14 +1338,13 @@ const DataCenterManagement = () => {
<Button <Button
color="primary" color="primary"
onClick={handleSubmit} onClick={handleSubmit}
disabled={!selectedDataCenter.name || !selectedDataCenter.externalId} disabled={
!selectedDataCenter.name || !selectedDataCenter.externalId
}
> >
{t("Common.save")} {t("Common.save")}
</Button> </Button>
<Button <Button color="secondary" onClick={handleCloseModal}>
color="secondary"
onClick={handleCloseModal}
>
{t("Common.cancel")} {t("Common.cancel")}
</Button> </Button>
</ModalFooter> </ModalFooter>
@@ -1083,9 +1418,7 @@ const DataCenterManagement = () => {
progressPending={dataCenterStore?.loading} progressPending={dataCenterStore?.loading}
progressComponent={<div className="text-center p-3">Loading...</div>} progressComponent={<div className="text-center p-3">Loading...</div>}
noDataComponent={ noDataComponent={
<div className="p-2 text-center"> <div className="p-2 text-center">{t("Common.noDataAvailable")}</div>
{t("Common.noDataAvailable")}
</div>
} }
/> />
</div> </div>

View File

@@ -263,7 +263,7 @@ const EmissionSource = () => {
?.totalElements / rowsPerPage ?.totalElements / rowsPerPage
).toFixed(1) ).toFixed(1)
); );
//asdaasdasd
return ( return (
<ReactPaginate <ReactPaginate
previousLabel={""} previousLabel={""}

View File

@@ -1,56 +1,157 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useMemo } from "react";
import { MaterialReactTable } from "material-react-table"; import { MaterialReactTable } from "material-react-table";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Card, CardHeader, CardTitle, Alert } from "reactstrap"; import {
Card,
CardHeader,
CardTitle,
Alert,
Row,
Col,
Label,
} from "reactstrap";
import { getVMEmissionSummary } from "../../redux/actions/mainDataTables/index"; import { getVMEmissionSummary } from "../../redux/actions/mainDataTables/index";
import { getDataCenters } from "../../redux/actions/dataCenter";
import { editNumbers } from "../../components/edit-numbers"; import { editNumbers } from "../../components/edit-numbers";
import Select from "react-select";
function MainDataTables() { function MainDataTables() {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useDispatch(); const dispatch = useDispatch();
const mainDataTablesStore = useSelector((state) => state.mainDataTables); const mainDataTablesStore = useSelector((state) => state.mainDataTables);
const dataCenterStore = useSelector((state) => state.dataCenter);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [selectedDataCenter, setSelectedDataCenter] = useState(null);
const [dataCenterOptions, setDataCenterOptions] = useState([]);
const [loading, setLoading] = useState(false);
// Fetch datacenters on component mount
useEffect(() => { useEffect(() => {
const fetchData = async () => { dispatch(getDataCenters());
try {
setLoading(true);
await dispatch(getVMEmissionSummary());
} catch (err) {
console.error('Error in MainDataTables:', err);
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [dispatch]); }, [dispatch]);
// Debug log for store data // Update datacenter options when datacenters are loaded
useEffect(() => { useEffect(() => {
console.log('Current store data:', mainDataTablesStore); if (dataCenterStore?.dataCenters?.length > 0) {
}, [mainDataTablesStore]); const options = dataCenterStore.dataCenters.map((dataCenter) => ({
value: dataCenter.id,
label: dataCenter.dataCenter,
externalId: dataCenter.externalId,
}));
setDataCenterOptions(options);
}
}, [dataCenterStore?.dataCenters]);
const [loading, setLoading] = useState(true); // Fetch VM emission data when datacenter is selected
useEffect(() => {
if (selectedDataCenter?.value) {
const fetchData = async () => {
try {
setLoading(true);
setError(null);
await dispatch(getVMEmissionSummary(selectedDataCenter.value));
} catch (err) {
console.error("Error in MainDataTables:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}
}, [selectedDataCenter, dispatch]);
const columns = [ // Memoize columns to prevent re-renders
{ header: t("VM ID"), accessorKey: "vmId", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, const columns = useMemo(
{ header: t("VM Name"), accessorKey: "vmName", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, () => [
{ header: t("VM Power"), accessorKey: "vmPower", Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span> }, {
{ header: t("VM Status"), accessorKey: "vmStatus", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, header: t("VM ID"),
{ header: t("Total Emission"), accessorKey: "totalEmission", Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span> }, accessorKey: "vmId",
{ header: t("Created Date"), accessorKey: "createdDate", Cell: ({ cell }) => (<span>{cell.getValue() ? new Date(cell.getValue()).toLocaleString() : "-"}</span>), sortable: true }, size: 150,
{ header: t("Physical Machine"), accessorKey: "physicalMachine", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
{ header: t("Project"), accessorKey: "project", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, },
{ header: t("Data Center"), accessorKey: "dataCenter", Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span> }, {
{ header: "CO2", accessorKey: "co2", Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span> }, header: t("VM Name"),
{ header: "CH4", accessorKey: "ch4", Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span> }, accessorKey: "vmName",
{ header: "N2O", accessorKey: "n2o", Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span> }, size: 200,
]; Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: t("VM Power"),
accessorKey: "vmPower",
size: 120,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: t("VM Status"),
accessorKey: "vmStatus",
size: 100,
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: t("Total Emission"),
accessorKey: "totalEmission",
size: 150,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: t("Physical Machine"),
accessorKey: "physicalMachine",
size: 150,
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: t("Cloud System"),
accessorKey: "cloudSystem",
size: 150,
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: t("Data Center"),
accessorKey: "dataCenter",
size: 150,
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "CO2",
accessorKey: "co2",
size: 100,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "CH4",
accessorKey: "ch4",
size: 100,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "N2O",
accessorKey: "n2o",
size: 100,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: t("Created Date"),
accessorKey: "createdDate",
size: 180,
Cell: ({ cell }) => (
<span>
{cell.getValue() ? new Date(cell.getValue()).toLocaleString() : "-"}
</span>
),
sortable: true,
},
],
[t]
);
const tableData = mainDataTablesStore?.vmEmissionSummary || []; // Memoize table data to prevent unnecessary re-renders
console.log('VM Emission data:', tableData); const tableData = useMemo(() => {
const data = mainDataTablesStore?.vmEmissionSummary || [];
console.log("VM Emission data count:", data.length);
return data;
}, [mainDataTablesStore?.vmEmissionSummary]);
if (error) { if (error) {
return ( return (
@@ -65,38 +166,108 @@ function MainDataTables() {
<Card> <Card>
<CardHeader className="border-bottom"> <CardHeader className="border-bottom">
<CardTitle tag="h4">{t("Raw Data")}</CardTitle> <CardTitle tag="h4">{t("Raw Data")}</CardTitle>
{tableData.length > 0 && (
<small className="text-muted">
{tableData.length} records loaded
</small>
)}
</CardHeader> </CardHeader>
<MaterialReactTable
columns={columns} {/* Datacenter Selection */}
data={tableData} <div className="p-3 border-bottom">
enableColumnFilters={true} <Row>
enableFilters={true} <Col md="6">
enableGlobalFilter={true} <Label for="datacenter-select">{t("Data Center")}</Label>
enablePagination={true} <Select
enableColumnResizing={true} id="datacenter-select"
enableStickyHeader={true} value={selectedDataCenter}
muiTableContainerProps={{ sx: { maxHeight: 'calc(100vh - 180px)' } }} onChange={setSelectedDataCenter}
muiTableProps={{ options={dataCenterOptions}
sx: { placeholder={t("Select a data center...")}
tableLayout: 'auto', isClearable
}, isSearchable
}} isLoading={dataCenterStore?.loading}
initialState={{ noOptionsMessage={() => t("No data centers available")}
pagination: { styles={{
pageSize: 100, menu: (provided) => ({
pageIndex: 0 ...provided,
}, zIndex: 9999, // Ensure dropdown appears above other elements
sorting: [ }),
{ id: 'createdDate', desc: true } }}
], menuPortalTarget={document.body} // Render dropdown in body to avoid container overflow
density: 'compact' />
}} </Col>
state={{ </Row>
isLoading: loading, </div>
showProgressBars: true,
showSkeletons: true, {selectedDataCenter ? (
}} <MaterialReactTable
/> columns={columns}
data={tableData}
// Performance optimizations for large datasets
enableColumnFilters={true}
enableFilters={true}
enableGlobalFilter={true}
enablePagination={true}
enableColumnResizing={true} // Disable resizing for better performance
enableStickyHeader={true}
enableRowVirtualization={true} // Enable virtualization for large datasets
enableColumnVirtualization={false} // Keep columns visible
// Pagination settings for large datasets
initialState={{
pagination: {
pageSize: 100, // Reduce page size for better performance
pageIndex: 0,
},
sorting: [{ id: "createdDate", desc: true }],
density: "compact",
}}
// Performance-optimized table props
muiTableContainerProps={{
sx: {
maxHeight: "calc(100vh - 250px)",
minHeight: "400px",
},
}}
muiTableProps={{
sx: {
tableLayout: "fixed", // Better performance with fixed layout
},
}}
// Pagination options
muiTablePaginationProps={{
rowsPerPageOptions: [10, 25, 50, 100],
showFirstButton: true,
showLastButton: true,
}}
// Loading and error states
state={{
isLoading: loading || mainDataTablesStore?.loading,
showProgressBars: loading || mainDataTablesStore?.loading,
showSkeletons: loading || mainDataTablesStore?.loading,
}}
// Disable features that can slow down large tables
enableRowSelection={false}
enableColumnOrdering={true}
enableColumnDragging={false}
enableDensityToggle={false}
enableFullScreenToggle={false}
// Custom loading overlay
renderProgressBarCell={({ cell }) => (
<div
style={{
width: "100%",
height: "20px",
backgroundColor: "#f0f0f0",
}}
/>
)}
/>
) : (
<div className="p-4 text-center text-muted">
{t("Please select a data center to view raw data")}
</div>
)}
</Card> </Card>
</div> </div>
); );

View File

@@ -32,15 +32,87 @@ import { getCities } from "../redux/actions/cities";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { getCity } from "../redux/actions/city"; import { getCity } from "../redux/actions/city";
import { getDistrict } from "../redux/actions/district"; import { getDistrict } from "../redux/actions/district";
import { // import {
getOrganisations, // getOrganisations,
getOrganisationById, // getOrganisationById,
} from "../redux/actions/organisations"; // } from "../redux/actions/organisations";
import { getAreasWithCriteria } from "../redux/actions/areas"; import { getAreasWithCriteria } from "../redux/actions/areas";
import { ChromePicker } from "react-color"; import { ChromePicker } from "react-color";
import { customFilterForSelect } from "../utility/Utils"; import { customFilterForSelect } from "../utility/Utils";
import { permissionCheck } from "../components/permission-check"; import { permissionCheck } from "../components/permission-check";
import { getDataCenters } from "../redux/actions/dataCenter"; import { getDataCenters } from "../redux/actions/dataCenter";
import L from "leaflet";
// Custom data center icon
const dataCenterIcon = new L.Icon({
iconUrl:
"data:image/svg+xml;base64," +
btoa(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
<defs>
<linearGradient id="serverGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#4A90E2;stop-opacity:1" />
<stop offset="100%" style="stop-color:#2E5BBA;stop-opacity:1" />
</linearGradient>
<linearGradient id="rackGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#F5F5F5;stop-opacity:1" />
<stop offset="100%" style="stop-color:#E0E0E0;stop-opacity:1" />
</linearGradient>
</defs>
<!-- Main server rack -->
<rect x="8" y="4" width="32" height="40" rx="2" ry="2" fill="url(#rackGradient)" stroke="#B0B0B0" stroke-width="1"/>
<!-- Server units -->
<rect x="10" y="6" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="12" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="18" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="24" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="30" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="36" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<!-- LED indicators -->
<circle cx="13" cy="8" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="14" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="20" r="0.8" fill="#FFFF00"/>
<circle cx="13" cy="26" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="32" r="0.8" fill="#FF0000"/>
<circle cx="13" cy="38" r="0.8" fill="#00FF00"/>
<!-- Power indicators -->
<circle cx="35" cy="8" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="14" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="20" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="26" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="32" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="38" r="0.6" fill="#0080FF"/>
<!-- Ventilation grilles -->
<rect x="16" y="7" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="8.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="13" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="14.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="19" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="20.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="25" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="26.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="31" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="32.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="37" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="38.5" width="16" height="0.5" fill="#1A4A8A"/>
<!-- Base/feet -->
<rect x="6" y="42" width="4" height="2" rx="1" fill="#808080"/>
<rect x="38" y="42" width="4" height="2" rx="1" fill="#808080"/>
<!-- Shadow -->
<ellipse cx="24" cy="45" rx="18" ry="2" fill="#000000" opacity="0.2"/>
</svg>
`),
iconSize: [48, 48],
iconAnchor: [18, 36],
popupAnchor: [0, -36],
});
const ColorPicker = ({ selectedColors, setSelectedColors, index }) => { const ColorPicker = ({ selectedColors, setSelectedColors, index }) => {
const [showColorPicker, setShowColorPicker] = useState(false); const [showColorPicker, setShowColorPicker] = useState(false);
@@ -117,20 +189,20 @@ const Map = () => {
const citiesStore = useSelector((state) => state.cities); const citiesStore = useSelector((state) => state.cities);
const cityStore = useSelector((state) => state.city); const cityStore = useSelector((state) => state.city);
const districtStore = useSelector((state) => state.district); const districtStore = useSelector((state) => state.district);
const OrganisationsStore = useSelector((state) => state.organizations); // const OrganisationsStore = useSelector((state) => state.organizations);
const areasStore = useSelector((state) => state.areas); const areasStore = useSelector((state) => state.areas);
const dataCenterStore = useSelector((state) => state.dataCenter); const dataCenterStore = useSelector((state) => state.dataCenter);
const [cities, setCities] = useState([]); const [cities, setCities] = useState([]);
const [districts, setDistricts] = useState([]); const [districts, setDistricts] = useState([]);
const [neighborhoods, setNeighborhoods] = useState([]); const [neighborhoods, setNeighborhoods] = useState([]);
const [organizationOptions, setOrganizationOptions] = useState([]); // const [organizationOptions, setOrganizationOptions] = useState([]);
const organizationId = localStorage.getItem("organizationId"); // const organizationId = localStorage.getItem("organizationId");
const roleTag = localStorage.getItem("roleTag"); // const roleTag = localStorage.getItem("roleTag");
const [selectedOrganization, setSelectedOrganization] = useState({ // const [selectedOrganization, setSelectedOrganization] = useState({
label: localStorage.getItem("organizationName"), // label: localStorage.getItem("organizationName"),
value: organizationId, // value: organizationId,
}); // });
const [areasOptions, setAreasOptions] = useState([]); const [areasOptions, setAreasOptions] = useState([]);
const [done, setDone] = useState(false); const [done, setDone] = useState(false);
@@ -146,7 +218,7 @@ const Map = () => {
const [showDataInputModal, setShowDataInputModal] = useState(false); const [showDataInputModal, setShowDataInputModal] = useState(false);
const [inputData, setInputData] = useState({ const [inputData, setInputData] = useState({
organization: selectedOrganization, // organization: selectedOrganization,
}); });
const [referance, setReferance] = useState( const [referance, setReferance] = useState(
Number(localStorage.getItem("referance")) || 1000 Number(localStorage.getItem("referance")) || 1000
@@ -176,15 +248,17 @@ const Map = () => {
dispatch(getDataCenters()); dispatch(getDataCenters());
}, []); }, []);
useEffect(() => { // useEffect(() => {
if (selectedOrganization?.value != "undefined") { // if (selectedOrganization?.value != "undefined") {
dispatch(getAreasWithCriteria(selectedOrganization.value)); // dispatch(getAreasWithCriteria(selectedOrganization.value));
} // }
}, [selectedOrganization]); // }, [selectedOrganization]);
useEffect(() => { useEffect(() => {
setAreasOptions([]); setAreasOptions([]);
// Load all areas without organization filter for now
// You may want to add organization filtering back later if needed
const citiesOptions = const citiesOptions =
areasStore?.areasWithCriteria areasStore?.areasWithCriteria
?.map((area) => ?.map((area) =>
@@ -235,13 +309,13 @@ const Map = () => {
]); ]);
}, [areasStore]); }, [areasStore]);
useEffect(() => { // useEffect(() => {
if (roleTag === "SUPER_ADMIN") { // if (roleTag === "SUPER_ADMIN") {
dispatch(getOrganisations()); // dispatch(getOrganisations());
} else { // } else {
dispatch(getOrganisationById(organizationId)); // dispatch(getOrganisationById(organizationId));
} // }
}, []); // }, []);
const handleDataInputButtonPressed = ({ area, type }) => { const handleDataInputButtonPressed = ({ area, type }) => {
const areaName = const areaName =
@@ -348,38 +422,38 @@ const Map = () => {
}); });
}, [selectedDistrict, districtStore?.district, year.value]); }, [selectedDistrict, districtStore?.district, year.value]);
useEffect(() => { // useEffect(() => {
let organizationOptions = []; // let organizationOptions = [];
if ( // if (
OrganisationsStore.organization && // OrganisationsStore.organization &&
OrganisationsStore.organization.length !== 0 // OrganisationsStore.organization.length !== 0
) { // ) {
organizationOptions.push({ // organizationOptions.push({
value: OrganisationsStore.organization.id, // value: OrganisationsStore.organization.id,
label: OrganisationsStore.organization.tag, // label: OrganisationsStore.organization.tag,
}); // });
if (OrganisationsStore.organization.children) { // if (OrganisationsStore.organization.children) {
organizationOptions = [ // organizationOptions = [
...organizationOptions, // ...organizationOptions,
...OrganisationsStore.organization.children.map((organization) => ({ // ...OrganisationsStore.organization.children.map((organization) => ({
value: organization.child.id, // value: organization.child.id,
label: organization.child.tag, // label: organization.child.tag,
})), // })),
]; // ];
} // }
} else { // } else {
organizationOptions = OrganisationsStore.dataOrganization.map( // organizationOptions = OrganisationsStore.dataOrganization.map(
(organization) => ({ // (organization) => ({
value: organization.id, // value: organization.id,
label: organization.tag, // label: organization.tag,
}) // })
); // );
} // }
setOrganizationOptions(organizationOptions); // setOrganizationOptions(organizationOptions);
}, [OrganisationsStore]); // }, [OrganisationsStore]);
const renderDataInputModal = () => { const renderDataInputModal = () => {
return ( return (
@@ -628,24 +702,55 @@ const Map = () => {
<Marker <Marker
key={dc.id} key={dc.id}
position={[dc.latitude, dc.longitude]} position={[dc.latitude, dc.longitude]}
icon={dataCenterIcon}
> >
<Popup> <Popup>
<div className="data-center-popup"> <div className="data-center-popup">
<h5 className="mb-2">{dc.dataCenter}</h5> <h5 className="mb-2 text-primary">{dc.dataCenter}</h5>
<p className="mb-1"><strong>{t('DataCenter.number')}:</strong> {dc.number}</p> <div className="mb-2">
<p className="mb-1"><strong>{t('DataCenter.externalId')}:</strong> {dc.externalId}</p>
<p className="mb-1"><strong>{t('DataCenter.city')}:</strong> {dc.area?.cities?.map(city => city.name).join(', ') || "-"}</p>
{dc.area && <p className="mb-1"><strong>{t('Area')}:</strong> {dc.area.tag}</p>}
{dc.projects?.length > 0 && (
<p className="mb-1"> <p className="mb-1">
<strong>{t('Projects')}:</strong> {dc.projects.length} <strong>{t("DataCenter.city")}:</strong>{" "}
<span>{dc.city?.name || "-"}</span>
</p>
{dc.address && (
<p className="mb-1 small text-muted">
<strong>{t("Address")}:</strong> {dc.address}
</p>
)}
</div>
<p className="mb-1">
<strong>{t("DataCenter.number")}:</strong> {dc.number}
</p>
<p className="mb-1">
<strong>{t("DataCenter.externalId")}:</strong>{" "}
{dc.externalId}
</p>
{dc.area && (
<p className="mb-1">
<strong>{t("Area")}:</strong> {dc.area.tag}
</p>
)}
{dc.physicalMachines?.length > 0 && (
<p className="mb-1">
<strong>{t("Physical Machines")}:</strong>{" "}
<span className="badge badge-secondary">
{dc.physicalMachines.length}
</span>
</p>
)}
{dc.dataCenterEmissionSources?.length > 0 && (
<p className="mb-1">
<strong>{t("EmissionSources.emissionSources")}:</strong>{" "}
<span className="badge badge-info">
{dc.dataCenterEmissionSources.length}
</span>
</p> </p>
)} )}
{dc.ayposURL && ( {dc.ayposURL && (
<Button <Button
className="w-100 mb-1" className="w-100 mb-1"
color="primary" color="primary"
onClick={() => window.open(dc.ayposURL, '_blank')} onClick={() => window.open(dc.ayposURL, "_blank")}
> >
Dashboard Dashboard
</Button> </Button>
@@ -699,7 +804,9 @@ const Map = () => {
setDistrictView(true); setDistrictView(true);
setZoom(8.0); setZoom(8.0);
let convertCordinates = convertCoordinates(city.coordinates); let convertCordinates = convertCoordinates(
city.coordinates
);
let length = convertCordinates[0][0][0].length; let length = convertCordinates[0][0][0].length;
let mlength = ((length + 1) / 2).toFixed(0); let mlength = ((length + 1) / 2).toFixed(0);
let lat1 = convertCordinates[0][0][0][0]; let lat1 = convertCordinates[0][0][0][0];
@@ -710,7 +817,7 @@ const Map = () => {
lat: ((lat1 + lat2) / 2).toFixed(2), lat: ((lat1 + lat2) / 2).toFixed(2),
lng: ((lng1 + lng2) / 2).toFixed(2), lng: ((lng1 + lng2) / 2).toFixed(2),
}); });
} },
}} }}
> >
<Tooltip permanent direction="center"> <Tooltip permanent direction="center">