238 Commits

Author SHA1 Message Date
b64abe3a3a harbor test v2 2026-03-10 12:11:40 +03:00
abdelbari
54dcb584d6 test: trigger harbor push for backend 2026-03-10 08:30:33 +00:00
b6a4f0e303 Merge pull request 'fix: use internal IP for Harbor and add network-resilient fetch' (#16) from fix/harbor-connection-port into main
Reviewed-on: Abdulbari/sgeUpdated#16
2026-03-10 11:25:25 +03:00
abdelbari
e0c8286475 fix: use internal IP for Harbor and add network-resilient fetch 2026-03-10 08:19:13 +00:00
1ebf2f2f9d Merge pull request 'fix/harbor-connection-port' (#15) from fix/harbor-connection-port into main
Reviewed-on: Abdulbari/sgeUpdated#15
2026-03-10 10:42:58 +03:00
abdelbari
4ddffb6fff chore: update harbor registry to 10.150.1.166:8085 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: Abdulbari/sgeUpdated#14
2026-03-09 14:07:36 +03:00
d4ffcb9438 harbor test v 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: Abdulbari/sgeUpdated#13
2025-10-30 20:23:54 +03:00
7976d56552 Update sge-backend/src/main/java/com/sgs/SgsApplication.java 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: Abdulbari/sgeUpdated#12
2025-10-30 20:12:13 +03:00
fcc5edcbe2 Update sge-frontend/package.json 2025-10-30 20:11:53 +03:00
8f41ce3d51 Merge pull request 'Test branch' (#11) from test into main
Reviewed-on: Abdulbari/sgeUpdated#11
2025-10-30 20:11:09 +03:00
abdelbari
4ea1cfa9b4 Test branch 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: Abdulbari/sgeUpdated#4
2025-10-30 19:31:36 +03:00
853230e742 Update sge-frontend/package.json 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: Abdulbari/sgeUpdated#3
2025-10-30 19:23:16 +03:00
1174707918 Update sge-frontend/src/views/DataSet/EmissionSource.js 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 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: Abdulbari/sgeUpdated#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
All checks were successful
sgeUpdated CI/CD / deploy (push) Successful in 7s
2025-10-30 18:54:48 +03:00
4a9b65cc30 Update .gitea/workflows/sgeupdated.yml 2025-10-30 18:46:25 +03:00
472a5daf09 Update sge-frontend/src/views/Communication.js 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 2025-10-28 18:56:54 +03:00
caa0549983 Update sge-frontend/package.json 2025-10-28 18:46:42 +03:00
4400572a45 Update sge-frontend/package.json 2025-10-28 18:41:04 +03:00
04ee05a96b Update sge-frontend/package.json 2025-10-28 18:20:22 +03:00
7580bf7cdb Update sge-frontend/README.md 2025-10-28 18:06:28 +03:00
0d017c0a4b Update sge-frontend/package.json 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 2025-10-28 16:42:50 +03:00
8b82b44591 Update sge-backend/pom.xml 2025-10-28 16:41:26 +03:00
5c534314df Update sge-backend/README.md 2025-10-28 16:40:53 +03:00
dde5fece3b Update sge-backend/README.md 2025-10-28 16:31:43 +03:00
f3b893f05c Update sge-backend/README.md 2025-10-28 16:19:26 +03:00
08e8badae2 Update sge-backend/README.md 2025-10-28 16:02:04 +03:00
dd1083db82 Update .gitea/workflows/sgeupdated.yml 2025-10-28 15:33:14 +03:00
fad8037371 Update sgeupdated pipeline v25+ 2025-10-28 15:04:50 +03:00
61faf1bf46 Update sge-backend/README.md 2025-10-27 18:39:50 +03:00
230c4bcb6e Update sge-backend/README.md 2025-10-27 17:53:46 +03:00
cbe2660080 Update sgeupdated pipeline v25
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 2025-10-25 23:53:46 +03:00
f585763563 Update .gitea/workflows/sgeupdated.yml 2025-10-25 23:52:38 +03:00
7bee15a901 Update sge-frontend/README.md 2025-10-24 18:04:13 +03:00
1ae3d76781 Update sgeupdated pipeline v22-+ 2025-10-24 18:03:14 +03:00
53d5bf2e77 Update sge-frontend/README.md 2025-10-24 17:57:15 +03:00
60e50dc9e8 Update .gitea/workflows/sgeupdated.yml 2025-10-24 17:50:36 +03:00
aaf116ca71 Update .gitea/workflows/sgeupdated.yml 2025-10-24 17:47:44 +03:00
061c0cb376 Update sgeupdated pipeline v22- 2025-10-24 17:46:55 +03:00
bd155fadb2 Update sge-backend/README.md 2025-10-24 17:32:23 +03:00
11541714f5 Update sge-frontend/README.md 2025-10-24 17:07:27 +03:00
91559134cd Update sge-backend/README.md 2025-10-24 17:03:16 +03:00
d26ca12e0c Update sgeupdated pipeline v22- 2025-10-24 15:35:57 +03:00
18c8c49a3d Update sge-frontend/README.md 2025-10-24 15:28:43 +03:00
97253a54eb Update sge-backend/README.md 2025-10-24 15:26:53 +03:00
f411f44006 Update sgeupdated pipeline v22 2025-10-24 15:21:53 +03:00
f4f4fb976b Update sgeupdated pipeline v22+ 2025-10-24 15:19:57 +03:00
385eda2132 Update sgeupdated pipeline v22 2025-10-24 15:13:23 +03:00
23a3d8252e Update sge-backend/pom.xml 2025-10-24 15:11:40 +03:00
eeda227698 Update sgeupdated pipeline v24 2025-10-24 15:09:18 +03:00
871bcf9651 Update sgeupdated pipeline v23++++ 2025-10-23 13:04:06 +03:00
614cbe8b04 Update sgeupdated pipeline v23+++ 2025-10-23 13:01:17 +03:00
ce19adb1a0 Update sgeupdated pipeline v23++ 2025-10-23 12:56:52 +03:00
5471db463f Update sgeupdated pipeline v23+ 2025-10-23 12:47:17 +03:00
845417ee49 Update sgeupdated pipeline v23 2025-10-23 12:41:49 +03:00
1c12ac1e16 Update sge-frontend/package.json 2025-10-23 12:08:16 +03:00
eb2ec01d28 Update sgeupdated pipeline v22
new script for gitea
2025-10-23 12:06:40 +03:00
4d40015fd1 Update sge-frontend/package.json 2025-10-22 19:24:33 +03:00
c55f5ce7d1 Update sge-frontend/package.json 2025-10-22 19:17:57 +03:00
07a8973b92 Update for pipeline testing Back-end + 2025-10-22 19:07:18 +03:00
54b47eee05 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:46:53 +03:00
3f0550f9f2 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:45:08 +03:00
6499c9471e Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:42:07 +03:00
71e507c21b Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:39:28 +03:00
737fd6da53 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:34:24 +03:00
490f3b539e Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:32:24 +03:00
9c0c4c4828 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:29:51 +03:00
b28a73b4ff Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:27:20 +03:00
f087b6eb88 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:23:55 +03:00
d07932cc1e Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:21:17 +03:00
76d37d6038 Update .gitea/workflows/sgeupdated.yml 2025-10-22 18:11:36 +03:00
50abcab358 Update sgeupdated pipeline v21++++++++
Commented the backend section
2025-10-22 17:55:10 +03:00
445f9256a1 Update sgeupdated pipeline v21+++++++
Commented the backend section
2025-10-22 17:53:16 +03:00
4d1a82fe92 Update for pipeline testing Front-end v099 2025-10-22 17:12:00 +03:00
6d6e935b52 Update sgeupdated pipeline v21++++++
commenting the frontend dependencies installation
2025-10-22 17:10:24 +03:00
a51a81ce7c Update sgeupdated pipeline v21+++++
Paused the concurrency check temporally
2025-10-22 16:05:33 +03:00
3b6000bc40 Update sgeupdated pipeline v21++++ 2025-10-22 15:52:38 +03:00
78ed73acc6 Update .gitea/workflows/sgeupdated.yml 2025-10-22 15:47:39 +03:00
7f8a7b1bf8 Update sgeupdated pipeline v21++++ 2025-10-22 15:39:57 +03:00
8c6e37ad72 Update sgeupdated pipeline v21+++ 2025-10-22 15:38:04 +03:00
85151e536d Update sgeupdated pipeline v21++ 2025-10-22 15:08:02 +03:00
573db7fee9 Update sgeupdated pipeline v21+ 2025-10-22 14:49:07 +03:00
a11f9614ed Update sgeupdated pipeline v21
new condition to be added
2025-10-22 14:29:27 +03:00
02bd570573 Update sge-backend/pom.xml 2025-10-21 16:12:15 +03:00
5da26152a9 update to sgeupdated pipeline v20++++++ 2025-09-05 23:07:35 +03:00
4f4c2e2ce5 Update .gitea/workflows/sgeupdated.yml 2025-09-05 23:01:04 +03:00
79ddbf2207 Update docker-compose.yml 2025-09-05 22:59:28 +03:00
23d9e65a7f update to sgeupdated pipeline v20+++++ 2025-09-05 22:55:07 +03:00
c8f9abe5e9 update to sgeupdated pipeline v20+++++
changing in npm installation
2025-09-05 22:49:34 +03:00
fa96969bc7 update to sgeupdated pipeline v20++++ 2025-09-05 22:37:40 +03:00
dc67f75027 Update sge-frontend/nginx.conf 2025-09-05 22:01:33 +03:00
e22c880673 Update sge-backend/Dockerfile 2025-09-05 21:57:44 +03:00
b37ed8797b update to sgeupdated pipeline v20+++ 2025-09-01 05:14:58 +03:00
04ed88e45e Update for pipeline testing Back-end 2025-09-01 05:11:10 +03:00
5f8de8105b update to sgeupdated pipeline v21 2025-09-01 05:09:20 +03:00
8fb923a4db Update for pipeline testing Back-end 2025-09-01 05:01:57 +03:00
a088889a67 update to sgeupdated pipeline v20+++ 2025-09-01 04:50:38 +03:00
b3de688265 update to sgeupdated pipeline v20++ 2025-09-01 04:41:12 +03:00
080924f788 update to sgeupdated pipeline v20+ 2025-09-01 03:57:59 +03:00
e43199f086 Update sge-frontend/nginx.conf 2025-09-01 03:52:57 +03:00
49e2020455 update to sgeupdated pipeline v20 2025-09-01 03:33:42 +03:00
876227286c Update for pipeline testing Front-end v00 2025-09-01 03:28:59 +03:00
af518cef20 Update for pipeline testing Back-end 2025-09-01 03:27:48 +03:00
2e5bf41ed9 update to sgeupdated pipeline v19
changes the concept of rebuilding
2025-09-01 03:26:26 +03:00
f61199cedb Update for pipeline testing Front-end 2025-09-01 03:06:55 +03:00
5001a44406 Update for pipeline testing 2025-09-01 03:03:47 +03:00
87487510ce update to sgeupdated pipeline v18
added some feature to avoid failing when nothing is changed
2025-09-01 03:02:23 +03:00
547ade53ae update to sgeupdated pipeline v17 2025-09-01 02:57:34 +03:00
95afe7b877 Back to sgeupdated pipeline v16 2025-09-01 02:46:07 +03:00
ae0e112572 Delete smoke file 2025-09-01 02:41:02 +03:00
b35eac74a1 Update sgeupdated pipeline v17
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 2025-08-30 21:12:44 +03:00
517d4d499b Update for pipeline testing 2025-08-30 21:12:22 +03:00
1aa745ebf5 Update sgeupdated pipeline v16 2025-08-30 21:11:03 +03:00
88a312d37c Update sgeupdated pipeline v15
forgot to add the dependencies installation
2025-08-30 21:04:54 +03:00
b1019b21cf Update for pipeline testing Front-end 2025-08-30 21:02:37 +03:00
57c28e4a90 Update for pipeline testing 2025-08-30 21:02:19 +03:00
b1cf711420 Update sgeupdated pipeline v14
multiple changes applied to make the workflows works over ssh
2025-08-30 20:58:45 +03:00
1d6b026710 Update for pipeline testing 2025-08-30 20:21:33 +03:00
02e4993c2c Update for pipeline testing Front-end 2025-08-30 20:20:37 +03:00
be71b59a3e Update for pipeline testing Front-end 2025-08-30 20:11:43 +03:00
7e5761993b Update for pipeline testing Front-end 2025-08-30 04:20:34 +03:00
66bd7b5a68 Update for pipeline testing 2025-08-30 04:20:16 +03:00
206d8a2bbf Update sgeupdated pipeline v13 2025-08-30 04:14:36 +03:00
6fbca1c29a Update for pipeline testing Front-end 2025-08-30 03:41:56 +03:00
1f6b06260c Update for pipeline testing 2025-08-30 03:38:28 +03:00
b00a8e1bf1 Update Front-End after pipeline v10 2025-08-30 03:11:38 +03:00
0f01ddefe9 Update Back-End after pipeline v12 2025-08-30 03:11:13 +03:00
2116b0f28a Update Front-End after pipeline v9 2025-08-30 03:02:45 +03:00
5161286279 Update Back-End after pipeline v11 2025-08-30 03:02:19 +03:00
29963d5388 Update sgeupdated pipeline v12 2025-08-30 03:00:47 +03:00
990b98c171 Update sgeupdated pipeline v12 2025-08-30 02:58:54 +03:00
f2d5182215 Update sgeupdated pipeline v12 2025-08-30 02:57:42 +03:00
e9a361489e Update sgeupdated pipeline v12
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 2025-08-30 01:58:28 +03:00
cac67b815c Update Front-End after pipeline v8 2025-08-30 01:38:03 +03:00
28fc21e9f2 Update Back-End after pipeline v10 2025-08-30 01:37:40 +03:00
98a2515735 Update sgeupdated pipeline v11 2025-08-30 01:36:21 +03:00
4503d7c319 Update sgeupdated pipeline v11 2025-08-30 01:33:48 +03:00
e2a1b6f940 Update sgeupdated pipeline v11 2025-08-30 01:33:02 +03:00
d25a7975c7 Update sgeupdated pipeline v11 2025-08-30 01:29:50 +03:00
926c6b0b66 Update sgeupdated pipeline v11 2025-08-30 01:28:12 +03:00
986bec559b Update Front-End after pipeline v7 2025-08-30 01:14:28 +03:00
77d5c94cf7 Update Back-End after pipeline v9 2025-08-30 01:14:02 +03:00
75c2f7ff19 Update sgeupdated pipeline v10
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 2025-08-30 01:02:15 +03:00
f50803f469 Update Back-End after pipeline v8 2025-08-30 01:01:47 +03:00
adce8cddd8 Update sgeupdated pipeline v9 2025-08-29 20:17:14 +03:00
c2ddc08802 Update Front-End after pipeline v5 2025-08-29 20:11:39 +03:00
2c79300663 Update Back-End after pipeline v7 2025-08-29 20:11:17 +03:00
a6bb799caa Update sgeupdated pipeline v8 2025-08-29 20:05:03 +03:00
a4791d6a57 Update Front-End after pipeline v4 2025-08-29 19:40:12 +03:00
168cfaa8a7 Update Back-End after pipeline v6 2025-08-29 19:39:45 +03:00
710655c1fd Update docker-compose.yml 2025-08-29 19:37:41 +03:00
6f445f205a Update sgeupdated pipeline v7 2025-08-29 19:35:49 +03:00
32b9533a33 Update docker-compose.yml 2025-08-29 19:27:28 +03:00
62829194e2 Update Front-End after pipeline v3 2025-08-29 19:24:43 +03:00
87a80f63ed Update Back-End after pipeline v5 2025-08-29 19:24:21 +03:00
f12c5cb8d4 Update sgeupdated pipeline v6
Some mistakes in directory
2025-08-29 19:20:39 +03:00
7148bdf834 Update Front-End after pipeline v2 2025-08-29 19:12:06 +03:00
9eb903a450 Update Back-End after pipeline v4 2025-08-29 19:11:38 +03:00
991aef0417 Update sgeupdated pipeline v5
working on updating the docker
2025-08-29 19:09:11 +03:00
a1c0f71fbf Update Front-End after pipeline 2025-08-29 00:21:02 +03:00
64c36cb617 Update Back-End after pipeline v3 2025-08-29 00:20:41 +03:00
0f2bf5a800 Update Front-End after pipeline 2025-08-29 00:17:33 +03:00
d6375c320a Update Back-End after pipeline v3 2025-08-29 00:17:07 +03:00
3d440798e3 Update sgeupdated pipeline v4
Made a force for rebuilding the docker
2025-08-29 00:16:07 +03:00
8cdc00f921 Update sgeupdated pipeline v3 2025-08-29 00:11:13 +03:00
593e5ceb6a Update Front-End after pipeline
problem with dockerizing
2025-08-29 00:07:10 +03:00
b2eebfce64 Update Back-End after pipeline v2
problem with not dockerizing
2025-08-29 00:06:18 +03:00
c3ed359103 Update sgeupdated pipeline v3
a typo in docker names for front-end and back-end
2025-08-29 00:02:27 +03:00
7b4143ba52 Update sgeupdated pipeline v3
problem in restarting docker
2025-08-28 23:56:54 +03:00
0322235404 Update Back-End after pipeline 2025-08-28 23:48:21 +03:00
95a344a7a6 Update Front-End after CI/CD 2025-08-28 23:45:33 +03:00
c477143b30 Update sgeupdated pipeline v2 2025-08-28 23:42:13 +03:00
6202f7ec26 Update sgeupdated pipeline 2025-08-28 23:28:23 +03:00
8eb9835e13 Update sgeupdated pipeline 2025-08-28 19:09:57 +03:00
08941cc7d5 Update sgeupdated pipeline 2025-08-28 19:01:37 +03:00
994e81b1fb Add sgeupdated pipeline 2025-08-28 18:47:24 +03:00
0c03a110e5 DELETE 2025-08-28 17:56:30 +03:00
7c5eb3a210 Delete .gitea/workflows/deploy.yml 2025-08-28 17:55:52 +03:00
a943925325 Add a Smoke test workflow 2025-08-28 17:53:33 +03:00
5bd98fb09d update a Smoke test workflow 2025-08-27 03:42:02 +03:00
cdb6d98ae7 Add a Smoke test workflow 2025-08-27 03:40:09 +03:00
243f89457f Add test workflow 2025-08-27 03:34:14 +03:00
03875dde53 Add test workflow updated name 2025-08-27 03:32:21 +03:00
e695d06f5b Add CI/CD deploy workflows 2025-08-27 03:04:15 +03:00
837353bc45 Add test workflow 2025-08-27 03:02:45 +03:00
2459ba092b Add CI/CD deploy workflow update 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
89b4644983 few translation edits and changing it to use vmEmission query 2025-08-09 20:08:56 +03:00
39fffadbd2 fixed issue GUI and Datacenter tab related 2025-08-07 19:28:56 +03:00
49 changed files with 6057 additions and 4341 deletions

View File

@@ -0,0 +1,27 @@
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: |
# We add -tt to force a pseudo-terminal (fixes that stdin error)
# We call bash -lc to force a Login Shell, which loads your credentials
ssh -tt ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} "bash -lc 'cd /home/ubuntu/Bgreen/sgeUpdated && ./deploy.sh'"

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.10.100.110: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

View File

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

View File

@@ -121,7 +121,8 @@ public class SgsApplication implements CommandLineRunner {
@Autowired
public SgsApplication(RoleService roleService, PermissionService permissionService, RoleRepo roleRepo,
AreaService areaService, NeighborhoodRepo neighborhoodRepo, NeighborhoodService neighborhoodService, CityService cityService,
AreaService areaService, NeighborhoodRepo neighborhoodRepo, NeighborhoodService neighborhoodService,
CityService cityService,
CityRepo cityRepo, DistrictRepo districtRepo, DistrictService districtService, CountryRepo countryRepo,
CountryService countryService, OrganizationService organizationService, UserService userService,
PasswordEncoder passwordEncoder, SectorService sectorService, SubSectorService subSectorService,
@@ -186,7 +187,7 @@ public class SgsApplication implements CommandLineRunner {
admin.setFirstName("Seda");
admin.setLastName("Kemikli");
admin.setEmail("seda.kemikli@blc-css.com");
admin.setPhoneNumber("11111111");
admin.setPhoneNumber("11111511");
admin.setPassword(passwordEncoder.encode("admin"));
// if (organizations.size() == 1) {
// admin.setOrganizations(organizations);
@@ -858,6 +859,7 @@ public class SgsApplication implements CommandLineRunner {
}
if (cityService.findAll().isEmpty()) {
createCitiesFromJson();
createDefaultArea();
}
if (districtService.findAll().isEmpty()) {
createDistrictFromJson();
@@ -865,16 +867,13 @@ public class SgsApplication implements CommandLineRunner {
if (neighborhoodService.findAll().isEmpty()) {
createNeighborhoodsFromJson();
}
if (!cityService.findAll().isEmpty()) {
createDefaultArea();
}
}
void createDefaultArea() {
// Check if default area already exists
List<Area> existingAreas = areaService.findAll();
boolean defaultAreaExists = existingAreas.stream()
.anyMatch(area -> "Turkiye".equals(area.getTag()) && area.isDefaultArea());
.anyMatch(area -> "Turkiye".equals(area.getTag()) && area.isDefaultArea());
if (!defaultAreaExists) {
Area defaultArea = new Area();

View File

@@ -1,4 +1,5 @@
package com.sgs.graphql.dataCenter.domain;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.sgs.graphql.area.domain.Area;
@@ -15,7 +16,6 @@ import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@@ -46,9 +46,7 @@ public class DataCenter extends BaseDomain {
private Double latitude;
private Double longitude;
@Column(name = "data_center_name")
@Transactional
public String getDataCenter() {
return dataCenter;
}
@@ -96,7 +94,6 @@ public class DataCenter extends BaseDomain {
this.number = number;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "sector_id")
public Sector getSector() {

View File

@@ -1,18 +1,26 @@
package com.sgs.graphql.dataCenter.mutation;
import com.sgs.exception.GraphQLCustomException;
import com.sgs.graphql.dataCenter.mutation.mapper.DataCenterMapper;
import com.sgs.graphql.dataCenter.service.DataCenterService;
import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterCreateInput;
import com.sgs.graphql.dataCenter.mutation.input.DataCenterUpdateInput;
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.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.transaction.Transactional;
import javax.validation.Valid;
import java.util.NoSuchElementException;
import java.util.UUID;
@Validated
@@ -21,57 +29,128 @@ public class DataCenterMutation implements GraphQLMutationResolver {
private final DataCenterService dataCenterService;
private final DataCenterMapper dataCenterMapper;
private final SystemLogger systemLogger;
private final UserLogger userLogger;
private final UserNotificationMutation notificationMutation;
@Autowired
public DataCenterMutation(DataCenterService dataCenterService, DataCenterMapper dataCenterMapper) {
public DataCenterMutation(DataCenterService dataCenterService, DataCenterMapper dataCenterMapper,
SystemLogger systemLogger, UserLogger userLogger,
UserNotificationMutation notificationMutation) {
this.dataCenterService = dataCenterService;
this.dataCenterMapper = dataCenterMapper;
this.systemLogger = systemLogger;
this.userLogger = userLogger;
this.notificationMutation = notificationMutation;
}
@PreAuthorize("hasAuthority('" + PermissionName.DATA_CENTER_CREATE + "')")
public DataCenter createDataCenter(@Valid DataCenterCreateInput input) {
// Check for duplicate externalId
if (input.getExternalId() != null && dataCenterService.existsByExternalId(input.getExternalId())) {
throw new RuntimeException("This external id already exists: " + input.getExternalId());
@Transactional
public DataCenter createDataCenter(@Valid DataCenterCreateInput input, DataFetchingEnvironment environment) {
try {
// 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 + "')")
public DataCenter updateDataCenter(UUID id, @Valid DataCenterUpdateInput input) {
return dataCenterService.findById(id)
.map(dataCenter -> {
// Check for duplicate externalId if it's being updated
if (input.getExternalId() != null &&
!input.getExternalId().equals(dataCenter.getExternalId()) &&
dataCenterService.existsByExternalId(input.getExternalId())) {
throw new RuntimeException("This external id already exists: " + input.getExternalId());
}
return dataCenterService.update(dataCenterMapper.updateEntity(dataCenter, input));
})
.orElseThrow(() -> new RuntimeException("Data center not found with ID: " + id));
@Transactional
public DataCenter updateDataCenter(UUID id, @Valid DataCenterUpdateInput input,
DataFetchingEnvironment environment) {
try {
DataCenter dataCenter = dataCenterService.findById(id)
.orElseThrow(() -> new NoSuchElementException("Data center not found with ID: " + id));
// Check for duplicate externalId if it's being updated
if (input.getExternalId() != null &&
!input.getExternalId().equals(dataCenter.getExternalId()) &&
dataCenterService.existsByExternalId(input.getExternalId())) {
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 + "')")
public Boolean deleteDataCenter(UUID id) {
@Transactional
public String deleteDataCenter(UUID id, DataFetchingEnvironment environment) {
String dataCenterName = "";
try {
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);
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) {
System.out.println("DataCenter deletion error: " + e.getMessage());
return false;
systemLogger.createSystemLog(LogType.ERROR, "Veri merkezi silinirken hata oluştu: " + e.getMessage());
return "false";
}
}
}

View File

@@ -16,7 +16,6 @@ public class DataCenterCreateInput extends BaseCreateInput {
private Integer number;
private Double consuptionAmount;
@NotNull(message = "Alan ID gereklidir")
private UUID areaId;
private UUID cityId;

View File

@@ -4,6 +4,8 @@ import com.sgs.lib.dao.mutation.input.BaseUpdateInput;
import java.util.List;
import java.util.UUID;
import javax.validation.constraints.NotNull;
public class DataCenterUpdateInput extends BaseUpdateInput {
private String dataCenter;
private Integer externalId;
@@ -12,6 +14,7 @@ public class DataCenterUpdateInput extends BaseUpdateInput {
private UUID areaId;
private UUID cityId;
@NotNull(message = "Sektör ID gereklidir")
private UUID sectorId;
private UUID subSectorId;
private UUID emissionScopeId;

View File

@@ -97,16 +97,19 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
// Set EmissionSource
if (emissionSourceInput.getEmissionSourceId() != null) {
dcEmissionSource.setEmissionSource(emissionSourceService.findById(UUID.fromString(emissionSourceInput.getEmissionSourceId())).orElse(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));
dcEmissionSource.setConsuptionUnit(consuptionUnitService
.findById(UUID.fromString(emissionSourceInput.getConsuptionUnitId())).orElse(null));
}
// Set optional fields
dcEmissionSource.setIsDefault(emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setIsDefault(
emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setPercentage(emissionSourceInput.getPercentage());
dataCenterEmissionSources.add(dcEmissionSource);
@@ -163,28 +166,31 @@ public class DataCenterMapper extends BaseCreateUpdateMapper<DataCenter, DataCen
// Handle multiple emission sources update if provided
if (input.getDataCenterEmissionSources() != null) {
// Clear existing emission sources and add new ones
// Clear existing emission sources from the managed collection
entity.getDataCenterEmissionSources().clear();
List<DataCenterEmissionSource> dataCenterEmissionSources = new ArrayList<>();
// 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));
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.setConsuptionUnit(consuptionUnitService
.findById(UUID.fromString(emissionSourceInput.getConsuptionUnitId())).orElse(null));
}
dcEmissionSource.setIsDefault(emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setIsDefault(
emissionSourceInput.getIsDefault() != null ? emissionSourceInput.getIsDefault() : false);
dcEmissionSource.setPercentage(emissionSourceInput.getPercentage());
dataCenterEmissionSources.add(dcEmissionSource);
// Add to the existing managed collection instead of creating a new one
entity.getDataCenterEmissionSources().add(dcEmissionSource);
}
entity.setDataCenterEmissionSources(dataCenterEmissionSources);
}
// New attributes (partial update - only if provided)

View File

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

View File

@@ -2,7 +2,8 @@ package com.sgs.graphql.dataCenter.repo;
import com.sgs.graphql.dataCenter.domain.DataCenter;
import com.sgs.graphql.dataCenter.domain.DataCenterEmissionSource;
import org.springframework.data.jpa.repository.JpaRepository;
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;
@@ -11,7 +12,7 @@ import java.util.List;
import java.util.Optional;
@Repository
public interface DataCenterEmissionSourceRepo extends JpaRepository<DataCenterEmissionSource, String> {
public interface DataCenterEmissionSourceRepo extends BaseRepo<DataCenterEmissionSource> {
List<DataCenterEmissionSource> findByDataCenter(DataCenter dataCenter);

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.stereotype.Service;
import java.util.Optional;
@Service
public class DataCenterService extends BaseService<DataCenter, DataCenterRepo, DataCenterCriteria, DataCenterCriteriaSpec> {
public class DataCenterService
extends BaseService<DataCenter, DataCenterRepo, DataCenterCriteria, DataCenterCriteriaSpec> {
@Autowired
public DataCenterService(DataCenterRepo repository, DataCenterCriteriaSpec criteriaSpec) {
@@ -19,4 +22,12 @@ public class DataCenterService extends BaseService<DataCenter, DataCenterRepo, D
public boolean existsByExternalId(Integer 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

@@ -22,7 +22,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MainDataTableService extends BaseService<MainDataTable, MainDataTableRepo, MainDataTableCriteria, MainDataTableCriteriaSpec> {
public class MainDataTableService
extends BaseService<MainDataTable, MainDataTableRepo, MainDataTableCriteria, MainDataTableCriteriaSpec> {
@PersistenceContext
private EntityManager entityManager;
@@ -112,6 +113,7 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
/**
* Converts PostgreSQL hex format UUID to proper UUID format
*
* @param hexUuid UUID in hex format (e.g., \x6205c18b8d1e4f0fa5154212fb44050b)
* @return UUID object
*/
@@ -122,10 +124,10 @@ public class MainDataTableService extends BaseService<MainDataTable, MainDataTab
// Insert hyphens to make it a proper UUID format
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
String formatted = hex.substring(0, 8) + "-" +
hex.substring(8, 12) + "-" +
hex.substring(12, 16) + "-" +
hex.substring(16, 20) + "-" +
hex.substring(20);
hex.substring(8, 12) + "-" +
hex.substring(12, 16) + "-" +
hex.substring(16, 20) + "-" +
hex.substring(20);
return UUID.fromString(formatted);
} else {
// If it's already in proper format, parse directly

View File

@@ -839,7 +839,7 @@ public class MessageListener {
System.out.println("🔍 Setting VM ID: " + vm.getId());
// Use the source-specific power consumption (percentage of total VM power)
// Format to 6 decimal places to avoid very long strings
// 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");
@@ -850,6 +850,7 @@ public class MessageListener {
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 ID: " + vm.getId());
System.out.println(" VM Name: " + vm.getVmName());

View File

@@ -17,16 +17,10 @@ security.jwt.token.secret-key=secret
app.survey.base-url=http://localhost.com
# spring.rabbitmq.host=188.132.198.145
# spring.rabbitmq.port=5672
# spring.rabbitmq.username=testuser
# spring.rabbitmq.password=JGasF24561AZv2894De
#spring.rabbitmq.host=rabbitmq
spring.rabbitmq.host=localhost
spring.rabbitmq.host=188.132.198.145
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.username=testuser
spring.rabbitmq.password=JGasF24561AZv2894De
spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=20000
spring.rabbitmq.template.retry.enabled=true
@@ -34,3 +28,6 @@ spring.rabbitmq.template.retry.max-attempts=3
spring.rabbitmq.template.retry.initial-interval=1000ms
logging.level.org.springframework.amqp=DEBUG
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

View File

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

View File

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

View File

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

View File

@@ -67,7 +67,11 @@
"Common": {
"save": "Save",
"cancel": "Cancel"
"cancel": "Cancel",
"yes": "Yes",
"no": "No",
"areYouSure": "Are you sure?",
"cantRevert": "This action cannot be undone!"
},
"DataInput": {

View File

@@ -66,7 +66,11 @@
"Common": {
"save": "Kaydet",
"cancel": " İptal"
"cancel": "İptal",
"yes": "Evet",
"no": "Hayır",
"areYouSure": "Emin misiniz?",
"cantRevert": "Bu işlem geri alınamaz!"
},
"DataInput": {

View File

@@ -49,9 +49,9 @@ export default [
permissionCheck("paginate_roles_get")) && [
{
id: "Organizations",
title: "DataCenters.title",
title: "Data Center Management",
icon: <Home size={20} />,
navLink: "/organizasyonlar",
navLink: "/veri-merkezi-yonetimi",
display: (permissionCheck("paginate_datacenters_get") ||
permissionCheck("data_center_create") ||
permissionCheck("data_center_update") ||
@@ -142,9 +142,63 @@ export default [
},
{
id: "DataCenter",
title: "Data Centers",
title: "Data Center Overview",
icon: <Zap size={20} />,
navLink: "/verimerkezi",
navLink: "/veri-merkezi-genel",
},
{
id: "Areas",
title: "Areas.areas",
icon: <Map size={20} />,
display:
permissionCheck("paginate_areas_get") ||
permissionCheck("paginate_countries_get") ||
permissionCheck("paginate_cities_get") ||
permissionCheck("paginate_districts_get") ||
permissionCheck("paginate_neighborhoods_get")
? ""
: "none",
children: (permissionCheck("paginate_areas_get") ||
permissionCheck("paginate_countries_get") ||
permissionCheck("paginate_cities_get") ||
permissionCheck("paginate_districts_get") ||
permissionCheck("paginate_neighborhoods_get")) && [
{
id: "AreasManagement",
title: "Areas.areas",
icon: <ArrowRight size={20} />,
navLink: "/alanlar",
display: permissionCheck("paginate_areas_get") ? "" : "none",
},
{
id: "Countries",
title: "Areas.countries",
icon: <ArrowRight size={20} />,
navLink: "/ulkeler",
display: permissionCheck("paginate_countries_get") ? "" : "none",
},
{
id: "Cities",
title: "Areas.cities",
icon: <ArrowRight size={20} />,
navLink: "/iller",
display: permissionCheck("paginate_cities_get") ? "" : "none",
},
{
id: "Districts",
title: "Areas.districts",
icon: <ArrowRight size={20} />,
navLink: "/ilceler",
display: permissionCheck("paginate_districts_get") ? "" : "none",
},
{
id: "Neighborhoods",
title: "Areas.neighborhoods",
icon: <ArrowRight size={20} />,
navLink: "/mahalleler",
display: permissionCheck("paginate_neighborhoods_get") ? "" : "none",
},
],
},
{
id: "Survey",

View File

@@ -49,9 +49,9 @@ export default [
permissionCheck("paginate_roles_get")) && [
{
id: "DataCenters",
title: "DataCenters.title",
title: "Data Center Management",
icon: <Zap size={20} />,
navLink: "/organizasyonlar",
navLink: "/veri-merkezi-yonetimi",
display: (permissionCheck("paginate_datacenters_get") ||
permissionCheck("data_center_create") ||
permissionCheck("data_center_update") ||
@@ -142,9 +142,63 @@ export default [
},
{
id: "DataCenter",
title: "DataCenters",
title: "Data Center Overview",
icon: <Zap size={20} />,
navLink: "/verimerkezi",
navLink: "/veri-merkezi-genel",
},
{
id: "Areas",
title: "Areas.areas",
icon: <Map size={20} />,
display:
permissionCheck("paginate_areas_get") ||
permissionCheck("paginate_countries_get") ||
permissionCheck("paginate_cities_get") ||
permissionCheck("paginate_districts_get") ||
permissionCheck("paginate_neighborhoods_get")
? ""
: "none",
children: (permissionCheck("paginate_areas_get") ||
permissionCheck("paginate_countries_get") ||
permissionCheck("paginate_cities_get") ||
permissionCheck("paginate_districts_get") ||
permissionCheck("paginate_neighborhoods_get")) && [
{
id: "AreasManagement",
title: "Areas.areas",
icon: <ArrowRight size={20} />,
navLink: "/alanlar",
display: permissionCheck("paginate_areas_get") ? "" : "none",
},
{
id: "Countries",
title: "Areas.countries",
icon: <ArrowRight size={20} />,
navLink: "/ulkeler",
display: permissionCheck("paginate_countries_get") ? "" : "none",
},
{
id: "Cities",
title: "Areas.cities",
icon: <ArrowRight size={20} />,
navLink: "/iller",
display: permissionCheck("paginate_cities_get") ? "" : "none",
},
{
id: "Districts",
title: "Areas.districts",
icon: <ArrowRight size={20} />,
navLink: "/ilceler",
display: permissionCheck("paginate_districts_get") ? "" : "none",
},
{
id: "Neighborhoods",
title: "Areas.neighborhoods",
icon: <ArrowRight size={20} />,
navLink: "/mahalleler",
display: permissionCheck("paginate_neighborhoods_get") ? "" : "none",
},
],
},
{
id: "Survey",

View File

@@ -12,6 +12,15 @@ export const getAreas = () => {
id
tag
isDeleted
cities {
id
name
coordinates
country {
id
name
}
}
}
}
`,

View File

@@ -34,30 +34,69 @@ export const getDataCenters = () => {
latitude
longitude
area {
tag
name
cityId
districtId
}
projects {
id
name
physicalMachines {
tag
cities {
id
name
vms {
active {
id
status
name
power
config {
id
cpu
ram
disk
}
}
}
districts {
id
name
}
}
city {
id
name
}
emissionScope {
id
tag
description
}
sector {
id
tag
}
subSector {
id
tag
}
dataCenterEmissionSources {
id
emissionSource {
id
tag
}
consuptionUnit {
id
description
}
isDefault
percentage
}
activitySubUnit {
id
tag
}
physicalMachines {
id
name
vms {
id
vmName
state
power
calcOn
hostingPm
host
flavorName
tag
config {
id
cpu
ram
disk
}
}
}
@@ -77,7 +116,7 @@ export const getDataCenters = () => {
console.log("GraphQL Response:", {
status: response.status,
data: response.data,
errors: response.data?.errors
errors: response.data?.errors,
});
// Check for GraphQL errors
@@ -110,7 +149,7 @@ export const getDataCenters = () => {
message: error.message,
response: error.response?.data,
status: error.response?.status,
stack: error.stack
stack: error.stack,
});
// Check for specific error types
@@ -155,10 +194,50 @@ export const createDataCenter = (dataCenterData) => {
latitude
longitude
area {
id
tag
cities {
id
name
}
districts {
id
name
}
}
city {
id
name
cityId
districtId
}
emissionScope {
id
tag
description
}
sector {
id
tag
}
subSector {
id
tag
}
dataCenterEmissionSources {
id
emissionSource {
id
tag
}
consuptionUnit {
id
description
}
isDefault
percentage
}
activitySubUnit {
id
tag
}
}
}
@@ -169,13 +248,23 @@ export const createDataCenter = (dataCenterData) => {
externalId: parseInt(dataCenterData.externalId),
ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId,
areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "",
latitude: dataCenterData.latitude ? parseFloat(dataCenterData.latitude) : null,
longitude: dataCenterData.longitude ? parseFloat(dataCenterData.longitude) : null,
city: dataCenterData.city
}
}
latitude: dataCenterData.latitude
? parseFloat(dataCenterData.latitude)
: null,
longitude: dataCenterData.longitude
? parseFloat(dataCenterData.longitude)
: null,
emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null,
dataCenterEmissionSources:
dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null,
},
},
},
{
headers: {
@@ -188,7 +277,7 @@ export const createDataCenter = (dataCenterData) => {
console.log("Create Response:", {
status: response.status,
data: response.data,
errors: response.data?.errors
errors: response.data?.errors,
});
if (response.data?.errors) {
@@ -240,10 +329,50 @@ export const updateDataCenter = (id, dataCenterData) => {
latitude
longitude
area {
id
tag
cities {
id
name
}
districts {
id
name
}
}
city {
id
name
cityId
districtId
}
emissionScope {
id
tag
description
}
sector {
id
tag
}
subSector {
id
tag
}
dataCenterEmissionSources {
id
emissionSource {
id
tag
}
consuptionUnit {
id
description
}
isDefault
percentage
}
activitySubUnit {
id
tag
}
}
}
@@ -255,13 +384,23 @@ export const updateDataCenter = (id, dataCenterData) => {
externalId: parseInt(dataCenterData.externalId),
ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId,
areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "",
latitude: dataCenterData.latitude ? parseFloat(dataCenterData.latitude) : null,
longitude: dataCenterData.longitude ? parseFloat(dataCenterData.longitude) : null,
city: dataCenterData.city
}
}
latitude: dataCenterData.latitude
? parseFloat(dataCenterData.latitude)
: null,
longitude: dataCenterData.longitude
? parseFloat(dataCenterData.longitude)
: null,
emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null,
dataCenterEmissionSources:
dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null,
},
},
},
{
headers: {
@@ -276,7 +415,7 @@ export const updateDataCenter = (id, dataCenterData) => {
dispatch({
type: "UPDATE_DATA_CENTER_SUCCESS",
payload: response.data.data.updateDataCenter
payload: response.data.data.updateDataCenter,
});
return response.data.data.updateDataCenter;
@@ -309,8 +448,8 @@ export const deleteDataCenter = (id) => {
}
`,
variables: {
id: id
}
id: id,
},
},
{
headers: {
@@ -325,7 +464,7 @@ export const deleteDataCenter = (id) => {
dispatch({
type: "DELETE_DATA_CENTER_SUCCESS",
payload: id
payload: id,
});
return true;
@@ -342,69 +481,113 @@ export const deleteDataCenter = (id) => {
};
};
export const getEmissionScopes = () => {
return async (dispatch) => {
dispatch({
type: "GET_EMISSION_SCOPES_LOADING",
});
try {
const response = await ApplicationService.http().post(
"/graphql",
{
query: `
query GetEmissionScopes {
emissionScopes {
id
tag
description
}
}
`,
},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("accessToken"),
},
}
);
if (response.data?.errors) {
throw new Error(response.data.errors[0].message);
}
dispatch({
type: "GET_EMISSION_SCOPES_SUCCESS",
payload: response.data.data.emissionScopes,
});
return response.data.data.emissionScopes;
} catch (error) {
console.error("Error fetching emission scopes:", error);
dispatch({
type: "GET_EMISSION_SCOPES_ERROR",
payload: {
error: error.message || "Failed to fetch emission scopes",
},
});
throw error;
}
};
};
export const getDataCenterVMs = (dataCenterId) => {
return new Promise(async (resolve, reject) => {
// Don't make the request if dataCenterId is undefined, null, or empty
if (!dataCenterId || dataCenterId === "undefined") {
console.log('getDataCenterVMs: No dataCenterId provided');
console.log("getDataCenterVMs: No dataCenterId provided");
resolve([]);
return;
}
try {
console.log('getDataCenterVMs: Fetching VMs for data center:', dataCenterId);
const response = await ApplicationService.http()
.post(
"/graphql",
{
query: `
console.log(
"getDataCenterVMs: Fetching VMs for data center:",
dataCenterId
);
const response = await ApplicationService.http().post(
"/graphql",
{
query: `
{
dataCenter(id: "${dataCenterId}") {
id
dataCenter
projects {
physicalMachines {
id
name
physicalMachines {
vms {
id
name
vms {
id
name
status
power
}
vmName
state
power
}
}
}
}
`,
},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("accessToken"),
},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("accessToken"),
},
}
);
}
);
const dataCenter = response?.data?.data?.dataCenter;
console.log('getDataCenterVMs: Data center response:', dataCenter);
console.log("getDataCenterVMs: Data center response:", dataCenter);
let allVMs = [];
if (dataCenter && dataCenter.projects) {
dataCenter.projects.forEach(project => {
if (project.physicalMachines) {
project.physicalMachines.forEach(pm => {
if (pm.vms) {
allVMs = allVMs.concat(pm.vms);
}
});
if (dataCenter && dataCenter.physicalMachines) {
dataCenter.physicalMachines.forEach((pm) => {
if (pm.vms) {
allVMs = allVMs.concat(pm.vms);
}
});
}
console.log('getDataCenterVMs: Found VMs:', allVMs);
console.log("getDataCenterVMs: Found VMs:", allVMs);
resolve(allVMs);
} catch (error) {
console.error("Error fetching VMs by data center:", error);

View File

@@ -1,6 +1,6 @@
import ApplicationService from "../../../services/ApplicationService";
export const getVMEmissionSummary = () => {
export const getVMEmissionSummary = (datacenterId) => {
return async (dispatch) => {
try {
const response = await ApplicationService.http()
@@ -8,8 +8,8 @@ export const getVMEmissionSummary = () => {
"/graphql",
{
query: `
{
vmEmissionSummary {
query GetVMEmissions($datacenterId: ID) {
vmEmissionSummary(datacenterId: $datacenterId) {
vmId
vmName
vmPower
@@ -17,7 +17,7 @@ export const getVMEmissionSummary = () => {
totalEmission
createdDate
physicalMachine
project
cloudSystem
dataCenter
co2
ch4
@@ -25,7 +25,10 @@ export const getVMEmissionSummary = () => {
reportGeneratedTime
}
}
`
`,
variables: {
datacenterId: datacenterId
}
},
{
headers: {
@@ -125,11 +128,12 @@ export const getMainDataTablesWithPaginate = (data) => {
{
paginateMainDataTables(
pagination: { page: 0, rowsPerPage: 100 }
criteria: { deleted: false }
criteria: { deleted: false, hasVm: true }
sortBy: [{ field: "createdDate", direction: DESC }]
) {
content {
id
year
sector {
id
tag
@@ -138,11 +142,40 @@ export const getMainDataTablesWithPaginate = (data) => {
id
tag
}
activitySubUnit {
id
tag
}
emissionSource {
id
tag
}
emissionScope {
id
tag
}
co2
ch4
n2o
totalEmission
createdDate
vm {
id
vmName
state
power
calcOn
hostingPm
host
flavorName
tag
config {
id
cpu
ram
disk
}
}
}
pageInfo {
totalElements

View File

@@ -0,0 +1,33 @@
const initialState = {
emissionScopes: [],
loading: false,
error: null,
};
const emissionScopeReducer = (state = initialState, action) => {
switch (action.type) {
case "GET_EMISSION_SCOPES_LOADING":
return {
...state,
loading: true,
error: null,
};
case "GET_EMISSION_SCOPES_SUCCESS":
return {
...state,
loading: false,
emissionScopes: action.payload,
error: null,
};
case "GET_EMISSION_SCOPES_ERROR":
return {
...state,
loading: false,
error: action.payload.error,
};
default:
return state;
}
};
export default emissionScopeReducer;

View File

@@ -27,6 +27,7 @@ import surveys from "./surveys";
import uploads from "./upload";
import mailSettings from "./mailSettings";
import dataCenter from "./dataCenter";
import emissionScope from "./emissionScope";
const rootReducer = combineReducers({
accessToken,
@@ -57,6 +58,7 @@ const rootReducer = combineReducers({
uploads,
mailSettings,
dataCenter,
emissionScope,
});
export default rootReducer;

View File

@@ -25,7 +25,7 @@ const Routes = [
display: permissionCheck("paginate_users_get"),
},
{
path: "/organizasyonlar",
path: "/veri-merkezi-yonetimi",
component: lazy(() => import("../../views/DataCenterManagement")),
display: permissionCheck("paginate_datacenters_get") ||
permissionCheck("data_center_create") ||
@@ -74,7 +74,7 @@ const Routes = [
display: permissionCheck("activity_sub_units_get"),
},
{
path: "/verimerkezi",
path: "/veri-merkezi-genel",
component: lazy(() => import("../../views/DataCenter")),
},
{

View File

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

View File

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

View File

@@ -18,17 +18,16 @@ const DataCenter = () => {
const [refreshInterval, setRefreshInterval] = useState(null);
const getAllPhysicalMachines = (dataCenter) => {
if (!dataCenter.projects) return [];
return dataCenter.projects.flatMap(project =>
project.physicalMachines || []
);
// Physical machines are directly in the dataCenter object, not in projects
const pms = dataCenter.physicalMachines || [];
return pms;
};
// Table columns following your pattern
const initialColumns = [
{
name: "Number",
selector: (row) => row.number,
name: "External ID",
selector: (row) => row.externalId,
sortable: true,
minWidth: "100px",
},
@@ -38,19 +37,33 @@ const DataCenter = () => {
sortable: true,
minWidth: "200px",
},
// Projects
{
name: "Projects",
selector: (row) =>
(row.projects || []).map((p) => p.name).join(", "),
sortable: false,
minWidth: "200px",
cell: (row) => (
<span>
{(row.projects || []).map((p) => p.name).join(", ") || "-"}
</span>
),
},
// Projects - Based on API response, this field might not exist or be structured differently
// {
// name: "Projects",
// selector: (row) => row.projects?.length || 0,
// sortable: true,
// minWidth: "200px",
// cell: (row) => (
// <div>
// {row.projects && row.projects.length > 0 ? (
// <div className="d-flex flex-column">
// {row.projects.map((project, index) => (
// <div
// key={project.id}
// className={`badge badge-light-primary ${
// index > 0 ? "mt-1" : ""
// }`}
// >
// {project.name}
// </div>
// ))}
// </div>
// ) : (
// <span className="text-muted">-</span>
// )}
// </div>
// ),
// },
// Physical Machines
{
name: "Physical Machines",
@@ -68,26 +81,55 @@ const DataCenter = () => {
},
},
{
name: "Total Active VMs",
name: "Virtual Machines",
selector: (row) => {
const pms = getAllPhysicalMachines(row);
return pms.reduce(
(total, pm) => total + (pm.vms?.active?.length || 0),
0
const vms = pms.reduce(
(acc, pm) => {
if (!pm.vms) return acc;
return {
active:
acc.active +
pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return vms.total;
},
sortable: true,
minWidth: "150px",
minWidth: "200px",
cell: (row) => {
const pms = getAllPhysicalMachines(row);
const totalVMs = pms.reduce(
(total, pm) => total + (pm.vms?.active?.length || 0),
0
const vms = pms.reduce(
(acc, pm) => {
if (!pm.vms) return acc;
return {
active:
acc.active +
pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return (
<div className="d-flex align-items-center">
<Monitor size={16} className="mr-1" />
<span>{totalVMs}</span>
<Monitor size={16} className="mr-2" />
<div>
<div className="font-weight-bold">{vms.total} Total</div>
<div className="small">
<span className="text-success">{vms.active} Active</span>
<span className="text-muted mx-1"></span>
<span className="text-warning">
{vms.total - vms.active} Inactive
</span>
</div>
</div>
</div>
);
},
@@ -138,76 +180,112 @@ const DataCenter = () => {
<div key={pm.id} className="mb-3 border rounded p-3">
<h6 className="text-primary">{pm.name}</h6>
{/* Active VMs */}
<p className="mb-2">
<strong>Active VMs ({pm.vms?.active?.length || 0}):</strong>
</p>
{pm.vms?.active?.length > 0 ? (
<div className="ml-3">
{pm.vms.active.map((vm) => (
<div
key={vm.id}
className="mb-2 p-2 border-left border-success"
>
<div className="row">
<div className="col-md-3">
<strong>Name:</strong> {vm.name}
</div>
<div className="col-md-2">
<strong>Status:</strong>
<span className="badge badge-success ml-1">
{vm.status}
</span>
</div>
<div className="col-md-2">
<strong>Power:</strong> {vm.power}
</div>
<div className="col-md-5">
<strong>Config:</strong> CPU: {vm.config?.cpu}, RAM:{" "}
{vm.config?.ram}, Disk: {vm.config?.disk}
</div>
</div>
</div>
))}
{/* All VMs */}
<div className="mb-2 d-flex justify-content-between align-items-center">
<h6 className="mb-0">
<Monitor size={16} className="mr-1" />
Virtual Machines ({pm.vms?.length || 0})
</h6>
</div>
{pm.vms?.length > 0 ? (
<div className="table-responsive mt-2">
<table className="table table-bordered table-hover">
<thead className="thead-light">
<tr>
<th>Name</th>
<th>Status</th>
<th>Power (W)</th>
<th>Configuration</th>
<th>Host</th>
</tr>
</thead>
<tbody>
{pm.vms.map((vm) => {
const isActive =
vm.state && ["ACTIVE", "active"].includes(vm.state);
return (
<tr key={vm.id}>
<td>
<span className="font-weight-bold">
{vm.vmName || vm.vm_name}
</span>
</td>
<td>
<div
className={`d-inline-block px-2 py-1 rounded-pill ${
isActive
? "bg-light-success text-success"
: "bg-light-warning text-warning"
}`}
>
{vm.state}
</div>
</td>
<td>
{vm.power ? (
<span>{vm.power.toFixed(2)}</span>
) : (
<span className="text-muted">-</span>
)}
</td>
<td>
<div className="d-flex align-items-center">
<div className="mr-3">
<small className="text-muted d-block">
CPU
</small>
<span>
{vm.config?.cpu ||
(vm.confg && vm.confg[1]) ||
"-"}
</span>
</div>
<div className="mr-3">
<small className="text-muted d-block">
RAM
</small>
<span>
{vm.config?.ram ||
(vm.confg && vm.confg[2]) ||
"-"}{" "}
GB
</span>
</div>
<div>
<small className="text-muted d-block">
Disk
</small>
<span>
{vm.config?.disk ||
(vm.confg && vm.confg[3]) ||
"-"}{" "}
GB
</span>
</div>
</div>
</td>
<td>
<div className="d-flex align-items-center">
<Server size={14} className="mr-1" />
<span>
{vm.host ||
vm.hostingPm ||
(vm.confg && vm.confg[4]) ||
"-"}
</span>
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
) : (
<p className="text-muted ml-3">No active VMs</p>
)}
{/* Inactive VMs */}
<p className="mb-2 mt-3">
<strong>Inactive VMs ({pm.vms?.inactive?.length || 0}):</strong>
</p>
{pm.vms?.inactive?.length > 0 ? (
<div className="ml-3">
{pm.vms.inactive.map((vm) => (
<div
key={vm.id}
className="mb-2 p-2 border-left border-warning"
>
<div className="row">
<div className="col-md-3">
<strong>Name:</strong> {vm.name}
</div>
<div className="col-md-2">
<strong>Status:</strong>
<span className="badge badge-warning ml-1">
{vm.status}
</span>
</div>
<div className="col-md-2">
<strong>Power:</strong> {vm.power}
</div>
<div className="col-md-5">
<strong>Config:</strong> CPU: {vm.config?.cpu}, RAM:{" "}
{vm.config?.ram}, Disk: {vm.config?.disk}
</div>
</div>
</div>
))}
<div className="text-center p-3 bg-light-secondary rounded">
<Monitor size={24} className="text-muted mb-1" />
<p className="text-muted mb-0">No virtual machines found</p>
</div>
) : (
<p className="text-muted ml-3">No inactive VMs</p>
)}
</div>
))}
@@ -215,8 +293,6 @@ const DataCenter = () => {
);
};
return (
<div style={{ marginTop: "2%" }}>
<Card>

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,101 +1,157 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useMemo } from "react";
import { MaterialReactTable } from "material-react-table";
import { useDispatch, useSelector } from "react-redux";
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 { getDataCenters } from "../../redux/actions/dataCenter";
import { editNumbers } from "../../components/edit-numbers";
import Select from "react-select";
function MainDataTables() {
const { t } = useTranslation();
const dispatch = useDispatch();
const mainDataTablesStore = useSelector((state) => state.mainDataTables);
const dataCenterStore = useSelector((state) => state.dataCenter);
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(() => {
try {
// Fetch VM emission data
dispatch(getVMEmissionSummary());
} catch (err) {
console.error('Error in MainDataTables:', err);
setError(err.message);
}
dispatch(getDataCenters());
}, [dispatch]);
// Debug log for store data
// Update datacenter options when datacenters are loaded
useEffect(() => {
console.log('Current store data:', mainDataTablesStore);
}, [mainDataTablesStore]);
if (dataCenterStore?.dataCenters?.length > 0) {
const options = dataCenterStore.dataCenters.map((dataCenter) => ({
value: dataCenter.id,
label: dataCenter.dataCenter,
externalId: dataCenter.externalId,
}));
setDataCenterOptions(options);
}
}, [dataCenterStore?.dataCenters]);
const columns = [
{
header: "VM ID",
accessorKey: "vmId",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "Data Center",
accessorKey: "dataCenter",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "Project",
accessorKey: "project",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "Physical Machine",
accessorKey: "physicalMachine",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "Virtual Machine",
accessorKey: "vmName",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "VM Power (W)",
accessorKey: "vmPower",
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "VM Status",
accessorKey: "vmStatus",
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: "Total Emissions",
accessorKey: "totalEmission",
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "CO2",
accessorKey: "co2",
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "CH4",
accessorKey: "ch4",
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "N2O",
accessorKey: "n2o",
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
},
{
header: "Created Date",
accessorKey: "createdDate",
Cell: ({ cell }) => (
<span>
{cell.getValue() ? new Date(cell.getValue()).toLocaleString() : "-"}
</span>
),
},
];
// 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 tableData = mainDataTablesStore?.vmEmissionSummary || [];
console.log('VM Emission data:', tableData);
// Memoize columns to prevent re-renders
const columns = useMemo(
() => [
{
header: t("VM ID"),
accessorKey: "vmId",
size: 150,
Cell: ({ cell }) => <span>{cell.getValue() || "-"}</span>,
},
{
header: t("VM Name"),
accessorKey: "vmName",
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]
);
// Memoize table data to prevent unnecessary re-renders
const tableData = useMemo(() => {
const data = mainDataTablesStore?.vmEmissionSummary || [];
console.log("VM Emission data count:", data.length);
return data;
}, [mainDataTablesStore?.vmEmissionSummary]);
if (error) {
return (
@@ -109,37 +165,109 @@ function MainDataTables() {
<div style={{ marginTop: "2%" }}>
<Card>
<CardHeader className="border-bottom">
<CardTitle tag="h4">{t("Carbon Emission Data")}</CardTitle>
<CardTitle tag="h4">{t("Raw Data")}</CardTitle>
{tableData.length > 0 && (
<small className="text-muted">
{tableData.length} records loaded
</small>
)}
</CardHeader>
<MaterialReactTable
columns={columns}
data={tableData}
enableColumnFilters={true}
enableFilters={true}
enableGlobalFilter={true}
enablePagination={true}
enableColumnResizing={true}
enableStickyHeader={true}
muiTableContainerProps={{ sx: { maxHeight: 'calc(100vh - 180px)' } }}
muiTableProps={{
sx: {
tableLayout: 'auto',
},
}}
initialState={{
pagination: {
pageSize: 100,
pageIndex: 0
},
sorting: [
{ id: 'dataCenter', desc: false }
],
density: 'compact'
}}
state={{
isLoading: !mainDataTablesStore?.vmEmissionSummary
}}
/>
{/* Datacenter Selection */}
<div className="p-3 border-bottom">
<Row>
<Col md="6">
<Label for="datacenter-select">{t("Data Center")}</Label>
<Select
id="datacenter-select"
value={selectedDataCenter}
onChange={setSelectedDataCenter}
options={dataCenterOptions}
placeholder={t("Select a data center...")}
isClearable
isSearchable
isLoading={dataCenterStore?.loading}
noOptionsMessage={() => t("No data centers available")}
styles={{
menu: (provided) => ({
...provided,
zIndex: 9999, // Ensure dropdown appears above other elements
}),
}}
menuPortalTarget={document.body} // Render dropdown in body to avoid container overflow
/>
</Col>
</Row>
</div>
{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>
</div>
);

View File

@@ -32,15 +32,87 @@ import { getCities } from "../redux/actions/cities";
import { v4 as uuidv4 } from "uuid";
import { getCity } from "../redux/actions/city";
import { getDistrict } from "../redux/actions/district";
import {
getOrganisations,
getOrganisationById,
} from "../redux/actions/organisations";
// import {
// getOrganisations,
// getOrganisationById,
// } from "../redux/actions/organisations";
import { getAreasWithCriteria } from "../redux/actions/areas";
import { ChromePicker } from "react-color";
import { customFilterForSelect } from "../utility/Utils";
import { permissionCheck } from "../components/permission-check";
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 [showColorPicker, setShowColorPicker] = useState(false);
@@ -117,20 +189,20 @@ const Map = () => {
const citiesStore = useSelector((state) => state.cities);
const cityStore = useSelector((state) => state.city);
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 dataCenterStore = useSelector((state) => state.dataCenter);
const [cities, setCities] = useState([]);
const [districts, setDistricts] = useState([]);
const [neighborhoods, setNeighborhoods] = useState([]);
const [organizationOptions, setOrganizationOptions] = useState([]);
const organizationId = localStorage.getItem("organizationId");
const roleTag = localStorage.getItem("roleTag");
const [selectedOrganization, setSelectedOrganization] = useState({
label: localStorage.getItem("organizationName"),
value: organizationId,
});
// const [organizationOptions, setOrganizationOptions] = useState([]);
// const organizationId = localStorage.getItem("organizationId");
// const roleTag = localStorage.getItem("roleTag");
// const [selectedOrganization, setSelectedOrganization] = useState({
// label: localStorage.getItem("organizationName"),
// value: organizationId,
// });
const [areasOptions, setAreasOptions] = useState([]);
const [done, setDone] = useState(false);
@@ -146,7 +218,7 @@ const Map = () => {
const [showDataInputModal, setShowDataInputModal] = useState(false);
const [inputData, setInputData] = useState({
organization: selectedOrganization,
// organization: selectedOrganization,
});
const [referance, setReferance] = useState(
Number(localStorage.getItem("referance")) || 1000
@@ -176,15 +248,17 @@ const Map = () => {
dispatch(getDataCenters());
}, []);
useEffect(() => {
if (selectedOrganization?.value != "undefined") {
dispatch(getAreasWithCriteria(selectedOrganization.value));
}
}, [selectedOrganization]);
// useEffect(() => {
// if (selectedOrganization?.value != "undefined") {
// dispatch(getAreasWithCriteria(selectedOrganization.value));
// }
// }, [selectedOrganization]);
useEffect(() => {
setAreasOptions([]);
// Load all areas without organization filter for now
// You may want to add organization filtering back later if needed
const citiesOptions =
areasStore?.areasWithCriteria
?.map((area) =>
@@ -235,13 +309,13 @@ const Map = () => {
]);
}, [areasStore]);
useEffect(() => {
if (roleTag === "SUPER_ADMIN") {
dispatch(getOrganisations());
} else {
dispatch(getOrganisationById(organizationId));
}
}, []);
// useEffect(() => {
// if (roleTag === "SUPER_ADMIN") {
// dispatch(getOrganisations());
// } else {
// dispatch(getOrganisationById(organizationId));
// }
// }, []);
const handleDataInputButtonPressed = ({ area, type }) => {
const areaName =
@@ -348,38 +422,38 @@ const Map = () => {
});
}, [selectedDistrict, districtStore?.district, year.value]);
useEffect(() => {
let organizationOptions = [];
// useEffect(() => {
// let organizationOptions = [];
if (
OrganisationsStore.organization &&
OrganisationsStore.organization.length !== 0
) {
organizationOptions.push({
value: OrganisationsStore.organization.id,
label: OrganisationsStore.organization.tag,
});
// if (
// OrganisationsStore.organization &&
// OrganisationsStore.organization.length !== 0
// ) {
// organizationOptions.push({
// value: OrganisationsStore.organization.id,
// label: OrganisationsStore.organization.tag,
// });
if (OrganisationsStore.organization.children) {
organizationOptions = [
...organizationOptions,
...OrganisationsStore.organization.children.map((organization) => ({
value: organization.child.id,
label: organization.child.tag,
})),
];
}
} else {
organizationOptions = OrganisationsStore.dataOrganization.map(
(organization) => ({
value: organization.id,
label: organization.tag,
})
);
}
// if (OrganisationsStore.organization.children) {
// organizationOptions = [
// ...organizationOptions,
// ...OrganisationsStore.organization.children.map((organization) => ({
// value: organization.child.id,
// label: organization.child.tag,
// })),
// ];
// }
// } else {
// organizationOptions = OrganisationsStore.dataOrganization.map(
// (organization) => ({
// value: organization.id,
// label: organization.tag,
// })
// );
// }
setOrganizationOptions(organizationOptions);
}, [OrganisationsStore]);
// setOrganizationOptions(organizationOptions);
// }, [OrganisationsStore]);
const renderDataInputModal = () => {
return (
@@ -628,24 +702,55 @@ const Map = () => {
<Marker
key={dc.id}
position={[dc.latitude, dc.longitude]}
icon={dataCenterIcon}
>
<Popup>
<div className="data-center-popup">
<h5 className="mb-2">{dc.dataCenter}</h5>
<p className="mb-1"><strong>{t('DataCenter.number')}:</strong> {dc.number}</p>
<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 && (
<h5 className="mb-2 text-primary">{dc.dataCenter}</h5>
<div className="mb-2">
<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>
)}
{dc.ayposURL && (
<Button
className="w-100 mb-1"
color="primary"
onClick={() => window.open(dc.ayposURL, '_blank')}
onClick={() => window.open(dc.ayposURL, "_blank")}
>
Dashboard
</Button>
@@ -699,7 +804,9 @@ const Map = () => {
setDistrictView(true);
setZoom(8.0);
let convertCordinates = convertCoordinates(city.coordinates);
let convertCordinates = convertCoordinates(
city.coordinates
);
let length = convertCordinates[0][0][0].length;
let mlength = ((length + 1) / 2).toFixed(0);
let lat1 = convertCordinates[0][0][0][0];
@@ -710,7 +817,7 @@ const Map = () => {
lat: ((lat1 + lat2) / 2).toFixed(2),
lng: ((lng1 + lng2) / 2).toFixed(2),
});
}
},
}}
>
<Tooltip permanent direction="center">