Compare commits

...
53 Commits
Author SHA1 Message Date
Alexander Holliday 16a8552e6c Merge pull request #2890 from bluewave-labs/develop
develop->master
2025-08-30 19:31:37 -07:00
Alexander Holliday c953ec6152 Merge pull request #2889 from bluewave-labs/fix/package-lock
regenerate package-lock
2025-08-30 19:31:02 -07:00
Alex Holliday a433f10240 regenerate package-lock 2025-08-30 19:30:24 -07:00
Alexander Holliday b73b97b5e9 Merge pull request #2887 from bluewave-labs/feat/add-maintenance-window-description
Update maintenance window description
2025-08-30 19:01:45 -07:00
gorkem-bwl 0607e0b228 refactor: simplify maintenance window description per feedback
- Remove redundant words 'active' and 'completely'
- Remove technical details about specific check types
- Keep the description concise while maintaining clarity
- Maintain all key information about maintenance behavior
2025-08-30 21:57:17 -04:00
gorkem-bwl 3bd4f67ec7 docs: add comprehensive maintenance window behavior description
- Update maintenance window description to clearly explain what happens during maintenance
- Clarify that ALL monitoring types are suspended (pings, HTTP, port checks, etc.)
- Explain that no notifications or alerts will be triggered
- Describe status page behavior (maintenance indicator shown)
- Note that monitoring resumes automatically when maintenance ends
- Clarify that maintenance periods don't affect uptime calculations
- Provide users with complete understanding of maintenance window impact
2025-08-30 21:31:44 -04:00
Alexander Holliday 845d5a5d51 Merge pull request #2885 from bluewave-labs/develop
develop->master
2025-08-30 16:23:40 -07:00
Alexander Holliday 0101da731f Merge pull request #2884 from bluewave-labs/fix/bump-version
bump version
2025-08-30 16:23:03 -07:00
Alex Holliday 68592acd39 bump version 2025-08-30 16:22:16 -07:00
Alexander Holliday b86fc5edb3 Merge pull request #2883 from bluewave-labs/develop
develop -> master
2025-08-30 16:21:19 -07:00
Alexander Holliday 32b54ddf11 Merge pull request #2882 from bluewave-labs/feat/migration
add migration for statusWindowThreshold
2025-08-30 16:20:23 -07:00
Alex Holliday f8a0741e6c <= -> < 2025-08-30 16:19:17 -07:00
Alex Holliday 652d231771 add migration for statusWindowThreshold 2025-08-30 16:07:03 -07:00
Alexander Holliday 1c3c5f4fec Merge pull request #2881 from bluewave-labs/fix/queue
fix: queue
2025-08-30 11:30:38 -07:00
Alex Holliday e7006a4a44 fix default value 2025-08-30 11:28:54 -07:00
Alex Holliday 0f81d54f25 remove success toast 2025-08-30 11:18:05 -07:00
Alex Holliday f3121c24c6 add interval to queue table 2025-08-30 11:17:34 -07:00
Alex Holliday 7abd0f2cd4 add root level gitignore 2025-08-30 11:13:53 -07:00
Alex Holliday 46b342005a update monitor interval and data 2025-08-30 11:11:58 -07:00
Alex Holliday 4e0349bd58 bump queue 2025-08-30 11:11:19 -07:00
Alexander Holliday 30a569233b Merge pull request #2873 from bluewave-labs/feat/docker-container-name-monitoring
feat: Enable Docker container monitoring by name in addition to ID
2025-08-29 09:33:45 -07:00
Alex Holliday 44ba6b4d0f early returns 2025-08-29 09:22:02 -07:00
Alexander Holliday 9065070eb2 Merge pull request #2871 from bluewave-labs/feat/incident-tooltip
feat:incident tooltip
2025-08-29 09:07:35 -07:00
gorkem-bwl ba757b9aa4 style: fix prettier formatting in validation.js 2025-08-29 00:58:03 -04:00
gorkem-bwlandClaude c445463c0c refactor: improve Docker container matching with deterministic priority-based logic
Address code review feedback to eliminate ambiguity issues and improve reliability:

**Backend Improvements:**
- Implement priority-based matching: exact ID → exact name → partial ID
- Add input normalization (strip leading slashes, case-insensitive)
- Add ambiguity detection with warning logs for debugging
- Maintain full backwards compatibility with existing monitors

**Frontend Improvements:**
- Update validation regex to support leading slashes (/container-name)
- Improve error message clarity for user guidance

**Resolves Ambiguity Issues:**
- Container name "abc" vs Container ID "abc123..." now deterministic
- Multiple containers with similar names handled predictably
- Case-insensitive matching for better user experience

**Priority Order:**
1. Exact full ID match (64-char) - highest priority
2. Exact container name match - case-insensitive
3. Partial ID match - backwards compatibility fallback

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 00:53:40 -04:00
gorkem-bwlandClaude 4693177e4b feat: add Docker container monitoring by name
- Update Docker monitoring to support both container names and IDs
- Maintain backward compatibility with existing container ID monitoring
- Add logic to find containers by name (with or without "/" prefix)
- Update frontend UI labels and placeholders to reflect name/ID support
- Update instructions to clarify both name and ID are supported

Resolves user request: "It would be great if we could monitor docker containers by name and not just ID - given that the ID changes when containers are taken down for any reason"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 00:27:01 -04:00
Alex Holliday 30b135eba3 add tooltip to incident table 2025-08-28 12:21:34 -07:00
Alex Holliday bda48e07f1 add optional tooltip 2025-08-28 12:21:23 -07:00
Alexander Holliday 0ad759a384 Merge pull request #2865 from bluewave-labs/fix/status-page-deletion-error
Fix status page deletion error
2025-08-27 14:49:45 -07:00
gorkem-bwl d3d20b29c3 Fix status page deletion error - missing module reference
- Fix deleteStatusPage method call to use statusPageModule
- Change this.db.deleteStatusPage to this.db.statusPageModule.deleteStatusPage
- Ensures consistency with other controller methods
- Resolves "this.db.deleteStatusPage is not a function" error

Fixes bug where status page deletion failed due to incorrect database module reference.
2025-08-27 17:47:11 -04:00
Alexander Holliday fbb570c0d5 Merge pull request #2862 from bluewave-labs/fix/advanced-matching
fix: advanced matching
2025-08-26 14:56:20 -07:00
Alex Holliday 2318082bb8 fix advanced matching 2025-08-26 14:54:24 -07:00
Alexander Holliday 05dd5f7de2 Merge pull request #2858 from bluewave-labs/develop
develop -> master
2025-08-25 15:06:19 -07:00
Alexander Holliday 841251d09e Merge pull request #2857 from bluewave-labs/fix/model-types
fix/model types
2025-08-25 15:05:41 -07:00
Alexander Holliday a4dd8f70f0 Merge branch 'develop' into fix/model-types 2025-08-25 15:05:30 -07:00
Alex Holliday 9d0d1329b6 bump version 2025-08-25 15:04:44 -07:00
Alex Holliday 7a929777b4 fix model types 2025-08-25 15:03:31 -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 4f7847275e Merge pull request #2854 from bluewave-labs/feat/bump-version
bump version
2025-08-25 14:37:21 -07:00
Alex Holliday 9a5ddb22b3 bump version 2025-08-25 14:37:00 -07:00
Alexander Holliday b1322cbec3 Merge pull request #2853 from bluewave-labs/fix/string-service-path
fix: string service path, resolves #2847, resolves #2848
2025-08-25 14:32:21 -07:00
Alex Holliday 637bc84136 fix string service path 2025-08-25 14:30:41 -07:00
Alexander Holliday 3147f02b6a Merge pull request #2843 from bluewave-labs/fix/notification-channel-validation
fix notification validation
2025-08-22 11:34:38 -07:00
Alex Holliday dabff74946 fix notification validation 2025-08-22 11:33:14 -07:00
Gorkem Cetin (BWL) de99577b9d Merge pull request #2838 from bluewave-labs/disabledbydefault
Fix Settings Page Select Component Value Handling for URL Visibility Option
2025-08-22 10:38:16 -04:00
Alexander Holliday 1846432601 Merge pull request #2839 from bluewave-labs/fix/docker-compose-arm
fix: update arm dist docker compose
2025-08-21 22:39:03 -07:00
Alex Holliday 6f307dc822 update arm dist docker compose 2025-08-21 22:37:59 -07:00
imjainish f43210e29e Address PR Comments - Format 2025-08-21 23:13:50 -04:00
imjainish 50b9be4eca Address PR Comments 2025-08-21 23:05:50 -04:00
imjainish 1a38222974 Fix Disabled Field in Settings 2025-08-21 22:39:41 -04:00
Alexander Holliday cb9cd0a43c Merge pull request #2829 from bluewave-labs/fix-timestamps-format
fix: add missing tooltip date format for 'recent' timeframe in charts
2025-08-21 11:39:13 -07:00
karenvicent 75a2e0deee Merge branch 'develop' into fix-timestamps-format 2025-08-20 18:16:50 -04:00
karenvicent b857137f1a fix data format in uptime and infrastructure charts 2025-08-20 18:14:42 -04:00
26 changed files with 544 additions and 1354 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.vscode
+4 -622
View File
@@ -491,262 +491,6 @@
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
@@ -763,134 +507,6 @@
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
@@ -2063,123 +1679,6 @@
}
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz",
"integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz",
"integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz",
"integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz",
"integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz",
"integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz",
"integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz",
"integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz",
"integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz",
"integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz",
@@ -2193,71 +1692,6 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz",
"integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz",
"integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz",
"integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz",
"integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz",
"integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz",
@@ -2284,45 +1718,6 @@
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz",
"integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz",
"integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz",
"integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -4342,14 +3737,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -4363,20 +3759,6 @@
"dev": true,
"license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -1,5 +1,6 @@
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",
+48 -16
View File
@@ -7,6 +7,7 @@ import {
TableHead,
TableRow,
} from "@mui/material";
import Tooltip from "@mui/material/Tooltip";
import SkeletonLayout from "./skeleton";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
@@ -41,6 +42,7 @@ const DataTable = ({
data = [],
config = {
emptyView: "No data",
tooltipContent: null,
onRowClick: () => {},
},
}) => {
@@ -101,24 +103,54 @@ const DataTable = ({
data.map((row) => {
const key = row.id || row._id || Math.random();
return (
<TableRow
<Tooltip
key={key}
sx={config?.rowSX ?? {}}
onClick={config?.onRowClick ? () => config.onRowClick(row) : null}
followCursor
enterDelay={500}
enterNextDelay={500}
title={
typeof config.tooltipContent === "function"
? config.tooltipContent(row)
: config.tooltipContent
}
slotProps={{
tooltip: {
sx: {
background: "unset",
},
},
popper: {
modifiers: [
{
name: "offset",
options: {
offset: ({ popper }) => {
return [popper.width / 2 + 20, -popper.height / 8];
},
},
},
],
},
}}
>
{headers.map((header, index) => {
return (
<TableCell
align={index === 0 ? "left" : "center"}
key={header.id}
onClick={header.onClick ? (e) => header.onClick(e, row) : null}
sx={header.getCellSx ? header.getCellSx(row) : {}}
>
{header.render(row)}
</TableCell>
);
})}
</TableRow>
<TableRow
sx={config?.rowSX ?? {}}
onClick={config?.onRowClick ? () => config.onRowClick(row) : null}
>
{headers.map((header, index) => {
return (
<TableCell
align={index === 0 ? "left" : "center"}
key={header.id}
onClick={header.onClick ? (e) => header.onClick(e, row) : null}
sx={header.getCellSx ? header.getCellSx(row) : {}}
>
{header.render(row)}
</TableCell>
);
})}
</TableRow>
</Tooltip>
);
})
)}
-3
View File
@@ -15,9 +15,6 @@ const useFetchLogs = () => {
setIsLoading(true);
const response = await networkService.getLogs();
setLogs(response.data.data);
createToast({
body: t("logsPage.toast.fetchLogsSuccess"),
});
} catch (error) {
setError(error);
createToast({
@@ -1,5 +1,10 @@
//Components
import Table from "../../../../Components/Table";
import Stack from "@mui/material/Stack";
import DataTable from "../../../../Components/Table";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableRow from "@mui/material/TableRow";
import TableCell from "@mui/material/TableCell";
import TableSkeleton from "../../../../Components/Table/skeleton";
import Pagination from "../../../../Components/Table/TablePagination";
import { StatusLabel } from "../../../../Components/Label";
@@ -16,7 +21,68 @@ import { useTranslation } from "react-i18next";
import { useFetchChecksTeam } from "../../../../Hooks/checkHooks";
import { useFetchChecksByMonitor } from "../../../../Hooks/checkHooks";
import { useResolveIncident } from "../../../../Hooks/checkHooks";
import { Button, Typography } from "@mui/material";
import { Button, Typography, useTheme } from "@mui/material";
import { lighten } from "@mui/material/styles";
const GetTooltip = (row) => {
const theme = useTheme();
const phases = row?.timings?.phases;
const phaseKeyFormattingMap = {
firstByte: "first byte",
};
return (
<Stack
backgroundColor={lighten(theme.palette.primary.main, 0.1)}
border={`1px solid ${theme.palette.primary.lowContrast}`}
borderRadius={theme.shape.borderRadius}
py={theme.spacing(2)}
px={theme.spacing(4)}
>
<Typography
variant="body2"
color={theme.palette.primary.contrastText}
>{`Status code: ${row?.statusCode}`}</Typography>
<Typography
variant="body2"
color={theme.palette.primary.contrastText}
>{`Response time: ${row?.responseTime} ms`}</Typography>
{phases && (
<>
<Typography
variant="body2"
color={theme.palette.primary.contrastText}
>{`Request timing: `}</Typography>
<Table
size="small"
sx={{ ml: theme.spacing(2), mt: theme.spacing(2) }}
>
<TableBody>
{Object.keys(phases)?.map((phaseKey) => (
<TableRow key={phaseKey}>
<TableCell sx={{ border: "none", p: 0 }}>
<Typography
variant="body2"
color="success"
>
{`${phaseKeyFormattingMap[phaseKey] || phaseKey}:`}
</Typography>
</TableCell>
<TableCell sx={{ border: "none", p: 0 }}>
<Typography
color={theme.palette.primary.contrastText}
variant="body2"
>{`${phases[phaseKey]} ms`}</Typography>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</>
)}
</Stack>
);
};
const IncidentTable = ({
isLoading,
@@ -167,9 +233,10 @@ const IncidentTable = ({
return (
<>
<Table
<DataTable
headers={headers}
data={checks}
config={{ tooltipContent: GetTooltip }}
/>
<Pagination
paginationLabel={t("incidentsTablePaginationLabel")}
@@ -121,6 +121,7 @@ const InfrastructureDetails = () => {
<AreaChartBoxes
shouldRender={!isLoading}
monitor={monitor}
dateRange={dateRange}
/>
</>
)}
@@ -46,6 +46,11 @@ const JobTable = ({ jobs = [] }) => {
content: t("queuePage.jobTable.urlHeader"),
render: (row) => row.monitorUrl,
},
{
id: "interval",
content: t("queuePage.jobTable.intervalHeader"),
render: (row) => `${row.monitorInterval} ms`,
},
{
id: "type",
content: t("queuePage.jobTable.typeHeader"),
+1 -1
View File
@@ -29,7 +29,7 @@ const SettingsURL = ({ HEADING_SX, handleChange, showURL = false }) => {
<Select
name="showURL"
label={t("settingsPage.urlSettings.label")}
value={showURL || ""}
value={showURL === true}
onChange={handleChange}
items={[
{ _id: true, name: t("settingsPage.urlSettings.selectEnabled") },
+4 -2
View File
@@ -130,10 +130,12 @@ const monitorValidation = joi.object({
then: joi
.string()
.trim()
.regex(/^[a-z0-9]{64}$/)
.regex(
/^(\/+)?([a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9]|[a-zA-Z0-9]+|[a-f0-9]{12,64})$/
)
.messages({
"string.empty": "This field is required.",
"string.pattern.base": "Please enter a valid 64-character Docker container ID.",
"string.pattern.base": "Please enter a valid container name or ID.",
}),
otherwise: joi
.string()
+5 -4
View File
@@ -251,7 +251,7 @@
"edit": "Edit",
"createA": "Create a",
"remove": "Remove",
"maintenanceWindowDescription": "Your pings won't be sent during this time frame",
"maintenanceWindowDescription": "During maintenance windows, all monitoring is suspended for selected monitors. No network checks will be performed, preventing any status updates or notifications from being triggered. Your monitors will appear frozen at their last known status, and status pages will display a maintenance indicator. Once the maintenance window ends, monitoring automatically resumes, and alerts will trigger if issues are detected. Maintenance periods do not count against uptime calculations.",
"startTime": "Start time",
"timeZoneInfo": "All dates and times are in GMT+0 time zone.",
"monitorsToApply": "Monitors to apply maintenance window to",
@@ -440,7 +440,7 @@
"uptimeGeneralInstructions": {
"http": "Enter the URL or IP to monitor (e.g., https://example.com/ or 192.168.1.100) and add a clear display name that appears on the dashboard.",
"ping": "Enter the IP address or hostname to ping (e.g., 192.168.1.100 or example.com) and add a clear display name that appears on the dashboard.",
"docker": "Enter the Docker ID of your container. Docker IDs must be the full 64 char Docker ID. You can run docker inspect <short_id> to get the full container ID.",
"docker": "Enter the Docker container name or ID. You can use either the container name (e.g., my-app) or the container ID (full 64-char ID or short ID).",
"port": "Enter the URL or IP of the server, the port number and a clear display name that appears on the dashboard.",
"game": "Enter the IP address or hostname and the port number to ping (e.g., 192.168.1.100 or example.com) and choose game type."
},
@@ -740,6 +740,7 @@
"idHeader": "Monitor ID",
"urlHeader": "URL",
"typeHeader": "Type",
"intervalHeader": "Interval",
"activeHeader": "Active",
"lockedAtHeader": "Locked at",
"runCountHeader": "Run count",
@@ -1014,9 +1015,9 @@
},
"monitorType": {
"docker": {
"label": "Container ID",
"label": "Container Name/ID",
"namePlaceholder": "My Container",
"placeholder": "abcd1234"
"placeholder": "my-app or abcd1234"
},
"http": {
"label": "URL to monitor",
+1 -1
View File
@@ -5,7 +5,7 @@ import { execSync } from "child_process";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
let version = "3.1.1";
let version = "3.1.4";
return {
base: "/",
+1 -2
View File
@@ -15,9 +15,8 @@ services:
- mongodb
mongodb:
image: mongo:4.4.18
container_name: checkmate-mongodb
restart: always
command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
command: ["mongod", "--quiet", --bind_ip_all"]
ports:
- "27017:27017"
volumes:
+259 -661
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -46,7 +46,7 @@
"ping": "0.4.4",
"sharp": "0.33.5",
"ssl-checker": "2.0.10",
"super-simple-scheduler": "1.3.0",
"super-simple-scheduler": "1.4.0",
"swagger-ui-express": "5.0.1",
"winston": "^3.13.0"
},
@@ -95,7 +95,7 @@ class StatusPageController extends BaseController {
deleteStatusPage = this.asyncHandler(
async (req, res) => {
await this.db.deleteStatusPage(req.params.url);
await this.db.statusPageModule.deleteStatusPage(req.params.url);
return res.success({
msg: this.stringService.statusPageDelete,
});
+1 -1
View File
@@ -72,7 +72,7 @@ const CheckSchema = new mongoose.Schema(
},
type: {
type: String,
enum: ["http", "hardware", "pagespeed", "distributed"],
enum: ["http", "ping", "pagespeed", "hardware", "docker", "port", "game"],
required: true,
index: true,
},
+1 -1
View File
@@ -38,7 +38,7 @@ const MonitorSchema = mongoose.Schema(
},
statusWindowThreshold: {
type: Number,
default: 0.6,
default: 60,
},
type: {
type: String,
+3 -1
View File
@@ -1,6 +1,6 @@
import mongoose from "mongoose";
import AppSettings from "../models/AppSettings.js";
import { runMigrations } from "./migration/index.js";
class MongoDB {
static SERVICE_NAME = "MongoDB";
@@ -65,6 +65,8 @@ class MongoDB {
service: this.SERVICE_NAME,
method: "connect",
});
await runMigrations();
} catch (error) {
this.logger.error({
message: error.message,
@@ -0,0 +1,18 @@
import Monitor from "../../models/Monitor.js";
async function migrateStatusWindowThreshold() {
try {
const monitors = await Monitor.find({ statusWindowThreshold: { $lt: 1 } });
for (const monitor of monitors) {
monitor.statusWindowThreshold = monitor.statusWindowThreshold * 100;
await monitor.save();
console.log(`Migrated monitor ${monitor._id}: statusWindowThreshold set to ${monitor.statusWindowThreshold}`);
}
console.log("StatusWindowThreshold migration complete.");
return true;
} catch (err) {
console.error("Migration error:", err);
return false;
}
}
export { migrateStatusWindowThreshold };
+7
View File
@@ -0,0 +1,7 @@
import { migrateStatusWindowThreshold } from "./0001_migrateStatusWindowThreshold.js";
const runMigrations = async () => {
await migrateStatusWindowThreshold();
};
export { runMigrations };
@@ -88,7 +88,7 @@ class SuperSimpleQueue {
};
updateJob = async (monitor) => {
this.scheduler.updateJob(monitor._id.toString(), monitor.interval);
this.scheduler.updateJob(monitor._id.toString(), { repeat: monitor.interval, data: monitor.toObject() });
};
shutdown = async () => {
@@ -141,6 +141,7 @@ class SuperSimpleQueue {
monitorId: job.id,
monitorUrl: job?.data?.url || null,
monitorType: job?.data?.type || null,
monitorInterval: job?.data?.interval || null,
active: job.active,
lockedAt: job.lockedAt,
runCount: job.runCount || 0,
@@ -1,3 +1,5 @@
import { match } from "assert";
const SERVICE_NAME = "NetworkService";
class NetworkService {
@@ -147,16 +149,24 @@ class NetworkService {
httpResponse.payload = payload;
httpResponse.timings = response.timings || {};
if (!expectedValue) {
if (!expectedValue && !jsonPath) {
return httpResponse;
}
this.logger.info({
service: this.SERVICE_NAME,
method: "requestHttp",
message: `Job: [${name}](${_id}) match result with expected value`,
details: { expectedValue, payload, jsonPath, matchMethod },
});
if (expectedValue) {
let ok = false;
if (matchMethod === "equal") ok = payload === expectedValue;
if (matchMethod === "include") ok = payload.includes(expectedValue);
if (matchMethod === "regex") ok = new RegExp(expectedValue).test(payload);
if (ok === true) {
return httpResponse;
} else {
httpResponse.code = 500;
httpResponse.status = false;
return httpResponse;
}
}
if (jsonPath) {
const contentType = response.headers["content-type"];
@@ -243,24 +253,76 @@ class NetworkService {
handleError: true, // Enable error handling
});
const containers = await docker.listContainers({ all: true });
const containerExists = containers.some((c) => c.Id.startsWith(monitor.url));
if (!containerExists) {
throw new Error(this.stringService.dockerNotFound);
}
const container = docker.getContainer(monitor.url);
const { response, responseTime, error } = await this.timeRequest(() => container.inspect());
const dockerResponse = {
monitorId: monitor._id,
type: monitor.type,
responseTime,
status: response?.State?.Status === "running" ? true : false,
code: 200,
message: "Docker container status fetched successfully",
};
const containers = await docker.listContainers({ all: true });
// Normalize input: strip leading slashes and convert to lowercase for comparison
const normalizedInput = monitor.url.replace(/^\/+/, "").toLowerCase();
// Priority-based matching to avoid ambiguity:
// 1. Exact full ID match (64-char)
let exactIdMatch = containers.find((c) => c.Id.toLowerCase() === normalizedInput);
// 2. Exact container name match (case-insensitive)
let exactNameMatch = containers.find((c) =>
c.Names.some((name) => {
const cleanName = name.replace(/^\/+/, "").toLowerCase();
return cleanName === normalizedInput;
})
);
// 3. Partial ID match (fallback for backwards compatibility)
let partialIdMatch = containers.find((c) => c.Id.toLowerCase().startsWith(normalizedInput));
// Select container based on priority
let targetContainer = exactIdMatch || exactNameMatch || partialIdMatch;
// Return negative response if no container
if (!targetContainer) {
this.logger.warn({
message: `No container found for "${monitor.url}".`,
service: this.SERVICE_NAME,
method: "requestDocker",
details: { url: monitor.url },
});
dockerResponse.code = 404;
dockerResponse.status = false;
dockerResponse.message = this.stringService.dockerNotFound;
return dockerResponse;
}
// Return negative response if ambiguous matches exist
const matchTypes = [];
if (exactIdMatch) matchTypes.push("exact ID");
if (exactNameMatch) matchTypes.push("exact name");
if (partialIdMatch && !exactIdMatch) matchTypes.push("partial ID");
if (matchTypes.length > 1) {
this.logger.warn({
message: `Ambiguous container match for "${monitor.url}". Matched by: ${matchTypes.join(", ")}. Using ${exactIdMatch ? "exact ID" : exactNameMatch ? "exact name" : "partial ID"} match.`,
service: this.SERVICE_NAME,
method: "requestDocker",
details: { url: monitor.url },
});
dockerResponse.status = 404;
dockerResponse.status = false;
dockerResponse.message = `Ambiguous container match for "${monitor.url}". Matched by: ${matchTypes.join(", ")}. Using ${exactIdMatch ? "exact ID" : exactNameMatch ? "exact name" : "partial ID"} match.`;
return dockerResponse;
}
const container = docker.getContainer(targetContainer.Id);
const { response, responseTime, error } = await this.timeRequest(() => container.inspect());
dockerResponse.responseTime = responseTime;
dockerResponse.status = response?.State?.Status === "running" ? true : false;
dockerResponse.code = 200;
dockerResponse.message = "Docker container status fetched successfully";
if (error) {
dockerResponse.status = false;
dockerResponse.code = error.statusCode || this.NETWORK_ERROR;
@@ -158,7 +158,7 @@ class StatusService {
statusChanged = true;
}
// If the failure rate is below the threshold and the monitor is down, recover:
else if (failureRate <= monitor.statusWindowThreshold && monitor.status === false) {
else if (failureRate < monitor.statusWindowThreshold && monitor.status === false) {
newStatus = true;
statusChanged = true;
}
@@ -7,7 +7,7 @@ class TranslationService {
this.logger = logger;
this.translations = {};
this._language = "en";
this.localesDir = path.join(process.cwd(), "locales");
this.localesDir = path.join(process.cwd(), "src/locales");
}
get serviceName() {
+25 -11
View File
@@ -580,17 +580,31 @@ const createNotificationBodyValidation = joi.object({
}),
address: joi.when("type", {
is: "email",
then: joi.string().email().required().messages({
"string.empty": "E-mail address cannot be empty",
"any.required": "E-mail address is required",
"string.email": "Please enter a valid e-mail address",
}),
otherwise: joi.string().uri().required().messages({
"string.empty": "Webhook URL cannot be empty",
"any.required": "Webhook URL is required",
"string.uri": "Please enter a valid Webhook URL",
}),
switch: [
{
is: "email",
then: joi.string().email().required().messages({
"string.empty": "E-mail address cannot be empty",
"any.required": "E-mail address is required",
"string.email": "Please enter a valid e-mail address",
}),
},
{
is: "pager_duty",
then: joi.string().required().messages({
"string.empty": "PagerDuty integration key cannot be empty",
"any.required": "PagerDuty integration key is required",
}),
},
{
is: joi.string().valid("webhook", "slack", "discord"),
then: joi.string().uri().required().messages({
"string.empty": "Webhook URL cannot be empty",
"any.required": "Webhook URL is required",
"string.uri": "Please enter a valid Webhook URL",
}),
},
],
}),
});