Compare commits

..
Author SHA1 Message Date
Alex Holliday a236bec6c1 notification channel fix 2026-01-08 18:55:17 +00:00
Alex Holliday b4d127c6ce role fix 2026-01-08 18:53:11 +00:00
Alex Holliday 0dd977eeef refactore role service 2026-01-08 18:51:56 +00:00
Alex Holliday 58a77d6aa2 refactor to use repository 2026-01-08 17:47:26 +00:00
Alex Holliday c42932a7b3 refactor 2026-01-08 17:27:02 +00:00
Alex Holliday c1bb1fd29d refactor me service 2026-01-07 22:18:48 +00:00
Alex Holliday 03ce8f84ea fe 2026-01-07 21:39:32 +00:00
Alex Holliday 77f943a7c7 be 2026-01-07 21:11:44 +00:00
Alex Holliday 9248870716 auth service 2026-01-07 19:50:06 +00:00
Alex Holliday a3e24b5420 refactor auth service 2026-01-07 00:00:50 +00:00
Alex Holliday 3611aee468 ts fixes 2026-01-06 23:04:30 +00:00
Alex Holliday 61bf2a0dfb use repos 2026-01-06 22:53:54 +00:00
Alex Holliday 052b9377bc delete many 2026-01-06 21:08:41 +00:00
Alex Holliday ba7cc3bb0c ts errors 2026-01-06 20:55:27 +00:00
Alex Holliday 51081a6a0e incidents repo and data reversal 2026-01-06 20:49:06 +00:00
Alex Holliday 605b4713af ts errors 2026-01-05 23:50:34 +00:00
Alex Holliday 81d6c4651f CheckService 2026-01-05 23:14:19 +00:00
Alex Holliday 74f22a3e70 fix date tick 2026-01-05 21:23:15 +00:00
Alex Holliday ce568424a3 fix remaining type issues 2026-01-05 21:12:28 +00:00
Alex Holliday 9583332852 data utils fix 2026-01-05 20:23:20 +00:00
Alex Holliday afb30dceff up/down check fix 2026-01-05 19:57:56 +00:00
Alex Holliday 7aae57e9ab refactor monitor stats 2026-01-05 19:45:30 +00:00
Alex Holliday 36cdb20dfc types 2026-01-05 17:58:47 +00:00
Alex Holliday e62e4898b9 notificaitons 2026-01-05 04:35:01 +00:00
Alex Holliday 3182141d0a GroupedChecks 2026-01-05 04:17:11 +00:00
Alex Holliday cdc58e5905 import 2026-01-04 22:44:39 +00:00
Alex Holliday 7ef1803cf0 getallembedchecks 2026-01-04 22:24:55 +00:00
Alex Holliday 6e341108bb inject check repo 2026-01-03 21:16:46 +00:00
Alex Holliday af6c242a18 Create repo and domain model 2026-01-03 20:58:37 +00:00
Alex Holliday e2b012fdde auth service 2026-01-03 20:47:02 +00:00
Alex Holliday e5ef14215f status pages 2026-01-03 20:32:16 +00:00
Alex Holliday 602597abe2 jobqueue and stauts service 2026-01-02 23:28:36 +00:00
Alex Holliday 3bdfe5567d Rename methods 2026-01-02 22:20:43 +00:00
Alex Holliday 56aa7b3e1a refactor service 2026-01-02 22:16:00 +00:00
Alex Holliday 82cb59ae9e docker, infra, and pagespeed 2026-01-02 20:53:50 +00:00
Alex Holliday 8e6a8e5a06 uptime 2026-01-02 20:33:34 +00:00
Alex Holliday 7f15811fdf defensive checks 2025-12-31 20:51:30 +00:00
Alex Holliday 86cfc89545 docker details tweaks 2025-12-30 22:21:51 +00:00
Alex Holliday 5c9d6b5523 server 2025-12-30 21:50:38 +00:00
Alex Holliday 8b079905a3 client 2025-12-30 21:47:03 +00:00
Alex Holliday 7a01a8a8a3 stauts 2025-12-30 20:30:20 +00:00
Alex Holliday f56f91c31d rollup 2025-12-30 19:49:13 +00:00
Alex Holliday dea0ff106f health and status 2025-12-30 19:27:26 +00:00
Alex Holliday 445b594cab client 2025-12-30 19:23:48 +00:00
Alex Holliday 4f4863db75 details barebones 2025-12-29 23:00:39 +00:00
Alex Holliday a4d818e0c5 docker monitors skeleotn 2025-12-29 20:22:28 +00:00
Alex Holliday 378a40ce84 backend implementation 2025-12-29 19:52:22 +00:00
Alex Holliday a250bf38aa Merge branch 'fix/form-cleanup' into feat/saas 2025-12-29 18:32:18 +00:00
Alex Holliday 18408a6bf6 finish form extraction 2025-12-29 18:28:30 +00:00
Alex Holliday 6dcfb67246 status page 2025-12-28 19:49:36 +00:00
Alex Holliday 8fb13273bf settings 2025-12-28 19:36:14 +00:00
Alex Holliday a2454cbab6 teams 2025-12-28 19:25:51 +00:00
Alex Holliday 15ceb4af46 teams 2025-12-28 19:20:06 +00:00
Alex Holliday 24cbcec2c9 maintenance 2025-12-28 19:12:35 +00:00
Alex Holliday e55ae64222 infra and notification 2025-12-28 18:59:05 +00:00
Alex Holliday 4dfeb71a9d infra refactor 2025-12-28 18:35:14 +00:00
Alex Holliday df707ab194 pagespeed cleanup 2025-12-28 07:05:09 +00:00
Alex Holliday 16aec18c28 refactor uptime forms' 2025-12-28 01:48:08 +00:00
Alex Holliday de39688663 Merge branch 'feat/saas' of github.com:bluewave-labs/Checkmate into feat/saas 2025-12-28 00:10:33 +00:00
Alex Holliday 4ed89ace23 restore loading state 2025-12-27 16:09:02 +00:00
Alex Holliday 7961a9a88e cleanup register and login 2025-12-27 16:07:57 +00:00
Alex Holliday 805ee93914 translations 2025-12-23 13:50:24 -08:00
Alex Holliday a967c12ba5 Merge branch 'feat/saas' of github.com:bluewave-labs/Checkmate into feat/saas 2025-12-23 20:10:43 +00:00
Alex Holliday 3f8198f3df remove unused indexes 2025-12-23 20:10:18 +00:00
Alex Holliday 658c7c090f error fixes 2025-12-23 19:54:00 +00:00
Alex Holliday 4667c59573 improve checks fetch and paginaiton 2025-12-23 19:26:07 +00:00
Alex Holliday 6978a7e2bb check indexes 2025-12-23 18:15:59 +00:00
Alex Holliday 7f33251961 checks table message 2025-12-22 16:53:05 -08:00
Alex Holliday 46740aa4b9 ts 2025-12-23 00:36:03 +00:00
Alex Holliday 92fd405395 check card details 2025-12-23 00:34:40 +00:00
Alex Holliday 9f32eb6362 legend 2025-12-22 17:59:11 +00:00
Alex Holliday b200157f28 chart 2025-12-22 16:28:14 +00:00
Alex Holliday 6323f70bd2 check details 2025-12-22 06:39:00 +00:00
Alex Holliday 7681edbf49 navigate on click 2025-12-21 19:37:43 +00:00
Alex Holliday 66c406151a check details base 2025-12-19 15:12:30 -08:00
Alex Holliday d139e0b643 cleanup 2025-12-19 22:28:08 +00:00
Alex Holliday 1a8a18248b cleanup 2025-12-19 20:27:24 +00:00
Alex Holliday 26ed713923 extract getStartState 2025-12-19 19:10:06 +00:00
Alex Holliday 9fa2980204 Remove deprecated dateFormat 2025-12-19 18:54:53 +00:00
Alex Holliday 0535ddbc38 fix 1h range 2025-12-19 18:52:07 +00:00
Alex Holliday caca71dce5 2h -> 1h 2025-12-19 18:41:01 +00:00
Alex Holliday 08d53b80b7 extract methods 2025-12-19 18:26:24 +00:00
Alex Holliday d8007a9a5f fix peer cert 2025-12-19 18:18:42 +00:00
Alex Holliday df95ee7687 temporarily comment out cert 2025-12-19 09:26:02 -08:00
Alex Holliday e07c82611c disable cert expiry 2025-12-18 14:46:56 -08:00
Alex Holliday e76fc05f8d weakset for sockets 2025-12-18 21:37:09 +00:00
Alex Holliday 4d7c5ca885 Merge branch 'feat/saas' of github.com:bluewave-labs/Checkmate into feat/saas 2025-12-18 21:21:25 +00:00
Alex Holliday 61d40c7cd8 reuse socket listener 2025-12-18 21:21:18 +00:00
Alex Holliday 88dc2f4096 format x-axis 2025-12-18 12:57:05 -08:00
Alex Holliday 6f41167456 missing x axis 2025-12-18 12:53:16 -08:00
Alex Holliday 40977775f0 fix conditional rendering 2025-12-18 12:45:34 -08:00
Alex Holliday 93dd49c875 fix breadcrumb 2025-12-18 12:41:43 -08:00
Alex Holliday a2db7b46d6 date trunc 2025-12-18 19:20:06 +00:00
Alex Holliday 58f5896d15 conditional sort, bounded end date 2025-12-18 19:17:32 +00:00
Alex Holliday aa346abf5b indexes 2025-12-18 19:04:44 +00:00
Alex Holliday 1ee8a873f6 Merge branch 'feat/saas' of github.com:bluewave-labs/Checkmate into feat/saas 2025-12-18 18:50:47 +00:00
Alex Holliday fdd935c676 check idx 2025-12-18 18:50:20 +00:00
Alex Holliday d12a6cce8a cleanup StatsAggregation 2025-12-17 16:04:18 -08:00
Alex Holliday 35a6d5711d remove logs 2025-12-17 15:13:08 -08:00
Alex Holliday 8c9a4bd6ec logs 2025-12-17 23:08:19 +00:00
Alex Holliday 3f33b302f9 midbucket date 2025-12-17 22:44:39 +00:00
Alex Holliday 96567a9818 tests 2025-12-17 22:26:03 +00:00
Alex Holliday 5489a107f9 diagnostics locale 2025-12-17 14:18:06 -08:00
Alex Holliday 9f695ecdcc ts error 2025-12-17 21:13:34 +00:00
Alex Holliday c8dc5b93cb aggregates 2025-12-17 21:11:51 +00:00
Alex Holliday 95e415ed13 comments 2025-12-17 19:27:20 +00:00
Alex Holliday 59e85f7613 hourly stats and daily rollup 2025-12-17 19:20:03 +00:00
Alex Holliday e1db8ea513 debian 2025-12-16 23:51:34 +00:00
Alex Holliday f9f94cc33c qemu 2025-12-16 23:46:00 +00:00
Alex Holliday a17309e17c job name 2025-12-16 23:37:25 +00:00
Alex Holliday 57d714ac59 SSH 2025-12-16 23:36:38 +00:00
Alex Holliday 60e50cb5db action 2025-12-16 23:19:04 +00:00
Alex Holliday aa282439fc Fix autocomlete alignment 2025-12-16 21:49:03 +00:00
Alex Holliday f92d08810a stripe service test 2025-12-16 21:20:19 +00:00
Alex Holliday 9222d0b62d setting sservices tests 2025-12-16 21:17:29 +00:00
Alex Holliday 4b1e8fb002 Remove unused service registry 2025-12-16 21:12:58 +00:00
Alex Holliday 837c4598ff loading state 2025-12-16 20:37:25 +00:00
Alex Holliday 0b626f991f move ApiResponse 2025-12-16 19:09:08 +00:00
Alex Holliday 03b6d5976c remove me from auth controller 2025-12-16 18:40:13 +00:00
Alex Holliday 968eb6a2a8 skeleton card colors 2025-12-16 18:26:20 +00:00
Alex Holliday 465e673f4b empty view updated 2025-12-16 18:15:47 +00:00
Alex Holliday 422d13ef25 udpate /me 2025-12-15 23:36:50 +00:00
Alex Holliday 666d522ee9 fc -> plain 2025-12-15 22:19:00 +00:00
Alex Holliday 660346d2bc close sidebar on click 2025-12-15 20:42:33 +00:00
Alex Holliday 07b08d0037 paginaiton fix 2025-12-15 20:31:37 +00:00
Alex Holliday 71575a9d86 useTeamIdAsKey 2025-12-15 19:48:38 +00:00
Alex Holliday e4183baf75 reload on team change 2025-12-15 19:39:23 +00:00
Alex Holliday 4e3630465c infra error handling 2025-12-15 19:24:38 +00:00
Alex Holliday 2e523cc431 render strings 2025-12-15 19:13:20 +00:00
Alex Holliday 1a2d11e6de refactor /auth/me into /me 2025-12-14 17:16:21 +00:00
Alex Holliday 4b92b2a8df entitlements factory 2025-12-14 16:41:38 +00:00
Alex Holliday fc2c3aa6a6 teams form 2025-12-14 00:35:39 +00:00
Alex Holliday 2eb6850cb9 diagnostics access 2025-12-14 00:24:53 +00:00
Alex Holliday 6f99249d62 client 2025-12-13 23:12:02 +00:00
Alex Holliday 9aa87f57ae Fe 2025-12-13 22:04:32 +00:00
Alex Holliday 16c7a007d5 env 2025-12-13 16:58:30 +00:00
Alex Holliday 92f7a929fa billing 2025-12-12 14:56:54 -08:00
Alex Holliday 5e9c85f372 billing 2025-12-12 14:54:20 -08:00
Alex Holliday 901b5a43c8 auth 2025-12-12 12:17:18 -08:00
Alex Holliday c9dea5c0ae strings 2025-12-12 10:54:26 -08:00
Alex Holliday 22f7d002fd notifications 2025-12-11 15:20:21 -08:00
Alex Holliday 63dd455e4a infra locale 2025-12-11 13:30:43 -08:00
Alex Holliday 64d1ba08f9 locale 2025-12-11 12:50:30 -08:00
Alex Holliday b94e6052c3 strings 2025-12-11 10:55:17 -08:00
Alex Holliday d6cddbd812 locale reset 2025-12-11 18:48:28 +00:00
Alex Holliday fe03451393 status page pagination 2025-12-11 18:41:38 +00:00
Alex Holliday b6a3d1e34d refactor entitlements 2025-12-11 18:07:22 +00:00
Alex Holliday 9bfe146e2b index 2025-12-10 19:58:50 +00:00
Alex Holliday c7945aa4a9 dockerfile 2025-12-10 19:26:24 +00:00
Alex Holliday 0d41e7229b env 2025-12-10 19:14:07 +00:00
Alex Holliday 8d3d764a0d config 2025-12-10 19:01:59 +00:00
Alex Holliday 35679fb433 gitignore 2025-12-10 18:23:07 +00:00
Alex Holliday 4eb2f0bee3 assets 2025-12-10 18:22:52 +00:00
Alex Holliday 2cb803948c dockerfile 2025-12-10 17:47:02 +00:00
Alex Holliday 85589d6d3a dockerfile 2025-12-10 17:43:35 +00:00
Alex Holliday 93317cbba7 ts 2025-12-09 22:11:19 +00:00
Alex Holliday 8ae7638432 logo adjustment, remove console.log 2025-12-09 22:10:07 +00:00
Alex Holliday 4f01ed7019 config trim 2025-12-09 21:27:23 +00:00
Alex Holliday b4e4ec1110 ts 2025-12-09 21:15:27 +00:00
Alex Holliday bda3a7e91c loading indicators 2025-12-09 21:01:47 +00:00
Alex Holliday 03d681f212 log 2025-12-09 19:24:48 +00:00
Alex Holliday 69ea8eaf6b table 2025-12-09 19:01:56 +00:00
Alex Holliday bd14ea3461 fix skeleton 2025-12-09 18:49:57 +00:00
Alex Holliday 3616b69925 pagespeed 2025-12-08 23:55:27 +00:00
Alex Holliday e12e198aed export team incidents 2025-12-08 23:18:46 +00:00
Alex Holliday 36208aacea pagespeed fixes 2025-12-08 22:19:07 +00:00
Alex Holliday f78ea7ab9c remove ripples 2025-12-08 22:12:07 +00:00
Alex Holliday a8e55db134 fix buttons 2025-12-08 22:08:22 +00:00
Alex Holliday 50b734cf24 sidebar 2025-12-08 21:58:35 +00:00
Alex Holliday a3f7ac8ae3 dialogs 2025-12-08 21:40:04 +00:00
Alex Holliday 4525f8035b status box update and res card update 2025-12-08 21:25:33 +00:00
Alex Holliday 8274eb2ec9 fix logo 2025-12-08 21:13:37 +00:00
Alex Holliday b6c699c141 finish nuking theme 2025-12-08 21:10:29 +00:00
Alex Holliday dd463bb60b nuke theme 2025-12-08 19:55:29 +00:00
Alex Holliday 32fbb8f434 new palette 2025-12-08 18:43:22 +00:00
Alex Holliday 28ebdcb216 update incident table 2025-12-08 18:19:07 +00:00
Alex Holliday c762f9425a cleanup 2025-12-08 18:13:49 +00:00
Alex Holliday b3206f4011 resolutionc ard width 2025-12-08 17:43:02 +00:00
Alex Holliday c0a8398baa incident links 2025-12-08 17:22:17 +00:00
Alex Holliday 2b3c601a05 resolution card 2025-12-08 02:29:52 +00:00
Alex Holliday b4135e26ce details 2025-12-07 04:38:37 +00:00
Alex Holliday 0453b790af infra thresholds FE 2025-12-07 03:34:33 +00:00
Alex Holliday 7631e65cd2 thresholds be 2025-12-05 22:46:46 +00:00
Alex Holliday 2ab983eff5 evaluate threshold 2025-12-05 01:13:23 +00:00
Alex Holliday 75ef6c934d add monitor thresholds 2025-12-04 21:52:50 +00:00
Alex Holliday ba6c9a481d most popular chip 2025-12-04 20:26:21 +00:00
Alex Holliday 5c889f3a63 plan card tweaks 2025-12-03 21:21:00 +00:00
Alex Holliday c088956d6f numeric values 2025-12-03 20:49:00 +00:00
Alex Holliday 30d7b3d258 fix entitlements on login 2025-12-02 21:46:01 +00:00
Alex Holliday 53355cad04 price cards 2025-12-02 20:52:27 +00:00
Alex Holliday 07efd08837 billing tweaks 2025-12-02 19:12:19 +00:00
Alex Holliday a9a598941f fix 2025-12-02 17:44:44 +00:00
Alex Holliday ad2954e326 fix 2025-12-02 17:33:16 +00:00
Alex Holliday d77de3b6bc logging 2025-12-02 17:24:42 +00:00
Alex Holliday e0e260be8f success page 2025-12-02 17:00:37 +00:00
Alex Holliday 634885c362 update socket 2025-12-02 00:31:21 +00:00
Alex Holliday 1b162578c2 stripe 2025-12-02 00:20:09 +00:00
Alex Holliday 01c0e9ef4d create customer 2025-12-01 03:45:57 +00:00
Alex Holliday 7b207f2ccb fe 2025-12-01 00:35:53 +00:00
Alex Holliday 6bca0ed00b billing skeleton 2025-11-30 17:16:30 +00:00
Alex Holliday d76da4b00c relocate permissions 2025-11-30 17:08:31 +00:00
Alex Holliday 6eabaebd86 stripe controller 2025-11-30 16:52:48 +00:00
Alex Holliday f476a57748 protect routes and import function 2025-11-29 19:24:08 +00:00
Alex Holliday e600f293b0 entitlements FE 2025-11-28 22:48:32 +00:00
Alex Holliday c43241eb52 entitlementsBE 2025-11-28 21:31:44 +00:00
Alex Holliday 86ce30b5f4 admin settings 2025-11-28 19:48:57 +00:00
Alex Holliday 08887bbc58 checks retention routes 2025-11-27 23:37:29 +00:00
Alex Holliday ce97e201c9 correct check ttl 2025-11-27 23:05:58 +00:00
Alex Holliday 229027830d udpate tests 2025-11-27 21:23:09 +00:00
Alex Holliday 5876b97ede reject unauthorized 2025-11-27 20:41:49 +00:00
Alex Holliday 686b96d4b3 ssl 2025-11-27 19:39:26 +00:00
Alex Holliday ee04ac2b98 delete all 2025-11-26 23:57:40 +00:00
Alex Holliday 6c04f46e8a fix deps 2025-11-26 23:17:41 +00:00
Alex Holliday 8774042725 search 2025-11-26 22:22:15 +00:00
Alex Holliday c50b0cbfd6 ts 2025-11-26 13:51:44 -08:00
Alex Holliday 5780c0b969 button groups 2025-11-26 21:37:12 +00:00
Alex Holliday 36d13d556e test notifications 2025-11-26 20:40:21 +00:00
Alex Holliday cb5d8c3468 parallelization 2025-11-26 19:56:47 +00:00
Alex Holliday 4e8281aefb parallelize notifications 2025-11-26 19:26:16 +00:00
Alex Holliday 92750ce8f9 native props 2025-11-26 18:57:51 +00:00
Alex Holliday 5f43c23b26 fixes for allback 2025-11-26 18:56:48 +00:00
Alex Holliday 746ed4a3c1 fix fallback 2025-11-26 18:46:58 +00:00
Alex Holliday 816a1607a1 middleware 2025-11-26 17:52:39 +00:00
Alex Holliday 3bffe61b42 border 2025-11-25 23:58:30 +00:00
Alex Holliday 33aab936fe radio 2025-11-25 23:37:56 +00:00
Alex Holliday b5bdd73a90 settings 2025-11-25 23:07:16 +00:00
Alex Holliday 4a79013ef2 gap 2025-11-25 20:32:58 +00:00
Alex Holliday a8d83b33b4 add heatmap chart 2025-11-25 19:56:26 +00:00
Alex Holliday c2a1d6d97e use heathmap 2025-11-25 19:03:48 +00:00
Alex Holliday 68ab185f84 404 2025-11-24 22:55:37 +00:00
Alex Holliday 82dbac9ac9 error pages 2025-11-24 22:50:33 +00:00
Alex Holliday 1e26fb1e3b improve test coverage 2025-11-24 22:49:55 +00:00
Alex Holliday d5f1032bdf Add message to check table 2025-11-24 20:04:07 +00:00
Alex Holliday db64ad1de4 add additional tests 2025-11-24 20:03:06 +00:00
Alex Holliday ef4ca52285 Fix tests 2025-11-24 19:19:27 +00:00
Alex Holliday e0d4f0d0f6 Add init box 2025-11-24 19:13:38 +00:00
Alex Holliday f7490ffe64 consistent spacing for autocomplete 2025-11-24 19:03:06 +00:00
Alex Holliday 9be77a547d checkboxes 2025-11-24 18:54:52 +00:00
Alex Holliday e4d6e0930f fix single item display 2025-11-24 18:42:30 +00:00
Alex Holliday 2319b67d05 add placeholder 2025-11-24 18:07:47 +00:00
Alex Holliday 94ecaddae2 ts 2025-11-21 15:48:06 -08:00
Alex Holliday e032e4b9b6 ts 2025-11-21 15:46:07 -08:00
Alex Holliday b88c46a6a1 fix invite 2025-11-21 23:44:20 +00:00
Alex Holliday 3c71583324 permissions on FE for email settings 2025-11-21 14:26:41 -08:00
Alex Holliday 710d506de2 fix middleware 2025-11-21 13:59:29 -08:00
Alex Holliday c92c7fb9c1 ts errors 2025-11-21 21:06:16 +00:00
Alex Holliday 3a1fb61847 docker 2025-11-21 21:00:36 +00:00
Alex Holliday 9bce91c20d incident cleanup 2025-11-21 20:18:34 +00:00
Alex Holliday 1683c2980e round port resonse time 2025-11-21 20:06:11 +00:00
Alex Holliday 5d825537ae implement port monitoring 2025-11-21 20:03:03 +00:00
Alex Holliday caa863afe8 add loading state to dialog 2025-11-20 23:34:05 +00:00
Alex Holliday 6881be7555 monitor import/export 2025-11-20 23:27:30 +00:00
Alex Holliday af6fede1b3 email config 2025-11-20 21:17:52 +00:00
Alex Holliday 60153a88e2 email env priority 2025-11-20 19:27:22 +00:00
Alex Holliday 3faff5dc54 email settings 2025-11-19 23:55:29 +00:00
Alex Holliday 819c0ca05a default sort 2025-11-19 21:01:45 +00:00
Alex Holliday 459d78cbcb sorting 2025-11-19 20:53:25 +00:00
Alex Holliday eea6b12be6 isActive -> stauts === paused 2025-11-19 19:06:17 +00:00
Alex Holliday 196ebc30dc isActive -> stauts === paused 2025-11-19 19:06:04 +00:00
Alex Holliday f40667615e system settings 2025-11-19 00:00:08 +00:00
Alex Holliday 986e8b926a featur eflags 2025-11-18 23:11:25 +00:00
Alex Holliday bab99059c5 simplify 2025-11-18 21:49:07 +00:00
Alex Holliday adbb4e7817 implement monitor filter 2025-11-18 21:43:35 +00:00
Alex Holliday a40277be4a udpate server 2025-11-14 15:56:52 -08:00
Alex Holliday dd302c08b3 fixes 2025-11-14 15:35:37 -08:00
Alex Holliday 55784c93de cleanup 2025-11-14 15:30:02 -08:00
Alex Holliday 3b738100ec remove files 2025-11-14 15:22:58 -08:00
Alex Holliday c7046be642 Merge branch 'feat/saas' of github.com:bluewave-labs/Checkmate into feat/saas 2025-11-14 23:19:39 +00:00
Alex Holliday 841a9832ec fix build 2025-11-14 23:19:11 +00:00
Alex Holliday 6379a66a8d dependencies 2025-11-14 14:55:23 -08:00
Alexander Holliday f8cea8b075 Merge pull request #3065 from bluewave-labs/feat/tests
Feat/tests
2025-11-14 14:49:54 -08:00
Alex Holliday 29b68b8c87 test case 2025-11-14 22:48:48 +00:00
Alex Holliday 30ce3f6bf4 requestStatus 2025-11-14 22:15:14 +00:00
Alex Holliday 313121d9a4 requestPing 2025-11-14 22:10:20 +00:00
Alex Holliday 04c9b28216 requestInfra 2025-11-14 21:54:44 +00:00
Alex Holliday c9d33c4292 add tests 2025-11-14 19:10:34 +00:00
Alex Holliday b4da045770 add test env 2025-11-14 17:17:41 +00:00
Alex Holliday 75acf7b38f initial commit 2025-11-13 13:47:26 -08:00
Alexander Holliday 7cb985116e Merge pull request #3050 from TudorGR/chore/status-page-include-game-type-3048
feat: include game monitor type in status page monitor selection
2025-11-03 09:20:29 -08:00
Alexander Holliday 2297494d21 Merge pull request #3055 from matserix/develop
feat(kubernetes): support Storage Classes other than 'gp3'
2025-11-03 09:19:54 -08:00
matserix 19a61b6ce4 fix: update installation guide and values for MongoDB and Redis storage classes 2025-11-03 01:10:45 +01:00
matserix 492aed200a feat: support Storage Classes other than 'gp3' 2025-11-03 00:44:57 +01:00
Alexander Holliday be2f33b5d1 Merge pull request #3052 from bluewave-labs/fix/addjob
fix missing param
2025-10-30 10:58:45 -07:00
Alex Holliday 5d48cecee8 fix missing param 2025-10-30 10:57:48 -07:00
Gorkem Cetin (BWL) f0bfe1a152 Merge pull request #3049 from magicpages/detailed-response-times
fix: use sentence case for tooltip labels
2025-10-30 10:38:39 -04:00
Tudor Gradinaru d2ff386f97 feat: include game monitor type in status page monitor selection 2025-10-30 11:37:43 +02:00
Jannis Fedoruk-Betschki 42eaa75437 fix: use sentence case for tooltip labels 2025-10-30 07:25:48 +01:00
Alexander Holliday 7fb4e75956 Merge pull request #3047 from magicpages/detailed-response-times
feat: add detailed response time breakdown in Response Times table
2025-10-29 19:11:08 -07:00
Jannis Fedoruk-Betschki 87c549960e fix: use array parameter instead of closure for i18n-safe bold styling 2025-10-29 20:33:14 +01:00
Jannis Fedoruk-Betschki 4ac0f1e87f feat: add detailed response time breakdown in Response Times table 2025-10-29 20:22:57 +01:00
Alexander Holliday 5465bee630 Merge pull request #3046 from bluewave-labs/feat/cleanup
prune
2025-10-29 10:04:11 -07:00
Alex Holliday 60a3d46e59 prune 2025-10-29 10:03:16 -07:00
Gorkem Cetin (BWL) e100d54eed Simplify README by removing redundant content
Removed redundant section about Checkmate's codebase walkthrough and dataflow simulation tutorial.
2025-10-29 07:28:09 -04:00
Gorkem Cetin (BWL) 848d50ec43 Merge pull request #3043 from Abdullah85MBA/codecanvas-diagram-1761668096103
Added interactive CodeCanvas diagram for Checkmate
2025-10-29 07:26:29 -04:00
Alexander Holliday a9a8686295 Merge pull request #3044 from bluewave-labs/fix/cache-dns
add cacheable dns, stagger start times
2025-10-29 01:17:22 -07:00
Alex Holliday 30a9309bd8 add cacheable dns, stagger start times 2025-10-28 22:41:05 -07:00
Abi ab64cd192b Updated Readme screenshot 2025-10-28 12:29:59 -04:00
Abi 5fc2c8c14b Add CodeCanvas diagram to README 2025-10-28 12:15:26 -04:00
Abi ea7ce450f1 Merge develop into codecanvas-diagram-1761668096103 to sync with upstream 2025-10-28 12:15:00 -04:00
Abi ce77b43705 CodeCanvas: Save 2025-10-28 12:14:58 -04:00
Alexander Holliday bd2ba804ee Merge pull request #3040 from bluewave-labs/feat/bump-version
bump version
2025-10-27 10:30:23 -07:00
Alexander Holliday bd75f7b0fc Merge pull request #3041 from bluewave-labs/translation-update-80
🌐 Updated Translations from POEditor
2025-10-27 10:30:07 -07:00
GitHub Action 32e4f7514d feat: translations updated from POEditor 2025-10-27 17:29:47 +00:00
Alex Holliday c9e1d35daf bump version 2025-10-27 10:27:45 -07:00
Alexander Holliday 3be6ae91f2 Merge pull request #3039 from bluewave-labs/fix/bump-scheduler
bump-scheduler
2025-10-27 09:46:23 -07:00
Alex Holliday 931104fbcf type error 2025-10-27 09:45:21 -07:00
Alex Holliday 1d5cec94a5 bump-scheduler 2025-10-27 09:42:27 -07:00
Alexander Holliday faeec01a6d Merge pull request #3029 from LinPr/fix
fix/v1: Remove unnecessary import
2025-10-27 09:37:38 -07:00
Alexander Holliday b8db987579 Merge pull request #3037 from TudorGR/feat/matrix-notifications
feat: Add Matrix notification support
2025-10-27 09:36:09 -07:00
Tudor Gradinaru 1fad85d48d feat: Add Matrix notification support Fixes #3034 2025-10-25 18:35:15 +03:00
Alexander Holliday eb70c9f5f0 Merge pull request #3036 from TudorGR/feature/add-monitor-name-to-notification-title
feat: Add monitor name to notification titles
2025-10-23 09:38:29 -07:00
Tudor Gradinaru ce025df7b7 feat: Add monitor name to notification titles 2025-10-23 15:32:29 +03:00
Alexander Holliday daf5797fed Merge pull request #3031 from bluewave-labs/translation-update-79
🌐 Updated Translations from POEditor
2025-10-20 10:36:43 -07:00
GitHub Action 0baa7d9891 feat: translations updated from POEditor 2025-10-20 17:36:14 +00:00
Gorkem Cetin (BWL) f6cd0f668f Merge pull request #3028 from bluewave-labs/feat/remove-unused-css-variables
Got an OK from Owaise.
2025-10-20 09:22:52 -04:00
LinPr 9ae83cc34d fix/v1: remove unnecessary import 2025-10-20 14:22:20 +08:00
gorkem-bwlandClaude 06ebb76948 chore: remove 13 unused CSS variables from index.css
Removed the following unused CSS variables that were leftovers from when
the project switched to the MUI theme system:

- --env-var-radius-1
- --env-var-width-1
- --env-var-width-3
- --env-var-height-1
- --env-var-spacing-3
- --env-var-spacing-4
- --env-var-spacing-5
- --env-var-img-width-1
- --env-var-img-width-2
- --env-var-img-width-3
- --env-var-default-1
- --env-var-default-2
- --env-var-shadow-1

These variables are not referenced anywhere in the codebase. The project
now uses MUI theme configuration (theme.spacing(), theme.palette.*)
instead of CSS variables for styling.

Kept 19 CSS variables that are still actively used during the migration
to pure MUI theme.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 23:18:50 -04:00
Alexander Holliday 3a8ba154b2 Merge pull request #2992 from AlexHladin/chore/drop-nodemon
chore: drop nodemon
2025-10-17 20:03:45 -07:00
Alexander Holliday 089801109e Merge pull request #3018 from bluewave-labs/v2-select-component
Add Select component v2 with TypeScript and improved code efficiency
2025-10-14 13:24:33 -07:00
karenvicent a8a4b5c2b4 Merge branch 'develop' into v2-select-component 2025-10-14 15:58:52 -04:00
Alexander Holliday 089bda2de0 Merge pull request #3023 from bluewave-labs/fix/v2-utils
move v2 utils to v2 dir
2025-10-14 12:45:34 -07:00
Alex Holliday e18e2e26da move v2 utils to v2 dir 2025-10-14 12:45:11 -07:00
karenvicent 104cf194ac fix create more specific component 2025-10-14 12:22:20 -04:00
Alexander Holliday de7cdb4aef Merge pull request #3019 from bluewave-labs/feature/monitor-grouping-backend
feat: Add monitor grouping functionality (Backend)
2025-10-14 09:05:34 -07:00
gorkem-bwlandClaude 6bdf9891e8 Fix server formatting issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 21:51:06 -04:00
gorkem-bwlandClaude 27d37ece7d feat: Add monitor grouping functionality to backend
- Add optional 'group' field to Monitor schema with trimming and validation
- Add group validation to Joi schemas for create and edit monitor endpoints
- Add GET /api/v1/monitors/team/groups endpoint to fetch unique groups
- Implement case-insensitive group filtering in database layer
- Support for organizing monitors into collapsible groups

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 21:11:20 -04:00
karenvicent b9afca3608 Merge branch 'develop' into v2-select-component 2025-10-09 18:25:38 -04:00
karenvicent b796464241 select component V2 2025-10-09 18:16:25 -04:00
Alexander Holliday 97a14ed926 Merge pull request #3017 from bluewave-labs/fix/v2/sticky-sidebar
fix/v2: sticky sidebar
2025-10-09 14:00:35 -07:00
Alex Holliday 5018c56d0d stikcy sidebar 2025-10-09 14:00:04 -07:00
Alexander Holliday c7799ca7dc Merge pull request #3016 from bluewave-labs/fix/v2/normalization
Fix/v2/normalization
2025-10-09 13:56:10 -07:00
Alex Holliday 78b5cc9c6f ts 2025-10-09 13:55:39 -07:00
Alex Holliday ab3e6cdff9 normalzie on FE 2025-10-09 13:53:34 -07:00
Alexander Holliday 1cc01e6952 Merge pull request #3015 from bluewave-labs/feat/v2/fallbacks
feat/v2: add fallbacks
2025-10-09 12:46:19 -07:00
Alex Holliday fb90f193b1 add fallbacks 2025-10-09 12:44:27 -07:00
Alexander Holliday 1bacab89bb Merge pull request #3014 from bluewave-labs/fix/v2/auth-pages
fix/v2: add missing auth elements
2025-10-09 11:07:43 -07:00
Alex Holliday 7378f2e33b add missing auth elements 2025-10-09 11:06:34 -07:00
Alexander Holliday d0bb2b2ad5 Merge pull request #3013 from bluewave-labs/fix/network-timing
fix network timing for port and docker
2025-10-09 09:35:41 -07:00
Alex Holliday 376da7c70e fix network timing for port and docker 2025-10-09 09:33:14 -07:00
Alexander Holliday d58e5cf7ee Merge pull request #3012 from bluewave-labs/fix/keep-previous-data
fix/v2: add keep previous data
2025-10-08 15:29:41 -07:00
Alex Holliday e02eb2e30c add keep previous data 2025-10-08 15:27:53 -07:00
Alexander Holliday c4906d069a Merge pull request #3009 from bluewave-labs/feat/v2-implement-actions
update usePatch, implement actions
2025-10-08 15:00:43 -07:00
Alex Holliday d4ed535454 update prod env 2025-10-08 14:52:21 -07:00
Alex Holliday f9d0ab5e07 update usePatch, implement actions 2025-10-08 14:28:51 -07:00
Alexander Holliday 0a5efc75cd Merge pull request #3008 from bluewave-labs/feat/v2/uptime-details
feat/v2/uptime details
2025-10-08 13:48:05 -07:00
Alex Holliday aae1fefb31 add checks endpoint 2025-10-08 13:45:07 -07:00
Alex Holliday 86bb28e239 pagination 2025-10-08 13:44:41 -07:00
Alex Holliday 16b68b3d00 rever types 2025-10-07 15:46:35 -07:00
Alex Holliday a700f446fd add header 2025-10-07 15:46:09 -07:00
Alex Holliday 2246f227d1 30m -> 2h 2025-10-07 14:45:07 -07:00
Alex Holliday 29fbf0a362 charts 2025-10-07 14:44:55 -07:00
Alex Holliday 8a1fc94c31 stat boxes 2025-10-06 15:08:55 -07:00
Alex Holliday abadc99bf1 status 2025-10-06 13:59:31 -07:00
Alexander Holliday 7af7647bbf Merge pull request #2999 from bluewave-labs/feat-allow-admin-change-passwords
Add superadmin password reset functionality for team members
2025-10-06 12:52:46 -07:00
karenvicent 9a24090337 fix variable name 2025-10-06 15:43:17 -04:00
karenvicent d81a4ef0ee fix user service 2025-10-06 15:15:56 -04:00
Alexander Holliday cfb1830b55 Merge pull request #3005 from bluewave-labs/feat/v2/uptime
Feat/v2/uptime
2025-10-06 11:48:39 -07:00
Alex Holliday f7c094317a remove unused 2025-10-06 11:43:13 -07:00
Alex Holliday 56e0ac9640 actions menu 2025-10-06 11:40:08 -07:00
Alex Holliday 61651a0f4d action menu 2025-10-06 11:34:29 -07:00
Alex Holliday 7c3a05077c tooltip 2025-10-06 10:56:29 -07:00
Gorkem Cetin (BWL) 2d29bce97b Update CONTRIBUTING.md 2025-10-06 12:35:23 -04:00
Alexander Holliday 4f45baab00 Merge pull request #3003 from evermos/develop
Add Affinity, Tolerations, Request limit
2025-10-06 09:00:57 -07:00
Alexander Holliday 6def64d38e Merge pull request #3004 from bluewave-labs/fix/incident/numbers
Fix: Total Incident Number
2025-10-06 08:58:23 -07:00
Br0wnHammer 32b31076e6 Fix: Total Incident Number 2025-10-06 20:14:21 +05:30
ariretiarno 91a4911d42 protocol 2025-10-05 22:49:20 +07:00
ariretiarno 7298faac2b protocol 2025-10-05 22:47:48 +07:00
ariretiarno 711253beb2 affinity request limit 2025-10-05 22:36:39 +07:00
ariretiarno a380389386 ingress server 2025-10-05 22:25:33 +07:00
Alex Holliday f6b97c691e iniital uptime 2025-10-03 15:40:53 -07:00
karenvicent f31ff994fe fix errors 2025-10-03 17:11:05 -04:00
Alexander Holliday a46ef5c9dd Merge pull request #3001 from bluewave-labs/fix/v2/text-input
theme update
2025-10-03 12:57:33 -07:00
Alex Holliday 0018c452bb theme update 2025-10-03 12:56:52 -07:00
Alexander Holliday 6c6fc28f6e Merge pull request #3000 from bluewave-labs/feat/v2/create/uptime
feat/v2/create/uptime
2025-10-03 12:50:31 -07:00
Alex Holliday 575cf31c78 add typescript dev dep 2025-10-03 12:49:51 -07:00
Alex Holliday 938d9b6642 feat/v2/uptime/create 2025-10-03 12:45:21 -07:00
Gorkem Cetin (BWL) 9d68d35ca8 Merge pull request #2996 from JithendraKavala/docs/imporove-contributing-setup-instructions
docs: improve local development setup instructions in CONTRIBUTING.md
2025-10-03 15:34:18 -04:00
Alexander Holliday 8033eea267 Merge pull request #2997 from a-y-a-n-das/fix-week-datestring
fix(chart): correct 'week' date string format in chart aggregation
2025-10-02 13:35:40 -07:00
Alexander Holliday 469c4d7e99 Merge pull request #2994 from VivekKavala/fix-inaccurate-ping-times
fix: Correct inaccurate ping response times
2025-10-02 13:34:11 -07:00
karenvicent 5159d43cad fix save button validation 2025-10-02 15:40:21 -04:00
karenvicent c5bbb7aa2c Merge branch 'develop' into feat-allow-admin-change-passwords 2025-10-02 15:20:32 -04:00
karenvicent 4317d1a47e chace password by superadmin 2025-10-02 15:19:42 -04:00
a-y-a-n-das a1c04ba35e fixed the format 2025-10-02 20:43:00 +05:30
Alexander Holliday 95ad3e71ca Merge pull request #2987 from bluewave-labs/feat/v2/components
feat: move components to v1 and v2 dirs
2025-10-02 17:22:20 +05:30
AlexHladin 8bf3875d9a chore: add engines section to package.json 2025-10-02 14:17:23 +03:00
jithendra Kavala 080a33fac7 docs: improve local development setup instructions in CONTRIBUTING.md 2025-10-02 13:51:30 +05:30
Vivek Kavala 851d722746 fix: remove manual response time calculation in favor of library-native timing
The manual timing calculations were adding Node.js processing overhead
and were less accurate than the native timing provided by the respective
libraries (ping, got, etc.). Now using response.time from each library
for more accurate network response time measurements.
2025-10-02 12:46:51 +05:30
AlexHladin 3b22ce75db chore: drop nodemon 2025-10-02 00:47:11 +03:00
Alexander Holliday 5dbfb3b8c5 Merge pull request #2991 from bluewave-labs/feat/v2/sidebar
feat: v2/sidebar
2025-10-01 13:58:26 -07:00
Alex Holliday 735054b4e1 remove unused error 2025-10-01 13:57:04 -07:00
Alex Holliday 3ae2f857d4 add v2 sidebar 2025-10-01 13:55:32 -07:00
Alexander Holliday 220abb8579 Merge pull request #2989 from evermos/helmchart
helm chart
2025-10-01 13:34:50 -07:00
karenvicent 468a67f937 git stash push -m "work in progress" 2025-10-01 12:49:48 -04:00
Muhamad Ari Retiarno 99b3e3c516 Merge pull request #1 from evermos/helmchart
Helmchart
2025-10-01 11:06:47 +07:00
ariretiarno 8d48b2cc8a client host 2025-10-01 09:33:32 +07:00
ariretiarno d63731fced client host 2025-10-01 09:22:42 +07:00
ariretiarno 7a352cdcb3 client host 2025-10-01 09:16:45 +07:00
ariretiarno 4744c05f07 pvc 2025-09-30 11:35:14 +07:00
ariretiarno c6cf7a4639 helm chart 2025-09-30 11:30:21 +07:00
ariretiarno 7f2318da01 helm chart 2025-09-30 11:28:22 +07:00
Alex Holliday fc9018e314 Add collapse button and logo 2025-09-27 15:47:56 -07:00
Alexander Holliday c30d6019df Merge pull request #2987 from bluewave-labs/feat/v2/components
feat: move components to v1 and v2 dirs
2025-09-27 14:58:11 -07:00
Alex Holliday b57ed47592 remove mode prop 2025-09-27 14:57:55 -07:00
Alexander Holliday 6234be17cd Merge pull request #2986 from bluewave-labs/feat/v2/root/layout
feat/v2/root/layout
2025-09-27 14:55:17 -07:00
Alex Holliday 5cab842f0a move components to v1 and v2 dirs 2025-09-27 14:54:55 -07:00
Alex Holliday ca84c60614 Merge branch 'feat/v2/root/layout' of github.com:bluewave-labs/checkmate into feat/v2/root/layout 2025-09-27 14:48:44 -07:00
Alex Holliday 09fbc6b0b2 remove unused mode 2025-09-27 14:48:05 -07:00
Alexander Holliday f8b1998564 Merge branch 'develop' into feat/v2/root/layout 2025-09-27 14:43:18 -07:00
Alex Holliday 4d254b004d add gitignore 2025-09-27 14:38:14 -07:00
Alex Holliday 1d5f2427ed add root layout 2025-09-26 16:01:05 -07:00
Alexander Holliday 0249f89a8c Merge pull request #2984 from bluewave-labs/feat/v2/router
move v2 routes to v2 router
2025-09-26 15:33:23 -07:00
Alex Holliday ce0aaa7ac7 move v2 routes to v2 router 2025-09-26 15:31:55 -07:00
Alexander Holliday b7db3f96ba Merge pull request #2983 from bluewave-labs/feat/v2/register
add v2 register page
2025-09-26 15:25:41 -07:00
Alex Holliday ad5ab82c3b add v2 register page 2025-09-26 15:23:56 -07:00
Alexander Holliday 0567569faa Merge pull request #2982 from bluewave-labs/feat/v2/theme
feat: add typography to theme, change UsePost return type
2025-09-26 15:23:23 -07:00
Alex Holliday a8f111b399 generic return type 2025-09-26 15:22:15 -07:00
Alex Holliday 7c2f789a31 add typography to theme, change UsePost return type 2025-09-26 15:19:35 -07:00
Alexander Holliday 77c76b6b6d Merge pull request #2981 from bluewave-labs/feat/v2/auth/login
feat/v2/auth/login
2025-09-26 14:49:21 -07:00
Alex Holliday 60a90ce424 node types 2025-09-26 14:36:15 -07:00
Alex Holliday 3f581ae1b0 esm safe path 2025-09-26 14:32:16 -07:00
Alex Holliday 277aff3898 remove unused 2025-09-26 14:22:25 -07:00
Alex Holliday 0c5b9a863b add loading 2025-09-26 14:16:59 -07:00
Alex Holliday cb1e10f0a9 add v2 login page 2025-09-25 16:06:52 -07:00
Alexander Holliday 659162d60c Merge pull request #2980 from bluewave-labs/feat/typescript-config
Add typescript config, move to v1 dir
2025-09-25 10:23:15 -07:00
Alex Holliday 28ef465b3a update action name 2025-09-25 10:22:47 -07:00
Alex Holliday e29f7af858 add client build check 2025-09-25 10:21:31 -07:00
Alex Holliday 17b84cbe8a format 2025-09-25 10:19:08 -07:00
Alex Holliday 4d89213e1c Add typescript config, move to v1 dir 2025-09-25 10:11:41 -07:00
Alexander Holliday 879cbb8886 Merge pull request #2979 from bluewave-labs/fix/start-v2-queue
create and start v2 queue
2025-09-25 09:47:21 -07:00
Alex Holliday 5957479d03 express type 2025-09-25 09:46:11 -07:00
Alexander Holliday d7bc9bdb90 Merge pull request #2978 from bluewave-labs/feat/v2/routes
add v2 routes, controllers
2025-09-25 09:43:54 -07:00
Alex Holliday 811a6bf222 create and start v2 queue 2025-09-25 09:38:41 -07:00
Alex Holliday 6d0c560948 add v2 routes, controllers 2025-09-24 15:55:09 -07:00
Alexander Holliday f4b76baaa2 Merge pull request #2977 from bluewave-labs/feat/v2/services
feat/v2/services
2025-09-24 14:21:28 -07:00
Alex Holliday 76f4e974db dev types 2025-09-24 14:20:30 -07:00
Alex Holliday 66e5441bdf fix import path 2025-09-23 15:23:20 -07:00
Alex Holliday 68f4adfbfe add v2 services 2025-09-23 15:22:08 -07:00
Alexander Holliday 35a712eafb Merge pull request #2976 from bluewave-labs/feat/v2/models
feat: add v2 models
2025-09-23 14:57:03 -07:00
Alex Holliday 2d12fbdff1 fix notification schema 2025-09-23 14:56:02 -07:00
Alex Holliday c0ff162ed9 remove v2 files 2025-09-23 14:46:32 -07:00
Alex Holliday 059408f098 add v2 models 2025-09-23 14:40:57 -07:00
Alexander Holliday b118a321b9 Merge pull request #2975 from bluewave-labs/feat/v1/structure
feat/v1/structure
2025-09-23 14:25:46 -07:00
Alex Holliday b3b6f1d834 move all v1 files to v1 dirs 2025-09-23 14:23:45 -07:00
Alex Holliday 1383d8b59a add workflow 2025-09-23 14:12:17 -07:00
Alex Holliday 990aed9f2e Revert "Merge pull request #2973 from bluewave-labs/feat/v2/auth"
This reverts commit 72882fded9, reversing
changes made to bfb299cfca.
2025-09-23 14:05:23 -07:00
Alex Holliday 003d419a64 Revert "Merge pull request #2974 from bluewave-labs/fix/cleanup"
This reverts commit 7368cb2567, reversing
changes made to 72882fded9.
2025-09-23 14:05:16 -07:00
Alexander Holliday 7368cb2567 Merge pull request #2974 from bluewave-labs/fix/cleanup
move v1 to v1 dir, add build workflow
2025-09-23 12:00:06 -07:00
Alex Holliday f945a27011 move v1 to v1 dir, add build workflow 2025-09-23 11:59:02 -07:00
Alexander Holliday 72882fded9 Merge pull request #2973 from bluewave-labs/feat/v2/auth
feat: v2/auth
2025-09-23 11:45:39 -07:00
Alex Holliday 0030394008 add migrations table 2025-09-23 11:34:25 -07:00
Alexander Holliday bfb299cfca Merge pull request #2972 from bluewave-labs/fix/update-docker-files
fix/update docker files
2025-09-23 11:01:19 -07:00
Alexander Holliday b06d5c10ea Merge pull request #2971 from bluewave-labs/feat/v2-controllers
Feat/v2 controllers
2025-09-23 11:00:40 -07:00
Alexander Holliday 2a0d4195a1 Merge pull request #2970 from bluewave-labs/feat/v2-routes
feat: v2 routes
2025-09-23 11:00:18 -07:00
Alex Holliday 11ff99613a implement auth routes, add user migration 2025-09-22 15:56:41 -07:00
Alex Holliday 0b646ee64f update docker files to build 2025-09-22 13:26:45 -07:00
Alex Holliday 23126a92cd move v1 controllers to v1 dir 2025-09-22 13:04:45 -07:00
Alex Holliday f767125acd tsx, tpyescript 2025-09-22 13:03:54 -07:00
Alex Holliday d8ed9abebf add gitignore 2025-09-22 12:53:44 -07:00
Alexander Holliday e4e75632c5 Merge pull request #2963 from bluewave-labs/translation-update-78
🌐 Updated Translations from POEditor
2025-09-18 13:40:10 -07:00
GitHub Action ddb7c24832 feat: translations updated from POEditor 2025-09-18 20:25:11 +00:00
Alexander Holliday 4a824dec81 Merge pull request #2960 from bluewave-labs/feat/bump-version
bump version
2025-09-18 12:03:26 -07:00
Alex Holliday b35fee1be8 bump version 2025-09-18 12:02:49 -07:00
Alexander Holliday 1b167af12b Merge pull request #2959 from Owaiseimdad/Addition-of-sliding-window-implementation
Addition of incident tab in creation and config page which is same.
2025-09-18 11:50:55 -07:00
Owaise f2962e34ae Fixed the formatting. 2025-09-19 00:06:31 +05:30
Owaise 386db5029a Addition of incident tab in creation and config page which is same. 2025-09-19 00:03:18 +05:30
Alexander Holliday 0e6e54a124 Merge pull request #2957 from FrancocDev/develop
Allow jsonPath to be used along expectedValue and validate the response.
2025-09-18 09:47:53 -07:00
Franco Carrara c666cb3879 fix formatting issues 2025-09-17 23:46:20 -03:00
Franco Carrara 4039517683 Add response messages to string service 2025-09-17 23:33:45 -03:00
Franco Carrara 00fc7b8038 Allow jsonPath to be used along expectedValue and validate the response. 2025-09-17 23:23:16 -03:00
Alexander Holliday 81d283ec8d Merge pull request #2956 from ajhollid/bump-dependencies
chore: bump deps
2025-09-17 15:17:14 -07:00
Alex Holliday 105100e349 bump deps 2025-09-17 15:07:55 -07:00
Alexander Holliday 4598690dbf Merge pull request #2954 from brownyroll/develop
feat: Support Thailand language
2025-09-16 09:00:51 -07:00
Bamz Kittisak Udomsri f68341c315 feat: thailang 2025-09-16 20:41:13 +07:00
Alexander Holliday e8a8cea909 Merge pull request #2953 from bluewave-labs/fix-skip-maintenance-notifications
Fix: Skip notifications during maintenance windows
2025-09-15 11:13:28 -07:00
karenvicent bf53f107e3 Merge branch 'develop' into fix-skip-maintenance-notifications 2025-09-15 12:29:47 -04:00
karenvicent 00de974528 Fix: Skip notifications for monitors during active maintenance windows 2025-09-15 12:28:37 -04:00
Alexander Holliday 0445398e94 Merge pull request #2952 from bluewave-labs/feat-notifications-body
Add monitor name and URL formatting for hardware notifications
2025-09-15 09:15:10 -07:00
karenvicent 272e2ba955 add monitor name and url to infrastructure alert 2025-09-15 08:34:51 -04:00
Alexander Holliday 0a2adc2d92 Merge pull request #2948 from bluewave-labs/feat-discord-format
Add Discord embed message formatting for notifications
2025-09-12 09:03:19 -07:00
karenvicent 7008fc1770 Merge branch 'develop' into feat-discord-format 2025-09-12 10:14:07 -04:00
karenvicent 041a261540 add llama sugestions 2025-09-12 10:13:38 -04:00
Gorkem Cetin (BWL) 1008d819f7 Update README.md 2025-09-11 22:40:11 -04:00
karenvicent fb84a79a04 Add Discord embed message formatting for notifications 2025-09-11 16:29:08 -04:00
Alexander Holliday 45bfdbdce0 Merge pull request #2935 from bluewave-labs/fix/mono-dist-ping
fix vite.config
2025-09-08 20:40:33 -07:00
Alex Holliday 1537c2141f fix vite.config 2025-09-08 20:39:45 -07:00
Alexander Holliday 3ba1a52644 Merge pull request #2932 from bluewave-labs/fix/mono-dist-ping
fix: mono dist ping
2025-09-08 20:31:01 -07:00
Alex Holliday a015cc6706 fix dist-arm, bump version 2025-09-08 20:29:38 -07:00
Alex Holliday 5bad362793 fix server build order 2025-09-08 20:27:20 -07:00
Alexander Holliday 5520756edd Merge pull request #2923 from bluewave-labs/feat-page-initialization-hook
Add PageStateWrapper and fix initial render flash
2025-09-08 09:12:14 -07:00
karenvicent ba954a1d6e run format 2025-09-08 11:15:14 -04:00
karenvicent 2944ff298c Merge branch 'develop' into feat-page-initialization-hook 2025-09-08 10:50:15 -04:00
karenvicent 80d121e87a add llama suggestions 2025-09-08 10:49:42 -04:00
Alexander Holliday ed8352d857 Merge pull request #2928 from bluewave-labs/fix/install-ping
fix: install ping
2025-09-08 07:11:34 -07:00
Alex Holliday 41f64ca9fe bump version 2025-09-08 07:10:29 -07:00
Alex Holliday 738e49dc92 Merge branch 'develop' into fix/install-ping 2025-09-08 07:10:15 -07:00
Alex Holliday 68a16257c6 add ping to dist 2025-09-08 07:09:39 -07:00
Alex Holliday 5dcbae55f4 install ping 2025-09-08 06:57:10 -07:00
Alexander Holliday e0d963256c Merge pull request #2926 from bluewave-labs/fix/bump-version
fix: bump version
2025-09-08 06:45:15 -07:00
Alexander Holliday 2bff4bbd15 Merge pull request #2927 from bluewave-labs/fix/ping-error-logging
fix: throw ping error if present
2025-09-08 06:45:00 -07:00
Alex Holliday a0eba89f34 bump version 2025-09-08 06:43:35 -07:00
Alex Holliday 4e78de9da2 throw error if present 2025-09-08 06:42:36 -07:00
karenvicent 85f00eb7e8 Merge branch 'develop' into feat-page-initialization-hook 2025-09-05 15:59:14 -04:00
karenvicent 8e13855b66 feat create pagestate wrapper 2025-09-05 15:53:22 -04:00
Alexander Holliday 06f49e24c2 Merge pull request #2867 from antonstrover/fix/uptime%-charts-toggles
fix(status-page): toggles for charts and uptime %
2025-09-05 09:08:40 -07:00
antonstrover e598ae45f7 Merge branch 'develop' into fix/uptime%-charts-toggles 2025-09-05 16:46:04 +01:00
anton.strover ad7f469e06 add display name for bar 2025-09-05 16:27:48 +01:00
Alexander Holliday cb57ff5cc2 Merge pull request #2920 from bluewave-labs/fix/arm
fix/arm
2025-09-04 15:44:44 -07:00
Alex Holliday 72f070fbcb fix multiarch build 2025-09-04 15:15:09 -07:00
Alex Holliday fb0a86d37c update docker compoes and docker file 2025-09-04 13:39:53 -07:00
Alexander Holliday 36402dfefa Merge pull request #2870 from bluewave-labs/feat/add-team-member
Add direct user registration for team management
2025-09-03 09:58:35 -07:00
karenvicent c61874dbdd fix format error 2025-09-03 12:34:35 -04:00
Alex Holliday 20848f28d5 package 2025-09-03 09:21:24 -07:00
Alexander Holliday 5d23966f00 Merge pull request #2919 from bluewave-labs/fix/format-action
update format action, no need for ci
2025-09-03 09:20:43 -07:00
Alex Holliday 294cc66e4a update format action, no need for ci 2025-09-03 09:20:15 -07:00
Alex Holliday 0fd2e7032a update package-lock 2025-09-03 09:17:19 -07:00
Alex Holliday 340b85043e Merge branch 'feat/add-team-member' of github.com:bluewave-labs/checkmate into feat/add-team-member 2025-09-03 09:15:22 -07:00
Alex Holliday 1821ae3c2b add root gitignore 2025-09-03 09:14:30 -07:00
karenvicent c536cb2afa run format 2025-09-03 10:18:09 -04:00
karenvicent 3f79b4c2f6 Merge branch 'develop' into feat/add-team-member 2025-09-03 09:56:31 -04:00
karenvicent 137ba9185e fix details 2025-09-03 09:55:53 -04:00
Alexander Holliday 2f6a0913dc Merge pull request #2917 from bluewave-labs/fix/bump-scheduler
bump scheduler
2025-09-02 10:35:09 -07:00
Alex Holliday 2c7336d440 bump scheduler 2025-09-02 10:34:33 -07:00
Gorkem Cetin (BWL) 5a022ff3f6 Create .coderabbit.yml so it doesnt add summary to the PR 2025-09-01 19:33:33 -04:00
Alexander Holliday fe4855500e Merge pull request #2896 from PaiJi/feat/update-i18n-scripts
feat(i18n): add zh-CN
2025-09-01 10:46:21 -07:00
Alexander Holliday ce8f5cbe0c Merge pull request #2878 from antonstrover/fix/failed-prop-type-status
Fixed Bar component
2025-09-01 10:43:43 -07:00
Alexander Holliday b6bebe33fe Merge branch 'master' into develop 2025-09-01 10:32:59 -07:00
Alexander Holliday 9cf8072c1e Merge pull request #2914 from bluewave-labs/fix/bump-multiarch-node
Fix/bump multiarch node
2025-09-01 10:30:51 -07:00
Alex Holliday 0ca00ca6a1 esbuild 2025-09-01 10:28:41 -07:00
Alex Holliday 619c5242db bump versions 2025-09-01 10:14:57 -07:00
Alexander Holliday ff07854590 Merge pull request #2913 from bluewave-labs/revert-2910-fix/alpine-to-slim
Revert "pin dependency"
2025-09-01 09:27:03 -07:00
Alexander Holliday ba99989c66 Revert "pin dependency" 2025-09-01 09:26:51 -07:00
Alexander Holliday 3c75933cf2 Merge pull request #2912 from bluewave-labs/revert-2911-develop
Revert "develop->master"
2025-09-01 09:26:35 -07:00
Alexander Holliday ea9ef7afd3 Revert "develop->master" 2025-09-01 09:26:23 -07:00
Alexander Holliday f5e633a781 Merge pull request #2911 from bluewave-labs/develop
develop->master
2025-09-01 09:23:01 -07:00
Alexander Holliday 90b94816dd Merge pull request #2910 from bluewave-labs/fix/alpine-to-slim
pin dependency
2025-09-01 09:22:26 -07:00
Alex Holliday 11dcaef3ff pin 2025-09-01 09:21:56 -07:00
Alex Holliday 3f3e7f71ec pin dependency 2025-09-01 09:21:11 -07:00
Alexander Holliday b6070572cf Merge pull request #2909 from bluewave-labs/develop
develop->master
2025-09-01 09:15:48 -07:00
Alexander Holliday e818a02a2a Merge pull request #2908 from bluewave-labs/fix/alpine-to-slim
fix build
2025-09-01 09:15:17 -07:00
Alex Holliday d8c8e222c8 fix build 2025-09-01 09:14:35 -07:00
Alexander Holliday f12b9715bc Merge pull request #2907 from bluewave-labs/develop
develop -> master
2025-09-01 09:07:57 -07:00
Alexander Holliday 31c65d3e0b Merge pull request #2906 from bluewave-labs/fix/alpine-to-slim
add omit optional flag
2025-09-01 09:07:21 -07:00
Alex Holliday fcd6741cf9 add omit optional flag 2025-09-01 09:06:42 -07:00
Alexander Holliday d663b9230f Merge pull request #2905 from bluewave-labs/develop
Develop -> Master
2025-09-01 09:00:25 -07:00
Alexander Holliday 5f2d61ad7a Merge pull request #2904 from bluewave-labs/fix/alpine-to-slim
remove alpine fix
2025-09-01 08:58:42 -07:00
Alex Holliday ec80a2dc0b remove alpine fix 2025-09-01 08:57:55 -07:00
Alexander Holliday 2cece3de59 Merge pull request #2902 from bluewave-labs/develop
develop -> master
2025-09-01 08:54:38 -07:00
Alexander Holliday 79eb580802 Merge pull request #2901 from bluewave-labs/fix/alpine-to-slim
alpine -> slim
2025-09-01 08:54:10 -07:00
Alex Holliday b93e3327a7 alpine -> slim 2025-09-01 08:53:03 -07:00
anton.strover f01030a47a move width out of sx object 2025-09-01 11:44:10 +01:00
JiPai 3cbd907c09 feat(i18n): add zh-CN 2025-09-01 04:53:24 +08:00
karenvicent 8fae69b7a4 Merge branch 'develop' into feat/add-team-member 2025-08-31 10:19:01 -04:00
karenvicent e45dd4240e fix errors 2025-08-31 10:18:15 -04:00
Alexander Holliday 16a8552e6c Merge pull request #2890 from bluewave-labs/develop
develop->master
2025-08-30 19:31:37 -07:00
Alexander Holliday 845d5a5d51 Merge pull request #2885 from bluewave-labs/develop
develop->master
2025-08-30 16:23:40 -07:00
Alexander Holliday b86fc5edb3 Merge pull request #2883 from bluewave-labs/develop
develop -> master
2025-08-30 16:21:19 -07:00
anton.strover fd951bfdd5 Fixed Bar component
Moved width prop from direct prop to sx prop, updated PropTypes to accept string|object.
2025-08-29 11:24:57 +01:00
anton.strover 27d613b594 remove carried away-ness 2025-08-29 10:49:22 +01:00
karenvicent 7c8ab64e34 fix sucess toast msg 2025-08-28 13:38:05 -04:00
karenvicent ec7855bd02 Merge branch 'develop' into feat/add-team-member 2025-08-28 13:21:20 -04:00
karenvicent d401eefd6b Add direct user registration 2025-08-28 12:58:38 -04:00
Alexander Holliday 05dd5f7de2 Merge pull request #2858 from bluewave-labs/develop
develop -> master
2025-08-25 15:06:19 -07:00
Alexander Holliday ce3ec99c9f Merge pull request #2855 from bluewave-labs/develop
develop -> master
2025-08-25 14:38:06 -07:00
Alexander Holliday c2e2ae8dbd Merge pull request #2834 from bluewave-labs/develop
develop -> master
2025-08-21 10:13:48 -07:00
Alexander Holliday 25c66cff43 Merge pull request #2831 from bluewave-labs/develop
develop -> master
2025-08-21 09:15:40 -07:00
Alexander Holliday 8f971cfb02 Merge pull request #2826 from bluewave-labs/develop
develop -> master
2025-08-20 14:05:35 -07:00
Alexander Holliday 9b3ad54d0a Merge pull request #2797 from bluewave-labs/develop
develop -> master
2025-08-15 12:21:10 -07:00
Alexander Holliday 122a84b9e2 Merge pull request #2787 from bluewave-labs/develop
develop -> master for 3.0-beta
2025-08-14 15:28:35 -07:00
Alexander Holliday 9716e64c93 Merge pull request #2612 from bluewave-labs/develop
Develop -> Master
2025-07-14 14:23:40 -07:00
Alexander Holliday eb8cf1b6da Merge pull request #2584 from bluewave-labs/develop
bump version
2025-07-08 09:51:08 -07:00
Alexander Holliday c633a9ad8d Merge pull request #2582 from bluewave-labs/develop
develop -> master
2025-07-07 15:38:46 -07:00
Alexander Holliday 923eda1307 Merge pull request #2545 from bluewave-labs/develop
develop -> master
2025-06-25 12:42:33 +08:00
Alexander Holliday 997342a31c Merge pull request #2536 from bluewave-labs/develop
Develop -> Master for 2.2 release
2025-06-25 09:38:08 +08:00
1132 changed files with 71967 additions and 96783 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
release_notes: false
+1 -1
View File
@@ -7,7 +7,7 @@ import { URLSearchParams } from "url";
const API_TOKEN = process.env.POEDITOR_API;
const PROJECT_ID = process.env.POEDITOR_PROJECT_ID;
const LANGUAGES = (
process.env.LANGUAGES || "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja"
process.env.LANGUAGES || "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn,th"
).split(",");
const EXPORT_FORMAT = process.env.EXPORT_FORMAT || "key_value_json";
+40
View File
@@ -0,0 +1,40 @@
name: Build Check (Client & Server)
on:
pull_request:
workflow_dispatch:
jobs:
build-client:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install client dependencies
working-directory: client
run: npm install
- name: Check client build
working-directory: client
run: npm run build
build-server:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install server dependencies
working-directory: server
run: npm install
- name: Check server build
working-directory: server
run: npm run build
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
- name: Install client dependencies
working-directory: client
run: npm ci
run: npm install
- name: Check client formatting
working-directory: client
@@ -34,7 +34,7 @@ jobs:
- name: Install server dependencies
working-directory: server
run: npm ci
run: npm install
- name: Check server formatting
working-directory: server
@@ -0,0 +1,75 @@
name: Build images (feat/saas)
on:
push:
branches: ["feat/saas"]
workflow_dispatch:
env:
PLATFORMS: linux/amd64,linux/arm64
TAG: latest
IMAGE_CLIENT: ghcr.io/ajhollid/checkmate-saas-client
IMAGE_SERVER: ghcr.io/ajhollid/checkmate-saas-server
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up QEMU (for multi-arch emulation)
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Set up Docker Buildx (multiarch)
uses: docker/setup-buildx-action@v3
with:
install: true
driver-opts: |
network=host
buildkitd-flags: --debug
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USER }}
password: ${{ secrets.GHCR_AJHOLLID_TOKEN }}
- name: Build and push Client (multi-arch)
uses: docker/build-push-action@v5
with:
context: client
file: client/Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
tags: ${{ env.IMAGE_CLIENT }}:${{ env.TAG }}
- name: Build and push Server (multi-arch)
uses: docker/build-push-action@v5
with:
context: server
file: server/Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
tags: ${{ env.IMAGE_SERVER }}:${{ env.TAG }}
deploy-to-ajhollid:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: SSH into server and restart container using Docker Compose
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.AJHOLLID_HOST }}
username: ${{ secrets.AJHOLLID_USER }}
key: ${{ secrets.AJHOLLID_SSH_PRIVATE_KEY }}
script: |
cd checkmate-saas
docker compose down
docker compose pull
docker compose up -d
docker system prune -af
+1 -1
View File
@@ -7,7 +7,7 @@ on:
languages:
description: "Languages to synchronize (comma separated, e.g.: tr,en,es)"
required: false
default: "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja"
default: "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn,th"
format:
description: "Export format (key_value_json or json)"
required: false
+1
View File
@@ -88,3 +88,4 @@ jobs:
docker compose down
docker compose pull
docker compose up -d
docker system prune -af
+8 -1
View File
@@ -1 +1,8 @@
.vscode
.idea
.vscode
.VSCodeCounter
AGENTS.md
*.sh
notes
docker-compose.yml
mongo
+166 -12
View File
@@ -6,7 +6,7 @@ We truly appreciate all kinds of contributions — code, ideas, translations or
Before you start, please take a moment to read the relevant section. It helps us review and accept contributions faster, and makes the whole process smoother for everyone. 💚
PS: **We work closely with contributors on our [Discord channel](https://discord.com/invite/NAb6H3UTjK)**. You’ll find community members, core maintainers, and first-timers helping each other out.
PS: **We work closely with contributors on our [Discord channel](https://discord.com/invite/NAb6H3UTjK)**. You'll find community members, core maintainers, and first-timers helping each other out.
---
@@ -32,12 +32,12 @@ PS: **We work closely with contributors on our [Discord channel](https://discord
### Get help or ask a question?
Ask anything in our [Discord server](https://discord.com/invite/NAb6H3UTjK) — we’re friendly and happy to help. [Our core contributors](https://github.com/bluewave-labs/checkmate?tab=readme-ov-file#-contributing) are active and ready to support you. You can also use [GitHub Discussions](https://github.com/bluewave-labs/Checkmate/discussions) section to ask your questions.
Ask anything in our [Discord server](https://discord.com/invite/NAb6H3UTjK) — we're friendly and happy to help. [Our core contributors](https://github.com/bluewave-labs/checkmate?tab=readme-ov-file#-contributing) are active and ready to support you. You can also use [GitHub Discussions](https://github.com/bluewave-labs/Checkmate/discussions) section to ask your questions.
### Report a bug?
1. Search [existing issues](https://github.com/bluewave-labs/checkmate/issues).
2. If it’s not listed, open a **new issue**.
2. If it's not listed, open a **new issue**.
3. Include as much detail as possible: what happened, what you expected, and steps to reproduce. Logs and screenshots help.
### Suggest a new feature?
@@ -48,19 +48,175 @@ Ask anything in our [Discord server](https://discord.com/invite/NAb6H3UTjK) —
### Set up Checkmate locally?
Frontend & backend:
#### Prerequisites
- Node.js (with npm)
- Docker
- Git
#### Step 1: Clone the Repository
```bash
git clone https://github.com/bluewave-labs/Checkmate.git
cd Checkmate
```
#### Step 2: Set Up Docker Containers (MongoDB)
Navigate to the Docker dev directory:
```bash
cd server/docker/dev
```
Build the Docker images:
```bash
./build_images.sh
```
Run MongoDB container:
```bash
docker run -d -p 27017:27017 -v $(pwd)/mongo/data:/data/db --name uptime_database_mongo uptime_database_mongo
```
Navigate back to the root directory:
```bash
cd ../../..
```
#### Step 3: Set Up the Backend (Server)
Navigate to the server directory:
```bash
cd server
```
Install dependencies:
```bash
npm install
```
Create a `.env` file in the `server` directory with the following minimum required configuration:
```env
CLIENT_HOST="http://localhost:5173"
JWT_SECRET="my_secret_key_change_this"
DB_CONNECTION_STRING="mongodb://localhost:27017/uptime_db"
TOKEN_TTL="99d"
ORIGIN="localhost"
LOG_LEVEL="debug"
```
**Environment Variables Explained:**
- `CLIENT_HOST`: Frontend URL (default: http://localhost:5173)
- `JWT_SECRET`: Secret key for JWT tokens (change to something secure)
- `DB_CONNECTION_STRING`: MongoDB connection URL
- `ORIGIN`: Origin for CORS purposes
- `TOKEN_TTL`: Token time to live (in vercel/ms format)
- `LOG_LEVEL`: Debug level (debug, info, warn, error)
Start the backend server:
```bash
npm run dev
```
By default, the frontend expects the backend on `http://localhost:3001`. Update configs if needed.
The server will run at `http://localhost:52345`.
#### Step 4: Set Up the Frontend (Client)
Open a new terminal window and navigate to the client directory from the root:
```bash
cd client
```
Install dependencies:
```bash
npm install
```
Create a `.env` file in the `client` directory:
```env
VITE_APP_API_BASE_URL="http://localhost:52345/api/v1"
VITE_APP_LOG_LEVEL="debug"
```
**Environment Variables Explained:**
- `VITE_APP_API_BASE_URL`: Backend API URL
- `VITE_APP_LOG_LEVEL`: Log level (none, error, warn, debug, info)
Start the frontend:
```bash
npm run dev
```
The client will run at `http://localhost:5173`.
#### Step 5: Access the Application
Open your browser and navigate to:
- **Frontend**: http://localhost:5173
- **Backend API**: http://localhost:52345
- **API Documentation**: http://localhost:52345/api-docs
#### Managing Docker Containers
Stop containers:
```bash
docker stop uptime_database_mongo
```
Start containers:
```bash
docker start uptime_database_mongo
```
Remove containers (if needed):
```bash
docker rm uptime_database_mongo
```
#### Troubleshooting
**Port already in use:**
- Check if another service is using ports 5173, 52345, 27017, or 6379
- Stop the conflicting service or change the port in `.env` files
**MongoDB connection issues:**
- Verify container is running: `docker ps`
- Check container logs: `docker logs uptime_database_mongo`
**Module not found errors:**
- Ensure you ran `npm install` in both `client` and `server` directories
**Need more help?**
- Check the [full documentation](https://docs.checkmate.so)
- Ask on [Discord](https://discord.com/invite/NAb6H3UTjK)
### Start contributing code?
1. Pick or open an issue (check `good-first-issue`s first)
2. (optional but highly suggested) Read a detailed structure of [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) if you would like to deep dive into the architecture.
3. Ask to be assigned. If there is alrady someone assigned and it's been more than 7 days, you can raise the flag and ask to be assigned as well.
3. Ask to be assigned. If there is already someone assigned and it's been more than 7 days, you can raise the flag and ask to be assigned as well.
4. Create a branch from `develop`.
5. Write your code.
6. Run and test locally.
@@ -75,6 +231,7 @@ Docs live in [checkmate-documentation](https://github.com/bluewave-labs/checkmat
### Help with translations?
We use [PoEditor](https://poeditor.com) for translations. You can:
- [Sign up and join your language team](https://poeditor.com/join/project/lRUoGZFCsJ).
- Translate UI strings.
- Ask questions on Discord in the relevant #translations channel.
@@ -84,6 +241,7 @@ Make sure all new UI strings in code use `t('key')`.
### Submit a pull request?
Follow the [pull request checklist](#pull-request-checklist). Your PR should:
- Be focused on one issue.
- Be tested locally.
- Use our linting and translation rules.
@@ -123,7 +281,6 @@ If one or more of these are missing, we may ask you to update your pull request
## Branching model
- Code contributions should go to the `develop` branch.
- `master` is used for stable releases.
- Use descriptive branch names, like `fix/login-error` or `feat/add-alerts`.
@@ -137,13 +294,10 @@ If one or more of these are missing, we may ask you to update your pull request
## Thank you
Thanks for making Checkmate better. We mean it. Whether it’s your first pull request or your 50th, we’re excited to build with you.
Thanks for making Checkmate better. We mean it. Whether it's your first pull request or your 50th, we're excited to build with you.
PS: feel free to introduce yourself on [Discord](https://discord.gg/YOUR-DISCORD-LINK) and say hi.
PS: feel free to introduce yourself on [Discord](https://discord.gg/NAb6H3UTjK) and say hi.
-- Checkmate team
Also make sure you read the [document about how to make a good pull request](/PULLREQUESTS.md).
+11325
View File
File diff suppressed because it is too large. Load diff
+44 -176
View File
@@ -1,182 +1,50 @@
<p align=center> <a href="https://trendshift.io/repositories/12443" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12443" alt="bluewave-labs%2Fcheckmate | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a></p>
![](https://img.shields.io/github/license/bluewave-labs/checkmate)
![](https://img.shields.io/github/repo-size/bluewave-labs/checkmate)
![](https://img.shields.io/github/commit-activity/m/bluewave-labs/checkmate)
![](https://img.shields.io/github/last-commit/bluewave-labs/checkmate)
![](https://img.shields.io/github/languages/top/bluewave-labs/checkmate)
![](https://img.shields.io/github/issues/bluewave-labs/checkmate)
![](https://img.shields.io/github/issues-pr/bluewave-labs/checkmate)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9901/badge)](https://www.bestpractices.dev/projects/9901)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/bluewave-labs/checkmate)
# Checkmate
<h1 align="center"><a href="https://bluewavelabs.ca" target="_blank">Checkmate</a></h1>
A full‑stack uptime and infrastructure monitoring app. The repository contains an Express/TypeScript API and a React/TypeScript client.
<p align="center"><strong>An open source uptime and infrastructure monitoring application</strong></p>
## Project Structure
- `server/` – Node.js API (TypeScript, ESM)
- Source: `server/src`
- Routes mounted under `/api/v1/*` via `server/src/init/routes.ts`
- Tests: `server/tests`
- Build output: `server/dist`
- `client/` – React + TypeScript (Vite)
- Source: `client/src`
- Public assets: `client/public`
<img width="1660" alt="image" src="https://github.com/user-attachments/assets/b748f36d-a271-4965-ad0a-18bf153bbee7" />
## Key Features
- JWT authentication and permission checks (team/org).
- Monitors API: create, list (with sorting/pagination), get checks, toggle pause, update, delete.
- Import/Export monitors (`GET /api/v1/monitors/export`, `POST /api/v1/monitors/import`).
- Notification channels and diagnostics endpoints.
- System settings (SMTP) with env‑first email transport fallback to DB settings.
This repository contains both the frontend and the backend of Checkmate, an open-source, self-hosted monitoring tool for tracking server hardware, uptime, response times, and incidents in real-time with beautiful visualizations. Checkmate regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.
## Getting Started
1. Prerequisites: Node 18+, MongoDB
2. Environment
- Server: create `server/.env` with at least:
- `MONGODB_URI=mongodb://localhost:27017/saas`
- `JWT_SECRET=replace_me`
- `ORIGIN=http://localhost:5173`
- Optional SMTP: `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`
3. Install
- `cd server && npm ci`
- `cd ../client && npm ci`
4. Run
- API: `cd server && npm run dev` (listens on `http://localhost:52345`)
- Client: `cd client && npm run dev` (Vite dev server)
Checkmate also has an agent, called [Capture](https://github.com/bluewave-labs/capture), to retrieve data from remote servers. While Capture is not required to run Checkmate, it provides additional insights about your servers' CPU, RAM, disk, and temperature status. Capture can run on Linux, Windows, Mac, Raspberry Pi, or any device that can run Go.
## Scripts
- Server
- `npm run dev` – Start API in watch mode
- `npm run build` – Type‑check and compile (tsc + tsc‑alias)
- `npm test` / `npm run test:coverage` – Jest tests and coverage
- Client
- `npm run dev` – Start Vite dev server
- `npm run build` – Type‑check and build
- `npm run preview` – Preview production build
Checkmate has been stress-tested with 1000+ active monitors without any particular issues or performance bottlenecks.
**If you would like to sponsor a feature, [see this link](https://checkmate.so/sponsored-features).**
## 📚 Table of contents
- [📦 Demo](#demo)
- [🔗 User's guide](#users-guide)
- [🛠️ Installation](#installation)
- [🏁 Translations](#translations)
- [🚀 Performance](#performance)
- [💚 Questions & Ideas](#questions--ideas)
- [🧩 Features](#features)
- [🏗️ Screenshots](#screenshots)
- [🏗️ Tech stack](#tech-stack)
- [🔗 A few links](#a-few-links)
- [🤝 Contributing](#contributing)
- [💰 Our sponsors](#our-sponsors)
## Demo
You can see the latest build of [Checkmate](https://checkmate-demo.bluewavelabs.ca/) in action. The username is uptimedemo@demo.com and the password is Demouser1! (just a note that we update the demo server from time to time, so if it doesn't work for you, please ping us on the Discussions channel).
## User's guide
Usage instructions can be found [here](https://docs.checkmate.so/checkmate-2.1). It's still WIP and some of the information there might be outdated as we continuously add features weekly. Rest assured, we are doing our best! :)
## Installation
See installation instructions in [Checkmate documentation portal](https://docs.checkmate.so/checkmate-2.1/users-guide/quickstart).
Alternatively, you can also use [Coolify](https://coolify.io/), [Elestio](https://elest.io/open-source/checkmate), [K8s](./charts/helm/checkmate/INSTALLATION.md) or [Pikapods](https://www.pikapods.com/) to quickly spin off a Checkmate instance. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.
### Using a Custom CA
If you need to monitor internal HTTPS endpoints with certificates from private Certificate Authorities (like Smallstep), see our [Custom CA Trust Guide](./docs/custom-ca-trust.md) for Docker configuration options.
For more documentation, see the [docs directory](./docs/).
## Translations
If you would like to use Checkmate in your language, please [go to this page](https://poeditor.com/join/project/lRUoGZFCsJ) and register for the language you would like to translate Checkmate to.
## Performance
Thanks to extensive optimizations, Checkmate operates with an exceptionally small memory footprint, requiring minimal memory and CPU resources. Here’s the memory usage of a Node.js instance running on a server that monitors 323 servers every minute:
![image](https://github.com/user-attachments/assets/37e04a75-d83a-488f-b25c-025511b492c9)
You can see the memory footprint of MongoDB and Redis on the same server (398Mb and 15Mb) for the same amount of servers:
![image](https://github.com/user-attachments/assets/3b469e85-e675-4040-a162-3f24c1afc751)
## Questions & Ideas
If you have any questions, suggestions or comments, you have several options:
- [Discord channel](https://discord.gg/NAb6H3UTjK)
- [GitHub Discussions](https://github.com/bluewave-labs/bluewave-uptime/discussions)
- [Reddit group](https://www.reddit.com/r/CheckmateMonitoring/)
Feel free to ask questions or share your ideas - we'd love to hear from you!
## Features
- Completely open source, deployable on your servers or home devices (e.g Raspberry Pi 4 or 5)
- Website monitoring
- Page speed monitoring
- Infrastructure monitoring (memory, disk usage, CPU performance, network etc) - requires [Capture](https://github.com/bluewave-labs/capture) agent
- Docker monitoring
- Ping monitoring
- SSL monitoring
- Port monitoring
- Game server monitoring (3.0)
- Incidents at a glance
- Status pages
- E-mail, Webhooks, Discord and Slack notifications
- Scheduled maintenance
- JSON query monitoring
- Multi-language support for English, German, Japanese, Portuguese (Brazil), Russian, Turkish, Ukrainian, Vietnamese, Chinese (Traditional, Taiwan)
**Short term roadmap:**
- Plugins that will help Checkmate get any information from a remote service (e.g database, etc)
- Better notifications
- Network monitoring
- ..and a few more features
If you would like to sponsor an additional feature, [see this page](https://checkmate.so/sponsored-features).
## Screenshots
<p>
<img width="1628" alt="image" src="https://github.com/user-attachments/assets/2eff6464-0738-4a32-9312-26e1e8e86275" />
</p>
<p>
<img width="1656" alt="image" src="https://github.com/user-attachments/assets/616c3563-c2a7-4ee4-af6c-7e6068955d1a" />
</p>
<p>
</p><img width="1652" alt="image" src="https://github.com/user-attachments/assets/7912d7cf-0d0e-4f26-aa5c-2ad7170b5c99" />
</p>
<p>
<img width="1652" alt="image" src="https://github.com/user-attachments/assets/08c2c6ac-3a2f-44d1-a229-d1746a3f9d16" />
</p>
## Tech stack
- [ReactJs](https://react.dev/)
- [MUI (React framework)](https://mui.com/)
- [Node.js](https://nodejs.org/en)
- [MongoDB](https://mongodb.com)
- [Recharts](https://recharts.org)
- Lots of other open source components!
## A few links
- If you would like to support us, please consider giving it a ⭐ and click on "watch".
- Have a question or suggestion for the roadmap/featureset? Check our [Discord channel](https://discord.gg/NAb6H3UTjK) or [Discussions](https://github.com/bluewave-labs/checkmate/discussions) forum.
- Need a ping when there's a new release? Use [Newreleases](https://newreleases.io/), a free service to track releases.
- Watch a Checkmate [installation and usage video](https://www.youtube.com/watch?v=GfFOc0xHIwY)
## Contributing
We are [Alex](http://github.com/ajhollid) (team lead), [Gorkem](http://github.com/gorkem-bwl/), [Owaise](http://github.com/Owaiseimdad), [Aryaman](https://github.com/Br0wnHammer), [Mert](https://github.com/mertssmnoglu) and [Karen](https://github.com/karenvicent) helping individuals and businesses monitor their infra and servers.
We pride ourselves on building strong connections with contributors at every level. Despite being a young project, Checkmate has already earned 7000+ stars and attracted 90+ contributors from around the globe.
Our repo is starred by employees from **Google, Microsoft, Intel, Cisco, Tencent, Electronic Arts, ByteDance, JP Morgan Chase, Deloitte, Accenture, Foxconn, Broadcom, China Telecom, Barclays, Capgemini, Wipro, Cloudflare, Dassault Systèmes and NEC**, so don’t hold back — jump in, contribute and learn with us!
Here's how you can contribute:
0. Star this repo :)
1. Check [Contributor's guideline](https://github.com/bluewave-labs/Checkmate/blob/develop/CONTRIBUTING.md). First timers are encouraged to check `good-first-issue` tag.
2. Check [project structure](https://docs.checkmate.so/checkmate-2.1/developers-guide/general-project-structure) and [high level overview](https://bluewavelabs.gitbook.io/checkmate/developers-guide/high-level-overview).
3. Read a detailed structure of [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) if you would like to deep dive into the architecture.
4. Open an issue if you believe you've encountered a bug.
5. Check for good-first-issue's if you are a newcomer.
6. Make a pull request to add new features/make quality-of-life improvements/fix bugs.
<a href="https://github.com/bluewave-labs/checkmate/graphs/contributors">
<img src="https://contrib.rocks/image?repo=bluewave-labs/checkmate" />
</a>
[![Star History Chart](https://api.star-history.com/svg?repos=bluewave-labs/checkmate&type=Date)](https://star-history.com/#bluewave-labs/bluewave-uptime&Date)
## Our sponsors
Thanks to [Gitbook](https://gitbook.io/) for giving us a free tier for their documentation platform, and [Poeditor](https://poeditor.com/) providing us a free account to use their i18n services. If you would like to sponsor Checkmate, please send an email to hello@bluewavelabs.ca
If you would like to sponsor a feature, [see this page](https://checkmate.so/sponsored-features).
Also check other developer and contributor-friendly projects of BlueWave:
- [VerifyWise](https://github.com/bluewave-labs/verifywise), the first open source AI governance platform.
- [DataRoom](https://github.com/bluewave-labs/bluewave-dataroom), an secure file sharing application, aka dataroom.
- [Guidefox](https://github.com/bluewave-labs/guidefox), an application that helps new users learn how to use your product via hints, tours, popups and banners.
## Notes
- The API expects valid JWTs on most routes; see `server/src/routes` for middleware usage.
- Mongo connection retries are handled in `server/src/db/MongoDB.ts`.
- Email transport prioritizes env config; if unset, it uses values from system settings.
-17
View File
@@ -1,17 +0,0 @@
.DS_Store
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
*.swp
*.bak
*.tmp
*.orig
*~
.project
.idea/
*.tmproj
.vscode/
-6
View File
@@ -1,6 +0,0 @@
apiVersion: v2
name: checkmate-chart
description: A Helm chart for Checkmate App
type: application
version: 0.1.0
appVersion: "2.3"
-39
View File
@@ -1,39 +0,0 @@
# Kubernetes Installation Guide for Checkmate
This guide walks you through deploying Checkmate on your Kubernetes cluster using Helm.
## Prerequisites
- A running Kubernetes cluster
- Helm CLI installed and configured
- `kubectl` configured to access your cluster
## Steps
### 1. Clone the repo and navigate to the Helm chart
```bash
git clone https://github.com/bluewave-labs/checkmate.git
cd checkmate/charts/helm/checkmate
```
### 2. Customize values.yaml
Edit `values.yaml` to update:
- `client.ingress.host` and `server.ingress.host` with your domain names
- `server.protocol` (usually http or https)
- Secrets under the `secrets` section (`JWT_SECRET`, email credentials, API keys, etc.) — replace all change_me values
### 3. Deploy the Helm chart
```bash
helm install checkmate ./charts/helm/checkmate
```
This will deploy the client, server, MongoDB, and Redis components.
### 4. Verify the deployment
Check pods and services:
```bash
kubectl get pods
kubectl get svc
```
Once all pods are `Running` and `Ready`, you can access Checkmate via the configured ingress hosts.
@@ -1,12 +0,0 @@
{{- if eq .Values.client.ingress.host "change_me" }}
{{- fail "client.ingress.host must be overridden and not set to 'change_me'" }}
{{- end }}
{{- if eq .Values.server.ingress.host "change_me" }}
{{- fail "server.ingress.host must be overridden and not set to 'change_me'" }}
{{- end }}
{{- $protocol := .Values.server.protocol }}
{{- if not (or (eq $protocol "http") (eq $protocol "https")) }}
{{- fail "server.protocol must be either 'http' or 'https'" }}
{{- end }}
@@ -1,22 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: client
spec:
replicas: 1
selector:
matchLabels:
app: client
template:
metadata:
labels:
app: client
spec:
containers:
- name: client
image: {{ .Values.client.image }}
ports:
- containerPort: {{ .Values.client.port }}
env:
- name: UPTIME_APP_API_BASE_URL
value: "{{ .Values.server.protocol }}://{{ .Values.server.ingress.host }}/api/v1"
@@ -1,20 +0,0 @@
{{- if .Values.client.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: client-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: {{ .Values.client.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: client
port:
number: {{ .Values.client.port }}
{{- end }}
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: client
spec:
selector:
app: client
ports:
- port: {{ .Values.client.port }}
@@ -1,27 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: {{ .Values.mongodb.image }}
ports:
- containerPort: {{ .Values.mongodb.port }}
command: ["mongod", "--quiet", "--bind_ip_all"]
volumeMounts:
- name: mongodb-data
mountPath: /data/db
volumes:
- name: mongodb-data
persistentVolumeClaim:
claimName: mongodb-pvc
@@ -1,10 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.persistence.mongodbSize }}
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: mongodb
spec:
selector:
app: mongodb
ports:
- port: {{ .Values.mongodb.port }}
@@ -1,26 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: {{ .Values.redis.image }}
ports:
- containerPort: {{ .Values.redis.port }}
volumeMounts:
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-pvc
@@ -1,10 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.persistence.redisSize }}
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- port: {{ .Values.redis.port }}
@@ -1,19 +0,0 @@
{{- $secrets := .Values.secrets }}
{{- if or (not $secrets.JWT_SECRET) (eq $secrets.JWT_SECRET "change_me") }}
{{- fail "secrets.JWT_SECRET must be overridden and cannot be 'change_me'" }}
{{- end }}
{{- if or (not $secrets.REFRESH_TOKEN_SECRET) (eq $secrets.REFRESH_TOKEN_SECRET "change_me") }}
{{- fail "secrets.REFRESH_TOKEN_SECRET must be overridden and cannot be 'change_me'" }}
{{- end }}
apiVersion: v1
kind: Secret
metadata:
name: checkmate-secrets
type: Opaque
stringData:
{{- range $key, $value := $secrets }}
{{ $key }}: {{ $value | quote }}
{{- end }}
@@ -1,22 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: server
spec:
replicas: 1
selector:
matchLabels:
app: server
template:
metadata:
labels:
app: server
spec:
containers:
- name: server
image: {{ .Values.server.image }}
ports:
- containerPort: {{ .Values.server.port }}
envFrom:
- secretRef:
name: checkmate-secrets
@@ -1,25 +0,0 @@
{{- if .Values.server.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: server-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "http://{{ .Values.client.ingress.host }},https://{{ .Values.client.ingress.host }}"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, PUT, POST, DELETE, PATCH, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
spec:
rules:
- host: {{ .Values.server.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: server
port:
number: {{ .Values.server.port }}
{{- end }}
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: server
spec:
selector:
app: server
ports:
- port: {{ .Values.server.port }}
-41
View File
@@ -1,41 +0,0 @@
client:
image: ghcr.io/bluewave-labs/checkmate-client:v2.3
port: 80
ingress:
enabled: true
host: change_me
server:
image: ghcr.io/bluewave-labs/checkmate-backend:v2.3
port: 52345
protocol: change_me
ingress:
enabled: true
host: change_me
redis:
image: redis:7.2
port: 6379
mongodb:
image: mongo:7.0
port: 27017
secrets:
JWT_SECRET: change_me
REFRESH_TOKEN_SECRET: change_me
SYSTEM_EMAIL_ADDRESS: test@example.com
SYSTEM_EMAIL_PASSWORD: change_me
SYSTEM_EMAIL_HOST: smtp.example.com
SYSTEM_EMAIL_PORT: "587"
PAGESPEED_API_KEY: change_me
DB_CONNECTION_STRING: mongodb://mongodb:27017/uptime_db
REDIS_HOST: redis
REDIS_PORT: "6379"
DB_TYPE: MongoDB
TOKEN_TTL: 99d
REFRESH_TOKEN_TTL: 99d
persistence:
mongodbSize: 5Gi
redisSize: 1Gi
-14
View File
@@ -1,14 +0,0 @@
language: "en-CA"
tone_instructions: "His palms are sweaty, knees weak, arms are heavy There’s vomit on his sweater already, mom’s spaghetti"
early_access: false
reviews:
profile: "chill"
request_changes_workflow: false
high_level_summary: false
poem: false
review_status: false
auto_review:
enabled: true
drafts: false
chat:
auto_reply: false
-3
View File
@@ -1,3 +0,0 @@
Client/node_modules/
Server/node_modules/
Server/*.env
-3
View File
@@ -1,3 +0,0 @@
VITE_APP_API_BASE_URL=UPTIME_APP_API_BASE_URL
VITE_APP_CLIENT_HOST=UPTIME_APP_CLIENT_HOST
VITE_APP_LOG_LEVEL=UPTIME_APP_LOG_LEVEL
-23
View File
@@ -1,23 +0,0 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
settings: { react: { version: "18.2" } },
plugins: ["react-refresh"],
rules: {
"react/jsx-no-target-blank": "off",
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
"react/no-unescaped-entities": "off",
},
globals: {
__APP_VERSION__: "readonly",
process: "readonly",
},
};
+1 -1
View File
@@ -24,7 +24,7 @@ dist-ssr
*.sw?
.env
.env.*
# Scripts
*.sh
-16
View File
@@ -1,16 +0,0 @@
{
"printWidth": 90,
"useTabs": true,
"tabWidth": 2,
"singleQuote": false,
"bracketSpacing": true,
"proseWrap": "preserve",
"bracketSameLine": false,
"singleAttributePerLine": true,
"semi": true,
"jsxSingleQuote": false,
"quoteProps": "as-needed",
"arrowParens": "always",
"trailingComma": "es5",
"htmlWhitespaceSensitivity": "css"
}
+17
View File
@@ -0,0 +1,17 @@
# syntax=docker/dockerfile:1.6
ARG NODE_VERSION=20
FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-bookworm-slim AS build
ENV NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Assets-only image: no web server. Contains built files at /dist.
FROM --platform=$TARGETPLATFORM busybox:stable
WORKDIR /
COPY --from=build /app/dist /dist
# No CMD provided intentionally — this image is for copying/volume population.
+73 -1
View File
@@ -1 +1,73 @@
This directory contains the client side (frontend) of Checkmate.
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
for i in $(env | grep UPTIME_APP_)
do
key=$(echo $i | cut -d '=' -f 1)
value=$(echo $i | cut -d '=' -f 2-)
echo $key=$value
find /usr/share/nginx/html -type f \( -name '*.js' -o -name '*.css' \) -exec sed -i "s|${key}|${value}|g" '{}' +
done
+28
View File
@@ -0,0 +1,28 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import { defineConfig, globalIgnores } from "eslint/config";
export default defineConfig([
globalIgnores(["dist"]),
{
files: ["**/*.{ts,tsx}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs["recommended-latest"],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/no-empty-object-type": "off",
},
},
]);
+6
View File
@@ -0,0 +1,6 @@
/** @type {import('i18n-unused').RunOptions} */
module.exports = {
localesPath: "src/locales",
srcPath: "src",
translationKeyMatcher: /\bt\s*\(\s*['"`](.*?)['"`]/g,
};
+13 -19
View File
@@ -1,24 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
rel="icon"
href="./checkmate_favicon.svg"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Checkmate</title>
</head>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="./checkmate_favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Checkmate</title>
</head>
<body>
<div id="root"></div>
<script src="/env.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
<body>
<div id="root"></div>
<script
type="module"
src="/src/main.jsx"
></script>
</body>
</html>
+5661 -6631
View File
File diff suppressed because it is too large. Load diff
+56 -64
View File
@@ -1,66 +1,58 @@
{
"name": "client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"build-dev": "vite build --mode development",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"format": "prettier --write .",
"format-check": "prettier --check ."
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@hello-pangea/dnd": "^18.0.0",
"@mui/icons-material": "6.4.11",
"@mui/lab": "6.0.0-dev.240424162023-9968b4889d",
"@mui/material": "6.4.11",
"@mui/x-charts": "^7.5.1",
"@mui/x-date-pickers": "7.29.0",
"@reduxjs/toolkit": "2.7.0",
"axios": "^1.7.4",
"dayjs": "1.11.13",
"flag-icons": "7.3.2",
"html2canvas": "^1.4.1",
"i18next": "^24.2.2",
"joi": "17.13.3",
"mui-color-input": "^6.0.0",
"react": "18.3.1",
"react-dom": "^18.2.0",
"react-i18next": "^15.4.0",
"react-icons": "5.5.0",
"react-redux": "9.2.0",
"react-router": "^6.23.0",
"react-router-dom": "^6.23.1",
"react-toastify": "^10.0.5",
"recharts": "2.15.2",
"redux-persist": "6.0.0",
"vite-plugin-svgr": "^4.2.0"
},
"unusedDepencies": {
"@solana/wallet-adapter-base": "0.9.25",
"@solana/wallet-adapter-material-ui": "0.16.35",
"@solana/wallet-adapter-react": "0.15.37",
"@solana/wallet-adapter-react-ui": "0.9.37",
"@solana/wallet-adapter-wallets": "0.19.34",
"@solana/web3.js": "1.98.0"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.6",
"prettier": "^3.3.3",
"vite": "6.3.5"
},
"optionalDependencies": {
"@rollup/rollup-linux-arm64-musl": "4.41.0"
}
"name": "checkmate",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"i18n:display": "i18n-unused display-unused > test.log",
"dev": "vite --host 127.0.0.1 --mode development",
"build": "tsc -b && vite build --mode production",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.1",
"@hookform/resolvers": "5.2.2",
"@mui/material": "7.3.4",
"@mui/x-date-pickers": "8.16.0",
"@reduxjs/toolkit": "2.9.0",
"axios": "1.12.2",
"dayjs": "1.11.18",
"flag-icons": "7.5.0",
"human-interval": "2.0.1",
"lucide-react": "0.553.0",
"ms": "2.1.3",
"pretty-ms": "9.3.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-i18next": "16.0.1",
"react-redux": "9.2.0",
"react-router": "7.9.4",
"react-router-dom": "7.9.4",
"react-toastify": "^11.0.5",
"recharts": "2.15.2",
"redux-persist": "6.0.0",
"swr": "2.3.6",
"vite-plugin-svgr": "4.5.0",
"zod": "4.1.12"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@types/ms": "2.1.0",
"@types/node": "^24.10.1",
"@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^5.0.4",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.22",
"globals": "^16.4.0",
"i18n-unused": "0.19.0",
"prettier": "^3.6.2",
"ts-node": "^10.9.2",
"typescript": "~5.9.3",
"typescript-eslint": "^8.45.0",
"vite": "^7.1.7"
}
}
@@ -1,6 +0,0 @@
type,name,url,interval,port,expectedValue,jsonPath,matchMethod
http,HTTP Monitor,https://www.google.com,60000,,,,
http,API Monitor,http://reqres.in/api/users/2,120000,,Janet,data.first_name,equal
ping,Ping monitor,127.0.0.1,60000,,,,
docker,Docker monitor,bbdd20b4e3757d63e070bc16e04d3f770c4a8f6e62e813de380f23b141e2ca01,60000,,,,
port,Port monitor,127.0.0.1,60000,5000,,,
1 type name url interval port expectedValue jsonPath matchMethod
2 http HTTP Monitor https://www.google.com 60000
3 http API Monitor http://reqres.in/api/users/2 120000 Janet data.first_name equal
4 ping Ping monitor 127.0.0.1 60000
5 docker Docker monitor bbdd20b4e3757d63e070bc16e04d3f770c4a8f6e62e813de380f23b141e2ca01 60000
6 port Port monitor 127.0.0.1 60000 5000
@@ -1 +0,0 @@
type,name,url,interval,port,expectedValue,jsonPath,matchMethod
1 type name url interval port expectedValue jsonPath matchMethod
-49
View File
@@ -1,49 +0,0 @@
<svg width="32" height="32" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M218.252 79.2667L218.045 78.4143C218.712 77.617 219.642 77.5282 220.615 77.4361C224.829 77.0374 243.307 76.7077 246.676 77.418C248.299 77.76 249.661 78.5248 250.932 79.5734C254.845 82.8003 259.018 88.0302 262.403 91.9284C263.57 93.2734 264.805 95.1623 266.183 96.2584C268.203 99.7185 274.532 101.602 278.167 102.623C278.397 102.688 278.631 102.741 278.863 102.797C274.983 106.185 272.016 110.321 268.272 113.745C272.574 124.188 286.689 184.953 289.397 187.986C290.165 188.212 290.291 188.048 291.045 187.739C290.627 188.446 290.337 189.3 289.588 189.656L288.963 188.533C286.703 188.347 273.044 195.497 269.836 196.808C267.39 197.808 264.851 198.458 262.414 199.405C261.197 196.797 260.413 193.923 259.329 191.244C254.43 179.142 250.091 166.843 245.71 154.552C240.241 139.206 234.226 124.026 228.882 108.642C226.389 101.466 223.549 94.5009 220.953 87.3749C220.026 84.8301 219.72 81.4795 218.252 79.2667Z" fill="#3158B7"/>
<path d="M218.252 79.2667L218.045 78.4143C218.712 77.617 219.642 77.5282 220.615 77.4361C224.829 77.0374 243.307 76.7077 246.676 77.418C248.299 77.76 249.661 78.5248 250.932 79.5734C254.845 82.8003 259.018 88.0302 262.403 91.9284C263.57 93.2734 264.805 95.1623 266.183 96.2584C268.203 99.7185 274.532 101.602 278.167 102.623C278.397 102.688 278.631 102.741 278.863 102.797C274.983 106.185 272.016 110.321 268.272 113.745C266.08 111.774 263.588 110.159 261.208 108.427C256.477 104.982 251.692 101.649 246.906 98.282L233.54 88.9767C228.729 85.5908 223.823 81.3267 218.252 79.2667Z" fill="#73E4FA"/>
<path d="M299.595 19.4005C302.177 17.8183 305.226 16.8946 307.955 15.5556C310.387 14.3626 312.673 12.8604 315.15 11.7619C315.624 11.5519 315.886 11.4697 316.398 11.4844C315.732 13.7848 316.431 26.6622 316.441 30.2652C316.474 42.2192 316.084 54.2432 316.385 66.1867C316.416 67.4343 316.377 68.6301 316.847 69.8026C316.457 79.0631 316.718 88.4086 316.651 97.6808L316.423 172.062C316.376 177.75 316.385 183.438 316.448 189.125C316.469 192.585 316.902 196.888 316.126 200.243C316.055 199.033 315.728 197.334 316.025 196.183C315.86 197.435 315.463 198.762 315.391 200.002C315.283 201.847 315.798 203.719 315.391 205.559C314.431 204.554 313.43 203.906 312.592 202.729C308.228 196.602 310.556 194.07 301.963 190.683C299.704 189.793 293.054 186.88 291.045 187.739C290.291 188.048 290.165 188.212 289.397 187.986C286.689 184.953 272.574 124.188 268.272 113.745C272.016 110.321 274.983 106.185 278.863 102.797C278.631 102.741 278.397 102.688 278.167 102.623C274.532 101.602 268.203 99.7184 266.183 96.2583C269.435 97.3504 272.901 97.5882 276.304 97.6583C280.306 97.7408 283.403 97.3026 286.383 94.3544C288.086 92.669 289.516 90.6569 291.136 88.8839C293.303 86.512 296.041 84.1801 297.633 81.3777C300.012 77.1924 299.115 62.4967 299.219 57.0841C296.538 56.7086 293.912 56.806 291.218 56.6995C288.184 56.5796 285.396 56.0507 283.294 53.6585C280.886 50.9188 280.696 47.3466 281.035 43.8756C282.423 29.6657 295.122 37.239 298.804 33.8184C299.712 32.9739 299.469 21.618 299.595 19.4005Z" fill="#3D7ECD"/>
<path d="M362.288 269.421L362.773 270.062C364.332 274.37 365.193 279.073 366.359 283.516C368.419 291.371 370.61 299.194 372.793 307.015L395.769 388.039L411.304 442.863L415.766 458.213C416.528 460.836 417.569 463.467 417.96 466.175C417.89 466.842 418.03 466.869 417.485 467.324C413.349 466.406 409.11 465.92 404.942 465.147C396.892 463.653 388.881 461.984 380.817 460.552C380.516 459.221 380.489 457.712 380.305 456.347C379.896 453.327 379.359 450.33 378.694 447.356C376.712 438.738 374.16 430.227 372.075 421.626L351.327 334.35C349.071 324.725 347.019 314.981 344.607 305.405C342.561 297.284 340.078 289.201 338.622 280.946C339.912 280.649 340.991 280.35 342.142 279.684C345.072 278.136 348.264 277.064 351.221 275.536C354.9 273.636 358.345 270.649 362.288 269.421Z" fill="#73E4FA"/>
<path d="M316.398 11.4845C316.949 11.6168 317.496 11.7682 318.021 11.982C320.527 13.0022 322.595 14.8975 325.025 16.0401C326.641 16.7993 328.506 17.0278 330.066 17.9189C330.615 18.2326 331.175 18.6401 331.516 19.1833C333.638 22.5617 329.941 33.143 334.144 34.5595C335.071 34.872 336.309 34.7269 337.278 34.6636C342.517 34.3216 346.04 34.3235 349.065 39.1827C350.891 42.117 351.841 45.3207 350.982 48.7564C350.164 52.0314 347.831 55.4635 344.902 57.2399C344.309 57.5993 343.657 57.8308 343.003 58.0488C342.382 58.2541 341.729 58.4831 341.176 58.8402C339.34 60.0257 337.705 61.6472 335.85 62.8819C335.083 63.3916 333.536 63.9343 333.114 64.7163C333.015 64.8989 332.938 65.0921 332.849 65.2797C331.994 71.778 330.942 74.7954 335.242 80.4525C338.105 84.2196 345.676 93.407 349.248 96.0711C350.329 96.8768 351.548 97.3899 352.858 97.674C354.638 97.679 356.567 97.8353 358.319 97.4932C366.986 95.8002 372.945 85.6789 379.155 80.1412C380.557 78.8916 382.117 77.8947 383.974 77.4926C387.385 76.754 391.296 77.2429 394.773 77.2627C400.744 77.2966 406.631 77.1509 412.603 77.4939C413.066 77.8038 413.08 77.6663 413.16 78.1487C413.385 79.5036 412.832 81.0938 412.41 82.377C409.805 90.2864 406.49 98.1119 403.607 105.936L387.525 150.29C383.617 161.269 379.569 172.195 375.381 183.07C373.017 189.241 370.826 195.663 367.756 201.518C366.906 200.846 366.105 200.384 365.115 199.946C357.118 196.547 349.468 191.947 341.757 187.926C341.211 187.423 341.102 187.207 340.301 187.318C338.422 187.579 336.346 188.419 334.502 188.929C330.434 190.055 321.796 191.764 319.469 195.652C318.572 197.151 317.692 200.22 316.337 201.245C316.225 200.886 316.145 200.621 316.126 200.243C316.902 196.888 316.469 192.585 316.448 189.125C316.385 183.438 316.377 177.75 316.423 172.062L316.651 97.6809C316.718 88.4087 316.457 79.0632 316.847 69.8027C316.377 68.6302 316.416 67.4344 316.385 66.1868C316.084 54.2433 316.474 42.2193 316.441 30.2653C316.431 26.6623 315.732 13.7849 316.398 11.4845Z" fill="#73E4FA"/>
<path d="M332.127 57.4141C335.751 57.5106 339.378 57.8905 343.003 58.0488C342.382 58.2541 341.729 58.4831 341.176 58.8402C339.34 60.0257 337.705 61.6472 335.85 62.8819C335.083 63.3916 333.536 63.9343 333.114 64.7163C333.015 64.8989 332.938 65.0921 332.849 65.2797C332.684 62.6459 332.422 60.0356 332.127 57.4141Z" fill="black"/>
<path d="M352.858 97.674C354.638 97.679 356.567 97.8353 358.319 97.4932C366.986 95.8002 372.945 85.6789 379.155 80.1412C380.557 78.8916 382.117 77.8947 383.974 77.4926C387.385 76.754 391.296 77.2429 394.773 77.2627C400.744 77.2966 406.631 77.1509 412.603 77.4939C412.123 77.5931 411.776 77.6589 411.35 77.9133C409.284 79.1482 407.188 81.3404 405.081 82.7802C394.559 89.9716 384.283 97.4873 373.787 104.715C371.042 106.605 368.398 108.696 365.587 110.481C363.016 106.042 360.879 102.667 356.684 99.576C355.908 99.004 354.963 98.1848 354.042 97.8844C353.777 97.7979 353.467 97.7915 353.199 97.7482C353.084 97.7297 352.972 97.6988 352.858 97.674Z" fill="#4F91E0"/>
<path d="M316.847 69.8027C321.242 72.4105 326.84 79.7356 330.518 83.5726C335.063 88.3145 340.305 92.4625 345.078 96.9857C348.754 100.47 359.102 112.197 362.531 113.979C362.884 116.416 347.596 173.131 345.411 179.979C344.657 182.345 343.764 185.35 342.254 187.338C342.099 187.543 341.927 187.734 341.757 187.926C341.211 187.423 341.102 187.207 340.301 187.318C338.422 187.579 336.346 188.419 334.502 188.929C330.434 190.055 321.796 191.764 319.469 195.652C318.572 197.151 317.692 200.22 316.337 201.245C316.225 200.886 316.145 200.621 316.126 200.243C316.902 196.888 316.469 192.585 316.448 189.125C316.385 183.438 316.376 177.75 316.423 172.062L316.651 97.6809C316.718 88.4087 316.457 79.0632 316.847 69.8027Z" fill="#5BBFFC"/>
<path d="M316.126 200.243C316.145 200.621 316.225 200.886 316.337 201.245C317.692 200.22 318.572 197.151 319.469 195.652C321.796 191.764 330.434 190.055 334.502 188.929C336.346 188.419 338.422 187.579 340.301 187.318C341.102 187.207 341.211 187.423 341.757 187.926C349.468 191.947 357.118 196.547 365.115 199.946C366.105 200.384 366.906 200.846 367.756 201.518C367.27 202.637 366.763 203.747 366.234 204.848C365.063 207.595 364.344 210.137 363.459 212.952C367.613 213.364 371.797 213.297 375.966 213.194C386.171 213.341 399.134 211.56 407.006 219.438C408.262 220.694 409.583 222.077 410.315 223.707C411.447 228.7 410.939 234.09 410.692 239.173C410.661 239.285 410.628 239.397 410.599 239.511C410.317 240.612 410.264 241.816 409.76 242.846C408.269 245.89 403.918 248.67 401.099 250.509L397.101 250.535C392.229 251.156 386.936 250.764 382.02 250.742C380.258 252.242 379.572 253.4 379.015 255.621C375.623 257.067 372.349 258.186 368.836 259.31C366.357 260.996 362.191 264.345 361.869 267.495C361.803 268.145 361.893 268.578 362.175 269.155L362.288 269.421C358.345 270.649 354.9 273.636 351.221 275.536C348.264 277.064 345.072 278.136 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965L337.631 281.175C336.996 280.978 336.122 280.707 335.64 280.22C335.013 279.586 332.112 273.818 330.826 272.131C327.237 267.42 322.458 264.909 316.638 264.129L316.192 264.037C314.993 265.535 316.083 270.149 315.579 272.213C315.076 269.916 316.559 267.352 315.272 265.334C314.562 264.951 314 264.949 313.234 265.15C310.643 265.828 308.244 267.144 305.601 267.663L305.359 267.78C304.526 268.174 303.726 268.445 302.836 268.679L302.422 268.516C302.97 267.994 303.581 267.707 304.249 267.371C303.346 267.089 302.592 267.405 301.795 267.828C300.798 268.358 299.724 269.109 298.638 269.418C296.45 270.04 293.748 268.782 292.771 271.723C291.539 275.429 292.836 276.598 289.342 279.245L289.264 279.106L289.746 279.665C289.922 279.642 290.098 279.617 290.274 279.596C290.788 279.534 291.072 279.562 291.552 279.784C283.761 280.886 276.08 271.943 269.481 268.727C269.532 267.685 269.414 267.036 268.848 266.155C266.793 262.951 261.551 259.21 258.011 257.869C256.773 257.4 255.382 257.17 254.087 256.899C250.725 256.497 247.482 255.358 244.173 254.665C241.651 254.137 239.029 253.962 236.466 253.728C236.969 252.907 236.631 251.749 236.978 250.742C234.444 250.731 231.884 250.523 229.351 250.403C226.903 249.086 224.175 246.485 222.644 244.15C220.166 240.368 220.112 229.455 221.195 225.05C221.962 221.93 223.946 219.508 226.648 217.845C227.525 217.021 228.391 216.267 229.547 215.874C232.606 214.832 236.233 214.827 239.433 214.547C243.327 214.206 247.238 213.733 251.141 213.538C256.502 213.269 261.883 213.36 267.25 213.257C267.293 213.167 267.345 213.08 267.378 212.986C268.103 210.948 263.421 201.839 262.414 199.405C264.851 198.458 267.39 197.808 269.836 196.808C273.044 195.497 286.703 188.347 288.963 188.533L289.588 189.656C290.337 189.3 290.627 188.446 291.045 187.739C293.054 186.88 299.704 189.793 301.963 190.683C310.556 194.07 308.228 196.602 312.592 202.729C313.43 203.906 314.431 204.554 315.391 205.559C315.798 203.719 315.283 201.847 315.391 200.002C315.463 198.762 315.86 197.435 316.025 196.183C315.728 197.334 316.055 199.033 316.126 200.243Z" fill="#73E4FA"/>
<path d="M226.648 217.845C227.525 217.021 228.391 216.267 229.547 215.874C232.606 214.832 236.233 214.827 239.433 214.547C243.327 214.206 247.238 213.733 251.141 213.538C256.502 213.269 261.883 213.36 267.25 213.257C273.5 213.971 279.834 213.445 286.108 213.605C286.028 213.626 285.948 213.648 285.867 213.666C283.762 214.153 281.367 213.997 279.208 214.037C272.251 214.165 265.326 213.83 258.375 213.88C253.031 213.919 247.886 214.67 242.578 215.017C240.895 215.127 236.024 214.805 235.01 216.105C234.814 216.356 234.778 216.499 234.672 216.773C235.26 217.358 235.736 217.319 236.534 217.341C240.179 217.439 243.921 217.212 247.585 217.238C254.057 217.283 260.516 217.54 266.99 217.551C270.978 217.557 278.548 217.235 282.283 217.919C273.611 218.558 264.721 217.948 256.023 218.03C249.71 217.873 243.396 217.847 237.081 217.954C233.732 217.991 229.946 218.398 226.648 217.845Z" fill="#4F91E0"/>
<path d="M321 196.5C321.019 196.878 320.86 194.141 320.972 194.5C322.327 193.475 318.572 197.151 319.469 195.652C321.796 191.764 330.434 190.055 334.502 188.929C336.346 188.419 338.422 187.579 340.301 187.318C341.102 187.207 341.211 187.423 341.757 187.926C349.468 191.947 357.118 196.547 365.115 199.946C366.105 200.384 366.906 200.846 367.756 201.518C367.27 202.637 366.763 203.747 366.234 204.848C365.063 207.595 364.344 210.137 363.459 212.952L361.76 212.951C346.809 213.807 331.759 213.014 316.787 213.074L315.391 205.559C315.798 203.719 315.283 201.847 315.391 200.002C315.463 198.762 315.835 196.752 316 195.5C315.5 195 323.374 191.757 321 196.5Z" fill="#3158B7"/>
<path d="M291.045 187.739C293.054 186.88 299.704 189.793 301.963 190.683C310.556 194.07 305.5 191.5 312.5 194.5C314 195 315.54 193.995 316.5 195L316.787 213.074C306.586 212.996 296.304 213.296 286.108 213.605C279.834 213.445 273.5 213.971 267.25 213.257C267.293 213.167 267.345 213.08 267.378 212.986C268.103 210.948 263.421 201.839 262.414 199.405C264.851 198.458 267.39 197.808 269.836 196.808C273.044 195.497 286.703 188.347 288.963 188.533L289.5 188.5C290.249 188.144 290.627 188.446 291.045 187.739Z" fill="#15337C"/>
<path d="M316.158 217.961C333.626 218.066 351.372 216.648 368.745 218.663C369.093 229.235 368.662 239.88 368.76 250.467L387.46 250.44C390.609 250.437 393.982 250.193 397.101 250.535C392.229 251.156 386.936 250.764 382.02 250.742L316.217 250.777C316.034 247.101 316.2 243.334 316.205 239.649C316.23 232.42 316.215 225.19 316.158 217.961Z" fill="#5BBFFC"/>
<path d="M229.351 250.403C226.903 249.086 224.175 246.485 222.644 244.15C220.166 240.368 220.112 229.455 221.195 225.05C221.962 221.93 223.946 219.508 226.648 217.845C229.946 218.398 233.732 217.991 237.081 217.954C243.396 217.847 249.71 217.873 256.023 218.03C264.721 217.948 273.611 218.558 282.283 217.919L316.158 217.961C316.215 225.19 316.23 232.42 316.205 239.649C316.2 243.334 316.034 247.101 316.217 250.777L382.02 250.742C380.258 252.242 379.572 253.4 379.015 255.621C375.623 257.067 372.349 258.186 368.836 259.31C366.357 260.996 362.191 264.345 361.869 267.495C361.803 268.145 361.893 268.578 362.175 269.155L362.288 269.421C358.345 270.649 354.9 273.636 351.221 275.536C348.264 277.064 345.072 278.136 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965L337.631 281.175C336.996 280.978 336.122 280.707 335.64 280.22C335.013 279.586 332.112 273.818 330.826 272.131C327.237 267.42 322.458 264.909 316.638 264.129L316.192 264.037C314.993 265.535 316.083 270.149 315.579 272.213C315.076 269.916 316.559 267.352 315.272 265.334C314.562 264.951 314 264.949 313.234 265.15C310.643 265.828 308.244 267.144 305.601 267.663L305.359 267.78C304.526 268.174 303.726 268.445 302.836 268.679L302.422 268.516C302.97 267.994 303.581 267.707 304.249 267.371C303.346 267.089 302.592 267.405 301.795 267.828C300.798 268.358 299.724 269.109 298.638 269.418C296.45 270.04 293.748 268.782 292.771 271.723C291.539 275.429 292.836 276.598 289.342 279.245L289.264 279.106L289.746 279.665C289.922 279.642 290.098 279.617 290.274 279.596C290.788 279.534 291.072 279.562 291.552 279.784C283.761 280.886 276.08 271.943 269.481 268.727C269.532 267.685 269.414 267.036 268.848 266.155C266.793 262.951 261.551 259.21 258.011 257.869C256.773 257.4 255.382 257.17 254.087 256.899C250.725 256.497 247.482 255.358 244.173 254.665C241.651 254.137 239.029 253.962 236.466 253.728C236.969 252.907 236.631 251.749 236.978 250.742C234.444 250.731 231.884 250.523 229.351 250.403Z" fill="#3D7ECD"/>
<path d="M229.5 250.5C227.052 249.183 224.175 246.485 222.644 244.15C220.166 240.368 220.112 229.455 221.195 225.05C221.962 221.93 223.946 219.508 226.648 217.845C229.946 218.398 233.732 217.991 237.081 217.954C243.396 217.847 249.71 217.873 256.023 218.03C258.057 218.243 260.081 218.239 262.124 218.245C262.036 228.982 261.779 239.713 261.935 250.452C267.117 250.445 282.096 249.873 286.095 250.724C281.121 250.989 276.017 250.759 271.029 250.75C261.584 250.723 252.14 250.748 242.696 250.824C240.816 250.676 238.867 250.759 236.978 250.742C234.444 250.731 232.033 250.62 229.5 250.5Z" fill="#3158B7"/>
<path d="M242.696 250.824C252.14 250.748 261.584 250.723 271.029 250.75C276.017 250.759 281.121 250.989 286.095 250.724C296.126 250.796 306.188 250.976 316.217 250.777L382.02 250.742C380.258 252.242 379.572 253.4 379.015 255.621C375.623 257.067 372.349 258.186 368.836 259.31C366.357 260.996 362.191 264.345 361.869 267.495C361.803 268.145 361.893 268.578 362.175 269.155L362.288 269.421C358.345 270.649 354.9 273.636 351.221 275.536C348.264 277.064 345.072 278.136 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965L337.631 281.175C336.996 280.978 336.122 280.707 335.64 280.22C335.013 279.586 332.112 273.818 330.826 272.131C327.237 267.42 322.458 264.909 316.638 264.129L316.192 264.037C314.993 265.535 316.083 270.149 315.579 272.213C315.076 269.916 316.559 267.352 315.272 265.334C314.562 264.951 314 264.949 313.234 265.15C310.643 265.828 308.244 267.144 305.601 267.663L305.359 267.78C304.526 268.174 303.726 268.445 302.836 268.679L302.422 268.516C302.97 267.994 303.581 267.707 304.249 267.371C303.346 267.089 302.592 267.405 301.795 267.828C300.798 268.358 299.724 269.109 298.638 269.418C296.45 270.04 293.748 268.782 292.771 271.723C291.539 275.429 292.836 276.598 289.342 279.245L289.264 279.106L289.746 279.665C289.922 279.642 290.098 279.617 290.274 279.596C290.788 279.534 291.072 279.562 291.552 279.784C283.761 280.886 276.08 271.943 269.481 268.727C269.532 267.685 269.414 267.036 268.848 266.155C266.793 262.951 261.551 259.21 258.011 257.869C256.773 257.4 255.382 257.17 254.087 256.899C250.725 256.497 247.482 255.358 244.173 254.665C241.651 254.137 239.029 253.962 236.466 253.728C236.969 252.907 236.631 251.749 236.978 250.742C238.867 250.759 240.816 250.676 242.696 250.824Z" fill="url(#paint0_linear_4222_6997)"/>
<path d="M236.978 250.742C238.867 250.759 240.816 250.676 242.696 250.824C242.881 250.874 243.066 250.928 243.252 250.974C245.298 251.479 247.92 251.212 250.051 251.224C248.443 251.53 247.073 251.291 245.943 252.702C245.85 253.55 245.913 253.633 246.31 254.399C248.336 255.702 252.778 255.161 254.087 256.899C250.725 256.497 247.482 255.358 244.173 254.665C241.651 254.137 239.029 253.962 236.466 253.728C236.969 252.907 236.631 251.749 236.978 250.742Z" fill="#15337C"/>
<path d="M315.839 263.948C315.537 262.501 315.708 261.013 315.229 259.629C314.46 258.966 313.976 259.049 312.984 258.933C313.102 258.884 313.213 258.814 313.338 258.787C315.769 258.246 325.519 258.983 328.801 258.983L357.499 259.017C359.803 259.006 366.156 258.505 368.097 258.96C368.485 259.051 368.546 259.119 368.836 259.31C366.357 260.996 362.191 264.345 361.869 267.495C361.803 268.145 361.893 268.578 362.175 269.155L362.288 269.421C358.345 270.649 354.9 273.636 351.221 275.536C348.264 277.064 345.072 278.136 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965L337.631 281.175C336.996 280.978 336.122 280.707 335.64 280.22C335.013 279.586 332.112 273.818 330.826 272.131C327.237 267.42 322.458 264.909 316.638 264.129L316.192 264.037C314.993 265.535 316.083 270.149 315.579 272.213C315.076 269.916 316.559 267.352 315.272 265.334C314.562 264.951 314 264.949 313.234 265.15C310.643 265.828 308.244 267.144 305.601 267.663C307.941 265.704 312.848 264.583 315.839 263.948Z" fill="url(#paint1_linear_4222_6997)"/>
<path d="M334.406 268.36C340.718 267.927 347.148 267.514 353.456 268.191C355.699 268.431 360.368 269.793 362.175 269.155L362.288 269.421C358.345 270.649 354.9 273.636 351.221 275.536C348.264 277.064 345.072 278.136 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965C338.013 279.917 337.843 278.75 337.605 277.665C336.155 274.684 336.233 271.392 334.406 268.36Z" fill="#4F91E0"/>
<path d="M337.605 277.665C338.101 277.244 338.105 277.263 338.759 277.253C340.026 277.925 341.077 278.732 342.142 279.684C340.991 280.35 339.912 280.649 338.622 280.946L338.374 280.965C338.013 279.917 337.843 278.75 337.605 277.665Z" fill="#5BBFFC"/>
<path d="M162.994 506.672C163.51 506.136 164.063 505.686 164.643 505.225C167.325 506.032 178.659 505.485 182.142 505.49L221.176 505.555C226.755 505.582 232.376 505.443 237.949 505.628C269.102 506.183 300.329 505.731 331.491 505.742L372.011 505.764C380.199 505.77 388.457 505.962 396.635 505.618C396.442 517.711 396.022 529.884 396.433 541.975C409.395 542.082 422.357 542.091 435.32 542.002C441.062 542.005 447.41 541.469 453.076 542.23C457.801 542.254 462.724 542.135 467.419 542.679C465.179 543.78 463.234 548.572 462.043 550.796V551.298L462.794 551.648C454.827 551.784 446.872 552.172 438.929 552.813C436.511 552.995 434.06 552.553 431.644 552.413C428.22 552.214 424.779 552.237 421.352 552.25C402.933 552.322 384.531 552.526 366.11 552.346L227.563 552.274C215.642 552.277 203.672 552.344 191.757 552.13C182.178 551.958 172.491 551.389 162.923 551.866C164.053 549.046 163.345 544.905 162.658 542.024C162.018 536.512 162.277 530.737 162.288 525.186C162.299 519.081 161.931 512.699 162.994 506.672Z" fill="#15337C"/>
<path d="M162.994 506.672C163.51 506.136 164.063 505.686 164.643 505.225C167.325 506.032 178.659 505.485 182.142 505.49L221.176 505.555C226.755 505.582 232.376 505.443 237.949 505.628C237.694 517.722 237.219 529.932 237.571 542.021L396.433 541.975C409.395 542.082 422.357 542.091 435.32 542.002C441.062 542.005 447.41 541.469 453.076 542.23C445.432 542.447 437.752 542.287 430.104 542.288L384.066 542.238L236.646 542.27L181.968 542.237C175.536 542.231 169.083 541.914 162.658 542.024C162.018 536.512 162.277 530.737 162.288 525.186C162.299 519.081 161.931 512.699 162.994 506.672Z" fill="#3158B7"/>
<path d="M237.949 505.628C269.102 506.183 300.329 505.731 331.491 505.742L372.011 505.764C380.199 505.77 388.457 505.962 396.635 505.618C396.442 517.711 396.022 529.884 396.433 541.975L237.571 542.021C237.219 529.932 237.694 517.722 237.949 505.628Z" fill="#3D7ECD"/>
<path d="M316.173 450.214L316.356 450.171C327.599 451.012 338.68 453.515 349.747 455.526C360.085 457.318 370.442 458.993 380.817 460.552C388.881 461.984 396.892 463.653 404.942 465.147C409.11 465.92 413.349 466.406 417.485 467.324C418.03 466.869 417.89 466.842 417.96 466.175C418.868 471.139 419.01 474.417 418.882 479.505C424.212 480.991 428.904 484.71 433.752 487.295L467.07 504.914C467.988 505.502 468.749 505.944 468.955 507.111C469.514 510.282 469.469 539.486 468.739 541.824C468.292 542.267 468.021 542.487 467.419 542.679C462.724 542.135 457.801 542.254 453.076 542.23C447.41 541.469 441.062 542.005 435.32 542.002C422.357 542.091 409.395 542.082 396.433 541.975C396.022 529.884 396.442 517.711 396.635 505.618C388.457 505.962 380.199 505.77 372.011 505.764L331.491 505.742C300.329 505.731 269.102 506.183 237.949 505.628C232.376 505.443 226.755 505.582 221.176 505.555L182.142 505.49C178.659 505.485 167.325 506.032 164.643 505.225C166.684 503.613 169.31 502.543 171.632 501.378C176.276 499.048 181.007 496.831 185.604 494.419C192.121 490.999 198.566 487.372 204.999 483.795C207.005 482.679 208.919 481.328 210.961 480.297C211.664 479.943 212.437 479.729 213.192 479.519C213.447 477.939 213.28 476.121 213.292 474.511C213.314 471.755 213.495 469.182 213.961 466.462C214.147 466.81 214.01 466.597 214.452 467.044C227.245 465.759 239.827 462.451 252.483 460.143C260.461 458.819 268.511 457.946 276.475 456.519L300.283 452.407C305.401 451.522 310.98 450.069 316.173 450.214Z" fill="#73E4FA"/>
<path d="M316.173 450.214L316.356 450.171C327.599 451.012 338.68 453.515 349.747 455.526C360.085 457.318 370.442 458.993 380.817 460.552C388.881 461.984 396.892 463.653 404.942 465.147C409.11 465.92 413.349 466.406 417.485 467.324C418.03 466.869 417.89 466.842 417.96 466.175C418.868 471.139 419.01 474.417 418.882 479.505C407.542 478.716 395.89 479.365 384.514 479.436C370.443 479.525 356.374 479.202 342.302 479.225L326.141 479.166C322.94 479.164 319.619 479.396 316.441 479.069C316.286 469.43 316.022 459.862 316.173 450.214Z" fill="#3D7ECD"/>
<path d="M467.07 504.914C467.988 505.502 468.749 505.944 468.955 507.111C469.514 510.282 469.469 539.486 468.739 541.824C468.292 542.267 468.021 542.487 467.419 542.679C462.724 542.135 457.801 542.254 453.076 542.23C447.41 541.469 441.062 542.005 435.32 542.002C422.357 542.091 409.395 542.082 396.433 541.975C396.022 529.884 396.442 517.711 396.635 505.618C399.774 505.933 403.063 505.785 406.221 505.786L422.299 505.784C435.31 505.785 448.476 506.228 461.464 505.68C463.339 505.6 465.314 505.634 467.07 504.914Z" fill="#5BBFFC"/>
<path d="M252.483 460.143C260.461 458.819 268.511 457.946 276.475 456.519L300.283 452.407C305.401 451.522 310.98 450.069 316.173 450.214C316.022 459.862 316.286 469.43 316.441 479.069C313.41 479.108 310.372 479.425 307.371 479.847C292.468 483.6 277.556 488.899 263.025 493.906C257.708 495.738 251.924 497.128 246.801 499.408C243.673 500.8 240.545 502.657 238.239 505.216L351.838 505.253L382.181 505.431C386.77 505.429 392.191 504.724 396.635 505.618C388.457 505.962 380.199 505.77 372.011 505.764L331.491 505.742C300.329 505.731 269.102 506.183 237.949 505.628C232.376 505.443 226.755 505.582 221.176 505.555L182.142 505.49C178.659 505.485 167.325 506.032 164.643 505.225C166.684 503.613 169.31 502.543 171.632 501.378C176.276 499.048 181.007 496.831 185.604 494.419C192.121 490.999 198.566 487.372 204.999 483.795C207.005 482.679 208.919 481.328 210.961 480.297C211.664 479.943 212.437 479.729 213.192 479.519C213.447 477.939 213.28 476.121 213.292 474.511C213.314 471.755 213.495 469.182 213.961 466.462C214.147 466.81 214.01 466.597 214.452 467.044C227.245 465.759 239.827 462.451 252.483 460.143Z" fill="url(#paint2_linear_4222_6997)"/>
<path d="M252.483 460.143C260.461 458.819 268.511 457.946 276.475 456.519L300.283 452.407C305.401 451.522 310.98 450.069 316.173 450.214C316.022 459.862 316.286 469.43 316.441 479.069C313.41 479.108 310.372 479.425 307.371 479.847C280.73 478.905 253.933 479.206 227.271 479.298C222.578 479.314 217.879 479.538 213.192 479.519C213.447 477.939 213.28 476.121 213.292 474.511C213.314 471.755 213.495 469.182 213.961 466.462C214.147 466.81 214.01 466.597 214.452 467.044C227.245 465.759 239.827 462.451 252.483 460.143Z" fill="#15337C"/>
<path d="M305.601 267.663C308.244 267.144 310.643 265.828 313.234 265.15C314 264.949 314.562 264.951 315.272 265.334C316.559 267.352 315.076 269.916 315.579 272.213C316.083 270.149 314.993 265.535 316.192 264.037L316.638 264.129C322.458 264.909 327.237 267.42 330.826 272.131C332.112 273.818 335.013 279.586 335.64 280.22C336.122 280.707 336.996 280.978 337.631 281.175L338.374 280.965L338.622 280.946C340.078 289.201 342.561 297.284 344.607 305.405C347.019 314.981 349.071 324.725 351.327 334.35L372.075 421.626C374.16 430.227 376.712 438.738 378.694 447.356C379.359 450.33 379.896 453.327 380.305 456.347C380.489 457.712 380.516 459.221 380.817 460.552C370.442 458.993 360.085 457.318 349.747 455.526C338.68 453.515 327.599 451.012 316.356 450.171L316.173 450.214C310.98 450.069 305.401 451.522 300.283 452.407L276.475 456.519C268.511 457.946 260.461 458.819 252.483 460.143C239.827 462.451 227.245 465.759 214.452 467.044C214.01 466.597 214.147 466.81 213.961 466.462C217.335 455.731 219.76 444.734 222.73 433.889L237.945 379.405L269.481 268.727C276.08 271.943 283.761 280.886 291.552 279.784C291.072 279.562 290.788 279.534 290.274 279.596C290.098 279.617 289.922 279.642 289.746 279.665L289.264 279.106L289.342 279.245C292.836 276.598 291.539 275.429 292.771 271.723C293.748 268.782 296.45 270.04 298.638 269.418C299.724 269.109 300.798 268.358 301.795 267.828C302.592 267.405 303.346 267.089 304.249 267.371C303.581 267.707 302.97 267.994 302.422 268.516L302.836 268.679C303.726 268.445 304.526 268.174 305.359 267.78L305.601 267.663Z" fill="#3D7ECD"/>
<path d="M213.961 466.462C217.335 455.731 219.76 444.734 222.73 433.889L237.945 379.405L269.481 268.727C276.08 271.943 283.761 280.886 291.552 279.784C294.318 279.786 297.526 280.103 300.239 279.671C302.32 279.34 293.35 281.165 295.5 281C292.765 282.129 294.815 282.321 291.94 282.461C291.8 282.468 291.66 282.481 291.519 282.489C291.435 282.494 291.35 282.496 291.266 282.5C290.329 287.67 289.473 292.882 288.349 298.015L265.21 399.097L256.243 437.602C255.364 441.302 250.844 457.078 251.4 459.744C251.766 459.902 252.097 460.037 252.483 460.143C239.827 462.451 227.245 465.759 214.452 467.044C214.01 466.597 214.147 466.81 213.961 466.462Z" fill="#3158B7"/>
<path d="M316.638 264.129C322.458 264.909 327.237 267.42 330.826 272.131C332.112 273.818 335.013 279.586 335.64 280.22C336.122 280.707 336.996 280.978 337.631 281.175L338.374 280.965L338.622 280.946C340.078 289.201 342.561 297.284 344.607 305.405C347.019 314.981 349.071 324.725 351.327 334.35L372.075 421.626C374.16 430.227 376.712 438.738 378.694 447.356C379.359 450.33 379.896 453.327 380.305 456.347C380.489 457.712 380.516 459.221 380.817 460.552C370.442 458.993 360.085 457.318 349.747 455.526C338.68 453.515 327.599 451.012 316.356 450.171L316.124 267.318C316.132 266.225 316.016 265.039 316.638 264.129Z" fill="#5BBFFC"/>
<path d="M162.602 542.012C222.681 542.667 282.903 542.133 343 542.146L421.144 542.172C436.934 542.179 452.86 542.406 468.631 542C468.259 556.284 468.631 576.5 466.168 585H164.5C162.602 574 162.11 556.297 162.602 542.012Z" fill="#2E57AB"/>
<path d="M263.193 261.724L235.532 253.517L232.5 252.5L229.5 250.5L402 250L377.5 261.724L364 275.5L339.134 284H289.345L269.731 271.69L263.193 261.724Z" fill="#2950B6"/>
<defs>
<linearGradient id="paint0_linear_4222_6997" x1="313.33" y1="251.065" x2="313.326" y2="279.202" gradientUnits="userSpaceOnUse">
<stop stop-color="#122869"/>
<stop offset="1" stop-color="#2950B6"/>
</linearGradient>
<linearGradient id="paint1_linear_4222_6997" x1="342.025" y1="256.698" x2="339.592" y2="280.614" gradientUnits="userSpaceOnUse">
<stop stop-color="#3052A7"/>
<stop offset="1" stop-color="#2671CE"/>
</linearGradient>
<linearGradient id="paint2_linear_4222_6997" x1="233.914" y1="479.018" x2="235.081" y2="504.885" gradientUnits="userSpaceOnUse">
<stop stop-color="#486DC9"/>
<stop offset="1" stop-color="#599BEA"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 29 KiB

+7
View File
@@ -0,0 +1,7 @@
window.__ENV = {
GLOBAL_REFRESH: "60000",
APP_HOST: "http://localhost:5173",
APP_API_BASE_URL: "http://localhost:52345/api/v1",
APP_DEPLOYMENT_MODE: "self_hosted",
// APP_DEPLOYMENT_MODE: "saas",
};
-5
View File
@@ -1,5 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"labels": ["dependencies"]
}
-41
View File
@@ -1,41 +0,0 @@
import { useEffect } from "react";
import { useSelector } from "react-redux";
import "react-toastify/dist/ReactToastify.css";
import { ToastContainer } from "react-toastify";
import { ThemeProvider } from "@emotion/react";
import lightTheme from "./Utils/Theme/lightTheme";
import darkTheme from "./Utils/Theme/darkTheme";
import { CssBaseline, GlobalStyles } from "@mui/material";
import { logger } from "./Utils/Logger"; // Import the logger
import { networkService } from "./main";
import { Routes } from "./Routes";
import WalletProvider from "./Components/WalletProvider";
import AppLayout from "./Components/Layouts/AppLayout";
function App() {
const mode = useSelector((state) => state.ui.mode);
// Cleanup
useEffect(() => {
return () => {
logger.cleanup();
networkService.cleanup();
};
}, []);
return (
/* Extract Themeprovider, baseline and global styles to Styles */
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
<WalletProvider>
<CssBaseline />
<AppLayout>
<Routes />
</AppLayout>
<ToastContainer />
</WalletProvider>
</ThemeProvider>
);
}
export default App;
+37
View File
@@ -0,0 +1,37 @@
import CssBaseline from "@mui/material/CssBaseline";
import AppRoutes from "@/routes/Router";
import { ThemeProvider } from "@mui/material/styles";
import { lightTheme, darkTheme } from "@/theme/theme";
import { I18nLoader } from "@/components/i18nLoader";
import { useAppSelector } from "./hooks/AppHooks";
import { BrowserRouter } from "react-router-dom";
import { AuthVerifier } from "@/components/auth-verifier";
import { ToastContainer } from "react-toastify";
function App() {
const mode = useAppSelector((state) => state.ui.mode);
return (
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
<CssBaseline />
<I18nLoader />
<BrowserRouter>
<AuthVerifier>
<AppRoutes />
</AuthVerifier>
</BrowserRouter>
<ToastContainer
newestOnTop={true}
theme={mode}
style={
{
"--toastify-color-progress-light": "#7C8BA1",
"--toastify-color-progress-dark": "#7C8BA1",
} as React.CSSProperties
}
/>
</ThemeProvider>
);
}
export default App;
-224
View File
@@ -1,224 +0,0 @@
// Components
import IconButton from "@mui/material/IconButton";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import Settings from "../../assets/icons/settings-bold.svg?react";
import Dialog from "../../Components/Dialog";
// Utils
import { useState } from "react";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { createToast } from "../../Utils/toastUtils";
import PropTypes from "prop-types";
import { usePauseMonitor, useDeleteMonitor } from "../../Hooks/monitorHooks";
const ActionsMenu = ({
monitor,
isAdmin,
updateRowCallback,
pauseCallback,
setIsLoading = () => {},
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const [actions, setActions] = useState({});
const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
const [pauseMonitor, isPausing, error] = usePauseMonitor();
const [deleteMonitor, isDeleting] = useDeleteMonitor();
const handleRemove = async (event) => {
event.preventDefault();
event.stopPropagation();
let monitor = { _id: actions.id };
await deleteMonitor({ monitor });
updateRowCallback();
};
const handlePause = async () => {
try {
setIsLoading(true);
await pauseMonitor({ monitorId: monitor._id });
pauseCallback();
} catch (error) {
createToast({ body: "Failed to pause monitor." });
} finally {
setIsLoading(false);
}
};
const openMenu = (event, id, url) => {
event.preventDefault();
event.stopPropagation();
setAnchorEl(event.currentTarget);
setActions({ id: id, url: url });
};
const openRemove = (e) => {
closeMenu(e);
setIsOpen(true);
};
const closeMenu = (e) => {
e.stopPropagation();
setAnchorEl(null);
};
const navigate = useNavigate();
return (
<>
<IconButton
aria-label="monitor actions"
onClick={(event) => {
event.stopPropagation();
openMenu(event, monitor._id, monitor.type === "ping" ? null : monitor.url);
}}
sx={{
"&:focus": {
outline: "none",
},
"& svg path": {
stroke: theme.palette.primary.contrastTextTertiary,
},
}}
>
<Settings />
</IconButton>
<Menu
className="actions-menu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={(e) => closeMenu(e)}
disableScrollLock
slotProps={{
paper: {
sx: {
"& ul": {
p: theme.spacing(2.5),
backgroundColor: theme.palette.primary.main,
},
"& li": { m: 0, color: theme.palette.primary.contrastTextSecondary },
/*
This should not be set automatically on the last of type
"& li:last-of-type": {
color: theme.palette.error.main,
}, */
},
},
}}
>
{actions.url !== null ? (
<MenuItem
onClick={(e) => {
closeMenu(e);
e.stopPropagation();
window.open(actions.url, "_blank", "noreferrer");
}}
>
Open site
</MenuItem>
) : (
""
)}
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/uptime/${actions.id}`);
}}
>
Details
</MenuItem>
{/* TODO - pass monitor id to Incidents page */}
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/incidents/${actions.id}`);
}}
>
Incidents
</MenuItem>
{isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/uptime/configure/${actions.id}`);
}}
>
Configure
</MenuItem>
)}
{isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/uptime/create/${actions.id}`);
}}
>
Clone
</MenuItem>
)}
{isAdmin && (
<MenuItem
onClick={(e) => {
closeMenu(e);
e.stopPropagation();
handlePause(e);
}}
>
{monitor?.isActive === true ? "Pause" : "Resume"}
</MenuItem>
)}
{isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
openRemove(e);
}}
sx={{ "&.MuiButtonBase-root": { color: theme.palette.error.main } }}
>
Remove
</MenuItem>
)}
</Menu>
<Dialog
open={isOpen}
theme={theme}
title="Do you really want to delete this monitor?"
description="Once deleted, this monitor cannot be retrieved."
/* Do we need stop propagation? */
onCancel={(e) => {
e.stopPropagation();
setIsOpen(false);
}}
confirmationButtonLabel="Delete"
/* Do we need stop propagation? */
onConfirm={(e) => {
e.stopPropagation();
handleRemove(e);
}}
isLoading={isDeleting}
modelTitle="modal-delete-monitor"
modelDescription="delete-monitor-confirmation"
/>
</>
);
};
ActionsMenu.propTypes = {
monitor: PropTypes.shape({
_id: PropTypes.string,
url: PropTypes.string,
type: PropTypes.string,
isActive: PropTypes.bool,
}).isRequired,
isAdmin: PropTypes.bool,
updateRowCallback: PropTypes.func,
pauseCallback: PropTypes.func,
setIsLoading: PropTypes.func,
};
export default ActionsMenu;
-9
View File
@@ -1,9 +0,0 @@
.alert {
margin: 0;
width: fit-content;
}
.alert,
.alert button,
.alert .MuiTypography-root {
font-size: var(--env-var-font-size-medium);
}
-127
View File
@@ -1,127 +0,0 @@
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { Box, Button, IconButton, Stack, Typography } from "@mui/material";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined";
import WarningAmberOutlinedIcon from "@mui/icons-material/WarningAmberOutlined";
import CloseIcon from "@mui/icons-material/Close";
import "./index.css";
/**
* Icons mapping for different alert variants.
* @type {Object<string, JSX.Element>}
*/
const icons = {
info: <InfoOutlinedIcon />,
error: <ErrorOutlineOutlinedIcon />,
warning: <WarningAmberOutlinedIcon />,
};
/**
* @param {Object} props
* @param {'info' | 'error' | 'warning'} props.variant - The type of alert.
* @param {string} [props.title] - The title of the alert.
* @param {string} [props.body] - The body text of the alert.
* @param {boolean} [props.isToast] - Indicates if the alert is used as a toast notification.
* @param {boolean} [props.hasIcon] - Whether to display an icon in the alert.
* @param {function} props.onClick - Toast dismiss function.
* @returns {JSX.Element}
*/
const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
const theme = useTheme();
/* TODO
Do we need other variants for alert?
*/
const text = theme.palette.secondary.contrastText;
const border = theme.palette.alert.contrastText;
const bg = theme.palette.alert.main;
const icon = icons[variant];
return (
<Stack
direction="row"
justifyContent="flex-start"
alignItems={hasIcon ? "" : "center"}
className="alert row-stack"
gap={theme.spacing(8)}
sx={{
padding: hasIcon ? theme.spacing(8) : `${theme.spacing(4)} ${theme.spacing(8)}`,
backgroundColor: bg,
border: `solid 1px ${border}`,
borderRadius: theme.shape.borderRadius,
}}
>
{hasIcon && <Box sx={{ color: text }}>{icon}</Box>}
<Stack
direction="column"
gap="2px"
sx={{ flex: 1 }}
>
{title && (
<Typography sx={{ fontWeight: "700", color: `${text}` }}>{title}</Typography>
)}
{body && (
<Typography sx={{ fontWeight: "400", color: `${text}` }}>{body}</Typography>
)}
{hasIcon && isToast && (
<Button
variant="text"
color="info"
onClick={onClick}
sx={{
fontWeight: "600",
width: "fit-content",
mt: theme.spacing(4),
padding: 0,
minWidth: 0,
}}
>
Dismiss
</Button>
)}
</Stack>
{isToast && (
<IconButton
onClick={onClick}
sx={{
alignSelf: "flex-start",
ml: "auto",
mr: "-5px",
mt: hasIcon ? "-5px" : 0,
padding: "5px",
"&:focus": {
outline: "none",
},
}}
>
<CloseIcon
sx={{
fontSize: "20px",
}}
/>
</IconButton>
)}
</Stack>
);
};
Alert.propTypes = {
variant: PropTypes.oneOf(["info", "error", "warning"]).isRequired,
title: PropTypes.string,
body: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
isToast: PropTypes.bool,
hasIcon: PropTypes.bool,
onClick: function (props, propName, componentName) {
if (props.isToast && !props[propName]) {
return new Error(
`Prop '${propName}' is required when 'isToast' is true in '${componentName}'.`
);
}
return null;
},
};
export default Alert;
@@ -1,68 +0,0 @@
import PropTypes from "prop-types";
import { Box, Stack, useTheme } from "@mui/material";
// import useUtils from "../../Pages/Uptime/utils";
/**
* A component that renders a pulsating dot with a specified color.
*
* @component
* @example
* // Example usage:
* <PulseDot color="#f00" />
*
* @param {Object} props
* @param {string} props.color - The color of the dot.
* @returns {JSX.Element} The PulseDot component.
*/
const PulseDot = ({ color }) => {
const theme = useTheme();
// const { statusToTheme } = useUtils();
/* TODO refactor so it gets status and gets theme color. Then uses theme.palette.[themeColor].lowContrast */
/* const themeColor = statusToTheme[status]; */
return (
<Stack
width="26px"
height="24px"
alignItems="center"
justifyContent="center"
>
<Box
minWidth="18px"
minHeight="18px"
sx={{
position: "relative",
backgroundColor: color,
borderRadius: "50%",
"&::before": {
content: `""`,
position: "absolute",
width: "100%",
height: "100%",
backgroundColor: "inherit",
borderRadius: "50%",
animation: "ripple 1.8s ease-out infinite",
},
"&::after": {
content: `""`,
position: "absolute",
width: "7px",
height: "7px",
borderRadius: "50%",
backgroundColor: theme.palette.accent.contrastText,
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
},
}}
/>
</Stack>
);
};
PulseDot.propTypes = {
color: PropTypes.string.isRequired,
};
export default PulseDot;
-35
View File
@@ -1,35 +0,0 @@
import LeftArrow from "../../assets/icons/left-arrow.svg?react";
import LeftArrowDouble from "../../assets/icons/left-arrow-double.svg?react";
import LeftArrowLong from "../../assets/icons/left-arrow-long.svg?react";
import PropTypes from "prop-types";
const ArrowLeft = ({ type, color = "#667085", ...props }) => {
if (type === "double") {
return (
<LeftArrowDouble
style={{ color }}
{...props}
/>
);
} else if (type === "long") {
return (
<LeftArrowLong
style={{ color }}
{...props}
/>
);
} else {
return (
<LeftArrow
style={{ color }}
{...props}
/>
);
}
};
ArrowLeft.propTypes = {
color: PropTypes.string,
type: PropTypes.oneOf(["double", "long", "default"]),
};
export default ArrowLeft;
@@ -1,28 +0,0 @@
import RightArrow from "../../assets/icons/right-arrow.svg?react";
import RightArrowDouble from "../../assets/icons/right-arrow-double.svg?react";
import PropTypes from "prop-types";
const ArrowRight = ({ type, color = "#667085", ...props }) => {
if (type === "double") {
return (
<RightArrowDouble
style={{ color }}
{...props}
/>
);
} else {
return (
<RightArrow
style={{ color }}
{...props}
/>
);
}
};
ArrowRight.propTypes = {
type: PropTypes.oneOf(["double", "default"]),
color: PropTypes.string,
};
export default ArrowRight;
Whitespace-only changes.
-73
View File
@@ -1,73 +0,0 @@
import { Avatar as MuiAvatar } from "@mui/material";
import PropTypes from "prop-types";
import { useSelector } from "react-redux";
import { useEffect, useState } from "react";
import { useTheme } from "@emotion/react";
/**
* @component
* @param {Object} props
* @param {string} props.src - Path to image for avatar
* @param {boolean} props.small - Specifies if avatar should be large
* @param {Object} [props.sx] - Additional styles to apply to the button.
* @returns {JSX.Element}
* @example
* // Render a red label
* <Avatar src="assets/img" first="Alex" last="Holliday" small />
*/
const Avatar = ({ src, small, sx, onClick = () => {} }) => {
const { user } = useSelector((state) => state.auth);
const theme = useTheme();
const style = small ? { width: 32, height: 32 } : { width: 64, height: 64 };
const border = small ? 1 : 3;
const [image, setImage] = useState();
useEffect(() => {
if (user.avatarImage) {
setImage(`data:image/png;base64,${user.avatarImage}`);
}
}, [user?.avatarImage]);
return (
<MuiAvatar
onClick={onClick}
alt={`${user?.firstName} ${user?.lastName}`}
/* TODO What is the /static/images/avatar/2.jpg ?*/
src={src ? src : user?.avatarImage ? image : "/static/images/avatar/2.jpg"}
sx={{
fontSize: small ? "16px" : "22px",
fontWeight: 400,
color: theme.palette.accent.contrastText,
backgroundColor: theme.palette.accent.main, // Same BG color as checkmate BG in sidebar
display: "inline-flex",
/*
TODO not sure what this is for*/
"&::before": {
content: `""`,
position: "absolute",
top: 0,
left: 0,
width: `100%`,
height: `100%`,
border: `${border}px solid rgba(255,255,255,0.2)`,
borderRadius: "50%",
},
...style,
...sx,
}}
>
{user.firstName?.charAt(0)}
{user.lastName?.charAt(0) || ""}
</MuiAvatar>
);
};
Avatar.propTypes = {
src: PropTypes.string,
small: PropTypes.bool,
sx: PropTypes.object,
onClick: PropTypes.func,
};
export default Avatar;
@@ -1,22 +0,0 @@
.MuiBreadcrumbs-root {
min-height: 34px;
}
.MuiBreadcrumbs-root svg {
width: 16px;
min-height: 16px;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li a {
font-size: var(--env-var-font-size-medium);
font-weight: 400;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child) {
cursor: pointer;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li:last-child a {
font-weight: 500;
opacity: 1;
cursor: default;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-separator {
margin: 0;
}
@@ -1,78 +0,0 @@
import PropTypes from "prop-types";
import { Box, Breadcrumbs as MUIBreadcrumbs } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import ArrowRight from "../ArrowRight";
import "./index.css";
/**
* Breadcrumbs component that displays a list of breadcrumb items.
*
* @param {Object} props
* @param {Array} props.list - Array of breadcrumb items. Each item should have `name` and `path` properties.
* @param {string} props.list.name - The name to display for the breadcrumb.
* @param {string} props.list.path - The path to navigate to when the breadcrumb is clicked.
*
* @returns {JSX.Element} The rendered Breadcrumbs component.
*/
const Breadcrumbs = ({ list }) => {
const theme = useTheme();
const navigate = useNavigate();
return (
<MUIBreadcrumbs
separator={<ArrowRight />}
aria-label="breadcrumb"
px={theme.spacing(2)}
py={theme.spacing(3.5)}
width="fit-content"
backgroundColor={theme.palette.secondary.main}
borderRadius={theme.shape.borderRadius}
lineHeight="18px"
sx={{
"& .MuiBreadcrumbs-li a": {
transition: "background-color 0.2s ease-in-out, color 0.2s ease-in-out",
},
"& .MuiBreadcrumbs-li:not(:last-of-type):hover a": {
backgroundColor: theme.palette.secondary.contrastText,
color: theme.palette.secondary.main,
},
}}
>
{list.map((item, index) => {
return (
<Box
component="a"
key={`${item.name}-${index}`}
px={theme.spacing(4)}
pt={theme.spacing(2)}
pb={theme.spacing(3)}
borderRadius={theme.shape.borderRadius}
onClick={() => navigate(item.path)}
sx={{
opacity: 0.8,
textTransform: "capitalize",
"&, &:hover": {
color: theme.palette.secondary.contrastText,
},
}}
>
{item.name}
</Box>
);
})}
</MUIBreadcrumbs>
);
};
Breadcrumbs.propTypes = {
list: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
}).isRequired
).isRequired,
};
export default Breadcrumbs;
@@ -1,30 +0,0 @@
import React from "react";
import Button from "@mui/material/Button";
import { styled } from "@mui/material/styles";
const RoundGradientButton = styled(Button)(({ theme }) => ({
position: "relative",
border: "5px solid transparent",
backgroundClip: "padding-box",
borderRadius: 30,
fontSize: "1.2rem",
color: theme.palette.primary.contrastText,
backgroundColor: theme.palette.background.main,
"&:after": {
position: "absolute",
top: -3,
left: -3,
right: -3,
bottom: -3,
background:
theme.palette.mode === "dark"
? "linear-gradient(90deg, #842bd2, #ff5451, #8c52ff)"
: "linear-gradient(90deg, #842bd2, #ff5451, #8c52ff)",
content: '""',
zIndex: -1,
borderRadius: 30,
},
}));
export default RoundGradientButton;
@@ -1,214 +0,0 @@
/**
* CustomAreaChart component for rendering an area chart with optional gradient and custom ticks.
*
* @param {Object} props - The properties object.
* @param {Array} props.data - The data array for the chart.
* @param {Array} props.dataKeys - An array of data keys to be plotted as separate areas.
* @param {string} props.xKey - The key for the x-axis data.
* @param {string} [props.yKey] - The key for the y-axis data (optional).
* @param {Object} [props.xTick] - Custom tick component for the x-axis.
* @param {Object} [props.yTick] - Custom tick component for the y-axis.
* @param {string} [props.strokeColor] - The base stroke color for the areas.
* If not provided, uses a predefined color palette.
* @param {string} [props.fillColor] - The base fill color for the areas.
* @param {boolean} [props.gradient=false] - Whether to apply a gradient fill to the areas.
* @param {string} [props.gradientDirection="vertical"] - The direction of the gradient.
* @param {string} [props.gradientStartColor] - The start color of the gradient.
* Defaults to the area's stroke color if not provided.
* @param {string} [props.gradientEndColor] - The end color of the gradient.
* @param {Object} [props.customTooltip] - Custom tooltip component for the chart.
* @param {string|number} [props.height="100%"] - Height of the chart container.
*
* @returns {JSX.Element} The rendered area chart component.
*
* @example
* // Single series chart
* <CustomAreaChart
* data={temperatureData}
* dataKeys={["temperature"]}
* xKey="date"
* yKey="temperature"
* gradient={true}
* gradientStartColor="#ff6b6b"
* gradientEndColor="#4ecdc4"
* />
*
* @example
* // Multi-series chart with custom tooltip
* <CustomAreaChart
* data={performanceData}
* dataKeys={["cpu.usage", "memory.usage"]}
* xKey="timestamp"
* xTick={<CustomTimeTick />}
* yTick={<PercentageTick />}
* gradient={true}
* customTooltip={({ active, payload, label }) => (
* <CustomTooltip
* label={label}
* payload={payload}
* active={active}
* />
* )}
* />
*/
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";
import { createGradient } from "../Utils/gradientUtils";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
import { useId } from "react";
import { Fragment } from "react";
const CustomAreaChart = ({
data,
dataKeys,
xKey,
xDomain,
yKey,
yDomain,
xTick,
yTick,
strokeColor,
fillColor,
gradient = false,
gradientDirection = "vertical",
gradientStartColor,
gradientEndColor,
customTooltip,
height = "100%",
}) => {
const theme = useTheme();
const uniqueId = useId();
const AREA_COLORS = [
// Blues
"#3182bd", // Deep blue
"#6baed6", // Medium blue
"#9ecae1", // Light blue
// Greens
"#74c476", // Soft green
"#a1d99b", // Light green
"#c7e9c0", // Pale green
// Oranges
"#fdae6b", // Warm orange
"#fdd0a2", // Light orange
"#feedde", // Pale orange
// Purples
"#9467bd", // Lavender
"#a55194", // Deep magenta
"#c994c7", // Soft magenta
// Reds
"#ff9896", // Soft red
"#de2d26", // Deep red
"#fc9272", // Medium red
// Cyans/Teals
"#17becf", // Cyan
"#7fcdbb", // Teal
"#a1dab4", // Light teal
// Yellows
"#fec44f", // Mustard
"#fee391", // Light yellow
"#ffffd4", // Pale yellow
// Additional colors
"#e377c2", // Soft pink
"#bcbd22", // Olive
"#2ca02c", // Vibrant green
];
return (
<ResponsiveContainer
width="100%"
height={height}
// FE team HELP! Why does this overflow if set to 100%?
>
<AreaChart data={data}>
<XAxis
dataKey={xKey}
{...(xDomain && { domain: xDomain })}
{...(xTick && { tick: xTick })}
/>
<YAxis
dataKey={yKey}
{...(yDomain && { domain: yDomain })}
{...(yTick && { tick: yTick })}
/>
<CartesianGrid
stroke={theme.palette.primary.lowContrast}
strokeWidth={1}
strokeOpacity={1}
fill="transparent"
vertical={false}
/>
{dataKeys.map((dataKey, index) => {
const gradientId = `gradient-${uniqueId}-${index}`;
return (
<Fragment key={dataKey}>
{gradient === true &&
createGradient({
id: gradientId,
startColor: gradientStartColor || AREA_COLORS[index],
endColor: gradientEndColor,
direction: gradientDirection,
})}
<Area
yKey={dataKey}
key={dataKey}
type="monotone"
dataKey={dataKey}
stroke={strokeColor || AREA_COLORS[index]}
fill={gradient === true ? `url(#${gradientId})` : fillColor}
/>
</Fragment>
);
})}
{customTooltip ? (
<Tooltip
cursor={{ stroke: theme.palette.primary.lowContrast }}
content={customTooltip}
wrapperStyle={{ pointerEvents: "none" }}
/>
) : (
<Tooltip />
)}
</AreaChart>
</ResponsiveContainer>
);
};
CustomAreaChart.propTypes = {
data: PropTypes.array.isRequired,
dataKeys: PropTypes.array.isRequired,
xTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself
yTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself
xKey: PropTypes.string.isRequired,
xDomain: PropTypes.array,
yKey: PropTypes.string,
yDomain: PropTypes.array,
fillColor: PropTypes.string,
strokeColor: PropTypes.string,
gradient: PropTypes.bool,
gradientDirection: PropTypes.string,
gradientStartColor: PropTypes.string,
gradientEndColor: PropTypes.string,
customTooltip: PropTypes.object,
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
export default CustomAreaChart;
Whitespace-only changes.
@@ -1,181 +0,0 @@
import { useTheme } from "@emotion/react";
import { Box, Stack, Tooltip, Typography } from "@mui/material";
import { formatDateWithTz } from "../../../Utils/timeUtils";
import { useEffect, useState } from "react";
import "./index.css";
import { useSelector } from "react-redux";
/* TODO add prop validation and jsdocs */
const BarChart = ({ checks = [] }) => {
const theme = useTheme();
const [animate, setAnimate] = useState(false);
const uiTimezone = useSelector((state) => state.ui.timezone);
useEffect(() => {
setAnimate(true);
});
// set responseTime to average if there's only one check
if (checks.length === 1) {
checks[0] = { ...checks[0], responseTime: 50 };
}
if (checks.length !== 25) {
const placeholders = Array(25 - checks.length).fill("placeholder");
checks = [...checks, ...placeholders];
}
return (
<Stack
direction="row"
flexWrap="nowrap"
gap={theme.spacing(1.5)}
height="50px"
width="fit-content"
onClick={(event) => event.stopPropagation()}
sx={{
cursor: "default",
}}
>
{checks.map((check, index) =>
check === "placeholder" ? (
/* TODO what is the purpose of this box? */
// CAIO_REVIEW the purpose of this box is to make sure there are always at least 25 bars
// even if there are less than 25 checks
<Box
key={`${check}-${index}`}
position="relative"
width={theme.spacing(4.5)}
height="100%"
backgroundColor={theme.palette.primary.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
}}
/>
) : (
<Tooltip
title={
<>
<Typography>
{formatDateWithTz(
check.updatedAt,
"ddd, MMMM D, YYYY, HH:mm A",
uiTimezone
)}
</Typography>
<Box mt={theme.spacing(2)}>
<Box
display="inline-block"
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
sx={{ borderRadius: "50%" }}
/>
<Stack
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.spacing(2)}
gap={theme.spacing(12)}
>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
Response Time
</Typography>
<Typography component="span">
{check.originalResponseTime}
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{" "}
ms
</Typography>
</Typography>
</Stack>
</Box>
</>
}
placement="top"
key={`check-${check?._id}`}
slotProps={{
popper: {
className: "bar-tooltip",
modifiers: [
{
name: "offset",
options: {
offset: [0, -10],
},
},
],
sx: {
"& .MuiTooltip-tooltip": {
backgroundColor: theme.palette.secondary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shape.boxShadow,
px: theme.spacing(4),
py: theme.spacing(3),
},
"& .MuiTooltip-tooltip p": {
/* TODO Font size should point to theme */
fontSize: 12,
color: theme.palette.secondary.contrastText,
fontWeight: 500,
},
"& .MuiTooltip-tooltip span": {
/* TODO Font size should point to theme */
fontSize: 11,
color: theme.palette.secondary.contrastText,
fontWeight: 600,
},
},
},
}}
>
<Box
position="relative"
width="9px"
height="100%"
backgroundColor={theme.palette.primary.lowContrast} // CAIO_REVIEW
sx={{
borderRadius: theme.spacing(1.5),
/*
TODO this doesn't seem to be used
"&:hover > .MuiBox-root": {
filter: "brightness(0.8)",
}, */
}}
>
<Box
position="absolute"
bottom={0}
width="100%"
height={`${animate ? check.responseTime : 0}%`}
backgroundColor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
sx={{
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>
</Box>
</Tooltip>
)
)}
</Stack>
);
};
export default BarChart;
@@ -1,106 +0,0 @@
// Components
import { Typography, Stack } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import IconBox from "../../IconBox";
/**
* `EmptyView` is a functional React component that displays an empty state view with an optional icon, header, and message.
*
* @component
* @param {Object} props - The properties that define the `EmptyView` component.
* @param {React.ReactNode} [props.icon] - An optional icon to display at the top of the empty view.
* @param {string} [props.header] - An optional header text displayed next to the icon.
* @param {string} [props.message="No Data"] - The message to be displayed in the empty view.
* @param {'h1' | 'h2' | 'h3'} [props.headingLevel="h2"] - The heading level for the message text.
* @param {string} [props.justifyContent="flex-start"] - The CSS `justify-content` value to align elements vertically.
* @param {string} [props.height="100%"] - The height of the empty view container.
*
* @example
* // Example usage of EmptyView component:
* <EmptyView
* icon={<SomeIcon />}
* header="Average Response Time"
* message="No Response Time Available"
* headingLevel="h2"
* justifyContent="center"
* height="50%"
* />
*
* @returns {React.Element} The `EmptyView` component with customizable icon, header, and message.
*/
const EmptyView = ({
icon,
header,
message = "No Data",
headingLevel = "h2",
justifyContent = "flex-start",
height = "100%",
}) => {
const theme = useTheme();
return (
<Stack
flex={1}
direction="row"
sx={{
backgroundColor: theme.palette.primary.main,
border: 1,
borderStyle: "solid",
borderColor: theme.palette.primary.lowContrast,
borderRadius: 2,
borderTopRightRadius: 4,
borderBottomRightRadius: 4,
}}
>
<Stack
flex={1}
alignItems="center"
sx={{
padding: theme.spacing(8),
justifyContent,
gap: theme.spacing(8),
height,
"& h2": {
color: theme.palette.primary.contrastTextSecondary,
fontSize: 15,
fontWeight: 500,
},
"& tspan, & text": {
fill: theme.palette.primary.contrastTextTertiary,
},
}}
>
<Stack
alignSelf="flex-start"
direction="row"
alignItems="center"
gap={theme.spacing(6)}
>
{icon && <IconBox>{icon}</IconBox>}
{header && <Typography component="h2">{header}</Typography>}
</Stack>
<Stack
flex={1}
justifyContent="center"
alignItems="center"
>
<Typography component={headingLevel}>{message}</Typography>
</Stack>
</Stack>
</Stack>
);
};
EmptyView.propTypes = {
message: PropTypes.string,
icon: PropTypes.node,
header: PropTypes.string,
headingLevel: PropTypes.oneOf(["h1", "h2", "h3"]),
justifyContent: PropTypes.string,
height: PropTypes.string,
};
export default EmptyView;
@@ -1,104 +0,0 @@
import { Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import IconBox from "../../IconBox";
import EmptyView from "./EmptyView";
import PropTypes from "prop-types";
const ChartBox = ({
children,
icon,
header,
height = "300px",
justifyContent = "space-between",
Legend,
borderRadiusRight = 4,
sx,
noDataMessage,
isEmpty = false,
}) => {
const theme = useTheme();
if (isEmpty) {
return (
<EmptyView
icon={icon}
header={header}
message={noDataMessage}
/>
);
}
return (
<Stack
flex={1}
direction="row"
sx={{
backgroundColor: theme.palette.primary.main,
border: 1,
borderStyle: "solid",
borderColor: theme.palette.primary.lowContrast,
borderRadius: 2,
borderTopRightRadius: borderRadiusRight,
borderBottomRightRadius: borderRadiusRight,
}}
>
<Stack
flex={1}
sx={{
padding: theme.spacing(8),
justifyContent,
gap: theme.spacing(8),
height,
minWidth: 250,
"& h2": {
color: theme.palette.primary.contrastTextSecondary,
fontSize: 15,
fontWeight: 500,
},
"& .MuiBox-root:not(.area-tooltip) p": {
color: theme.palette.primary.contrastTextTertiary,
fontSize: 13,
},
"& .MuiBox-root > span": {
color: theme.palette.primary.contrastText,
fontSize: 20,
"& span": {
opacity: 0.8,
marginLeft: 2,
fontSize: 15,
},
},
"& tspan, & text": {
fill: theme.palette.primary.contrastTextTertiary,
},
"& path": {
transition: "fill 300ms ease, stroke-width 400ms ease",
},
}}
>
<Stack
alignSelf="flex-start"
direction="row"
alignItems="center"
gap={theme.spacing(6)}
>
{icon && <IconBox>{icon}</IconBox>}
{header && <Typography component="h2">{header}</Typography>}
</Stack>
{children}
</Stack>
{Legend && Legend}
</Stack>
);
};
export default ChartBox;
ChartBox.propTypes = {
children: PropTypes.node,
icon: PropTypes.node,
header: PropTypes.string,
height: PropTypes.string,
noDataMessage: PropTypes.string,
isEmpty: PropTypes.bool,
};
@@ -1,14 +0,0 @@
.radial-chart {
position: relative;
display: inline-block;
}
.radial-chart-base {
opacity: 0.3;
}
.radial-chart-progress {
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset 1.5s ease-in-out;
}
@@ -1,148 +0,0 @@
import { useTheme } from "@emotion/react";
import { useEffect, useState, useMemo } from "react";
import Stack from "@mui/material/Stack";
import { Box, Typography } from "@mui/material";
import PropTypes from "prop-types";
import "./index.css";
import CircularProgress from "@mui/material/CircularProgress";
const MINIMUM_VALUE = 0;
const MAXIMUM_VALUE = 100;
/**
* A Performant SVG based circular gauge
*
* @component
* @param {Object} props - Component properties
* @param {number} [props.progress=0] - Progress percentage (0-100)
* @param {number} [props.radius=60] - Radius of the gauge circle
* @param {number} [props.strokeWidth=15] - Width of the gauge stroke
* @param {number} [props.precision=1] - Precision of the progress percentage
* @param {string} [props.unit="%"] - Unit of progress
*
* @example
* <CustomGauge
* progress={75}
* radius={50}
* strokeWidth={10}
* />
*
* @returns {React.ReactElement} Rendered CustomGauge component
*/
const CustomGauge = ({
isLoading = false,
progress = 0,
radius = 70,
strokeWidth = 15,
precision = 1,
unit = "%",
}) => {
const theme = useTheme();
// Calculate the length of the stroke for the circle
const { circumference, totalSize, strokeLength } = useMemo(
() => ({
circumference: 2 * Math.PI * radius,
totalSize: radius * 2 + strokeWidth * 2,
strokeLength: (progress / 100) * (2 * Math.PI * radius),
}),
[radius, strokeWidth, progress]
);
// Handle initial animation
const [offset, setOffset] = useState(circumference);
useEffect(() => {
setOffset(circumference);
const timer = setTimeout(() => {
setOffset(circumference - strokeLength);
}, 100);
return () => clearTimeout(timer);
}, [progress, circumference, strokeLength]);
const progressWithinRange = Math.max(MINIMUM_VALUE, Math.min(progress, MAXIMUM_VALUE));
let fillColor;
if (progressWithinRange < 50) {
fillColor = theme.palette.success.main;
} else if (progressWithinRange < 80) {
fillColor = theme.palette.warning.lowContrast;
} else {
fillColor = theme.palette.error.lowContrast;
}
if (isLoading) {
return (
<Stack
className="radial-chart"
width={radius}
height={radius}
alignItems="center"
justifyContent="center"
>
<CircularProgress color="accent" />
</Stack>
);
}
return (
<Box
className="radial-chart"
width={radius}
height={radius}
sx={{ backgroundColor: theme.palette.primary.main, borderRadius: "50%" }}
>
<svg
viewBox={`0 0 ${totalSize} ${totalSize}`}
width={radius}
height={radius}
>
<circle
className="radial-chart-base"
stroke={theme.palette.secondary.light}
strokeWidth={strokeWidth}
fill="none"
cx={totalSize / 2} // Center the circle
cy={totalSize / 2} // Center the circle
r={radius}
/>
<circle
className="radial-chart-progress"
stroke={fillColor}
strokeWidth={strokeWidth}
strokeDasharray={`${circumference} ${circumference}`}
strokeDashoffset={offset}
strokeLinecap="round"
fill="none"
cx={totalSize / 2}
cy={totalSize / 2}
r={radius}
/>
</svg>
<Typography
className="radial-chart-text"
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
...theme.typography.h2,
fill: theme.typography.h2.color,
}}
>
{`${progressWithinRange.toFixed(precision)}${unit}`}
</Typography>
</Box>
);
};
export default CustomGauge;
CustomGauge.propTypes = {
isLoading: PropTypes.bool,
progress: PropTypes.number,
radius: PropTypes.number,
strokeWidth: PropTypes.number,
precision: PropTypes.number,
unit: PropTypes.string,
};
@@ -1,181 +0,0 @@
// Components
import { Stack, Box, Tooltip, Typography } from "@mui/material";
// Utils
import { useTheme } from "@emotion/react";
import { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { formatDateWithTz } from "../../../Utils/timeUtils";
import { useSelector } from "react-redux";
const PlaceholderCheck = ({ daysToShow }) => {
const theme = useTheme();
return (
<Box
width={`calc(30vw / ${daysToShow})`}
height="100%"
backgroundColor={theme.palette.primary.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
}}
/>
);
};
PlaceholderCheck.propTypes = {
daysToShow: PropTypes.number,
};
const Check = ({ check, daysToShow }) => {
const [animate, setAnimate] = useState(false);
const theme = useTheme();
useEffect(() => {
setAnimate(true);
}, []);
const uiTimezone = useSelector((state) => state.ui.timezone);
return (
<Tooltip
title={
<>
<Typography>
{formatDateWithTz(check._id, "ddd, MMMM D, YYYY", uiTimezone)}
</Typography>
<Box mt={theme.spacing(2)}>
<Stack
display="inline-flex"
direction="row"
justifyContent="space-between"
gap={theme.spacing(4)}
>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
Uptime percentage
</Typography>
<Typography component="span">
{check.upPercentage.toFixed(2)}
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{" "}
%
</Typography>
</Typography>
</Stack>
</Box>
</>
}
placement="top"
key={`check-${check?._id}`}
slotProps={{
popper: {
className: "bar-tooltip",
modifiers: [
{
name: "offset",
options: {
offset: [0, -10],
},
},
],
sx: {
"& .MuiTooltip-tooltip": {
backgroundColor: theme.palette.secondary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shape.boxShadow,
px: theme.spacing(4),
py: theme.spacing(3),
},
"& .MuiTooltip-tooltip p": {
/* TODO Font size should point to theme */
fontSize: 12,
color: theme.palette.secondary.contrastText,
fontWeight: 500,
},
"& .MuiTooltip-tooltip span": {
/* TODO Font size should point to theme */
fontSize: 11,
color: theme.palette.secondary.contrastText,
fontWeight: 600,
},
},
},
}}
>
<Box
position="relative"
width={`calc(30vw / ${daysToShow})`}
height="100%"
backgroundColor={theme.palette.error.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
}}
>
<Box
position="absolute"
bottom={0}
width="100%"
height={`${animate ? check.upPercentage : 0}%`}
backgroundColor={theme.palette.success.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>
</Box>
</Tooltip>
);
};
Check.propTypes = {
check: PropTypes.object,
daysToShow: PropTypes.number,
};
const DePINStatusPageBarChart = ({ checks = [], daysToShow = 30 }) => {
if (checks.length !== daysToShow) {
const placeholders = Array(daysToShow - checks.length).fill("placeholder");
checks = [...checks, ...placeholders];
}
return (
<Stack
direction="row"
justifyContent="space-between"
width="100%"
flexWrap="nowrap"
height="50px"
>
{checks.map((check) => {
if (check === "placeholder") {
return (
<PlaceholderCheck
key={Math.random()}
daysToShow={daysToShow}
/>
);
}
return (
<Check
key={Math.random()}
check={check}
daysToShow={daysToShow}
/>
);
})}
</Stack>
);
};
DePINStatusPageBarChart.propTypes = {
checks: PropTypes.array,
daysToShow: PropTypes.number,
};
export default DePINStatusPageBarChart;
@@ -1,42 +0,0 @@
import { Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import IconBox from "../../IconBox";
import PropTypes from "prop-types";
const LegendBox = ({ children, icon, header, sx }) => {
const theme = useTheme();
return (
<Stack
direction="column"
gap={theme.spacing(4)}
borderRadius={theme.spacing(8)}
sx={{
...sx,
"& label": { pl: theme.spacing(6) },
borderLeftStyle: "solid",
borderLeftWidth: 1,
borderLeftColor: theme.palette.primary.lowContrast,
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(8),
background: `linear-gradient(325deg, ${theme.palette.tertiary.main} 20%, ${theme.palette.primary.main} 45%)`,
}}
>
<Stack
direction="row"
gap={theme.spacing(6)}
>
<IconBox>{icon}</IconBox>
<Typography component="h2">{header}</Typography>
</Stack>
{children}
</Stack>
);
};
LegendBox.propTypes = {
children: PropTypes.node,
icon: PropTypes.node,
header: PropTypes.string,
};
export default LegendBox;
Whitespace-only changes.
@@ -1,222 +0,0 @@
import PropTypes from "prop-types";
import {
AreaChart,
Area,
XAxis,
Tooltip,
CartesianGrid,
ResponsiveContainer,
Text,
} from "recharts";
import { Box, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useMemo, useState } from "react";
import { useSelector } from "react-redux";
import { formatDateWithTz } from "../../../Utils/timeUtils";
import {
tooltipDateFormatLookup,
tickDateFormatLookup,
} from "../Utils/chartUtilFunctions";
import "./index.css";
const CustomToolTip = ({ active, payload, label, dateRange }) => {
const format = tooltipDateFormatLookup(dateRange);
const uiTimezone = useSelector((state) => state.ui.timezone);
const theme = useTheme();
if (active && payload && payload.length) {
const responseTime = payload[0]?.payload?.originalAvgResponseTime
? payload[0]?.payload?.originalAvgResponseTime
: (payload[0]?.payload?.avgResponseTime ?? 0);
return (
<Box
className="area-tooltip"
sx={{
backgroundColor: theme.palette.primary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
py: theme.spacing(2),
px: theme.spacing(4),
}}
>
<Typography
sx={{
color: theme.palette.primary.contrastTextTertiary,
fontSize: 12,
fontWeight: 500,
}}
>
{formatDateWithTz(label, format, uiTimezone)}
</Typography>
<Box mt={theme.spacing(1)}>
<Box
display="inline-block"
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={theme.palette.primary.main}
sx={{ borderRadius: "50%" }}
/>
<Stack
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.spacing(3)}
sx={{
"& span": {
color: theme.palette.primary.contrastTextTertiary,
fontSize: 11,
fontWeight: 500,
},
}}
>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
Response time:
</Typography>
<Typography
ml={theme.spacing(4)}
component="span"
>
{Math.floor(responseTime)}
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{" "}
ms
</Typography>
</Typography>
</Stack>
</Box>
{/* Display original value */}
</Box>
);
}
return null;
};
CustomToolTip.propTypes = {
active: PropTypes.bool,
payload: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.number,
payload: PropTypes.shape({
_id: PropTypes.string,
avgResponseTime: PropTypes.number,
originalAvgResponseTime: PropTypes.number,
}),
})
),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
dateRange: PropTypes.string,
};
const CustomTick = ({ x, y, payload, dateRange }) => {
const format = tickDateFormatLookup(dateRange);
const theme = useTheme();
const uiTimezone = useSelector((state) => state.ui.timezone);
return (
<Text
x={x}
y={y + 10}
textAnchor="middle"
fill={theme.palette.primary.contrastTextTertiary}
fontSize={11}
fontWeight={400}
>
{formatDateWithTz(payload?.value, format, uiTimezone)}
</Text>
);
};
CustomTick.propTypes = {
x: PropTypes.number,
y: PropTypes.number,
payload: PropTypes.object,
index: PropTypes.number,
dateRange: PropTypes.string,
};
const MonitorDetailsAreaChart = ({ checks, dateRange }) => {
const theme = useTheme();
const memoizedChecks = useMemo(() => checks, [checks[0]]);
const [isHovered, setIsHovered] = useState(false);
return (
<ResponsiveContainer
width="100%"
minWidth={25}
height={220}
>
<AreaChart
width="100%"
height="100%"
data={memoizedChecks}
margin={{
top: 10,
right: 0,
left: 0,
bottom: 0,
}}
onMouseMove={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<CartesianGrid
stroke={theme.palette.primary.lowContrast}
strokeWidth={1}
strokeOpacity={1}
fill="transparent"
vertical={false}
/>
<defs>
<linearGradient
id="colorUv"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor={theme.palette.accent.main}
stopOpacity={0.8}
/>
<stop
offset="100%"
stopColor={theme.palette.accent.light}
stopOpacity={0}
/>
</linearGradient>
</defs>
<XAxis
stroke={theme.palette.primary.lowContrast}
dataKey="_id"
tick={<CustomTick dateRange={dateRange} />}
axisLine={false}
tickLine={false}
height={20}
/>
<Tooltip
cursor={{ stroke: theme.palette.primary.lowContrast }}
content={<CustomToolTip dateRange={dateRange} />}
wrapperStyle={{ pointerEvents: "none" }}
/>
<Area
type="monotone"
dataKey="avgResponseTime"
stroke={theme.palette.accent.main} // CAIO_REVIEW
fill="url(#colorUv)"
strokeWidth={isHovered ? 2.5 : 1.5}
activeDot={{ stroke: theme.palette.accent.main, r: 5 }} // CAIO_REVIEW
/>
</AreaChart>
</ResponsiveContainer>
);
};
MonitorDetailsAreaChart.propTypes = {
checks: PropTypes.array,
dateRange: PropTypes.string,
};
export default MonitorDetailsAreaChart;
@@ -1,211 +0,0 @@
import { useTheme } from "@emotion/react";
import { Box, Stack, Tooltip, Typography } from "@mui/material";
import { formatDateWithTz } from "../../../Utils/timeUtils";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import PropTypes from "prop-types";
/**
* A customizable Bar component that renders a colored bar with optional children.
* @component
*
* @param {string} width The width of the bar (e.g., "100px").
* @param {string} height The height of the bar (e.g., "50px").
* @param {string} backgroundColor The background color of the bar (e.g., "#FF5733").
* @param {string} [borderRadius] Optional border radius for the bar (e.g., "8px").
* @param {node} children The content to be rendered inside the bar.
* @returns {JSX.Element} The Bar component.
*/
const Bar = ({ width, height, backgroundColor, borderRadius, children }) => {
const theme = useTheme();
return (
<Box
position="relative"
width={width}
height={height}
backgroundColor={backgroundColor}
sx={{
borderRadius: borderRadius || theme.spacing(1.5),
}}
>
{children}
</Box>
);
};
Bar.propTypes = {
width: PropTypes.string.isRequired,
height: PropTypes.string.isRequired,
backgroundColor: PropTypes.string.isRequired,
borderRadius: PropTypes.string,
children: PropTypes.node,
};
/* TODO add prop validation and jsdocs */
const StatusPageBarChart = ({ checks = [] }) => {
const theme = useTheme();
const [animate, setAnimate] = useState(false);
const uiTimezone = useSelector((state) => state.ui.timezone);
const barWidth = {
xs: "calc(60% / 25)",
xl: "calc(40% / 25)",
};
useEffect(() => {
setAnimate(true);
}, []);
// set responseTime to average if there's only one check
if (checks.length === 1) {
checks[0] = { ...checks[0], responseTime: 50 };
}
if (checks.length !== 25) {
const placeholders = Array(25 - checks.length).fill("placeholder");
checks = [...checks, ...placeholders];
}
return (
<Stack
direction="row"
justifyContent="space-between"
width="100%"
flexWrap="nowrap"
height="50px"
onClick={(event) => event.stopPropagation()}
sx={{
cursor: "default",
}}
>
{checks.map((check, index) =>
check === "placeholder" ? (
/* TODO what is the purpose of this box? */
// CAIO_REVIEW the purpose of this box is to make sure there are always at least 25 bars
// even if there are less than 25 checks
<Bar
key={`${check}-${index}`}
width={barWidth}
height="100%"
backgroundColor={theme.palette.primary.lowContrast}
/>
) : (
<Tooltip
title={
<>
<Typography>
{formatDateWithTz(
check.createdAt,
"ddd, MMMM D, YYYY, HH:mm A",
uiTimezone
)}
</Typography>
<Box mt={theme.spacing(2)}>
<Box
display="inline-block"
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
sx={{ borderRadius: "50%" }}
/>
<Stack
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.spacing(2)}
gap={theme.spacing(12)}
>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
Response Time
</Typography>
<Typography component="span">
{check.originalResponseTime}
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{" "}
ms
</Typography>
</Typography>
</Stack>
</Box>
</>
}
placement="top"
key={`check-${check?._id}`}
slotProps={{
popper: {
className: "bar-tooltip",
modifiers: [
{
name: "offset",
options: {
offset: [0, -10],
},
},
],
sx: {
"& .MuiTooltip-tooltip": {
backgroundColor: theme.palette.secondary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shape.boxShadow,
px: theme.spacing(4),
py: theme.spacing(3),
},
"& .MuiTooltip-tooltip p": {
/* TODO Font size should point to theme */
fontSize: 12,
color: theme.palette.secondary.contrastText,
fontWeight: 500,
},
"& .MuiTooltip-tooltip span": {
/* TODO Font size should point to theme */
fontSize: 11,
color: theme.palette.secondary.contrastText,
fontWeight: 600,
},
},
},
}}
>
<Bar
width={barWidth}
height="100%"
backgroundColor={theme.palette.primary.lowContrast}
>
<Box
position="absolute"
bottom={0}
width="100%"
height={`${animate ? check.responseTime : 0}%`}
backgroundColor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
sx={{
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>
</Bar>
</Tooltip>
)
)}
</Stack>
);
};
export default StatusPageBarChart;
@@ -1,27 +0,0 @@
export const tooltipDateFormatLookup = (dateRange) => {
const dateFormatLookup = {
recent: "ddd. MMMM D, YYYY, hh:mm A",
day: "ddd. MMMM D, YYYY, hh:mm A",
week: "ddd. MMMM D, YYYY, hh:mm A",
month: "ddd. MMMM D, YYYY",
};
const format = dateFormatLookup[dateRange];
if (format === undefined) {
return "";
}
return format;
};
export const tickDateFormatLookup = (dateRange) => {
const tickFormatLookup = {
recent: "h:mm A",
day: "h:mm A",
week: "MM/D, h:mm A",
month: "ddd. M/D",
};
const format = tickFormatLookup[dateRange];
if (format === undefined) {
return "";
}
return format;
};
@@ -1,337 +0,0 @@
import PropTypes from "prop-types";
import { useSelector } from "react-redux";
import { useTheme } from "@mui/material";
import { Text } from "recharts";
import { formatDateWithTz } from "../../../Utils/timeUtils";
import { Box, Stack, Typography } from "@mui/material";
import { tickDateFormatLookup, tooltipDateFormatLookup } from "./chartUtilFunctions";
/**
* Custom tick component for rendering time with timezone.
*
* @param {Object} props - The properties object.
* @param {number} props.x - The x-coordinate for the tick.
* @param {number} props.y - The y-coordinate for the tick.
* @param {Object} props.payload - The payload object containing tick data.
* @param {number} props.index - The index of the tick.
* @returns {JSX.Element} The rendered tick component.
*/
export const TzTick = ({ x, y, payload, index, dateRange }) => {
const theme = useTheme();
const uiTimezone = useSelector((state) => state.ui.timezone);
const format = tickDateFormatLookup(dateRange);
return (
<Text
x={x}
y={y + 10}
textAnchor="middle"
fill={theme.palette.primary.contrastTextTertiary}
fontSize={11}
fontWeight={400}
>
{formatDateWithTz(payload?.value, format, uiTimezone)}
</Text>
);
};
TzTick.propTypes = {
x: PropTypes.number,
y: PropTypes.number,
payload: PropTypes.object,
index: PropTypes.number,
dateRange: PropTypes.string,
};
/**
* Custom tick component for rendering percentage values.
*
* @param {Object} props - The properties object.
* @param {number} props.x - The x-coordinate for the tick.
* @param {number} props.y - The y-coordinate for the tick.
* @param {Object} props.payload - The payload object containing tick data.
* @param {number} props.index - The index of the tick.
* @returns {JSX.Element|null} The rendered tick component or null for the first tick.
*/
export const PercentTick = ({ x, y, payload, index }) => {
const theme = useTheme();
if (index === 0) return null;
return (
<Text
x={x - 20}
y={y}
textAnchor="middle"
fill={theme.palette.primary.contrastTextTertiary}
fontSize={11}
fontWeight={400}
>
{`${(payload?.value * 100).toFixed()}%`}
</Text>
);
};
PercentTick.propTypes = {
x: PropTypes.number,
y: PropTypes.number,
payload: PropTypes.object,
index: PropTypes.number,
};
/**
* Converts a decimal value to a formatted percentage string.
*
* @param {number} value - The decimal value to convert (e.g., 0.75)
* @returns {string} Formatted percentage string (e.g., "75.00%") or original input if not a number
*
* @example
* getFormattedPercentage(0.7543) // Returns "75.43%"
* getFormattedPercentage(1) // Returns "100.00%"
* getFormattedPercentage("test") // Returns "test"
*/
const getFormattedPercentage = (value) => {
if (typeof value !== "number") return value;
return `${(value * 100).toFixed(2)}%`;
};
/**
* Custom tick component for rendering network bytes per second.
*
* @param {Object} props - The properties object.
* @param {number} props.x - The x-coordinate for the tick.
* @param {number} props.y - The y-coordinate for the tick.
* @param {Object} props.payload - The payload object containing tick data.
* @param {number} props.index - The index of the tick.
* @returns {JSX.Element|null} The rendered tick component or null for the first tick.
*/
export const NetworkTick = ({ x, y, payload, index, formatter }) => {
const theme = useTheme();
if (index === 0) return null;
if (formatter === undefined) {
formatter = (value, space = false) => {
if (typeof value !== "number") return value;
// need to add space between value and unit
return `${(value / 1024).toFixed(1)}${space ? " " : ""}Kbps`;
};
}
return (
<Text
x={x - 20}
y={y}
textAnchor="middle"
fill={theme.palette.primary.contrastTextTertiary}
fontSize={11}
fontWeight={400}
>
{formatter(payload?.value, true)}
</Text>
);
};
NetworkTick.propTypes = {
x: PropTypes.number,
y: PropTypes.number,
payload: PropTypes.object,
index: PropTypes.number,
formatter: PropTypes.func,
};
/**
* Custom tooltip component for displaying infrastructure data.
*
* @param {Object} props - The properties object.
* @param {boolean} props.active - Indicates if the tooltip is active.
* @param {Array} props.payload - The payload array containing tooltip data.
* @param {string} props.label - The label for the tooltip.
* @param {string} props.yKey - The key for the y-axis data.
* @param {string} props.yLabel - The label for the y-axis data.
* @param {string} props.dotColor - The color of the dot in the tooltip.
* @returns {JSX.Element|null} The rendered tooltip component or null if inactive.
*/
export const InfrastructureTooltip = ({
active,
payload,
label,
yKey,
yIdx = -1,
yLabel,
dotColor,
dateRange,
formatter = getFormattedPercentage,
}) => {
const uiTimezone = useSelector((state) => state.ui.timezone);
const theme = useTheme();
const format = tooltipDateFormatLookup(dateRange);
if (active && payload && payload.length) {
const [hardwareType, metric] = yKey.split(".");
return (
<Box
className="area-tooltip"
sx={{
backgroundColor: theme.palette.primary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
py: theme.spacing(2),
px: theme.spacing(4),
}}
>
<Typography
sx={{
color: theme.palette.primary.contrastTextTertiary,
fontSize: 12,
fontWeight: 500,
}}
>
{formatDateWithTz(label, format, uiTimezone)}
</Typography>
<Box mt={theme.spacing(1)}>
<Box
display="inline-block"
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={dotColor}
sx={{ borderRadius: "50%" }}
/>
<Stack
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.spacing(3)}
sx={{
"& span": {
color: theme.palette.primary.contrastTextTertiary,
fontSize: 11,
fontWeight: 500,
},
}}
>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{yIdx >= 0
? `${yLabel} ${formatter(payload[0].payload[hardwareType][yIdx][metric])}`
: `${yLabel} ${formatter(payload[0].payload[yKey])}`}
</Typography>
</Stack>
</Box>
{/* Display original value */}
</Box>
);
}
return null;
};
InfrastructureTooltip.propTypes = {
active: PropTypes.bool,
payload: PropTypes.array,
label: PropTypes.oneOfType([
PropTypes.instanceOf(Date),
PropTypes.string,
PropTypes.number,
]),
yKey: PropTypes.string,
yIdx: PropTypes.number,
yLabel: PropTypes.string,
dotColor: PropTypes.string,
dateRange: PropTypes.string,
};
export const TemperatureTooltip = ({
active,
payload,
label,
keys,
dotColor,
dateRange,
}) => {
const uiTimezone = useSelector((state) => state.ui.timezone);
const theme = useTheme();
const format = tooltipDateFormatLookup(dateRange);
const formatCoreKey = (key) => {
return key.replace(/^core(\d+)$/, "Core $1");
};
if (active && payload && payload.length) {
return (
<Box
className="area-tooltip"
sx={{
backgroundColor: theme.palette.primary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
py: theme.spacing(2),
px: theme.spacing(4),
}}
>
<Typography
sx={{
color: theme.palette.primary.contrastTextTertiary,
fontSize: 12,
fontWeight: 500,
}}
>
{formatDateWithTz(label, format, uiTimezone)}
</Typography>
<Stack direction="column">
{keys.map((key) => {
return (
<Stack
key={key}
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.spacing(3)}
sx={{
"& span": {
color: theme.palette.primary.contrastTextTertiary,
fontSize: 11,
fontWeight: 500,
},
}}
>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(2)}
>
<Box
display="inline-block"
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={dotColor}
sx={{ borderRadius: "50%" }}
/>
<Typography
component="span"
sx={{ opacity: 0.8 }}
>
{`${formatCoreKey(key)}: ${payload[0].payload[key]} °C`}
</Typography>
</Stack>
<Typography component="span"></Typography>
</Stack>
);
})}
</Stack>
</Box>
);
}
return null;
};
TemperatureTooltip.propTypes = {
active: PropTypes.bool,
keys: PropTypes.array,
payload: PropTypes.array,
label: PropTypes.oneOfType([
PropTypes.instanceOf(Date),
PropTypes.string,
PropTypes.number,
]),
dotColor: PropTypes.string,
dateRange: PropTypes.string,
};
@@ -1,47 +0,0 @@
/**
* Creates an SVG gradient definition for use in charts
* @param {Object} params - The gradient parameters
* @param {string} [params.id="colorUv"] - Unique identifier for the gradient
* @param {string} params.startColor - Starting color of the gradient (hex, rgb, or color name)
* @param {string} params.endColor - Ending color of the gradient (hex, rgb, or color name)
* @param {number} [params.startOpacity=0.8] - Starting opacity (0-1)
* @param {number} [params.endOpacity=0] - Ending opacity (0-1)
* @param {('vertical'|'horizontal')} [params.direction="vertical"] - Direction of the gradient
* @returns {JSX.Element} SVG gradient definition element
* @example
* createCustomGradient({
* startColor: "#1976D2",
* endColor: "#42A5F5",
* direction: "horizontal"
* })
*/
export const createGradient = ({
id,
startColor,
endColor,
startOpacity = 0.8,
endOpacity = 0,
direction = "vertical", // or "horizontal"
}) => (
<defs>
<linearGradient
id={id}
x1={direction === "vertical" ? "0" : "0"}
y1={direction === "vertical" ? "0" : "0"}
x2={direction === "vertical" ? "0" : "1"}
y2={direction === "vertical" ? "1" : "0"}
>
<stop
offset="0%"
stopColor={startColor}
stopOpacity={startOpacity}
/>
<stop
offset="100%"
stopColor={endColor}
stopOpacity={endOpacity}
/>
</linearGradient>
</defs>
);
-74
View File
@@ -1,74 +0,0 @@
import "./check.css";
import PropTypes from "prop-types";
import CheckGrey from "../../assets/icons/check.svg?react";
import CheckOutlined from "../../assets/icons/check-outlined.svg?react";
import { Box, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
/**
* `Check` is a functional React component that displays a check icon and a label.
*
* @component
* @param {Object} props - The properties that define the `Check` component.
* @param {string} props.text - The text to be displayed as the label next to the check icon.
* @param {'info' | 'error' | 'success'} [props.variant='info'] - The variant of the check component, affecting its styling.
* @param {boolean} [props.outlined] - Whether the check icon should be outlined or not.
*
* @example
* // To use this component, import it and use it in your JSX like this:
* <Check text="Your Text Here" />
*
* @returns {React.Element} The `Check` component with a check icon and a label, defined by the `text` prop.
*/
const Check = ({ text, noHighlightText, variant = "info", outlined = false }) => {
const theme = useTheme();
const colors = {
success: theme.palette.success.main,
error: theme.palette.error.main,
info: theme.palette.info.border,
};
return (
<Stack
direction="row"
className="check"
gap={outlined ? theme.spacing(6) : theme.spacing(4)}
alignItems="center"
>
{outlined ? (
<CheckOutlined alt="check" />
) : (
<Box
lineHeight={0}
sx={{
"& svg > path": { fill: colors[variant] },
}}
>
<CheckGrey alt="form checks" />
</Box>
)}
<Typography
component="span"
sx={{
color:
variant === "info"
? theme.palette.primary.contrastTextSecondary
: colors[variant],
opacity: 0.9,
fontWeight: 450,
}}
>
{noHighlightText && <Typography component="span">{noHighlightText}</Typography>}{" "}
{text}
</Typography>
</Stack>
);
};
Check.propTypes = {
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
noHighlightText: PropTypes.string,
variant: PropTypes.oneOf(["info", "error", "success"]),
outlined: PropTypes.bool,
};
export default Check;
Whitespace-only changes.
@@ -1,29 +0,0 @@
import { Box } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
const CircularCount = ({ count }) => {
const theme = useTheme();
return (
<Box
component="span"
color={theme.palette.tertiary.contrastText}
border={2}
borderColor={theme.palette.accent.main}
backgroundColor={theme.palette.tertiary.main}
sx={{
padding: ".25em .75em",
borderRadius: "50rem",
fontSize: "12px",
fontWeight: 500,
}}
>
{count}
</Box>
);
};
CircularCount.propTypes = {
count: PropTypes.number,
};
export default CircularCount;
-213
View File
@@ -1,213 +0,0 @@
import { useState } from "react";
import { styled, alpha } from "@mui/material/styles";
import Box from "@mui/material/Box";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import Button from "@mui/material/Button";
import IconButton from "@mui/material/IconButton";
import Container from "@mui/material/Container";
import MenuItem from "@mui/material/MenuItem";
import Drawer from "@mui/material/Drawer";
import MenuIcon from "@mui/icons-material/Menu";
import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
import ThemeSwitch from "../ThemeSwitch";
import { useTheme } from "@mui/material/styles";
import { useSelector } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom";
const StyledToolbar = styled(Toolbar)(({ theme, mode }) => ({
display: "flex",
alignItems: "center",
justifyContent: "space-between",
flexShrink: 0,
borderRadius: `calc(${theme.shape.borderRadius}px + 4px)`,
backdropFilter: "blur(24px)",
border: "1px solid",
borderColor:
mode === "light"
? alpha(theme.palette.common.black, 0.1)
: alpha(theme.palette.common.white, 0.1),
backgroundColor:
mode === "light"
? alpha(theme.palette.common.white, 0.4)
: alpha(theme.palette.common.black, 0.4),
boxShadow: theme.shadows[3],
padding: "8px 12px",
}));
const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
fontSize: "1.1rem",
margin: theme.spacing(4, 2),
}));
const AppAppBar = () => {
const [open, setOpen] = useState(false);
const theme = useTheme();
const mode = useSelector((state) => state.ui.mode);
const location = useLocation();
const navigate = useNavigate();
const logoSrc =
mode === "light" ? "/images/prism-black.png" : "/images/prism-white.png";
const toggleDrawer = (newOpen) => () => {
setOpen(newOpen);
};
const handleScroll = (id) => {
if (location.pathname === "/") {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({ behavior: "smooth" });
}
} else {
navigate(`/#${id}`);
}
};
return (
<AppBar
position="fixed"
sx={{
boxShadow: 0,
bgcolor: "transparent",
backgroundImage: "none",
border: "none",
mt: "calc(var(--template-frame-height, 0px) + 28px)",
}}
>
<Container maxWidth="lg">
<StyledToolbar
variant="dense"
disableGutters
mode={mode}
>
<Box sx={{ flexGrow: 1, display: "flex", alignItems: "center", px: 0 }}>
<img
src={logoSrc}
alt="Prism Logo"
style={{
height: "auto",
width: "auto",
marginRight: "10px",
maxHeight: "32px",
}}
/>
<Box sx={{ display: { xs: "none", md: "flex" } }}>
<Button
variant="text"
color="info"
size="large"
onClick={() => handleScroll("features")}
>
Features
</Button>
<Button
variant="text"
color="info"
size="large"
onClick={() => handleScroll("highlights")}
>
Highlights
</Button>
<Button
variant="text"
color="info"
size="large"
onClick={() => handleScroll("faq")}
>
FAQ
</Button>
<Button
variant="text"
color="info"
size="large"
href="https://uprock.com/blog"
>
Blog
</Button>
</Box>
</Box>
<Box
sx={{
display: { xs: "none", md: "flex" },
gap: 1,
alignItems: "center",
}}
>
{/* <Button color="primary" variant="text" size="small">
Sign in
</Button>
<Button color="primary" variant="contained" size="small">
Sign up
</Button> */}
</Box>
<Box
sx={{
display: { xs: "flex", md: "none" },
gap: 1,
}}
>
<IconButton
aria-label="Menu button"
onClick={toggleDrawer(true)}
>
<MenuIcon sx={{ color: theme.palette.text.primary }} />
</IconButton>
<Drawer
anchor="top"
open={open}
onClose={toggleDrawer(false)}
PaperProps={{
sx: {
top: 0,
marginTop: 0,
borderRadius: 0,
backgroundColor: theme.palette.background.paper,
},
}}
>
<Box sx={{ p: 4, backgroundColor: theme.palette.background.main }}>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
}}
>
<IconButton onClick={toggleDrawer(false)}>
<CloseRoundedIcon sx={{ color: theme.palette.text.primary }} />
</IconButton>
</Box>
<StyledMenuItem>Features</StyledMenuItem>
<StyledMenuItem>Testimonials</StyledMenuItem>
<StyledMenuItem>Highlights</StyledMenuItem>
<StyledMenuItem>FAQ</StyledMenuItem>
<StyledMenuItem
component="a"
href="https://uprock.com/blog"
>
Blog
</StyledMenuItem>
{/* <MenuItem>
<Button color="primary" variant="contained" fullWidth>
Sign up
</Button>
</MenuItem>
<MenuItem>
<Button color="primary" variant="outlined" fullWidth>
Sign in
</Button>
</MenuItem> */}
</Box>
</Drawer>
</Box>
<ThemeSwitch />
</StyledToolbar>
</Container>
</AppBar>
);
};
export default AppAppBar;
-255
View File
@@ -1,255 +0,0 @@
import * as React from "react";
import Box from "@mui/material/Box";
import Container from "@mui/material/Container";
import IconButton from "@mui/material/IconButton";
import Link from "@mui/material/Link";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { FaFacebook, FaLinkedin, FaGithub, FaTwitter, FaEnvelope } from "react-icons/fa";
function Copyright() {
return (
<Typography sx={{ color: "text.secondary", mt: 1 }}>
{"Copyright © "}
<Link
color="text.secondary"
href="https://prism.uprock.com/"
>
UpRock
</Link>
&nbsp;
{new Date().getFullYear()}
</Typography>
);
}
export default function Footer() {
return (
<Container
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: { xs: 4, sm: 8 },
py: { xs: 24, sm: 24 },
px: { xs: 12, sm: 12 },
textAlign: { sm: "center", md: "left" },
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
pt: { xs: 4, sm: 8 },
width: "100%",
borderColor: "divider",
}}
>
<div>
<Link
color="text.secondary"
href="https://uprock.com/privacy-policy"
>
Privacy Policy
</Link>
<Typography sx={{ display: "inline", mx: 0.5, opacity: 0.5 }}>
&nbsp;•&nbsp;
</Typography>
<Link
color="text.secondary"
href="https://uprock.com/terms-of-use"
>
Terms of Service
</Link>
<Copyright />
</div>
<Stack
direction="row"
spacing={1}
useFlexGap
sx={{ justifyContent: "left", color: "text.secondary" }}
>
<IconButton
color="inherit"
size="small"
href="mailto:prism@uprock.com?subject=Interested%20in%20UpRock%20Prism"
aria-label="Contact Us"
sx={{ alignSelf: "center" }}
>
<FaEnvelope />
</IconButton>
<IconButton
color="inherit"
size="small"
href="https://facebook.com/uprockcom"
aria-label="Facebook"
sx={{ alignSelf: "center" }}
>
<FaFacebook />
</IconButton>
<IconButton
color="inherit"
size="small"
href="https://x.com/uprockcom"
aria-label="X"
sx={{ alignSelf: "center" }}
>
<FaTwitter />
</IconButton>
<IconButton
color="inherit"
size="small"
href="https://www.linkedin.com/company/uprock/"
aria-label="LinkedIn"
sx={{ alignSelf: "center" }}
>
<FaLinkedin />
</IconButton>
<IconButton
color="inherit"
size="small"
href="https://github.com/uprockcom"
aria-label="GitHub"
sx={{ alignSelf: "center" }}
>
<FaGithub />
</IconButton>
</Stack>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
mt: 4,
}}
>
<Typography
variant="h2"
sx={{ color: "text.secondary" }}
>
Made with ❤️ by&nbsp;
<Link
href="https://uprock.com"
color="inherit"
sx={{ mx: 0.5 }}
>
UpRock&nbsp;
</Link>
&&nbsp;
<Link
href="https://bluewavelabs.ca"
color="inherit"
sx={{ mx: 0.5 }}
>
Bluewave Labs
</Link>
</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
mt: 2,
}}
>
<Typography
variant="h2"
sx={{ color: "text.secondary", mr: 1 }}
>
Built on&nbsp;
</Typography>
<svg
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 397.7 311.7"
xmlSpace="preserve"
width="15"
height="15"
>
<style type="text/css">
{`.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
.st2{fill:url(#SVGID_3_);}`}
</style>
<linearGradient
id="SVGID_1_"
gradientUnits="userSpaceOnUse"
x1="360.8791"
y1="351.4553"
x2="141.213"
y2="-69.2936"
gradientTransform="matrix(1 0 0 -1 0 314)"
>
<stop
offset="0"
style={{ stopColor: "rgb(0, 255, 163)" }}
/>
<stop
offset="1"
style={{ stopColor: "rgb(220, 31, 255)" }}
/>
</linearGradient>
<path
className="st0"
d="M64.6,237.9c2.4-2.4,5.7-3.8,9.2-3.8h317.4c5.8,0,8.7,7,4.6,11.1l-62.7,62.7c-2.4,2.4-5.7,3.8-9.2,3.8H6.5 c-5.8,0-8.7-7-4.6-11.1L64.6,237.9z"
/>
<linearGradient
id="SVGID_2_"
gradientUnits="userSpaceOnUse"
x1="264.8291"
y1="401.6014"
x2="45.163"
y2="-19.1475"
gradientTransform="matrix(1 0 0 -1 0 314)"
>
<stop
offset="0"
style={{ stopColor: "rgb(0, 255, 163)" }}
/>
<stop
offset="1"
style={{ stopColor: "rgb(220, 31, 255)" }}
/>
</linearGradient>
<path
className="st1"
d="M64.6,3.8C67.1,1.4,70.4,0,73.8,0h317.4c5.8,0,8.7,7,4.6,11.1l-62.7,62.7c-2.4,2.4-5.7,3.8-9.2,3.8H6.5 c-5.8,0-8.7-7-4.6-11.1L64.6,3.8z"
/>
<linearGradient
id="SVGID_3_"
gradientUnits="userSpaceOnUse"
x1="312.5484"
y1="376.688"
x2="92.8822"
y2="-44.061"
gradientTransform="matrix(1 0 0 -1 0 314)"
>
<stop
offset="0"
style={{ stopColor: "rgb(0, 255, 163)" }}
/>
<stop
offset="1"
style={{ stopColor: "rgb(220, 31, 255)" }}
/>
</linearGradient>
<path
className="st2"
d="M333.1,120.1c-2.4-2.4-5.7-3.8-9.2-3.8H6.5c-5.8,0-8.7,7-4.6,11.1l62.7,62.7c2.4,2.4,5.7,3.8,9.2,3.8h317.4 c5.8,0,8.7-7,4.6-11.1L333.1,120.1z"
/>
</svg>
<Typography
variant="h2"
sx={{ color: "text.secondary", ml: 1 }}
>
&nbsp;Solana
</Typography>
</Box>
</Box>
</Container>
);
}
-39
View File
@@ -1,39 +0,0 @@
import { Stack, styled } from "@mui/material";
const ConfigBox = styled(Stack)(({ theme }) => ({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
backgroundColor: theme.palette.primary.main,
border: 1,
borderStyle: "solid",
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.spacing(2),
"& > *": {
paddingTop: theme.spacing(15),
paddingBottom: theme.spacing(15),
},
"& > div:first-of-type": {
flex: 0.7,
borderRight: 1,
borderRightStyle: "solid",
borderRightColor: theme.palette.primary.lowContrast,
paddingRight: theme.spacing(15),
paddingLeft: theme.spacing(15),
backgroundColor: theme.palette.tertiary.background,
"& :is(h1, h2):first-of-type": {
fontWeight: 600,
marginBottom: theme.spacing(4),
},
},
"& > div:last-of-type": {
flex: 1,
paddingRight: theme.spacing(20),
paddingLeft: theme.spacing(20),
},
"& h1, & h2": {
color: theme.palette.primary.contrastTextSecondary,
},
}));
export default ConfigBox;
-58
View File
@@ -1,58 +0,0 @@
import { Box, Stack, Typography } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import ConfigBox from "../ConfigBox";
/**
* ConfigRow is a styled container used to layout content in a row format with specific padding, border, and spacing.
* It serves as the wrapper for ConfigBox, with the left section displaying the title and description,
* and the right section displaying the children.
*
* @component
* @example
* return (
* <ConfigBox>
* <div>Left content (Title + Description)</div>
* <div>Right content (Children)</div>
* </ConfigBox>
* );
*/
const ConfigRow = ({ title, description, children }) => {
const theme = useTheme();
return (
<ConfigBox>
<Box>
<Typography
component="h2"
variant="h2"
>
{title}
</Typography>
{description && (
<Typography
variant="body2"
mt={theme.spacing(2)}
>
{description}
</Typography>
)}
</Box>
<Stack
gap={theme.spacing(15)}
mt={theme.spacing(4)}
>
{children}
</Stack>
</ConfigBox>
);
};
ConfigRow.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string,
children: PropTypes.node,
};
export default ConfigRow;
@@ -1,69 +0,0 @@
import { useId } from "react";
import PropTypes from "prop-types";
import { Modal, Stack, Typography } from "@mui/material";
const GenericDialog = ({ title, description, open, onClose, theme, children }) => {
const titleId = useId();
const descriptionId = useId();
const ariaDescribedBy = description?.length > 0 ? descriptionId : "";
return (
<Modal
aria-labelledby={titleId}
aria-describedby={ariaDescribedBy}
open={open}
onClose={onClose}
onClick={(e) => e.stopPropagation()}
>
<Stack
gap={theme.spacing(2)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
minWidth: 400,
bgcolor: theme.palette.primary.main,
border: 1,
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
}}
>
<Typography
id={titleId}
component="h2"
fontSize={16}
color={theme.palette.primary.contrastText}
fontWeight={600}
>
{title}
</Typography>
{description && (
<Typography
id={descriptionId}
color={theme.palette.primary.contrastTextTertiary}
>
{description}
</Typography>
)}
{children}
</Stack>
</Modal>
);
};
GenericDialog.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string,
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired,
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
.isRequired,
};
export { GenericDialog };
-63
View File
@@ -1,63 +0,0 @@
import PropTypes from "prop-types";
import { Button, Stack } from "@mui/material";
import { GenericDialog } from "./genericDialog";
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
const Dialog = ({
title,
description,
open,
onCancel,
confirmationButtonLabel,
onConfirm,
isLoading,
}) => {
const theme = useTheme();
const { t } = useTranslation();
return (
<GenericDialog
title={title}
description={description}
open={open}
onClose={onCancel}
theme={theme}
>
<Stack
direction="row"
gap={theme.spacing(4)}
mt={theme.spacing(12)}
justifyContent="flex-end"
>
<Button
variant="contained"
color="secondary"
onClick={onCancel}
>
{t("cancel", "Cancel")}
</Button>
<Button
variant="contained"
color="error"
loading={isLoading}
onClick={onConfirm}
>
{confirmationButtonLabel}
</Button>
</Stack>
</GenericDialog>
);
};
Dialog.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string,
open: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
confirmationButtonLabel: PropTypes.string.isRequired,
onConfirm: PropTypes.func.isRequired,
isLoading: PropTypes.bool,
};
export default Dialog;
-24
View File
@@ -1,24 +0,0 @@
import PropTypes from "prop-types";
const Dot = ({ color = "gray", size = "4px", style }) => {
return (
<span
style={{
content: '""',
width: size,
height: size,
borderRadius: "50%",
backgroundColor: color,
opacity: 0.8,
...style,
}}
/>
);
};
Dot.propTypes = {
color: PropTypes.string,
size: PropTypes.string,
};
export default Dot;
@@ -1,44 +0,0 @@
import { Button, Stack } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import PropTypes from "prop-types";
const FallbackActionButtons = ({ link, type }) => {
const theme = useTheme();
const navigate = useNavigate();
const { t } = useTranslation();
return (
<Stack
gap={theme.spacing(10)}
alignItems="center"
>
<Button
variant="contained"
color="accent"
sx={{ fontWeight: 700 }}
onClick={() => navigate(link)}
>
{t(`${type}.fallback.actionButton`)}
</Button>
{type === "uptimeMonitor" && (
<Button
variant="contained"
color="accent"
sx={{ alignSelf: "center" }}
onClick={() => navigate("/uptime/bulk-import")}
>
{t("bulkImport.fallbackPage")}
</Button>
)}
</Stack>
);
};
FallbackActionButtons.propTypes = {
title: PropTypes.string.isRequired,
link: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
};
export default FallbackActionButtons;
@@ -1,39 +0,0 @@
import { useTheme } from "@emotion/react";
import Box from "@mui/material/Box";
import Background from "../../assets/Images/background-grid.svg?react";
import OutputAnimation from "../../assets/Animations/output.gif";
import DarkmodeOutput from "../../assets/Animations/darkmodeOutput.gif";
import { useSelector } from "react-redux";
const FallbackBackground = () => {
const theme = useTheme();
const mode = useSelector((state) => state.ui.mode);
return (
<>
<Box
component="img"
src={mode === "light" ? OutputAnimation : DarkmodeOutput}
background="transparent"
alt="Loading animation"
sx={{
zIndex: 1,
border: "none",
borderRadius: theme.spacing(8),
width: "100%",
transform: "scale(0.6667)",
}}
/>
<Box
className="background-pattern-svg"
sx={{
"& svg g g:last-of-type path": {
stroke: theme.palette.primary.lowContrast,
},
}}
>
<Background style={{ width: "100%" }} />
</Box>
</>
);
};
export default FallbackBackground;
@@ -1,35 +0,0 @@
import PropTypes from "prop-types";
import { useTheme } from "@mui/material/styles";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Check from "../Check/Check";
const FallbackCheckList = ({ checks, type }) => {
const theme = useTheme();
return (
<Box
sx={{
display: "flex",
flexWrap: "wrap",
gap: theme.spacing(2),
alignItems: "flex-start",
maxWidth: { xs: "90%", md: "80%", lg: "75%" },
}}
>
{checks?.map((check, index) => (
<Check
text={check}
key={`${type.trim().split(" ")[0]}-${index}`}
outlined={true}
/>
))}
</Box>
);
};
FallbackCheckList.propTypes = {
checks: PropTypes.arrayOf(PropTypes.string).isRequired,
title: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
};
export default FallbackCheckList;
@@ -1,44 +0,0 @@
import { useTheme } from "@emotion/react";
import { Box, Stack } from "@mui/material";
import PropTypes from "prop-types";
const FallbackContainer = ({ children, type }) => {
const theme = useTheme();
return (
<Box
border={1}
borderColor={theme.palette.tertiary.border}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.tertiary.background}
overflow="hidden"
sx={{
display: "flex",
borderStyle: "dashed",
height: "fit-content",
minHeight: "60vh",
width: {
sm: "90%",
md: "70%",
lg: "50%",
xl: "40%",
},
padding: `${theme.spacing(20)} ${theme.spacing(10)}`,
}}
>
<Stack
className={`fallback__${type?.trim().split(" ")[0]}`}
alignItems="center"
gap={theme.spacing(20)}
>
{children}
</Stack>
</Box>
);
};
FallbackContainer.propTypes = {
children: PropTypes.node,
type: PropTypes.string,
};
export default FallbackContainer;
@@ -1,69 +0,0 @@
import Box from "@mui/material/Box";
import { useTheme } from "@mui/material/styles";
import Link from "@mui/material/Link";
import { Link as RouterLink } from "react-router-dom";
import { useTranslation } from "react-i18next";
import Alert from "../Alert";
import PropTypes from "prop-types";
const renderWarningMessage = (t) => {
return (
<>
{t("pageSpeedWarning")}{" "}
<Link
component={RouterLink}
to="/settings"
sx={{
textDecoration: "underline",
color: "inherit",
fontWeight: "inherit",
"&:hover": {
textDecoration: "underline",
},
}}
>
{t("pageSpeedLearnMoreLink")}
</Link>{" "}
{t("pageSpeedAddApiKey")}
</>
);
};
const FallbackPageSpeedWarning = ({ settingsData }) => {
const theme = useTheme();
const { t } = useTranslation();
return (
<Box sx={{ width: "80%", maxWidth: "600px", zIndex: 1 }}>
<Box
sx={{
"& .alert.row-stack": {
backgroundColor: theme.palette.warningSecondary.main,
borderColor: theme.palette.warningSecondary.lowContrast,
"& .MuiTypography-root": {
color: theme.palette.warningSecondary.contrastText,
},
"& .MuiBox-root > svg": {
color: theme.palette.warningSecondary.contrastText,
},
},
}}
>
{settingsData?.pagespeedKeySet === false && (
<Alert
variant="warning"
hasIcon={true}
body={renderWarningMessage(t)}
/>
)}
</Box>
</Box>
);
};
FallbackPageSpeedWarning.propTypes = {
settingsData: PropTypes.shape({
pagespeedKeySet: PropTypes.bool,
}),
};
export default FallbackPageSpeedWarning;
@@ -1,21 +0,0 @@
import { useTheme } from "@mui/material/styles";
import { Typography } from "@mui/material";
import PropTypes from "prop-types";
const FallbackTitle = ({ title }) => {
const theme = useTheme();
return (
<Typography
alignSelf="center"
component="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastText}
>
{title}
</Typography>
);
};
FallbackTitle.propTypes = {
title: PropTypes.string.isRequired,
};
export default FallbackTitle;
-40
View File
@@ -1,40 +0,0 @@
[class*="fallback__"] {
width: fit-content;
margin: auto;
}
[class*="fallback__"] h1.MuiTypography-root {
font-size: var(--env-var-font-size-large);
font-weight: 600;
}
[class*="fallback__"] button.MuiButtonBase-root,
[class*="fallback__"] .check {
width: max-content;
}
[class*="fallback__"] button.MuiButtonBase-root {
min-height: 34px;
}
[class*="fallback__"] .check span.MuiTypography-root,
[class*="fallback__"] button.MuiButtonBase-root {
font-size: var(--env-var-font-size-medium);
}
[class*="fallback__"] .background-pattern-svg {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
z-index: 0;
width: 100%;
max-width: 800px;
height: 100%;
max-height: 800px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
-75
View File
@@ -1,75 +0,0 @@
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { Box, Stack } from "@mui/material";
import "./index.css";
import FallbackTitle from "./FallbackTitle";
import FallbackCheckList from "./FallbackCheckList";
import FallbackActionButtons from "./FallBackActionButtons";
import FallbackBackground from "./FallbackBackground";
import FallbackContainer from "./FallbackContainer";
/**
* Fallback component to display a fallback UI with a title, a list of checks, and a navigation button.
*
* @param {Object} props - The component props.
* @param {string} props.title - The title to be displayed in the fallback UI.
* @param {string} props.type - The type of the fallback (e.g., "pageSpeed", "notifications").
* @param {Array<string>} props.checks - An array of strings representing the checks to display.
* @param {string} [props.link="/"] - The link to navigate to.
* @param {boolean} [props.showPageSpeedWarning=false] - Whether to show the PageSpeed API warning.
* @returns {JSX.Element} The rendered fallback UI.
*/
const Fallback = ({ title, checks, link = "/", isAdmin, type, children }) => {
const theme = useTheme();
return (
<Box
position="relative"
sx={{
height: "100%",
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<FallbackContainer type={type}>
<FallbackBackground />
<Stack
gap={theme.spacing(5)}
zIndex={1}
alignItems="center"
>
<FallbackTitle title={title} />
<FallbackCheckList
checks={checks}
title={title}
type={type}
/>
</Stack>
{isAdmin && (
<Stack
gap={theme.spacing(10)}
alignItems="center"
>
<FallbackActionButtons
title={title}
link={link}
type={type}
/>
{children}
</Stack>
)}
</FallbackContainer>
</Box>
);
};
Fallback.propTypes = {
title: PropTypes.string.isRequired,
checks: PropTypes.arrayOf(PropTypes.string).isRequired,
link: PropTypes.string,
isAdmin: PropTypes.bool,
showPageSpeedWarning: PropTypes.bool,
type: PropTypes.string.isRequired,
children: PropTypes.node,
};
export default Fallback;
@@ -1,99 +0,0 @@
import { Checkbox, FormControl, ListItemText, MenuItem, Select } from "@mui/material";
import { useTheme } from "@emotion/react";
import PropTypes from "prop-types";
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
/**
* A reusable filter header component that displays a dropdown menu with selectable options.
*
* @component
* @param {Object} props - The component props.
* @param {string} props.header - The header text to display when no options are selected.
* @param {Array} props.options - An array of options to display in the dropdown menu. Each option should have a `value` and `label`.
* @param {Array} [props.value] - The currently selected values.
* @param {Function} props.onChange - The callback function to handle changes in the selected values.
* @param {boolean} [props.multiple=true] - Whether multiple options can be selected.
* @returns {JSX.Element} The rendered FilterHeader component.
*/
const FilterHeader = ({ header, options, value, onChange, multiple = true }) => {
const theme = useTheme();
const controlledValue = value === undefined ? [] : value; // Ensure value is always treated as an array for controlled component purposes
return (
<FormControl
sx={{ minWidth: "10%" }}
size="small"
>
<Select
multiple={multiple}
IconComponent={(props) => (
<AddCircleOutlineIcon
{...props}
sx={{ fontSize: "medium" }}
/>
)}
displayEmpty
value={controlledValue}
onChange={onChange}
renderValue={(selected) => {
if (!selected?.length) {
return header;
}
return (
header +
" | " +
selected
.map((value) => options.find((option) => option.value === value)?.label)
.filter(Boolean)
.join(", ")
);
}}
MenuProps={{
anchorOrigin: {
vertical: "bottom",
horizontal: "left",
},
transformOrigin: {
vertical: "top",
horizontal: "left",
},
}}
>
{options.map((option) => (
<MenuItem
key={option.value}
value={option.value}
sx={{
height: theme.spacing(17),
padding: 0,
}}
>
<Checkbox
checked={controlledValue.includes(option.value)}
size="small"
/>
<ListItemText primary={option.label} />
</MenuItem>
))}
</Select>
</FormControl>
);
};
FilterHeader.propTypes = {
header: PropTypes.string.isRequired,
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
})
).isRequired,
value: PropTypes.arrayOf(PropTypes.string),
onChange: PropTypes.func.isRequired,
multiple: PropTypes.bool,
};
export default FilterHeader;
@@ -1,23 +0,0 @@
import { Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
const NetworkError = () => {
const theme = useTheme();
const { t } = useTranslation();
return (
<>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</>
);
};
export default NetworkError;
@@ -1,85 +0,0 @@
import { useTheme } from "@emotion/react";
import { Box, Stack } from "@mui/material";
import OutputAnimation from "../../assets/Animations/output.gif";
import DarkmodeOutput from "../../assets/Animations/darkmodeOutput.gif";
import Background from "../../assets/Images/background-grid.svg?react";
import { useSelector } from "react-redux";
/**
* Fallback component to display a fallback UI for network errors
*
* @returns {JSX.Element} The rendered fallback UI.
*/
const GenericFallback = ({ children }) => {
const theme = useTheme();
const mode = useSelector((state) => state.ui.mode);
return (
<Box
padding={theme.spacing(16)}
position="relative"
border={1}
borderColor={theme.palette.primary.lowContrast}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.primary.main}
overflow="hidden"
sx={{
borderStyle: "dashed",
}}
>
<Stack
alignItems="center"
gap={theme.spacing(20)}
sx={{
width: "fit-content",
margin: "auto",
marginTop: "100px",
}}
>
<Box
component="img"
src={mode === "light" ? OutputAnimation : DarkmodeOutput}
Background="transparent"
alt="Loading animation"
sx={{
zIndex: 1,
border: "none",
borderRadius: theme.spacing(8),
width: "100%",
}}
/>
<Box
sx={{
"& svg g g:last-of-type path": {
stroke: theme.palette.primary.lowContrast,
},
position: "absolute",
top: "0",
left: "50%",
transform: "translate(-50%, -50%)",
width: "100%",
maxWidth: "800px",
height: "100%",
maxHeight: "800px",
backgroundPosition: "center",
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
}}
>
<Background style={{ width: "100%" }} />
</Box>
<Stack
gap={theme.spacing(4)}
alignItems="center"
maxWidth={"300px"}
zIndex={1}
>
{children}
</Stack>
</Stack>
</Box>
);
};
export default GenericFallback;
@@ -1,49 +0,0 @@
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { logger } from "../../Utils/Logger";
import { networkService } from "../../main";
const withAdminCheck = (WrappedComponent) => {
const WithAdminCheck = (props) => {
const navigate = useNavigate();
const [isChecking, setIsChecking] = useState(true);
const [superAdminExists, setSuperAdminExists] = useState(false);
useEffect(() => {
networkService
.doesSuperAdminExist()
.then((response) => {
if (response?.data?.data === true) {
navigate("/login");
} else {
setSuperAdminExists(false);
}
})
.catch((error) => {
logger.error(error);
})
.finally(() => {
setIsChecking(false);
});
}, [navigate]);
if (isChecking) {
return null;
}
return (
<WrappedComponent
{...props}
superAdminExists={superAdminExists}
/>
);
};
const wrappedComponentName =
WrappedComponent.displayName || WrappedComponent.name || "Component";
WithAdminCheck.displayName = `WithAdminCheck(${wrappedComponentName})`;
return WithAdminCheck;
};
export default withAdminCheck;
-32
View File
@@ -1,32 +0,0 @@
import { Typography } from "@mui/material";
import PropTypes from "prop-types";
/**
* A heading component that renders text with a specific heading level.
*
* @param {Object} props - The properties passed to the Heading component.
* @param {('h1'|'h2'|'h3')} props.component - The heading level for the component.
* @param {Object} props.style - Custom styles to apply to the heading.
* @param {string} props.children - The content to display inside the heading.
* @returns {JSX.Element} The Typography component with specified heading properties.
*/
function Heading({ component, style, children }) {
return (
<Typography
component={component}
variant="h2"
fontWeight={600}
style={style}
>
{children}
</Typography>
);
}
Heading.propTypes = {
component: PropTypes.oneOf(["h1", "h2", "h3"]).isRequired,
style: PropTypes.object,
children: PropTypes.string.isRequired,
};
export { Heading };
-56
View File
@@ -1,56 +0,0 @@
import { Stack, Typography } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import Dot from "../Dot";
/**
* Host component.
* This subcomponent receives a params object and displays the host details.
*
* @component
* @param {Object} params - An object containing the following properties:
* @param {string} params.url - The URL of the host.
* @param {string} params.title - The name of the host.
* @param {string} params.percentageColor - The color of the percentage text.
* @param {number} params.percentage - The percentage to display.
* @returns {React.ElementType} Returns a div element with the host details.
*/
const Host = ({ url, title, percentageColor, percentage, showURL }) => {
const theme = useTheme();
return (
<Stack>
<Stack
direction="row"
position="relative"
alignItems="center"
gap={theme.spacing(4)}
>
{title}
{percentageColor && percentage && (
<>
<Dot />
<Typography
component="span"
sx={{
color: percentageColor,
fontWeight: 500,
}}
>
{percentage}%
</Typography>
</>
)}
</Stack>
{showURL && <span style={{ opacity: 0.6 }}>{url}</span>}
</Stack>
);
};
Host.propTypes = {
title: PropTypes.string,
percentageColor: PropTypes.string,
percentage: PropTypes.string,
url: PropTypes.string,
showURL: PropTypes.bool,
};
export default Host;
Loaded 100 of 1132 files, more files were not shown because too many files have changed in this diff. Show more