mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-28 09:59:20 +08:00
Merge branch 'master' into ntfy-bearer-authorization
This commit is contained in:
@@ -159,6 +159,16 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Clear Form inputs */
|
||||
clearForm() {
|
||||
this.key = {
|
||||
name: "",
|
||||
expires: this.minDate,
|
||||
active: 1,
|
||||
};
|
||||
this.noExpire = false;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@@ -13,6 +13,9 @@
|
||||
:disabled="disabled"
|
||||
>
|
||||
|
||||
<!-- A hidden textarea for copying text on non-https -->
|
||||
<textarea ref="hiddenTextarea" style="position: fixed; left: -999999px; top: -999999px;"></textarea>
|
||||
|
||||
<a class="btn btn-outline-primary" @click="copyToClipboard(model)">
|
||||
<font-awesome-icon :icon="icon" />
|
||||
</a>
|
||||
@@ -111,24 +114,19 @@ export default {
|
||||
}, 3000);
|
||||
|
||||
// navigator clipboard api needs a secure context (https)
|
||||
// For http, use the text area method (else part)
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
// navigator clipboard api method'
|
||||
return navigator.clipboard.writeText(textToCopy);
|
||||
} else {
|
||||
// text area method
|
||||
let textArea = document.createElement("textarea");
|
||||
let textArea = this.$refs.hiddenTextarea;
|
||||
textArea.value = textToCopy;
|
||||
// make the textarea out of viewport
|
||||
textArea.style.position = "fixed";
|
||||
textArea.style.left = "-999999px";
|
||||
textArea.style.top = "-999999px";
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
return new Promise((res, rej) => {
|
||||
// here the magic happens
|
||||
document.execCommand("copy") ? res() : rej();
|
||||
textArea.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -129,6 +129,7 @@ export default {
|
||||
"ntfy": "Ntfy",
|
||||
"octopush": "Octopush",
|
||||
"OneBot": "OneBot",
|
||||
"Opsgenie": "Opsgenie",
|
||||
"PagerDuty": "PagerDuty",
|
||||
"pushbullet": "Pushbullet",
|
||||
"PushByTechulus": "Push by Techulus",
|
||||
@@ -143,6 +144,7 @@ export default {
|
||||
"stackfield": "Stackfield",
|
||||
"teams": "Microsoft Teams",
|
||||
"telegram": "Telegram",
|
||||
"twilio": "Twilio",
|
||||
"Splunk": "Splunk",
|
||||
"webhook": "Webhook",
|
||||
"GoAlert": "GoAlert",
|
||||
|
36
src/components/notifications/Opsgenie.vue
Normal file
36
src/components/notifications/Opsgenie.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="opsgenie-region" class="form-label">{{ $t("Region") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<select id="opsgenie-region" v-model="$parent.notification.opsgenieRegion" class="form-select" required>
|
||||
<option value="us">
|
||||
US (Default)
|
||||
</option>
|
||||
<option value="eu">
|
||||
EU
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="opsgenie-apikey" class="form-label">{{ $t("API Key") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<HiddenInput id="opsgenie-apikey" v-model="$parent.notification.opsgenieApiKey" required="true" autocomplete="false"></HiddenInput>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="opsgenie-priority" class="form-label">{{ $t("Priority") }}</label>
|
||||
<input id="opsgenie-priority" v-model="$parent.notification.opsgeniePriority" type="number" class="form-control" min="1" max="5" step="1">
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
|
||||
<a href="https://docs.opsgenie.com/docs/alert-api" target="_blank">https://docs.opsgenie.com/docs/alert-api</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
};
|
||||
</script>
|
27
src/components/notifications/Twilio.vue
Normal file
27
src/components/notifications/Twilio.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="twilio-account-sid" class="form-label">{{ $t("Account SID") }}</label>
|
||||
<input id="twilio-account-sid" v-model="$parent.notification.twilioAccountSID" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="twilio-auth-token" class="form-label">{{ $t("Auth Token") }}</label>
|
||||
<input id="twilio-auth-token" v-model="$parent.notification.twilioAuthToken" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="twilio-from-number" class="form-label">{{ $t("From Number") }}</label>
|
||||
<input id="twilio-from-number" v-model="$parent.notification.twilioFromNumber" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="twilio-to-number" class="form-label">{{ $t("To Number") }}</label>
|
||||
<input id="twilio-to-number" v-model="$parent.notification.twilioToNumber" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||
<a href="https://www.twilio.com/docs/sms" target="_blank">https://www.twilio.com/docs/sms</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</template>
|
@@ -21,6 +21,7 @@ import Mattermost from "./Mattermost.vue";
|
||||
import Ntfy from "./Ntfy.vue";
|
||||
import Octopush from "./Octopush.vue";
|
||||
import OneBot from "./OneBot.vue";
|
||||
import Opsgenie from "./Opsgenie.vue";
|
||||
import PagerDuty from "./PagerDuty.vue";
|
||||
import PagerTree from "./PagerTree.vue";
|
||||
import PromoSMS from "./PromoSMS.vue";
|
||||
@@ -41,6 +42,7 @@ import STMP from "./SMTP.vue";
|
||||
import Teams from "./Teams.vue";
|
||||
import TechulusPush from "./TechulusPush.vue";
|
||||
import Telegram from "./Telegram.vue";
|
||||
import Twilio from "./Twilio.vue";
|
||||
import Webhook from "./Webhook.vue";
|
||||
import WeCom from "./WeCom.vue";
|
||||
import GoAlert from "./GoAlert.vue";
|
||||
@@ -76,6 +78,7 @@ const NotificationFormList = {
|
||||
"ntfy": Ntfy,
|
||||
"octopush": Octopush,
|
||||
"OneBot": OneBot,
|
||||
"Opsgenie": Opsgenie,
|
||||
"PagerDuty": PagerDuty,
|
||||
"PagerTree": PagerTree,
|
||||
"promosms": PromoSMS,
|
||||
@@ -95,6 +98,7 @@ const NotificationFormList = {
|
||||
"stackfield": Stackfield,
|
||||
"teams": Teams,
|
||||
"telegram": Telegram,
|
||||
"twilio": Twilio,
|
||||
"Splunk": Splunk,
|
||||
"webhook": Webhook,
|
||||
"WeCom": WeCom,
|
||||
|
@@ -174,6 +174,7 @@
|
||||
"Avg. Response": "Avg. Response",
|
||||
"Entry Page": "Entry Page",
|
||||
"statusPageNothing": "Nothing here, please add a group or a monitor.",
|
||||
"statusPageRefreshIn": "Refresh in: {0}",
|
||||
"No Services": "No Services",
|
||||
"All Systems Operational": "All Systems Operational",
|
||||
"Partially Degraded Service": "Partially Degraded Service",
|
||||
@@ -708,5 +709,9 @@
|
||||
"lunaseaDeviceID": "Device ID",
|
||||
"lunaseaUserID": "User ID",
|
||||
"AuthenticationMethod": "Authentication Method",
|
||||
"UsernameAndPassword": "Username and Password"
|
||||
"UsernameAndPassword": "Username and Password",
|
||||
"twilioAccountSID": "Account SID",
|
||||
"twilioAuthToken": "Auth Token",
|
||||
"twilioFromNumber": "From Number",
|
||||
"twilioToNumber": "To Number"
|
||||
}
|
||||
|
@@ -944,6 +944,14 @@ message HealthCheckResponse {
|
||||
} else if (this.isEdit || this.isClone) {
|
||||
this.$root.getSocket().emit("getMonitor", this.$route.params.id, (res) => {
|
||||
if (res.ok) {
|
||||
|
||||
if (this.isClone) {
|
||||
// Reset push token for cloned monitors
|
||||
if (res.monitor.type === "push") {
|
||||
res.monitor.pushToken = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.monitor = res.monitor;
|
||||
|
||||
if (this.isClone) {
|
||||
|
@@ -306,6 +306,11 @@
|
||||
<p v-if="config.showPoweredBy">
|
||||
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
||||
</p>
|
||||
|
||||
<div class="refresh-info mb-2">
|
||||
<div>{{ $t("Last Updated") }}: <date-time :value="lastUpdateTime" /></div>
|
||||
<div>{{ $tc("statusPageRefreshIn", [ updateCountdownText]) }}</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -322,6 +327,7 @@
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import dayjs from "dayjs";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import Favico from "favico.js";
|
||||
// import highlighting library (you can use any library you want just return html string)
|
||||
import { highlight, languages } from "prismjs/components/prism-core";
|
||||
@@ -337,10 +343,12 @@ import DOMPurify from "dompurify";
|
||||
import Confirm from "../components/Confirm.vue";
|
||||
import PublicGroupList from "../components/PublicGroupList.vue";
|
||||
import MaintenanceTime from "../components/MaintenanceTime.vue";
|
||||
import DateTime from "../components/Datetime.vue";
|
||||
import { getResBaseURL } from "../util-frontend";
|
||||
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_MAINTENANCE, STATUS_PAGE_PARTIAL_DOWN, UP, MAINTENANCE } from "../util.ts";
|
||||
|
||||
const toast = useToast();
|
||||
dayjs.extend(duration);
|
||||
|
||||
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
||||
|
||||
@@ -359,6 +367,7 @@ export default {
|
||||
Confirm,
|
||||
PrismEditor,
|
||||
MaintenanceTime,
|
||||
DateTime,
|
||||
},
|
||||
|
||||
// Leave Page for vue route change
|
||||
@@ -400,6 +409,10 @@ export default {
|
||||
baseURL: "",
|
||||
clickedEditButton: false,
|
||||
maintenanceList: [],
|
||||
autoRefreshInterval: 5,
|
||||
lastUpdateTime: dayjs(),
|
||||
updateCountdown: null,
|
||||
updateCountdownText: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -637,11 +650,13 @@ export default {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
// 5mins a loop
|
||||
// Configure auto-refresh loop
|
||||
this.updateHeartbeatList();
|
||||
feedInterval = setInterval(() => {
|
||||
this.updateHeartbeatList();
|
||||
}, (300 + 10) * 1000);
|
||||
}, (this.autoRefreshInterval * 60 + 10) * 1000);
|
||||
|
||||
this.updateUpdateTimer();
|
||||
|
||||
// Go to edit page if ?edit present
|
||||
// null means ?edit present, but no value
|
||||
@@ -700,10 +715,29 @@ export default {
|
||||
favicon.badge(downMonitors);
|
||||
|
||||
this.loadedData = true;
|
||||
this.lastUpdateTime = dayjs();
|
||||
this.updateUpdateTimer();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup timer to display countdown to refresh
|
||||
* @returns {void}
|
||||
*/
|
||||
updateUpdateTimer() {
|
||||
clearInterval(this.updateCountdown);
|
||||
|
||||
this.updateCountdown = setInterval(() => {
|
||||
const countdown = dayjs.duration(this.lastUpdateTime.add(this.autoRefreshInterval, "minutes").add(10, "seconds").diff(dayjs()));
|
||||
if (countdown.as("seconds") < 0) {
|
||||
clearInterval(this.updateCountdown);
|
||||
} else {
|
||||
this.updateCountdownText = countdown.format("mm:ss");
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
/** Enable editing mode */
|
||||
edit() {
|
||||
if (this.hasToken) {
|
||||
@@ -1118,4 +1152,8 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
.refresh-info {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user