Merge branch 'master' into 2.0-last-part

This commit is contained in:
Louis Lam 2024-10-11 16:53:16 +08:00
commit 7562212483
16 changed files with 127 additions and 32 deletions

View file

@ -1,6 +1,6 @@
# Project Info # Project Info
First of all, I want to thank everyone who have wrote issues or shared pull requests for Uptime Kuma. First of all, I want to thank everyone who has submitted issues or shared pull requests for Uptime Kuma.
I never thought the GitHub community would be so nice! I never thought the GitHub community would be so nice!
Because of this, I also never thought that other people would actually read and edit my code. Because of this, I also never thought that other people would actually read and edit my code.
Parts of the code are not very well-structured or commented, sorry about that. Parts of the code are not very well-structured or commented, sorry about that.
@ -9,7 +9,7 @@ The project was created with `vite.js` and is written in `vue3`.
Our backend lives in the `server`-directory and mostly communicates via websockets. Our backend lives in the `server`-directory and mostly communicates via websockets.
Both frontend and backend share the same `package.json`. Both frontend and backend share the same `package.json`.
For production, the frontend is build into `dist`-directory and the server (`express.js`) exposes the `dist` directory as the root of the endpoint. For production, the frontend is built into the `dist`-directory and the server (`express.js`) exposes the `dist` directory as the root of the endpoint.
For development, we run vite in development mode on another port. For development, we run vite in development mode on another port.
## Directories ## Directories
@ -28,7 +28,7 @@ For development, we run vite in development mode on another port.
## Can I create a pull request for Uptime Kuma? ## Can I create a pull request for Uptime Kuma?
Yes or no, it depends on what you will try to do. Yes or no, it depends on what you will try to do.
Both your and our maintainers time is precious, and we don't want to waste both time. Both yours and our maintainers' time is precious, and we don't want to waste either.
If you have any questions about any process/.. is not clear, you are likely not alone => please ask them ^^ If you have any questions about any process/.. is not clear, you are likely not alone => please ask them ^^
@ -49,11 +49,11 @@ Different guidelines exist for different types of pull requests (PRs):
<p> <p>
If you come across a bug and think you can solve, we appreciate your work. If you come across a bug and think you can solve, we appreciate your work.
Please make sure that you follow by these rules: Please make sure that you follow these rules:
- keep the PR as small as possible, fix only one thing at a time => keeping it reviewable - keep the PR as small as possible, fix only one thing at a time => keeping it reviewable
- test that your code does what you came it does. - test that your code does what you claim it does.
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub> <sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
</p> </p>
</details> </details>
- <details><summary><b>translations / internationalisation (i18n)</b></summary> - <details><summary><b>translations / internationalisation (i18n)</b></summary>
@ -68,7 +68,7 @@ Different guidelines exist for different types of pull requests (PRs):
- language keys need to be **added to `en.json`** to be visible in weblate. If this has not happened, a PR is appreciated. - language keys need to be **added to `en.json`** to be visible in weblate. If this has not happened, a PR is appreciated.
- **Adding a new language** requires a new file see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md) - **Adding a new language** requires a new file see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md)
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub> <sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
</p> </p>
</details> </details>
- <details><summary><b>new notification providers</b></summary> - <details><summary><b>new notification providers</b></summary>
@ -102,7 +102,7 @@ Different guidelines exist for different types of pull requests (PRs):
Therefore, making sure that they work is also really important. Therefore, making sure that they work is also really important.
Because testing notification providers is quite time intensive, we mostly offload this onto the person contributing a notification provider. Because testing notification providers is quite time intensive, we mostly offload this onto the person contributing a notification provider.
To make shure you have tested the notification provider, please include screenshots of the following events in the pull-request description: To make sure you have tested the notification provider, please include screenshots of the following events in the pull-request description:
- `UP`/`DOWN` - `UP`/`DOWN`
- Certificate Expiry via https://expired.badssl.com/ - Certificate Expiry via https://expired.badssl.com/
- Testing (the test button on the notification provider setup page) - Testing (the test button on the notification provider setup page)
@ -117,7 +117,7 @@ Different guidelines exist for different types of pull requests (PRs):
| Testing | paste-image-here | paste-image-here | | Testing | paste-image-here | paste-image-here |
``` ```
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub> <sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
</p> </p>
</details> </details>
- <details><summary><b>new monitoring types</b></summary> - <details><summary><b>new monitoring types</b></summary>
@ -138,14 +138,14 @@ Different guidelines exist for different types of pull requests (PRs):
- -
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub> <sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
</p> </p>
</details> </details>
- <details><summary><b>new features/ major changes / breaking bugfixes</b></summary> - <details><summary><b>new features/ major changes / breaking bugfixes</b></summary>
<p> <p>
be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**.
This is especially important for a large pull request or you don't know if it will be merged or not. This is especially important for a large pull request or when you don't know if it will be merged or not.
<sub>Because of the large impact of this work, only senior maintainers may merge PRs in this area.</sub> <sub>Because of the large impact of this work, only senior maintainers may merge PRs in this area.</sub>
</p> </p>
@ -201,7 +201,7 @@ The rationale behind this is that we can align the direction and scope of the fe
## Project Styles ## Project Styles
I personally do not like something that requires so many configurations before you can finally start the app. I personally do not like something that requires a lot of configuration before you can finally start the app.
The goal is to make the Uptime Kuma installation as easy as installing a mobile app. The goal is to make the Uptime Kuma installation as easy as installing a mobile app.
- Easy to install for non-Docker users - Easy to install for non-Docker users
@ -260,7 +260,7 @@ Port `3000` and port `3001` will be used.
npm run dev npm run dev
``` ```
But sometimes, you would like to restart the server, but not the frontend, you can run these commands in two terminals: But sometimes you may want to restart the server without restarting the frontend. In that case, you can run these commands in two terminals:
```bash ```bash
npm run start-frontend-dev npm run start-frontend-dev
@ -409,7 +409,7 @@ https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
### What is a maintainer and what are their roles? ### What is a maintainer and what are their roles?
This project has multiple maintainers which specialise in different areas. This project has multiple maintainers who specialise in different areas.
Currently, there are 3 maintainers: Currently, there are 3 maintainers:
| Person | Role | Main Area | | Person | Role | Main Area |

View file

@ -87,7 +87,6 @@ class DingDing extends NotificationProvider {
* @returns {string} Status * @returns {string} Status
*/ */
statusToString(status) { statusToString(status) {
// TODO: Move to notification-provider.js to avoid repetition in classes
switch (status) { switch (status) {
case DOWN: case DOWN:
return "DOWN"; return "DOWN";

View file

@ -48,7 +48,7 @@ class Discord extends NotificationProvider {
}, },
{ {
name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL", name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL",
value: this.extractAdress(monitorJSON), value: this.extractAddress(monitorJSON),
}, },
{ {
name: `Time (${heartbeatJSON["timezone"]})`, name: `Time (${heartbeatJSON["timezone"]})`,
@ -85,7 +85,7 @@ class Discord extends NotificationProvider {
}, },
{ {
name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL", name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL",
value: this.extractAdress(monitorJSON), value: this.extractAddress(monitorJSON),
}, },
{ {
name: `Time (${heartbeatJSON["timezone"]})`, name: `Time (${heartbeatJSON["timezone"]})`,

View file

@ -24,7 +24,7 @@ class NotificationProvider {
* @param {?object} monitorJSON Monitor details (For Up/Down only) * @param {?object} monitorJSON Monitor details (For Up/Down only)
* @returns {string} The extracted address based on the monitor type. * @returns {string} The extracted address based on the monitor type.
*/ */
extractAdress(monitorJSON) { extractAddress(monitorJSON) {
if (!monitorJSON) { if (!monitorJSON) {
return ""; return "";
} }

View file

@ -32,7 +32,7 @@ class SevenIO extends NotificationProvider {
return okMsg; return okMsg;
} }
let address = this.extractAdress(monitorJSON); let address = this.extractAddress(monitorJSON);
if (address !== "") { if (address !== "") {
address = `(${address}) `; address = `(${address}) `;
} }

View file

@ -18,7 +18,7 @@ class SIGNL4 extends NotificationProvider {
msg, msg,
// Source system // Source system
"X-S4-SourceSystem": "UptimeKuma", "X-S4-SourceSystem": "UptimeKuma",
monitorUrl: this.extractAdress(monitorJSON), monitorUrl: this.extractAddress(monitorJSON),
}; };
const config = { const config = {

View file

@ -48,7 +48,7 @@ class Slack extends NotificationProvider {
} }
const address = this.extractAdress(monitorJSON); const address = this.extractAddress(monitorJSON);
if (address) { if (address) {
actions.push({ actions.push({
"type": "button", "type": "button",

View file

@ -93,7 +93,7 @@ class SMTP extends NotificationProvider {
if (monitorJSON !== null) { if (monitorJSON !== null) {
monitorName = monitorJSON["name"]; monitorName = monitorJSON["name"];
monitorHostnameOrURL = this.extractAdress(monitorJSON); monitorHostnameOrURL = this.extractAddress(monitorJSON);
} }
let serviceStatus = "⚠️ Test"; let serviceStatus = "⚠️ Test";

View file

@ -34,7 +34,7 @@ class Squadcast extends NotificationProvider {
data.status = "resolve"; data.status = "resolve";
} }
data.tags["AlertAddress"] = this.extractAdress(monitorJSON); data.tags["AlertAddress"] = this.extractAddress(monitorJSON);
monitorJSON["tags"].forEach(tag => { monitorJSON["tags"].forEach(tag => {
data.tags[tag["name"]] = { data.tags[tag["name"]] = {

View file

@ -225,7 +225,7 @@ class Teams extends NotificationProvider {
const payload = this._notificationPayloadFactory({ const payload = this._notificationPayloadFactory({
heartbeatJSON: heartbeatJSON, heartbeatJSON: heartbeatJSON,
monitorName: monitorJSON.name, monitorName: monitorJSON.name,
monitorUrl: this.extractAdress(monitorJSON), monitorUrl: this.extractAddress(monitorJSON),
dashboardUrl: dashboardUrl, dashboardUrl: dashboardUrl,
}); });

View file

@ -10,11 +10,22 @@ class TechulusPush extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully."; const okMsg = "Sent Successfully.";
let data = {
"title": notification?.pushTitle?.length ? notification.pushTitle : "Uptime-Kuma",
"body": msg,
"timeSensitive": notification.pushTimeSensitive ?? true,
};
if (notification.pushChannel) {
data.channel = notification.pushChannel;
}
if (notification.pushSound) {
data.sound = notification.pushSound;
}
try { try {
await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, { await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, data);
"title": "Uptime-Kuma",
"body": msg,
});
return okMsg; return okMsg;
} catch (error) { } catch (error) {
this.throwGeneralAxiosError(error); this.throwGeneralAxiosError(error);

View file

@ -85,7 +85,7 @@ class ZohoCliq extends NotificationProvider {
const payload = this._notificationPayloadFactory({ const payload = this._notificationPayloadFactory({
monitorMessage: heartbeatJSON.msg, monitorMessage: heartbeatJSON.msg,
monitorName: monitorJSON.name, monitorName: monitorJSON.name,
monitorUrl: this.extractAdress(monitorJSON), monitorUrl: this.extractAddress(monitorJSON),
status: heartbeatJSON.status status: heartbeatJSON.status
}); });

View file

@ -4,6 +4,53 @@
<HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="new-password"></HiddenInput> <HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="new-password"></HiddenInput>
</div> </div>
<div class="mb-3">
<label for="push-api-title" class="form-label">{{ $t("Title") }}</label>
<input id="push-api-title" v-model="$parent.notification.pushTitle" type="text" class="form-control">
</div>
<div class="mb-3">
<label for="push-api-channel" class="form-label">{{ $t("Notification Channel") }}</label>
<input id="push-api-channel" v-model="$parent.notification.pushChannel" type="text" class="form-control" patttern="[A-Za-z0-9-]+">
<div class="form-text">
{{ $t("Alphanumerical string and hyphens only") }}
</div>
</div>
<div class="mb-3">
<label for="push-api-sound" class="form-label">{{ $t("Sound") }}</label>
<select id="push-api-sound" v-model="$parent.notification.pushSound" class="form-select">
<option value="default">{{ $t("Default") }}</option>
<option value="arcade">{{ $t("Arcade") }}</option>
<option value="correct">{{ $t("Correct") }}</option>
<option value="fail">{{ $t("Fail") }}</option>
<option value="harp">{{ $t("Harp") }}</option>
<option value="reveal">{{ $t("Reveal") }}</option>
<option value="bubble">{{ $t("Bubble") }}</option>
<option value="doorbell">{{ $t("Doorbell") }}</option>
<option value="flute">{{ $t("Flute") }}</option>
<option value="money">{{ $t("Money") }}</option>
<option value="scifi">{{ $t("Scifi") }}</option>
<option value="clear">{{ $t("Clear") }}</option>
<option value="elevator">{{ $t("Elevator") }}</option>
<option value="guitar">{{ $t("Guitar") }}</option>
<option value="pop">{{ $t("Pop") }}</option>
</select>
<div class="form-text">
{{ $t("Custom sound to override default notification sound") }}
</div>
</div>
<div class="mb-3">
<div class="form-check form-switch">
<input v-model="$parent.notification.pushTimeSensitive" class="form-check-input" type="checkbox">
<label class="form-check-label">{{ $t("Time Sensitive (iOS Only)") }}</label>
</div>
<div class="form-text">
{{ $t("Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.") }}
</div>
</div>
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;"> <i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
<a href="https://docs.push.techulus.com" target="_blank">https://docs.push.techulus.com</a> <a href="https://docs.push.techulus.com" target="_blank">https://docs.push.techulus.com</a>
</i18n-t> </i18n-t>
@ -16,5 +63,19 @@ export default {
components: { components: {
HiddenInput, HiddenInput,
}, },
mounted() {
if (typeof this.$parent.notification.pushTitle === "undefined") {
this.$parent.notification.pushTitle = "Uptime-Kuma";
}
if (typeof this.$parent.notification.pushChannel === "undefined") {
this.$parent.notification.pushChannel = "uptime-kuma";
}
if (typeof this.$parent.notification.pushSound === "undefined") {
this.$parent.notification.pushSound = "default";
}
if (typeof this.$parent.notification.pushTimeSensitive === "undefined") {
this.$parent.notification.pushTimeSensitive = true;
}
},
}; };
</script> </script>

View file

@ -1027,5 +1027,25 @@
"greater than": "greater than", "greater than": "greater than",
"less than or equal to": "less than or equal to", "less than or equal to": "less than or equal to",
"greater than or equal to": "greater than or equal to", "greater than or equal to": "greater than or equal to",
"record": "record" "record": "record",
"Notification Channel": "Notification Channel",
"Sound": "Sound",
"Alphanumerical string and hyphens only": "Alphanumerical string and hyphens only",
"Arcade": "Arcade",
"Correct": "Correct",
"Fail":"Fail",
"Harp":"Harp",
"Reveal":"Reveal",
"Bubble":"Bubble",
"Doorbell":"Doorbell",
"Flute":"Flute",
"Money":"Money",
"Scifi":"Scifi",
"Clear":"Clear",
"Elevator":"Elevator",
"Guitar":"Guitar",
"Pop":"Pop",
"Custom sound to override default notification sound": "Custom sound to override default notification sound",
"Time Sensitive (iOS Only)": "Time Sensitive (iOS Only)",
"Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode."
} }

View file

@ -458,4 +458,4 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`); throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`);
} }
} }
exports.evaluateJsonQuery = evaluateJsonQuery; exports.evaluateJsonQuery = evaluateJsonQuery;

View file

@ -120,7 +120,11 @@ export const badgeConstants = {
defaultCertExpireDownDays: "7" defaultCertExpireDownDays: "7"
}; };
/** Flip the status of s */ /**
* Flip the status of s between UP and DOWN if this is possible
* @param s {number} status
* @returns {number} flipped status
*/
export function flipStatus(s: number) { export function flipStatus(s: number) {
if (s === UP) { if (s === UP) {
return DOWN; return DOWN;