# Conflicts: # src/pages/StatusPage.vuepull/2752/head
commit
9dd1b1ca0f
@ -0,0 +1 @@
|
|||||||
|
# This is a .gitignore style file for 'GrantBirki/json-yaml-validate' Action workflow
|
@ -0,0 +1,26 @@
|
|||||||
|
name: json-yaml-validate
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write # enable write permissions for pull request comments
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
json-yaml-validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: json-yaml-validate
|
||||||
|
id: json-yaml-validate
|
||||||
|
uses: GrantBirki/json-yaml-validate@v1.3.0
|
||||||
|
with:
|
||||||
|
comment: "true" # enable comment mode
|
||||||
|
exclude_file: ".github/config/exclude.txt" # gitignore style file for exclusions
|
@ -0,0 +1,13 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
CREATE TABLE [api_key] (
|
||||||
|
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
[key] VARCHAR(255) NOT NULL,
|
||||||
|
[name] VARCHAR(255) NOT NULL,
|
||||||
|
[user_id] INTEGER NOT NULL,
|
||||||
|
[created_date] DATETIME DEFAULT (DATETIME('now')) NOT NULL,
|
||||||
|
[active] BOOLEAN DEFAULT 1 NOT NULL,
|
||||||
|
[expires] DATETIME DEFAULT NULL,
|
||||||
|
CONSTRAINT FK_user FOREIGN KEY ([user_id]) REFERENCES [user]([id]) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
COMMIT;
|
@ -0,0 +1,11 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP TABLE maintenance_timeslot;
|
||||||
|
|
||||||
|
-- 999 characters. https://stackoverflow.com/questions/46134830/maximum-length-for-cron-job
|
||||||
|
ALTER TABLE maintenance ADD cron TEXT;
|
||||||
|
ALTER TABLE maintenance ADD timezone VARCHAR(255);
|
||||||
|
ALTER TABLE maintenance ADD duration INTEGER;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -0,0 +1,13 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD tls_ca TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD tls_cert TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD tls_key TEXT default null;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -0,0 +1,22 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
// Read the file from private/sort-contributors.txt
|
||||||
|
const file = fs.readFileSync("private/sort-contributors.txt", "utf8");
|
||||||
|
|
||||||
|
// Convert to an array of lines
|
||||||
|
let lines = file.split("\n");
|
||||||
|
|
||||||
|
// Remove empty lines
|
||||||
|
lines = lines.filter((line) => line !== "");
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
lines = [ ...new Set(lines) ];
|
||||||
|
|
||||||
|
// Remove @weblate and @UptimeKumaBot
|
||||||
|
lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam");
|
||||||
|
|
||||||
|
// Sort the lines
|
||||||
|
lines = lines.sort();
|
||||||
|
|
||||||
|
// Output the lines, concat with " "
|
||||||
|
console.log(lines.join(" "));
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,76 @@
|
|||||||
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const dayjs = require("dayjs");
|
||||||
|
|
||||||
|
class APIKey extends BeanModel {
|
||||||
|
/**
|
||||||
|
* Get the current status of this API key
|
||||||
|
* @returns {string} active, inactive or expired
|
||||||
|
*/
|
||||||
|
getStatus() {
|
||||||
|
let current = dayjs();
|
||||||
|
let expiry = dayjs(this.expires);
|
||||||
|
if (expiry.diff(current) < 0) {
|
||||||
|
return "expired";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.active ? "active" : "inactive";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object that ready to parse to JSON
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
key: this.key,
|
||||||
|
name: this.name,
|
||||||
|
userID: this.user_id,
|
||||||
|
createdDate: this.created_date,
|
||||||
|
active: this.active,
|
||||||
|
expires: this.expires,
|
||||||
|
status: this.getStatus(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object that ready to parse to JSON with sensitive fields
|
||||||
|
* removed
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
toPublicJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
userID: this.user_id,
|
||||||
|
createdDate: this.created_date,
|
||||||
|
active: this.active,
|
||||||
|
expires: this.expires,
|
||||||
|
status: this.getStatus(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new API Key and store it in the database
|
||||||
|
* @param {Object} key Object sent by client
|
||||||
|
* @param {int} userID ID of socket user
|
||||||
|
* @returns {Promise<bean>}
|
||||||
|
*/
|
||||||
|
static async save(key, userID) {
|
||||||
|
let bean;
|
||||||
|
bean = R.dispense("api_key");
|
||||||
|
|
||||||
|
bean.key = key.key;
|
||||||
|
bean.name = key.name;
|
||||||
|
bean.user_id = userID;
|
||||||
|
bean.active = key.active;
|
||||||
|
bean.expires = key.expires;
|
||||||
|
|
||||||
|
await R.store(bean);
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = APIKey;
|
@ -1,198 +0,0 @@
|
|||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
|
||||||
const { R } = require("redbean-node");
|
|
||||||
const dayjs = require("dayjs");
|
|
||||||
const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND, localToUTC } = require("../../src/util");
|
|
||||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
|
||||||
|
|
||||||
class MaintenanceTimeslot extends BeanModel {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an object that ready to parse to JSON for public
|
|
||||||
* Only show necessary data to public
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
async toPublicJSON() {
|
|
||||||
const serverTimezoneOffset = UptimeKumaServer.getInstance().getTimezoneOffset();
|
|
||||||
|
|
||||||
const obj = {
|
|
||||||
id: this.id,
|
|
||||||
startDate: this.start_date,
|
|
||||||
endDate: this.end_date,
|
|
||||||
startDateServerTimezone: utcToLocal(this.start_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
|
|
||||||
endDateServerTimezone: utcToLocal(this.end_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
|
|
||||||
serverTimezoneOffset,
|
|
||||||
};
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an object that ready to parse to JSON
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
async toJSON() {
|
|
||||||
return await this.toPublicJSON();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Maintenance} maintenance
|
|
||||||
* @param {dayjs} minDate (For recurring type only) Generate a next timeslot from this date.
|
|
||||||
* @param {boolean} removeExist Remove existing timeslot before create
|
|
||||||
* @returns {Promise<MaintenanceTimeslot>}
|
|
||||||
*/
|
|
||||||
static async generateTimeslot(maintenance, minDate = null, removeExist = false) {
|
|
||||||
if (removeExist) {
|
|
||||||
await R.exec("DELETE FROM maintenance_timeslot WHERE maintenance_id = ? ", [
|
|
||||||
maintenance.id
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maintenance.strategy === "manual") {
|
|
||||||
log.debug("maintenance", "No need to generate timeslot for manual type");
|
|
||||||
|
|
||||||
} else if (maintenance.strategy === "single") {
|
|
||||||
let bean = R.dispense("maintenance_timeslot");
|
|
||||||
bean.maintenance_id = maintenance.id;
|
|
||||||
bean.start_date = maintenance.start_date;
|
|
||||||
bean.end_date = maintenance.end_date;
|
|
||||||
bean.generated_next = true;
|
|
||||||
return await R.store(bean);
|
|
||||||
|
|
||||||
} else if (maintenance.strategy === "recurring-interval") {
|
|
||||||
// Prevent dead loop, in case interval_day is not set
|
|
||||||
if (!maintenance.interval_day || maintenance.interval_day <= 0) {
|
|
||||||
maintenance.interval_day = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
|
||||||
return startDateTime.add(maintenance.interval_day, "day");
|
|
||||||
}, () => {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if (maintenance.strategy === "recurring-weekday") {
|
|
||||||
let dayOfWeekList = maintenance.getDayOfWeekList();
|
|
||||||
log.debug("timeslot", dayOfWeekList);
|
|
||||||
|
|
||||||
if (dayOfWeekList.length <= 0) {
|
|
||||||
log.debug("timeslot", "No weekdays selected?");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValid = (startDateTime) => {
|
|
||||||
log.debug("timeslot", "nextDateTime: " + startDateTime);
|
|
||||||
|
|
||||||
let day = startDateTime.local().day();
|
|
||||||
log.debug("timeslot", "nextDateTime.day(): " + day);
|
|
||||||
|
|
||||||
return dayOfWeekList.includes(day);
|
|
||||||
};
|
|
||||||
|
|
||||||
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
|
||||||
while (true) {
|
|
||||||
startDateTime = startDateTime.add(1, "day");
|
|
||||||
|
|
||||||
if (isValid(startDateTime)) {
|
|
||||||
return startDateTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, isValid);
|
|
||||||
|
|
||||||
} else if (maintenance.strategy === "recurring-day-of-month") {
|
|
||||||
let dayOfMonthList = maintenance.getDayOfMonthList();
|
|
||||||
if (dayOfMonthList.length <= 0) {
|
|
||||||
log.debug("timeslot", "No day selected?");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValid = (startDateTime) => {
|
|
||||||
let day = parseInt(startDateTime.local().format("D"));
|
|
||||||
|
|
||||||
log.debug("timeslot", "day: " + day);
|
|
||||||
|
|
||||||
// Check 1-31
|
|
||||||
if (dayOfMonthList.includes(day)) {
|
|
||||||
return startDateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check "lastDay1","lastDay2"...
|
|
||||||
let daysInMonth = startDateTime.daysInMonth();
|
|
||||||
let lastDayList = [];
|
|
||||||
|
|
||||||
// Small first, e.g. 28 > 29 > 30 > 31
|
|
||||||
for (let i = 4; i >= 1; i--) {
|
|
||||||
if (dayOfMonthList.includes("lastDay" + i)) {
|
|
||||||
lastDayList.push(daysInMonth - i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("timeslot", lastDayList);
|
|
||||||
return lastDayList.includes(day);
|
|
||||||
};
|
|
||||||
|
|
||||||
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
|
||||||
while (true) {
|
|
||||||
startDateTime = startDateTime.add(1, "day");
|
|
||||||
if (isValid(startDateTime)) {
|
|
||||||
return startDateTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, isValid);
|
|
||||||
} else {
|
|
||||||
throw new Error("Unknown maintenance strategy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a next timeslot for all recurring types
|
|
||||||
* @param maintenance
|
|
||||||
* @param minDate
|
|
||||||
* @param {function} nextDayCallback The logic how to get the next possible day
|
|
||||||
* @param {function} isValidCallback Check the day whether is matched the current strategy
|
|
||||||
* @returns {Promise<null|MaintenanceTimeslot>}
|
|
||||||
*/
|
|
||||||
static async handleRecurringType(maintenance, minDate, nextDayCallback, isValidCallback) {
|
|
||||||
let bean = R.dispense("maintenance_timeslot");
|
|
||||||
|
|
||||||
let duration = maintenance.getDuration();
|
|
||||||
let startDateTime = maintenance.getStartDateTime();
|
|
||||||
let endDateTime;
|
|
||||||
|
|
||||||
// Keep generating from the first possible date, until it is ok
|
|
||||||
while (true) {
|
|
||||||
log.debug("timeslot", "startDateTime: " + startDateTime.format());
|
|
||||||
|
|
||||||
// Handling out of effective date range
|
|
||||||
if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
|
||||||
log.debug("timeslot", "Out of effective date range");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
endDateTime = startDateTime.add(duration, "second");
|
|
||||||
|
|
||||||
// If endDateTime is out of effective date range, use the end datetime from effective date range
|
|
||||||
if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
|
||||||
endDateTime = dayjs.utc(maintenance.end_date);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If minDate is set, the endDateTime must be bigger than it.
|
|
||||||
// And the endDateTime must be bigger current time
|
|
||||||
// Is valid under current recurring strategy
|
|
||||||
if (
|
|
||||||
(!minDate || endDateTime.diff(minDate) > 0) &&
|
|
||||||
endDateTime.diff(dayjs()) > 0 &&
|
|
||||||
isValidCallback(startDateTime)
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
startDateTime = nextDayCallback(startDateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
bean.maintenance_id = maintenance.id;
|
|
||||||
bean.start_date = localToUTC(startDateTime);
|
|
||||||
bean.end_date = localToUTC(endDateTime);
|
|
||||||
bean.generated_next = false;
|
|
||||||
return await R.store(bean);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MaintenanceTimeslot;
|
|
@ -0,0 +1,97 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { UP, DOWN } = require("../../src/util");
|
||||||
|
|
||||||
|
const opsgenieAlertsUrlEU = "https://api.eu.opsgenie.com/v2/alerts";
|
||||||
|
const opsgenieAlertsUrlUS = "https://api.opsgenie.com/v2/alerts";
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
class Opsgenie extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "Opsgenie";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let opsgenieAlertsUrl;
|
||||||
|
let priority = (notification.opsgeniePriority == "") ? 3 : notification.opsgeniePriority;
|
||||||
|
const textMsg = "Uptime Kuma Alert";
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (notification.opsgenieRegion) {
|
||||||
|
case "US":
|
||||||
|
opsgenieAlertsUrl = opsgenieAlertsUrlUS;
|
||||||
|
break;
|
||||||
|
case "EU":
|
||||||
|
opsgenieAlertsUrl = opsgenieAlertsUrlEU;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
opsgenieAlertsUrl = opsgenieAlertsUrlUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let notificationTestAlias = "uptime-kuma-notification-test";
|
||||||
|
let data = {
|
||||||
|
"message": msg,
|
||||||
|
"alias": notificationTestAlias,
|
||||||
|
"source": "Uptime Kuma",
|
||||||
|
"priority": "P5"
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.post(notification, opsgenieAlertsUrl, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON.status === DOWN) {
|
||||||
|
let data = {
|
||||||
|
"message": monitorJSON ? textMsg + `: ${monitorJSON.name}` : textMsg,
|
||||||
|
"alias": monitorJSON.name,
|
||||||
|
"description": msg,
|
||||||
|
"source": "Uptime Kuma",
|
||||||
|
"priority": `P${priority}`
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.post(notification, opsgenieAlertsUrl, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON.status === UP) {
|
||||||
|
let opsgenieAlertsCloseUrl = `${opsgenieAlertsUrl}/${encodeURIComponent(monitorJSON.name)}/close?identifierType=alias`;
|
||||||
|
let data = {
|
||||||
|
"source": "Uptime Kuma",
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.post(notification, opsgenieAlertsCloseUrl, data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {BeanModel} notification
|
||||||
|
* @param {string} url Request url
|
||||||
|
* @param {Object} data Request body
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async post(notification, url, data) {
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": `GenieKey ${notification.opsgenieApiKey}`,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = await axios.post(url, data, config);
|
||||||
|
if (res.status == null) {
|
||||||
|
return "Opsgenie notification failed with invalid response!";
|
||||||
|
}
|
||||||
|
if (res.status < 200 || res.status >= 300) {
|
||||||
|
return `Opsgenie notification failed with status code ${res.status}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Opsgenie;
|
@ -0,0 +1,91 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||||
|
const { setting } = require("../util-server");
|
||||||
|
let successMessage = "Sent Successfully.";
|
||||||
|
|
||||||
|
class PagerTree extends NotificationProvider {
|
||||||
|
name = "PagerTree";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
// general messages
|
||||||
|
return this.postNotification(notification, msg, monitorJSON, heartbeatJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON.status === UP && notification.pagertreeAutoResolve === "resolve") {
|
||||||
|
return this.postNotification(notification, null, monitorJSON, heartbeatJSON, notification.pagertreeAutoResolve);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON.status === DOWN) {
|
||||||
|
const title = `Uptime Kuma Monitor "${monitorJSON.name}" is DOWN`;
|
||||||
|
return this.postNotification(notification, title, monitorJSON, heartbeatJSON);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if result is successful, result code should be in range 2xx
|
||||||
|
* @param {Object} result Axios response object
|
||||||
|
* @throws {Error} The status code is not in range 2xx
|
||||||
|
*/
|
||||||
|
checkResult(result) {
|
||||||
|
if (result.status == null) {
|
||||||
|
throw new Error("PagerTree notification failed with invalid response!");
|
||||||
|
}
|
||||||
|
if (result.status < 200 || result.status >= 300) {
|
||||||
|
throw new Error("PagerTree notification failed with status code " + result.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the message
|
||||||
|
* @param {BeanModel} notification Message title
|
||||||
|
* @param {string} title Message title
|
||||||
|
* @param {Object} monitorJSON Monitor details (For Up/Down only)
|
||||||
|
* @param {?string} eventAction Action event for PagerTree (create, resolve)
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async postNotification(notification, title, monitorJSON, heartbeatJSON, eventAction = "create") {
|
||||||
|
|
||||||
|
if (eventAction == null) {
|
||||||
|
return "No action required";
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: "POST",
|
||||||
|
url: notification.pagertreeIntegrationUrl,
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
data: {
|
||||||
|
event_type: eventAction,
|
||||||
|
id: heartbeatJSON?.monitorID || "uptime-kuma",
|
||||||
|
title: title,
|
||||||
|
urgency: notification.pagertreeUrgency,
|
||||||
|
heartbeat: heartbeatJSON,
|
||||||
|
monitor: monitorJSON
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseURL = await setting("primaryBaseURL");
|
||||||
|
if (baseURL && monitorJSON) {
|
||||||
|
options.client = "Uptime Kuma";
|
||||||
|
options.client_url = baseURL + getMonitorRelativeURL(monitorJSON.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = await axios.request(options);
|
||||||
|
this.checkResult(result);
|
||||||
|
if (result.statusText != null) {
|
||||||
|
return "PagerTree notification succeed: " + result.statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return successMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PagerTree;
|
@ -0,0 +1,41 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Twilio extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "twilio";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
let accountSID = notification.twilioAccountSID;
|
||||||
|
let authToken = notification.twilioAuthToken;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
|
||||||
|
"Authorization": "Basic " + Buffer.from(accountSID + ":" + authToken).toString("base64"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = new URLSearchParams();
|
||||||
|
data.append("To", notification.twilioToNumber);
|
||||||
|
data.append("From", notification.twilioFromNumber);
|
||||||
|
data.append("Body", msg);
|
||||||
|
|
||||||
|
let url = "https://api.twilio.com/2010-04-01/Accounts/" + accountSID + "/Messages.json";
|
||||||
|
|
||||||
|
await axios.post(url, data, config);
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Twilio;
|
@ -0,0 +1,150 @@
|
|||||||
|
const { checkLogin } = require("../util-server");
|
||||||
|
const { log } = require("../../src/util");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const { nanoid } = require("nanoid");
|
||||||
|
const passwordHash = require("../password-hash");
|
||||||
|
const apicache = require("../modules/apicache");
|
||||||
|
const APIKey = require("../model/api_key");
|
||||||
|
const { Settings } = require("../settings");
|
||||||
|
const { sendAPIKeyList } = require("../client");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handlers for Maintenance
|
||||||
|
* @param {Socket} socket Socket.io instance
|
||||||
|
*/
|
||||||
|
module.exports.apiKeySocketHandler = (socket) => {
|
||||||
|
// Add a new api key
|
||||||
|
socket.on("addAPIKey", async (key, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
let clearKey = nanoid(40);
|
||||||
|
let hashedKey = passwordHash.generate(clearKey);
|
||||||
|
key["key"] = hashedKey;
|
||||||
|
let bean = await APIKey.save(key, socket.userID);
|
||||||
|
|
||||||
|
log.debug("apikeys", "Added API Key");
|
||||||
|
log.debug("apikeys", key);
|
||||||
|
|
||||||
|
// Append key ID and prefix to start of key seperated by _, used to get
|
||||||
|
// correct hash when validating key.
|
||||||
|
let formattedKey = "uk" + bean.id + "_" + clearKey;
|
||||||
|
await sendAPIKeyList(socket);
|
||||||
|
|
||||||
|
// Enable API auth if the user creates a key, otherwise only basic
|
||||||
|
// auth will be used for API.
|
||||||
|
await Settings.set("apiKeysEnabled", true);
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Added Successfully.",
|
||||||
|
key: formattedKey,
|
||||||
|
keyID: bean.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("getAPIKeyList", async (callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
await sendAPIKeyList(socket);
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("deleteAPIKey", async (keyID, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
log.debug("apikeys", `Deleted API Key: ${keyID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
await R.exec("DELETE FROM api_key WHERE id = ? AND user_id = ? ", [
|
||||||
|
keyID,
|
||||||
|
socket.userID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
apicache.clear();
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Deleted Successfully.",
|
||||||
|
});
|
||||||
|
|
||||||
|
await sendAPIKeyList(socket);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disableAPIKey", async (keyID, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
log.debug("apikeys", `Disabled Key: ${keyID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
await R.exec("UPDATE api_key SET active = 0 WHERE id = ? ", [
|
||||||
|
keyID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
apicache.clear();
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Disabled Successfully.",
|
||||||
|
});
|
||||||
|
|
||||||
|
await sendAPIKeyList(socket);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("enableAPIKey", async (keyID, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
log.debug("apikeys", `Enabled Key: ${keyID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
await R.exec("UPDATE api_key SET active = 1 WHERE id = ? ", [
|
||||||
|
keyID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
apicache.clear();
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Enabled Successfully",
|
||||||
|
});
|
||||||
|
|
||||||
|
await sendAPIKeyList(socket);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,229 @@
|
|||||||
|
<template>
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<div ref="keyaddmodal" class="modal fade" tabindex="-1" data-bs-backdrop="static">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
{{ $t("Add API Key") }}
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">{{ $t("Name") }}</label>
|
||||||
|
<input
|
||||||
|
id="name" v-model="key.name" type="text" class="form-control"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Expiry -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label class="form-label">{{ $t("Expiry date") }}</label>
|
||||||
|
<div class="d-flex flex-row align-items-center">
|
||||||
|
<div class="col-6">
|
||||||
|
<Datepicker
|
||||||
|
v-model="key.expires"
|
||||||
|
:dark="$root.isDark"
|
||||||
|
:monthChangeOnScroll="false"
|
||||||
|
:minDate="minDate"
|
||||||
|
format="yyyy-MM-dd HH:mm"
|
||||||
|
modelType="yyyy-MM-dd HH:mm:ss"
|
||||||
|
:required="!noExpire"
|
||||||
|
:disabled="noExpire"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 ms-3">
|
||||||
|
<div class="form-check mb-0">
|
||||||
|
<input
|
||||||
|
id="no-expire" v-model="noExpire" class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
>
|
||||||
|
<label class="form-check-label" for="no-expire">{{
|
||||||
|
$t("Don't expire")
|
||||||
|
}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button
|
||||||
|
id="monitor-submit-btn" class="btn btn-primary" type="submit"
|
||||||
|
:disabled="processing"
|
||||||
|
>
|
||||||
|
{{ $t("Generate") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ref="keymodal" class="modal fade" tabindex="-1" data-bs-backdrop="static">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
{{ $t("Key Added") }}
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ $t("apiKeyAddedMsg") }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<CopyableInput v-model="clearKey" disabled="disabled" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">
|
||||||
|
{{ $t('Continue') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import Datepicker from "@vuepic/vue-datepicker";
|
||||||
|
import CopyableInput from "./CopyableInput.vue";
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CopyableInput,
|
||||||
|
Datepicker
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
// emits: [ "added" ],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
keyaddmodal: null,
|
||||||
|
keymodal: null,
|
||||||
|
processing: false,
|
||||||
|
key: {},
|
||||||
|
dark: (this.$root.theme === "dark"),
|
||||||
|
minDate: this.$root.date(dayjs()) + " 00:00",
|
||||||
|
clearKey: null,
|
||||||
|
noExpire: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.keyaddmodal = new Modal(this.$refs.keyaddmodal);
|
||||||
|
this.keymodal = new Modal(this.$refs.keymodal);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Show modal
|
||||||
|
*/
|
||||||
|
show() {
|
||||||
|
this.id = null;
|
||||||
|
this.key = {
|
||||||
|
name: "",
|
||||||
|
expires: this.minDate,
|
||||||
|
active: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.keyaddmodal.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Submit data to server */
|
||||||
|
async submit() {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
if (this.noExpire) {
|
||||||
|
this.key.expires = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$root.addAPIKey(this.key, async (res) => {
|
||||||
|
this.keyaddmodal.hide();
|
||||||
|
this.processing = false;
|
||||||
|
if (res.ok) {
|
||||||
|
this.clearKey = res.key;
|
||||||
|
this.keymodal.show();
|
||||||
|
this.clearForm();
|
||||||
|
} else {
|
||||||
|
toast.error(res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Clear Form inputs */
|
||||||
|
clearForm() {
|
||||||
|
this.key = {
|
||||||
|
name: "",
|
||||||
|
expires: this.minDate,
|
||||||
|
active: 1,
|
||||||
|
};
|
||||||
|
this.noExpire = false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../assets/vars.scss";
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.modal-dialog .form-text, .modal-dialog p {
|
||||||
|
color: $dark-font-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow-box {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-calendar::-webkit-calendar-picker-indicator {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.weekday-picker {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
|
||||||
|
.form-check-inline {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-picker {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
|
||||||
|
.form-check-inline {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,9 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="lunasea-device" class="form-label">{{ $t("LunaSea Device ID") }}<span style="color: red;"><sup>*</sup></span></label>
|
<label for="lunasea-notification-target" class="form-label">{{ $t("lunaseaTarget") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
<input id="lunasea-device" v-model="$parent.notification.lunaseaDevice" type="text" class="form-control" required>
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p>
|
<p>
|
||||||
|
<select id="lunasea-notification-target" v-model="$parent.notification.lunaseaTarget" class="form-select" required>
|
||||||
|
<option value="device">{{ $t("lunaseaDeviceID") }}</option>
|
||||||
|
<option value="user">{{ $t("lunaseaUserID") }}</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="$parent.notification.lunaseaTarget === 'device'">
|
||||||
|
<label for="lunasea-device" class="form-label">{{ $t("lunaseaDeviceID") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="lunasea-device" v-model="$parent.notification.lunaseaDevice" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
<div v-if="$parent.notification.lunaseaTarget === 'user'">
|
||||||
|
<label for="lunasea-device" class="form-label">{{ $t("lunaseaUserID") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="lunasea-device" v-model="$parent.notification.lunaseaUserID" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted() {
|
||||||
|
if (typeof this.$parent.notification.lunaseaTarget === "undefined") {
|
||||||
|
this.$parent.notification.lunaseaTarget = "device";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@ -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>
|
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="pagertree-integration-url" class="form-label">{{ $t("pagertreeIntegrationUrl") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="pagertree-integration-url" v-model="$parent.notification.pagertreeIntegrationUrl" type="text" class="form-control" autocomplete="false">
|
||||||
|
<i18n-t tag="div" keypath="wayToGetPagerTreeIntegrationURL" class="form-text">
|
||||||
|
<a href="https://pagertree.com/docs/integration-guides/introduction#copy-the-endpoint-url" target="_blank">{{ $t("here") }}</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="pagertree-urgency" class="form-label">{{ $t("pagertreeUrgency") }}</label>
|
||||||
|
<select id="pagertree-urgency" v-model="$parent.notification.pagertreeUrgency" class="form-select">
|
||||||
|
<option value="silent">{{ $t("pagertreeSilent") }}</option>
|
||||||
|
<option value="low">{{ $t("pagertreeLow") }}</option>
|
||||||
|
<option value="medium" selected="selected">{{ $t("pagertreeMedium") }}</option>
|
||||||
|
<option value="high">{{ $t("pagertreeHigh") }}</option>
|
||||||
|
<option value="critical">{{ $t("pagertreeCritical") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="pagertree-resolve" class="form-label">{{ $t("pagertreeResolve") }}</label>
|
||||||
|
<select id="pagertree-resolve" v-model="$parent.notification.pagertreeAutoResolve" class="form-select">
|
||||||
|
<option value="resolve" selected="selected">{{ $t("pagertreeResolve") }}</option>
|
||||||
|
<option value="0">{{ $t("pagertreeDoNothing") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
};
|
||||||
|
</script>
|
@ -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>
|
@ -0,0 +1,257 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="add-btn">
|
||||||
|
<button class="btn btn-primary me-2" type="button" @click="$refs.apiKeyDialog.show()">
|
||||||
|
<font-awesome-icon icon="plus" /> {{ $t("Add API Key") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span v-if="Object.keys(keyList).length === 0" class="d-flex align-items-center justify-content-center my-3">
|
||||||
|
{{ $t("No API Keys") }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in keyList"
|
||||||
|
:key="index"
|
||||||
|
class="item"
|
||||||
|
:class="item.status"
|
||||||
|
>
|
||||||
|
<div class="left-part">
|
||||||
|
<div
|
||||||
|
class="circle"
|
||||||
|
></div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">{{ item.name }}</div>
|
||||||
|
<div class="status">
|
||||||
|
{{ $t("apiKey-" + item.status) }}
|
||||||
|
</div>
|
||||||
|
<div class="date">
|
||||||
|
{{ $t("Created") }}: {{ item.createdDate }}
|
||||||
|
</div>
|
||||||
|
<div class="date">
|
||||||
|
{{ $t("Expires") }}: {{ item.expires || $t("Never") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<button v-if="item.active" class="btn btn-normal" @click="disableDialog(item.id)">
|
||||||
|
<font-awesome-icon icon="pause" /> {{ $t("Disable") }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button v-if="!item.active" class="btn btn-primary" @click="enableKey(item.id)">
|
||||||
|
<font-awesome-icon icon="play" /> {{ $t("Enable") }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-danger" @click="deleteDialog(item.id)">
|
||||||
|
<font-awesome-icon icon="trash" /> {{ $t("Delete") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center mt-3" style="font-size: 13px;">
|
||||||
|
<a href="https://github.com/louislam/uptime-kuma/wiki/API-Keys" target="_blank">{{ $t("Learn More") }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Confirm ref="confirmPause" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="disableKey">
|
||||||
|
{{ $t("disableAPIKeyMsg") }}
|
||||||
|
</Confirm>
|
||||||
|
|
||||||
|
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteKey">
|
||||||
|
{{ $t("deleteAPIKeyMsg") }}
|
||||||
|
</Confirm>
|
||||||
|
|
||||||
|
<APIKeyDialog ref="apiKeyDialog" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import APIKeyDialog from "../../components/APIKeyDialog.vue";
|
||||||
|
import Confirm from "../Confirm.vue";
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
APIKeyDialog,
|
||||||
|
Confirm,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedKeyID: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
keyList() {
|
||||||
|
let result = Object.values(this.$root.apiKeyList);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Show dialog to confirm deletion
|
||||||
|
* @param {number} keyID ID of monitor that is being deleted
|
||||||
|
*/
|
||||||
|
deleteDialog(keyID) {
|
||||||
|
this.selectedKeyID = keyID;
|
||||||
|
this.$refs.confirmDelete.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a key
|
||||||
|
*/
|
||||||
|
deleteKey() {
|
||||||
|
this.$root.deleteAPIKey(this.selectedKeyID, (res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
toast.success(res.msg);
|
||||||
|
} else {
|
||||||
|
toast.error(res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show dialog to confirm pause
|
||||||
|
*/
|
||||||
|
disableDialog(keyID) {
|
||||||
|
this.selectedKeyID = keyID;
|
||||||
|
this.$refs.confirmPause.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause maintenance
|
||||||
|
*/
|
||||||
|
disableKey() {
|
||||||
|
this.$root.getSocket().emit("disableAPIKey", this.selectedKeyID, (res) => {
|
||||||
|
this.$root.toastRes(res);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume maintenance
|
||||||
|
*/
|
||||||
|
enableKey(id) {
|
||||||
|
this.$root.getSocket().emit("enableAPIKey", id, (res) => {
|
||||||
|
this.$root.toastRes(res);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../assets/vars.scss";
|
||||||
|
|
||||||
|
.mobile {
|
||||||
|
.item {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition: all ease-in-out 0.15s;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 90px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $highlight-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.circle {
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inactive {
|
||||||
|
.circle {
|
||||||
|
background-color: $danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.expired {
|
||||||
|
.left-part {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
background-color: $dark-font-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-part {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 50rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
width: 310px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
margin-top: 5px;
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0 10px;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
color: white;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.item {
|
||||||
|
&:hover {
|
||||||
|
background-color: $dark-bg2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,688 @@
|
|||||||
|
{
|
||||||
|
"Edit": "تعديل",
|
||||||
|
"Delete": "حذف",
|
||||||
|
"Current": "حالي",
|
||||||
|
"Uptime": "مدة التشغيل",
|
||||||
|
"Monitor": "مراقب | مراقبات",
|
||||||
|
"day": "يوم | أيام",
|
||||||
|
"-day": "-يوم",
|
||||||
|
"hour": "ساعة",
|
||||||
|
"-hour": "-ساعة",
|
||||||
|
"Response": "استجاية",
|
||||||
|
"Ping": "بينغ",
|
||||||
|
"Monitor Type": "نوع المراقب",
|
||||||
|
"Cert Exp.": "انتهاء صَلاحِيَة شهادة الأمان SSL",
|
||||||
|
"Theme - Heartbeat Bar": "موضوع - بار نبضات",
|
||||||
|
"Normal": "طبيعي",
|
||||||
|
"Bottom": "الأسفل",
|
||||||
|
"None": "لا أحد",
|
||||||
|
"Current Password": "كلمة المرور الحالي",
|
||||||
|
"New Password": "كلمة سر جديدة",
|
||||||
|
"Repeat New Password": "كرر كلمة المرور الجديدة",
|
||||||
|
"Update Password": "تطوير كلمة السر",
|
||||||
|
"Disable Auth": "تعطيل المصادقة",
|
||||||
|
"Enable Auth": "تمكين المصادقة",
|
||||||
|
"disableauth.message1": "هل أنت متأكد من أن <strong> تعطيل المصادقة </strong>؟",
|
||||||
|
"disableauth.message2": "تم تصميمه للسيناريوهات <strong> حيث تنوي تنفيذ مصادقة الطرف الثالث </strong> أمام كوما في وقت التشغيل مثل CloudFlare Access Authelia أو آليات المصادقة الأخرى.",
|
||||||
|
"Please use this option carefully!": "الرجاء استخدام هذا الخيار بعناية!",
|
||||||
|
"Logout": "تسجيل خروج",
|
||||||
|
"Leave": "غادر",
|
||||||
|
"I understand, please disable": "أنا أفهم من فضلك تعطيل",
|
||||||
|
"Confirm": "يتأكد",
|
||||||
|
"Yes": "نعم",
|
||||||
|
"No": "رقم",
|
||||||
|
"Username": "اسم المستخدم",
|
||||||
|
"Password": "كلمة المرور",
|
||||||
|
"Remember me": "تذكرنى",
|
||||||
|
"Login": "تسجيل الدخول",
|
||||||
|
"No Monitors, please": "لا شاشات من فضلك",
|
||||||
|
"alertNoFile": "الرجاء تحديد ملف للاستيراد.",
|
||||||
|
"Skip existing": "تخطي الموجود",
|
||||||
|
"Search...": "يبحث…",
|
||||||
|
"Avg. Ping": "متوسط. بينغ",
|
||||||
|
"Avg. Response": "متوسط. إجابة",
|
||||||
|
"Entry Page": "صفحة الدخول",
|
||||||
|
"statusPageNothing": "لا شيء هنا الرجاء إضافة مجموعة أو شاشة.",
|
||||||
|
"No Services": "لا توجد خدمات",
|
||||||
|
"All Systems Operational": "جميع الأنظمة التشغيلية",
|
||||||
|
"Partially Degraded Service": "الخدمة المتدهورة جزئيا",
|
||||||
|
"Degraded Service": "خدمة متدهورة",
|
||||||
|
"Add Group": "أضف مجموعة",
|
||||||
|
"Add a monitor": "إضافة شاشة",
|
||||||
|
"Edit Status Page": "تحرير صفحة الحالة",
|
||||||
|
"Go to Dashboard": "الذهاب إلى لوحة القيادة",
|
||||||
|
"Status Page": "صفحة الحالة",
|
||||||
|
"Application Token": "رمز التطبيق",
|
||||||
|
"Server URL": "عنوان URL الخادم",
|
||||||
|
"Priority": "أولوية",
|
||||||
|
"Read more": "قراءة المزيد",
|
||||||
|
"topic": "عنوان",
|
||||||
|
"Last Updated": "التحديث الاخير",
|
||||||
|
"Unpin": "إلغاء",
|
||||||
|
"Show Tags": "أضهر العلامات",
|
||||||
|
"Add one": "أضف واحدا",
|
||||||
|
"wayToGetCloudflaredURL": "(قم بتنزيل CloudFlared من {0})",
|
||||||
|
"cloudflareWebsite": "موقع CloudFlare",
|
||||||
|
"Message:": ":رسالة",
|
||||||
|
"Don't know how to get the token? Please read the guide:": "لا أعرف كيفية الحصول على الرمز المميز؟ يرجى قراءة الدليل:",
|
||||||
|
"telegramSendSilently": "أرسل بصمت",
|
||||||
|
"telegramSendSilentlyDescription": "ترسل الرسالة بصمت ويتلقى المستخدمون إشعارا بدون صوت.",
|
||||||
|
"Enable": "يُمكَِن",
|
||||||
|
"notificationRegional": "إقليمي",
|
||||||
|
"Clone": "استنسخ",
|
||||||
|
"cloneOf": "مُستنسَخ من {0}",
|
||||||
|
"grpcMethodDescription": "يتم تحويل اسم الطريقة إلى تنسيق Cammelcase مثل Sayhello Check وما إلى ذلك.",
|
||||||
|
"acceptedStatusCodesDescription": "حدد رموز الحالة التي تعتبر استجابة ناجحة.",
|
||||||
|
"deleteNotificationMsg": "هل أنت متأكد من حذف هذا الإشعار لجميع الشاشات؟",
|
||||||
|
"dnsPortDescription": "منفذ خادم DNS. الافتراضيات إلى 53. يمكنك تغيير المنفذ في أي وقت.",
|
||||||
|
"pauseMonitorMsg": "هل أنت متأكد من أن تتوقف مؤقتًا؟",
|
||||||
|
"API Keys": "مفاتيح API",
|
||||||
|
"Expiry": "نهاية الصلاحية",
|
||||||
|
"Expiry date": "تاريخ نهاية الصلاحية",
|
||||||
|
"Continue": "مواصلة",
|
||||||
|
"Add Another": "إضافة آخر",
|
||||||
|
"Add API Key": "أضف مفتاح API",
|
||||||
|
"apiKey-active": "نشط",
|
||||||
|
"apiKey-expired": "منتهي الصلاحية",
|
||||||
|
"Generate": "توليد",
|
||||||
|
"Settings": "الإعدادات",
|
||||||
|
"Dashboard": "لوح التحكم",
|
||||||
|
"Help": "المساعدة",
|
||||||
|
"New Update": "تحديث جديد متوفر",
|
||||||
|
"Language": "اللغة",
|
||||||
|
"Appearance": "المظهر",
|
||||||
|
"Theme": "الحُلة",
|
||||||
|
"General": "العامة",
|
||||||
|
"Version": "الإصدار",
|
||||||
|
"Primary Base URL": "الرابط التشعبي الأساسي",
|
||||||
|
"Check Update On GitHub": "التحقق من التحديث على GitHub",
|
||||||
|
"Add New Monitor": "أضف شاشة جديدة",
|
||||||
|
"Quick Stats": "إحصائيات سريعة",
|
||||||
|
"Pending": "قيد الانتظار",
|
||||||
|
"General Monitor Type": "نوع الشاشة العامة",
|
||||||
|
"Passive Monitor Type": "نوع الشاشة السلبي",
|
||||||
|
"Specific Monitor Type": "نوع شاشة محدد",
|
||||||
|
"markdownSupported": "دعم صيغة Markdown",
|
||||||
|
"pauseDashboardHome": "وقفة",
|
||||||
|
"Pause": "إيقاف مؤقت",
|
||||||
|
"Name": "الاسم",
|
||||||
|
"Status": "الحالة",
|
||||||
|
"DateTime": "الوقت والتاريخ",
|
||||||
|
"Message": "الرسالة",
|
||||||
|
"No important events": "لا توجد أحداث مهمة",
|
||||||
|
"Resume": "استمرار",
|
||||||
|
"Keyword": "كلمة مفتاحية",
|
||||||
|
"Friendly Name": "اسم معروف",
|
||||||
|
"URL": "عنوان URL",
|
||||||
|
"Hostname": "اسم المضيف",
|
||||||
|
"Port": "المنفذ",
|
||||||
|
"Heartbeat Interval": "فاصل نبضات القلب",
|
||||||
|
"Add": "إضافة",
|
||||||
|
"Up": "متصل",
|
||||||
|
"Down": "غير متصل",
|
||||||
|
"Maintenance": "الصيانة",
|
||||||
|
"Unknown": "مجهول",
|
||||||
|
"Retries": "يحاول مجدداً",
|
||||||
|
"Heartbeat Retry Interval": "الفاصل الزمني لإعادة محاكمة نبضات القلب",
|
||||||
|
"Resend Notification if Down X times consecutively": "إعادة تقديم الإخطار إذا انخفض x مرات بالتالي",
|
||||||
|
"Advanced": "متقدم",
|
||||||
|
"checkEverySecond": "تحقق من كل {0} ثانية",
|
||||||
|
"retryCheckEverySecond": "أعد محاولة كل {0} ثانية",
|
||||||
|
"resendEveryXTimes": "إعادة تقديم كل {0} مرات",
|
||||||
|
"resendDisabled": "إعادة الالتزام بالتعطيل",
|
||||||
|
"retriesDescription": "الحد الأقصى لإعادة المحاولة قبل تمييز الخدمة على أنها لأسفل وإرسال إشعار",
|
||||||
|
"ignoreTLSError": "تجاهل خطأ TLS/SSL لمواقع HTTPS",
|
||||||
|
"upsideDownModeDescription": "اقلب الحالة رأسًا على عقب. إذا كانت الخدمة قابلة للوصول إلى أسفل.",
|
||||||
|
"maxRedirectDescription": "الحد الأقصى لعدد إعادة التوجيه لمتابعة. ضبط على 0 لتعطيل إعادة التوجيه.",
|
||||||
|
"Upside Down Mode": "وضع أسفل أسفل",
|
||||||
|
"Max. Redirects": "الأعلى. إعادة التوجيه",
|
||||||
|
"Accepted Status Codes": "رموز الحالة المقبولة",
|
||||||
|
"Push URL": "دفع عنوان URL",
|
||||||
|
"needPushEvery": "يجب عليك استدعاء عنوان URL هذا كل ثانية.",
|
||||||
|
"pushOptionalParams": "المعلمات الاختيارية",
|
||||||
|
"Save": "يحفظ",
|
||||||
|
"Notifications": "إشعارات",
|
||||||
|
"Not available, please setup.": "غير متوفر من فضلك الإعداد.",
|
||||||
|
"Setup Notification": "إشعار الإعداد",
|
||||||
|
"Light": "نور",
|
||||||
|
"Dark": "داكن",
|
||||||
|
"Auto": "آلي",
|
||||||
|
"Timezone": "وحدة زمنية",
|
||||||
|
"Search Engine Visibility": "محرك بحث الرؤية",
|
||||||
|
"Allow indexing": "السماح الفهرسة",
|
||||||
|
"Discourage search engines from indexing site": "تثبيط محركات البحث من موقع الفهرسة",
|
||||||
|
"Change Password": "غير كلمة السر",
|
||||||
|
"add one": "أضف واحدا",
|
||||||
|
"Notification Type": "نوع إعلام",
|
||||||
|
"Email": "بريد إلكتروني",
|
||||||
|
"Test": "امتحان",
|
||||||
|
"Certificate Info": "معلومات الشهادة",
|
||||||
|
"Resolver Server": "خادم Resolver",
|
||||||
|
"Resource Record Type": "نوع سجل الموارد",
|
||||||
|
"Last Result": "اخر نتيجة",
|
||||||
|
"Create your admin account": "إنشاء حساب المسؤول الخاص بك",
|
||||||
|
"Repeat Password": "اعد كلمة السر",
|
||||||
|
"Import Backup": "استيراد النسخ الاحتياطي",
|
||||||
|
"Export Backup": "النسخ الاحتياطي تصدير",
|
||||||
|
"Export": "يصدّر",
|
||||||
|
"Import": "يستورد",
|
||||||
|
"respTime": "resp. الوقت (MS)",
|
||||||
|
"notAvailableShort": "ن/أ",
|
||||||
|
"Default enabled": "التمكين الافتراضي",
|
||||||
|
"Apply on all existing monitors": "تنطبق على جميع الشاشات الحالية",
|
||||||
|
"Create": "خلق",
|
||||||
|
"Clear Data": "امسح البيانات",
|
||||||
|
"Events": "الأحداث",
|
||||||
|
"Heartbeats": "نبضات القلب",
|
||||||
|
"Schedule maintenance": "جدولة الصيانة",
|
||||||
|
"Affected Monitors": "الشاشات المتأثرة",
|
||||||
|
"Pick Affected Monitors...": "اختر الشاشات المتأثرة …",
|
||||||
|
"Start of maintenance": "بداية الصيانة",
|
||||||
|
"All Status Pages": "جميع صفحات الحالة",
|
||||||
|
"Select status pages...": "حدد صفحات الحالة …",
|
||||||
|
"alertWrongFileType": "الرجاء تحديد ملف JSON.",
|
||||||
|
"Clear all statistics": "مسح جميع الإحصاءات",
|
||||||
|
"Overwrite": "الكتابة فوق",
|
||||||
|
"Options": "خيارات",
|
||||||
|
"Keep both": "احتفظ بكليهما",
|
||||||
|
"Verify Token": "تحقق من الرمز المميز",
|
||||||
|
"Setup 2FA": "الإعداد 2FA",
|
||||||
|
"Enable 2FA": "تمكين 2FA",
|
||||||
|
"Disable 2FA": "تعطيل 2FA",
|
||||||
|
"2FA Settings": "2FA إعدادات",
|
||||||
|
"Two Factor Authentication": "توثيق ذو عاملين",
|
||||||
|
"Active": "نشيط",
|
||||||
|
"Inactive": "غير نشط",
|
||||||
|
"Token": "رمز",
|
||||||
|
"Show URI": "أظهر URI",
|
||||||
|
"Tags": "العلامات",
|
||||||
|
"Add New below or Select...": "إضافة جديد أدناه أو تحديد …",
|
||||||
|
"Tag with this name already exist.": "علامة مع هذا الاسم موجود بالفعل.",
|
||||||
|
"Tag with this value already exist.": "علامة مع هذه القيمة موجودة بالفعل.",
|
||||||
|
"color": "اللون",
|
||||||
|
"value (optional)": "القيمة (اختياري)",
|
||||||
|
"Gray": "رمادي",
|
||||||
|
"Red": "أحمر",
|
||||||
|
"Orange": "البرتقالي",
|
||||||
|
"Green": "لون أخضر",
|
||||||
|
"Blue": "أزرق",
|
||||||
|
"Indigo": "النيلي",
|
||||||
|
"Purple": "نفسجي",
|
||||||
|
"webhookAdditionalHeadersDesc": "يحدد رؤوس إضافية مرسلة مع webhook.",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
"Pink": "لون القرنفل",
|
||||||
|
"Custom": "العادة",
|
||||||
|
"Status Pages": "صفحات الحالة",
|
||||||
|
"defaultNotificationName": "تنبيه {الإخطار} ({number})",
|
||||||
|
"here": "هنا",
|
||||||
|
"Required": "مطلوب",
|
||||||
|
"Post URL": "بعد عنوان URL",
|
||||||
|
"Content Type": "نوع المحتوى",
|
||||||
|
"webhookJsonDesc": "{0} مفيد لأي خوادم HTTP الحديثة مثل Express.js",
|
||||||
|
"webhookFormDataDesc": "{multipart} مفيد لـ PHP. سيحتاج JSON إلى تحليل {decodefunction}",
|
||||||
|
"webhookAdditionalHeadersTitle": "رؤوس إضافية",
|
||||||
|
"emojiCheatSheet": "ورقة الغش في الرموز التعبيرية",
|
||||||
|
"appriseInstalled": "تم تثبيت Prosise.",
|
||||||
|
"appriseNotInstalled": "الإبرام غير مثبت. {0}",
|
||||||
|
"Method": "طريقة",
|
||||||
|
"Body": "الجسم",
|
||||||
|
"Headers": "الرؤوس",
|
||||||
|
"PushUrl": "دفع عنوان URL",
|
||||||
|
"HeadersInvalidFormat": "رؤوس الطلبات غير صالحة JSON ",
|
||||||
|
"BodyInvalidFormat": "هيئة الطلب غير صالحة JSON ",
|
||||||
|
"Monitor History": "مراقبة التاريخ",
|
||||||
|
"clearDataOlderThan": "الحفاظ على بيانات سجل المراقبة للأيام {0}.",
|
||||||
|
"PasswordsDoNotMatch": "كلمة المرور غير مطابقة.",
|
||||||
|
"records": "السجلات",
|
||||||
|
"One record": "سجل واحد",
|
||||||
|
"steamApiKeyDescription": "لمراقبة خادم لعبة Steam ، تحتاج إلى مفتاح Steam Web-API. يمكنك تسجيل مفتاح API الخاص بك هنا ",
|
||||||
|
"Current User": "المستخدم الحالي",
|
||||||
|
"topicExplanation": "موضوع MQTT لرصد",
|
||||||
|
"successMessage": "نجاح رسالة",
|
||||||
|
"successMessageExplanation": "رسالة MQTT التي ستعتبر نجاحًا",
|
||||||
|
"recent": "الأخيرة",
|
||||||
|
"Done": "فعله",
|
||||||
|
"Info": "معلومات",
|
||||||
|
"Security": "حماية",
|
||||||
|
"Steam API Key": "مفتاح API Steam",
|
||||||
|
"Shrink Database": "تقلص قاعدة البيانات",
|
||||||
|
"Pick a RR-Type...": "اختر نوع RR …",
|
||||||
|
"Pick Accepted Status Codes...": "اختر أكواد الحالة المقبولة …",
|
||||||
|
"Default": "تقصير",
|
||||||
|
"HTTP Options": "خيارات HTTP",
|
||||||
|
"Create Incident": "إنشاء حادث",
|
||||||
|
"Title": "لقب",
|
||||||
|
"Content": "المحتوى",
|
||||||
|
"Style": "أسلوب",
|
||||||
|
"info": "معلومات",
|
||||||
|
"warning": "تحذير",
|
||||||
|
"danger": "خطر",
|
||||||
|
"error": "خطأ",
|
||||||
|
"critical": "شديد الأهمية",
|
||||||
|
"primary": "الأولية",
|
||||||
|
"light": "نور",
|
||||||
|
"dark": "ظلام",
|
||||||
|
"Post": "بريد",
|
||||||
|
"Please input title and content": "الرجاء إدخال العنوان والمحتوى",
|
||||||
|
"Created": "مخلوق",
|
||||||
|
"Switch to Light Theme": "التبديل إلى موضوع الضوء",
|
||||||
|
"Switch to Dark Theme": "التبديل إلى موضوع الظلام",
|
||||||
|
"Hide Tags": "إخفاء العلامات",
|
||||||
|
"Description": "وصف",
|
||||||
|
"No monitors available.": "لا شاشات المتاحة.",
|
||||||
|
"No Monitors": "لا شاشات",
|
||||||
|
"Untitled Group": "مجموعة بلا عنوان",
|
||||||
|
"Services": "خدمات",
|
||||||
|
"Discard": "تجاهل",
|
||||||
|
"Cancel": "يلغي",
|
||||||
|
"Powered by": "مشغل بواسطة",
|
||||||
|
"shrinkDatabaseDescription": "تشغيل فراغ قاعدة البيانات لـ SQLite. إذا تم إنشاء قاعدة البيانات الخاصة بك بعد تمكين 1.10.0 AUTO_VACUUM بالفعل ولا يلزم هذا الإجراء.",
|
||||||
|
"Customize": "يعدل أو يكيف",
|
||||||
|
"Custom Footer": "تذييل مخصص",
|
||||||
|
"Custom CSS": "لغة تنسيق ويب حسب الطلب",
|
||||||
|
"deleteStatusPageMsg": "هل أنت متأكد من حذف صفحة الحالة هذه؟",
|
||||||
|
"Proxies": "وكلاء",
|
||||||
|
"default": "تقصير",
|
||||||
|
"enabled": "تمكين",
|
||||||
|
"setAsDefault": "تعيين كافتراضي",
|
||||||
|
"deleteProxyMsg": "هل أنت متأكد من حذف هذا الوكيل لجميع الشاشات؟",
|
||||||
|
"proxyDescription": "يجب تعيين الوكلاء إلى شاشة للعمل.",
|
||||||
|
"enableProxyDescription": "لن يؤثر هذا الوكيل على طلبات الشاشة حتى يتم تنشيطه. يمكنك التحكم مؤقتًا في تعطيل الوكيل من جميع الشاشات حسب حالة التنشيط.",
|
||||||
|
"setAsDefaultProxyDescription": "سيتم تمكين هذا الوكيل افتراضيًا للشاشات الجديدة. لا يزال بإمكانك تعطيل الوكيل بشكل منفصل لكل شاشة.",
|
||||||
|
"Certificate Chain": "سلسلة الشهادة",
|
||||||
|
"Valid": "صالح",
|
||||||
|
"Invalid": "غير صالح",
|
||||||
|
"User": "المستعمل",
|
||||||
|
"Installed": "المثبتة",
|
||||||
|
"Not installed": "غير مثبت",
|
||||||
|
"Running": "جري",
|
||||||
|
"Not running": "لا يعمل",
|
||||||
|
"Remove Token": "إزالة الرمز المميز",
|
||||||
|
"Start": "بداية",
|
||||||
|
"Stop": "قف",
|
||||||
|
"Add New Status Page": "أضف صفحة حالة جديدة",
|
||||||
|
"Slug": "سبيكة",
|
||||||
|
"Accept characters:": "قبول الأحرف:",
|
||||||
|
"startOrEndWithOnly": "ابدأ أو ينتهي بـ {0} فقط",
|
||||||
|
"No consecutive dashes": "لا شرطات متتالية",
|
||||||
|
"Next": "التالي",
|
||||||
|
"The slug is already taken. Please choose another slug.": "تم أخذ سبيكة بالفعل. الرجاء اختيار سبيكة أخرى.",
|
||||||
|
"No Proxy": "لا الوكيل",
|
||||||
|
"Authentication": "المصادقة",
|
||||||
|
"HTTP Basic Auth": "HTTP الأساسي Auth",
|
||||||
|
"New Status Page": "صفحة حالة جديدة",
|
||||||
|
"Page Not Found": "الصفحة غير موجودة",
|
||||||
|
"Reverse Proxy": "وكيل عكسي",
|
||||||
|
"Backup": "دعم",
|
||||||
|
"About": "عن",
|
||||||
|
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "قد يضيع الاتصال الحالي إذا كنت تتصل حاليًا عبر نفق CloudFlare. هل أنت متأكد تريد إيقافها؟ اكتب كلمة المرور الحالية لتأكيدها.",
|
||||||
|
"HTTP Headers": "رؤوس HTTP",
|
||||||
|
"Trust Proxy": "الوكيل الثقة",
|
||||||
|
"Other Software": "برامج أخرى",
|
||||||
|
"For example: nginx, Apache and Traefik.": "على سبيل المثال: nginx و Apache و Traefik.",
|
||||||
|
"Please read": "يرجى القراءة",
|
||||||
|
"Subject:": "موضوع:",
|
||||||
|
"Valid To:": "صالحة ل:",
|
||||||
|
"Days Remaining:": "الأيام المتبقية:",
|
||||||
|
"Issuer:": "المُصدر:",
|
||||||
|
"Fingerprint:": "بصمة:",
|
||||||
|
"No status pages": "لا صفحات الحالة",
|
||||||
|
"Domain Name Expiry Notification": "اسم النطاق إشعار انتهاء الصلاحية",
|
||||||
|
"Proxy": "الوكيل",
|
||||||
|
"Date Created": "تاريخ الإنشاء",
|
||||||
|
"Footer Text": "نص تذييل",
|
||||||
|
"Show Powered By": "عرض مدعوم من قبل",
|
||||||
|
"Domain Names": "أسماء المجال",
|
||||||
|
"signedInDisp": "وقعت في {0}",
|
||||||
|
"signedInDispDisabled": "معاق المصادقة.",
|
||||||
|
"RadiusSecret": "سر نصف القطر",
|
||||||
|
"RadiusSecretDescription": "السر المشترك بين العميل والخادم",
|
||||||
|
"RadiusCalledStationId": "يسمى معرف المحطة",
|
||||||
|
"RadiusCalledStationIdDescription": "معرف الجهاز المتصل",
|
||||||
|
"RadiusCallingStationId": "معرف محطة الاتصال",
|
||||||
|
"RadiusCallingStationIdDescription": "معرف جهاز الاتصال",
|
||||||
|
"Certificate Expiry Notification": "إشعار انتهاء الصلاحية",
|
||||||
|
"API Username": "اسم المستخدم API",
|
||||||
|
"API Key": "مفتاح API",
|
||||||
|
"Show update if available": "عرض التحديث إذا كان ذلك متاحًا",
|
||||||
|
"Also check beta release": "تحقق أيضًا من الإصدار التجريبي",
|
||||||
|
"Using a Reverse Proxy?": "باستخدام وكيل عكسي؟",
|
||||||
|
"Check how to config it for WebSocket": "تحقق من كيفية تكوينه لـ WebSocket",
|
||||||
|
"Steam Game Server": "خادم لعبة البخار",
|
||||||
|
"Most likely causes:": "الأسباب المرجحة:",
|
||||||
|
"The resource is no longer available.": "لم يعد المورد متاحًا.",
|
||||||
|
"There might be a typing error in the address.": "قد يكون هناك خطأ مطبعي في العنوان.",
|
||||||
|
"What you can try:": "ماذا تستطيع أن تجرب:",
|
||||||
|
"Retype the address.": "اعد كتابة العنوان.",
|
||||||
|
"Go back to the previous page.": "عد للصفحة السابقة.",
|
||||||
|
"Coming Soon": "قريبا",
|
||||||
|
"Connection String": "سلسلة الاتصال",
|
||||||
|
"Query": "استفسار",
|
||||||
|
"settingsCertificateExpiry": "شهادة TLS انتهاء الصلاحية",
|
||||||
|
"certificationExpiryDescription": "شاشات HTTPS تضيء عندما تنتهي شهادة TLS في",
|
||||||
|
"Setup Docker Host": "إعداد مضيف Docker",
|
||||||
|
"Connection Type": "نوع الاتصال",
|
||||||
|
"Docker Daemon": "Docker Daemon",
|
||||||
|
"deleteDockerHostMsg": "هل أنت متأكد من حذف مضيف Docker لجميع الشاشات؟",
|
||||||
|
"socket": "قابس كهرباء",
|
||||||
|
"tcp": "TCP / HTTP",
|
||||||
|
"Docker Container": "حاوية Docker",
|
||||||
|
"Container Name / ID": "اسم الحاوية / معرف",
|
||||||
|
"Docker Host": "مضيف Docker",
|
||||||
|
"Docker Hosts": "مضيفي Docker",
|
||||||
|
"Domain": "اِختِصاص",
|
||||||
|
"Workstation": "محطة العمل",
|
||||||
|
"Packet Size": "حجم الحزمة",
|
||||||
|
"Bot Token": "رمز الروبوت",
|
||||||
|
"wayToGetTelegramToken": "يمكنك الحصول على رمز من {0}.",
|
||||||
|
"Chat ID": "معرف الدردشة",
|
||||||
|
"telegramMessageThreadID": "معرف المواضيع",
|
||||||
|
"supportTelegramChatID": "دعم الدردشة المباشرة / معرف الدردشة للقناة",
|
||||||
|
"wayToGetTelegramChatID": "يمكنك الحصول على معرف الدردشة الخاص بك عن طريق إرسال رسالة إلى الروبوت والانتقال إلى عنوان URL هذا لعرض Chat_id",
|
||||||
|
"YOUR BOT TOKEN HERE": "رمز الروبوت الخاص بك هنا",
|
||||||
|
"chatIDNotFound": "لم يتم العثور على معرف الدردشة ؛ الرجاء إرسال رسالة إلى هذا الروبوت أولاً",
|
||||||
|
"disableCloudflaredNoAuthMsg": "أنت في وضع مصادقة لا توجد كلمة مرور غير مطلوبة.",
|
||||||
|
"trustProxyDescription": "ثق في رؤوس \"X-Forwarded- *\". إذا كنت ترغب في الحصول على عنوان IP الصحيح للعميل وكان Uptime Kuma خلف وكيل مثل Nginx أو Apache ، فيجب عليك تمكين هذا.",
|
||||||
|
"wayToGetLineNotifyToken": "يمكنك الحصول على رمز الوصول من {0}",
|
||||||
|
"Examples": "أمثلة",
|
||||||
|
"Home Assistant URL": "Home Assistant URL",
|
||||||
|
"Long-Lived Access Token": "الرمز المميز للوصول منذ فترة طويلة",
|
||||||
|
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "يمكن إنشاء رمز الوصول منذ فترة طويلة عن طريق النقر على اسم ملف التعريف الخاص بك (أسفل اليسار) والتمرير إلى الأسفل ثم انقر فوق إنشاء الرمز المميز. ",
|
||||||
|
"Notification Service": "خدمة الإخطار",
|
||||||
|
"default: notify all devices": "الافتراضي: إخطار جميع الأجهزة",
|
||||||
|
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "يمكن العثور على قائمة بخدمات الإخطار في المساعد المنزلي ضمن \"Developer Tools > Services\" ابحث عن \"notification\" للعثور على اسم جهازك/هاتفك.",
|
||||||
|
"Automations can optionally be triggered in Home Assistant:": "يمكن تشغيل الأتمتة اختياريًا في Home Assistant:",
|
||||||
|
"Trigger type:": "نوع الزناد:",
|
||||||
|
"Event type:": "نوع الحدث:",
|
||||||
|
"Event data:": "بيانات الحدث:",
|
||||||
|
"Then choose an action, for example switch the scene to where an RGB light is red.": "ثم اختر إجراءً على سبيل المثال قم بتبديل المشهد إلى حيث يكون ضوء RGB أحمر.",
|
||||||
|
"Frontend Version": "إصدار الواجهة الأمامية",
|
||||||
|
"Frontend Version do not match backend version!": "إصدار Frontend لا يتطابق مع الإصدار الخلفي!",
|
||||||
|
"backupOutdatedWarning": "مهمل: نظرًا لأنه تمت إضافة الكثير من الميزات وأن ميزة النسخ الاحتياطي هذه لم يتم الحفاظ عليها قليلاً ، فلا يمكنها إنشاء نسخة احتياطية كاملة أو استعادتها.",
|
||||||
|
"backupRecommend": "يرجى النسخ الاحتياطي لحجم الصوت أو مجلد البيانات (./data/) مباشرة بدلاً من ذلك.",
|
||||||
|
"Optional": "اختياري",
|
||||||
|
"or": "أو",
|
||||||
|
"recurringInterval": "فترة",
|
||||||
|
"Recurring": "يتكرر",
|
||||||
|
"strategyManual": "نشط/غير نشط يدويًا",
|
||||||
|
"warningTimezone": "إنه يستخدم المنطقة الزمنية للخادم",
|
||||||
|
"weekdayShortMon": "الاثنين",
|
||||||
|
"weekdayShortTue": "الثلاثاء",
|
||||||
|
"weekdayShortWed": "تزوج",
|
||||||
|
"weekdayShortThu": "الخميس",
|
||||||
|
"weekdayShortFri": "الجمعة",
|
||||||
|
"No Maintenance": "لا صيانة",
|
||||||
|
"weekdayShortSat": "جلس",
|
||||||
|
"weekdayShortSun": "شمس",
|
||||||
|
"dayOfWeek": "يوم من الأسبوع",
|
||||||
|
"dayOfMonth": "يوم من الشهر",
|
||||||
|
"lastDay": "بالأمس",
|
||||||
|
"lastDay1": "آخر يوم من الشهر",
|
||||||
|
"lastDay2": "الثاني في اليوم الأخير من الشهر",
|
||||||
|
"lastDay3": "الثالث في اليوم الأخير من الشهر",
|
||||||
|
"lastDay4": "الرابع في اليوم الأخير من الشهر",
|
||||||
|
"pauseMaintenanceMsg": "هل أنت متأكد من أن تتوقف مؤقتًا؟",
|
||||||
|
"maintenanceStatus-under-maintenance": "تحت الصيانة",
|
||||||
|
"maintenanceStatus-inactive": "غير نشط",
|
||||||
|
"maintenanceStatus-scheduled": "المقرر",
|
||||||
|
"maintenanceStatus-ended": "انتهى",
|
||||||
|
"maintenanceStatus-unknown": "مجهول",
|
||||||
|
"Display Timezone": "عرض المنطقة الزمنية",
|
||||||
|
"Server Timezone": "المنطقة الزمنية الخادم",
|
||||||
|
"statusPageMaintenanceEndDate": "نهاية",
|
||||||
|
"IconUrl": "url url icon",
|
||||||
|
"Enable DNS Cache": "تمكين ذاكرة التخزين المؤقت DNS",
|
||||||
|
"Disable": "إبطال",
|
||||||
|
"dnsCacheDescription": "قد لا يعمل في بعض بيئات IPv6 تعطيله إذا واجهت أي مشكلات.",
|
||||||
|
"Single Maintenance Window": "نافذة صيانة واحدة",
|
||||||
|
"Maintenance Time Window of a Day": "نافذة وقت الصيانة لليوم",
|
||||||
|
"Effective Date Range": "نطاق التاريخ السريع",
|
||||||
|
"Schedule Maintenance": "جدولة الصيانة",
|
||||||
|
"Date and Time": "التاريخ و الوقت",
|
||||||
|
"DateTime Range": "نطاق DateTime",
|
||||||
|
"loadingError": "لا يمكن جلب البيانات ، يرجى المحاولة مرة أخرى في وقت لاحق.",
|
||||||
|
"plugin": "البرنامج المساعد | الإضافات",
|
||||||
|
"install": "ثَبَّتَ",
|
||||||
|
"installing": "التثبيت",
|
||||||
|
"uninstall": "الغاء التثبيت",
|
||||||
|
"uninstalling": "إلغاء التثبيت",
|
||||||
|
"confirmUninstallPlugin": "هل أنت متأكد من أنك تريد إلغاء تثبيت هذا المكون الإضافي؟",
|
||||||
|
"smtp": "البريد الإلكتروني (SMTP)",
|
||||||
|
"secureOptionNone": "لا شيء / startTls (25 587)",
|
||||||
|
"secureOptionTLS": "TLS (465)",
|
||||||
|
"Ignore TLS Error": "تجاهل خطأ TLS",
|
||||||
|
"From Email": "من البريد الإلكترونى",
|
||||||
|
"emailCustomSubject": "موضوع مخصص",
|
||||||
|
"To Email": "للبريد الإلكتروني",
|
||||||
|
"smtpCC": "نسخة",
|
||||||
|
"smtpBCC": "BCC",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
"wayToGetDiscordURL": "يمكنك الحصول على هذا بالانتقال إلى إعدادات الخادم -> عمليات التكامل -> عرض الخطافات على الويب -> خطاف ويب جديد",
|
||||||
|
"Bot Display Name": "اسم عرض الروبوت",
|
||||||
|
"Prefix Custom Message": "بادئة رسالة مخصصة",
|
||||||
|
"Hello @everyone is...": "مرحبًا {'@'} الجميع…",
|
||||||
|
"wayToGetTeamsURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||||
|
"wayToGetZohoCliqURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||||
|
"needSignalAPI": "تحتاج إلى وجود عميل إشارة مع REST API.",
|
||||||
|
"wayToCheckSignalURL": "يمكنك التحقق من عنوان URL هذا لعرض كيفية إعداد واحد",
|
||||||
|
"Number": "رقم",
|
||||||
|
"Recipients": "المستلمين",
|
||||||
|
"Access Token": "رمز وصول",
|
||||||
|
"Channel access token": "قناة الوصول إلى الرمز",
|
||||||
|
"Line Developers Console": "تحكم المطورين",
|
||||||
|
"lineDevConsoleTo": "وحدة المطورين Line Console - {0}",
|
||||||
|
"Basic Settings": "الإعدادات الأساسية",
|
||||||
|
"confirmClearStatisticsMsg": "هل أنت متأكد من أنك تريد حذف جميع الإحصائيات؟",
|
||||||
|
"importHandleDescription": "اختر 'تخطي موجود' إذا كنت تريد تخطي كل شاشة أو إشعار بنفس الاسم. 'الكتابة فوق' سوف يحذف كل شاشة وإخطار موجود.",
|
||||||
|
"User ID": "معرف المستخدم",
|
||||||
|
"Messaging API": "واجهة برمجة تطبيقات المراسلة",
|
||||||
|
"wayToGetLineChannelToken": "قم أولاً بالوصول إلى {0} إنشاء مزود وقناة (واجهة برمجة تطبيقات المراسلة) ، ثم يمكنك الحصول على رمز الوصول إلى القناة ومعرف المستخدم من عناصر القائمة المذكورة أعلاه.",
|
||||||
|
"Icon URL": "url url icon",
|
||||||
|
"aboutIconURL": "يمكنك توفير رابط لصورة في \"Icon URL\" لتجاوز صورة الملف الشخصي الافتراضي. لن يتم استخدامه إذا تم تعيين رمز رمز رمز.",
|
||||||
|
"aboutMattermostChannelName": "يمكنك تجاوز القناة الافتراضية التي تنشرها WebHook من خلال إدخال اسم القناة في \"Channel Name\" الحقل. يجب تمكين هذا في إعدادات Webhook Mattern. السابق",
|
||||||
|
"dataRetentionTimeError": "يجب أن تكون فترة الاستبقاء 0 أو أكبر",
|
||||||
|
"infiniteRetention": "ضبط على 0 للاحتفاظ لا نهائي.",
|
||||||
|
"confirmDeleteTagMsg": "هل أنت متأكد من أنك تريد حذف هذه العلامة؟ لن يتم حذف الشاشات المرتبطة بهذه العلامة.",
|
||||||
|
"enableGRPCTls": "السماح لإرسال طلب GRPC مع اتصال TLS",
|
||||||
|
"deleteMonitorMsg": "هل أنت متأكد من حذف هذا الشاشة؟",
|
||||||
|
"deleteMaintenanceMsg": "هل أنت متأكد من حذف هذه الصيانة؟",
|
||||||
|
"resolverserverDescription": "CloudFlare هو الخادم الافتراضي. يمكنك تغيير خادم المحوّل في أي وقت.",
|
||||||
|
"rrtypeDescription": "حدد نوع RR الذي تريد مراقبته",
|
||||||
|
"enableDefaultNotificationDescription": "سيتم تمكين هذا الإشعار افتراضيًا للشاشات الجديدة. لا يزال بإمكانك تعطيل الإخطار بشكل منفصل لكل شاشة.",
|
||||||
|
"clearEventsMsg": "هل أنت متأكد من حذف جميع الأحداث لهذا الشاشة؟",
|
||||||
|
"clearHeartbeatsMsg": "هل أنت متأكد من حذف جميع دقات القلب لهذا الشاشة؟",
|
||||||
|
"confirmImportMsg": "هل أنت متأكد من أنك تريد استيراد النسخ الاحتياطي؟ يرجى التحقق من أنك حددت خيار الاستيراد الصحيح.",
|
||||||
|
"twoFAVerifyLabel": "الرجاء إدخال الرمز المميز الخاص بك للتحقق من 2FA",
|
||||||
|
"pushoversounds pushover": "سداد (افتراضي)",
|
||||||
|
"pushoversounds bike": "دراجة هوائية",
|
||||||
|
"pushoversounds bugle": "بوق",
|
||||||
|
"tokenValidSettingsMsg": "الرمز المميز صالح! يمكنك الآن حفظ إعدادات 2FA.",
|
||||||
|
"confirmEnableTwoFAMsg": "هل أنت متأكد من أنك تريد تمكين 2FA؟",
|
||||||
|
"confirmDisableTwoFAMsg": "هل أنت متأكد من أنك تريد تعطيل 2FA؟",
|
||||||
|
"recurringIntervalMessage": "ركض مرة واحدة كل يوم | قم بالتشغيل مرة واحدة كل يوم {0}",
|
||||||
|
"affectedMonitorsDescription": "حدد المراقبين المتأثرة بالصيانة الحالية",
|
||||||
|
"affectedStatusPages": "إظهار رسالة الصيانة هذه على صفحات الحالة المحددة",
|
||||||
|
"atLeastOneMonitor": "حدد شاشة واحدة على الأقل من المتأثرين",
|
||||||
|
"passwordNotMatchMsg": "كلمة المرور المتكررة لا تتطابق.",
|
||||||
|
"notificationDescription": "يجب تعيين الإخطارات إلى شاشة للعمل.",
|
||||||
|
"keywordDescription": "ابحث في الكلمة الرئيسية في استجابة HTML العادية أو JSON. البحث حساس للحالة.",
|
||||||
|
"backupDescription": "يمكنك النسخ الاحتياطي لجميع الشاشات والإشعارات في ملف JSON.",
|
||||||
|
"backupDescription3": "يتم تضمين البيانات الحساسة مثل الرموز الإخطار في ملف التصدير ؛ يرجى تخزين التصدير بشكل آمن.",
|
||||||
|
"endpoint": "نقطة النهاية",
|
||||||
|
"octopushAPIKey": "\"API key\" from HTTP API بيانات اعتماد في لوحة التحكم",
|
||||||
|
"octopushLogin": "\"Login\" من بيانات اعتماد API HTTP في لوحة التحكم",
|
||||||
|
"promosmsLogin": "اسم تسجيل الدخول API",
|
||||||
|
"promosmsPassword": "كلمة مرور API",
|
||||||
|
"pushoversounds cashregister": "ماكينة تسجيل المدفوعات النقدية",
|
||||||
|
"pushoversounds classical": "كلاسيكي",
|
||||||
|
"pushoversounds cosmic": "كونية",
|
||||||
|
"pushoversounds falling": "هبوط",
|
||||||
|
"pushoversounds gamelan": "Gamelan",
|
||||||
|
"pushoversounds incoming": "واردة",
|
||||||
|
"pushoversounds intermission": "استراحة",
|
||||||
|
"pushoversounds magic": "سحر",
|
||||||
|
"pushoversounds mechanical": "ميكانيكي",
|
||||||
|
"pushoversounds pianobar": "شريط البيانو",
|
||||||
|
"pushoversounds siren": "صفارة إنذار",
|
||||||
|
"pushoversounds spacealarm": "إنذار الفضاء",
|
||||||
|
"pushoversounds tugboat": "قارب السحب",
|
||||||
|
"pushoversounds alien": "إنذار أجنبي (طويل)",
|
||||||
|
"pushoversounds climb": "تسلق (طويل)",
|
||||||
|
"pushoversounds persistent": "مستمر (طويل)",
|
||||||
|
"pushoversounds echo": "صدى مهووس (طويل)",
|
||||||
|
"pushoversounds updown": "صعودا (طويلة)",
|
||||||
|
"pushoversounds vibrate": "يهتز فقط",
|
||||||
|
"pushoversounds none": "لا شيء (صامت)",
|
||||||
|
"pushyAPIKey": "مفتاح API السري",
|
||||||
|
"pushyToken": "رمز الجهاز",
|
||||||
|
"apprise": "إبلاغ (دعم 50+ خدمات الإخطار)",
|
||||||
|
"GoogleChat": "دردشة Google",
|
||||||
|
"wayToGetKookBotToken": "قم بإنشاء تطبيق واحصل على رمز الروبوت الخاص بك على {0}",
|
||||||
|
"wayToGetKookGuildID": "قم بتشغيل 'وضع المطور' في إعداد Kook وانقر بزر الماوس الأيمن على النقابة للحصول على معرفه",
|
||||||
|
"Guild ID": "معرف النقابة",
|
||||||
|
"User Key": "مفتاح المستخدم",
|
||||||
|
"Device": "جهاز",
|
||||||
|
"Message Title": "عنوان الرسالة",
|
||||||
|
"Notification Sound": "صوت الإشعار",
|
||||||
|
"More info on:": "مزيد من المعلومات حول: {0}",
|
||||||
|
"pushoverDesc1": "أولوية الطوارئ (2) لها مهلة افتراضية 30 ثانية بين إعادة المحاولة وستنتهي صلاحيتها بعد ساعة واحدة.",
|
||||||
|
"pushoverDesc2": "إذا كنت ترغب في إرسال إشعارات إلى أجهزة مختلفة ، قم بملء حقل الجهاز.",
|
||||||
|
"SMS Type": "نوع الرسائل القصيرة",
|
||||||
|
"octopushTypePremium": "قسط (سريع - موصى به للتنبيه)",
|
||||||
|
"octopushTypeLowCost": "التكلفة المنخفضة (بطيئة - تم حظرها أحيانًا بواسطة المشغل)",
|
||||||
|
"checkPrice": "تحقق من الأسعار {0}",
|
||||||
|
"apiCredentials": "بيانات اعتماد API",
|
||||||
|
"octopushLegacyHint": "هل تستخدم الإصدار القديم من Octopush (2011-2020) أو الإصدار الجديد؟",
|
||||||
|
"Check octopush prices": "تحقق من أسعار Octopush {0}.",
|
||||||
|
"AccessKeyId": "معرف AccessKey",
|
||||||
|
"SecretAccessKey": "Accesskey Secret",
|
||||||
|
"PhoneNumbers": "أرقام الهواتف",
|
||||||
|
"octopushPhoneNumber": "رقم الهاتف (تنسيق intl على سبيل المثال ",
|
||||||
|
"octopushSMSSender": "اسم مرسل الرسائل القصيرة",
|
||||||
|
"LunaSea Device ID": "معرف جهاز Lunasea",
|
||||||
|
"Apprise URL": "إبلاغ عنوان URL",
|
||||||
|
"Example:": "مثال: {0}",
|
||||||
|
"Read more:": "{0} :قراءة المزيد",
|
||||||
|
"Status:": "{0} :حالة",
|
||||||
|
"Strategy": "إستراتيجية",
|
||||||
|
"Free Mobile User Identifier": "معرف مستخدم الهاتف المحمول المجاني",
|
||||||
|
"Free Mobile API Key": "مفتاح واجهة برمجة تطبيقات مجانية للهاتف المحمول",
|
||||||
|
"Enable TLS": "تمكين TLS",
|
||||||
|
"Proto Service Name": "اسم خدمة البروتو",
|
||||||
|
"Proto Method": "طريقة البروتو",
|
||||||
|
"Proto Content": "محتوى proto",
|
||||||
|
"Economy": "اقتصاد",
|
||||||
|
"Lowcost": "تكلفة منخفضة",
|
||||||
|
"high": "عالي",
|
||||||
|
"SendKey": "Sendkey",
|
||||||
|
"SMSManager API Docs": "مستندات SMSManager API ",
|
||||||
|
"Gateway Type": "نوع البوابة",
|
||||||
|
"You can divide numbers with": "يمكنك تقسيم الأرقام مع",
|
||||||
|
"Base URL": "عنوان URL الأساسي",
|
||||||
|
"goAlertInfo": "الهدف هو تطبيق مفتوح المصدر لجدولة الجدولة التلقائية والإشعارات (مثل الرسائل القصيرة أو المكالمات الصوتية). إشراك الشخص المناسب تلقائيًا بالطريقة الصحيحة وفي الوقت المناسب! {0}",
|
||||||
|
"goAlertIntegrationKeyInfo": "احصل على مفتاح تكامل API العام للخدمة في هذا التنسيق \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" عادةً قيمة المعلمة الرمزية لعنوان url المنسق.",
|
||||||
|
"TemplateCode": "TemplateCode",
|
||||||
|
"SignName": "اسم تسجيل الدخول",
|
||||||
|
"Sms template must contain parameters: ": "يجب أن يحتوي قالب الرسائل القصيرة على معلمات: ",
|
||||||
|
"Bark Endpoint": "نقطة نهاية اللحاء",
|
||||||
|
"Bark Group": "مجموعة اللحاء",
|
||||||
|
"Bark Sound": "صوت اللحاء",
|
||||||
|
"WebHookUrl": "webhookurl",
|
||||||
|
"SecretKey": "Secretkey",
|
||||||
|
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
|
||||||
|
"Device Token": "رمز الجهاز",
|
||||||
|
"Platform": "منصة",
|
||||||
|
"Android": "ذكري المظهر",
|
||||||
|
"Huawei": "هواوي",
|
||||||
|
"High": "عالٍ",
|
||||||
|
"Retry": "إعادة المحاولة",
|
||||||
|
"Topic": "عنوان",
|
||||||
|
"WeCom Bot Key": "WECOM BOT KEY",
|
||||||
|
"Setup Proxy": "وكيل الإعداد",
|
||||||
|
"Proxy Protocol": "بروتوكول الوكيل",
|
||||||
|
"Proxy Server": "مخدم بروكسي",
|
||||||
|
"Proxy server has authentication": "خادم الوكيل لديه مصادقة",
|
||||||
|
"promosmsTypeEco": "SMS Eco - رخيصة ولكن بطيئة وغالبًا ما تكون محملة. يقتصر فقط على المستفيدين البولنديين.",
|
||||||
|
"promosmsTypeFlash": "SMS Flash - سيتم عرض الرسالة تلقائيًا على جهاز المستلم. يقتصر فقط على المستفيدين البولنديين.",
|
||||||
|
"promosmsTypeFull": "SMS Full - Tier Premium SMS يمكنك استخدام اسم المرسل الخاص بك (تحتاج إلى تسجيل الاسم أولاً). موثوقة للتنبيهات.",
|
||||||
|
"promosmsTypeSpeed": "سرعة الرسائل القصيرة - أولوية قصوى في النظام. سريع وموثوق للغاية ولكنه مكلف (حوالي مرتين من الرسائل القصيرة السعر الكامل).",
|
||||||
|
"promosmsPhoneNumber": "رقم الهاتف (للمستلم البولندي ، يمكنك تخطي رموز المنطقة)",
|
||||||
|
"matrixDesc2": "يوصى بشدة بإنشاء مستخدم جديد ولا تستخدم رمز الوصول إلى مستخدم Matrix الخاص بك لأنه سيتيح الوصول الكامل إلى حسابك وجميع الغرف التي انضمت إليها. بدلاً من ذلك ، قم بإنشاء مستخدم جديد ودعوته فقط إلى الغرفة التي تريد تلقيها الإشعار فيها. يمكنك الحصول على رمز الوصول عن طريق تشغيل {0}",
|
||||||
|
"Channel Name": "اسم القناة",
|
||||||
|
"promosmsSMSSender": "اسم مرسل الرسائل القصيرة",
|
||||||
|
"promosmsAllowLongSMS": "السماح الرسائل القصيرة الطويلة",
|
||||||
|
"Feishu WebHookUrl": "Feishu Webhookurl",
|
||||||
|
"matrixHomeserverURL": "عنوان URL HomeServer (مع HTTP (S)",
|
||||||
|
"Internal Room Id": "معرف الغرفة الداخلية",
|
||||||
|
"matrixDesc1": "يمكنك العثور على معرف الغرفة الداخلي من خلال البحث في القسم المتقدم من إعدادات الغرفة في عميل Matrix الخاص بك. يجب أن تبدو مثل! QMDRCPUIFLWSFJXYE6",
|
||||||
|
"Uptime Kuma URL": "UPTIME KUMA URL",
|
||||||
|
"Icon Emoji": "أيقونة الرموز التعبيرية",
|
||||||
|
"signalImportant": "مهم",
|
||||||
|
"aboutWebhooks": "مزيد من المعلومات حول Webhooks ON",
|
||||||
|
"aboutChannelName": "أدخل اسم القناة في حقل اسم القناة {0} إذا كنت تريد تجاوز قناة WebHook. السابق",
|
||||||
|
"aboutKumaURL": "إذا تركت حقل URL في وقت التشغيل KUMA فارغًا ، فسيتم افتراضيًا إلى صفحة GitHub Project.",
|
||||||
|
"smtpDkimSettings": "إعدادات DKIM",
|
||||||
|
"smtpDkimDesc": "يرجى الرجوع إلى Nodemailer dkim {0} للاستخدام.",
|
||||||
|
"documentation": "توثيق",
|
||||||
|
"smtpDkimDomain": "اسم النطاق",
|
||||||
|
"smtpDkimKeySelector": "المحدد الرئيسي",
|
||||||
|
"smtpDkimPrivateKey": "مفتاح سري",
|
||||||
|
"smtpDkimHashAlgo": "خوارزمية التجزئة (اختياري)",
|
||||||
|
"smtpDkimheaderFieldNames": "مفاتيح الرأس للتوقيع (اختياري)",
|
||||||
|
"smtpDkimskipFields": "مفاتيح الرأس لا توقيع (اختياري)",
|
||||||
|
"wayToGetPagerDutyKey": "يمكنك الحصول على هذا عن طريق الانتقال إلى الخدمة -> دليل الخدمة -> (حدد خدمة) -> تكامل -> إضافة التكامل. هنا يمكنك البحث عن \"Events API V2\". مزيد من المعلومات {0}",
|
||||||
|
"Integration Key": "مفتاح التكامل",
|
||||||
|
"Integration URL": "URL تكامل",
|
||||||
|
"do nothing": "لا تفعل شيئا",
|
||||||
|
"alertaApiEndpoint": "نقطة نهاية API",
|
||||||
|
"alertaEnvironment": "بيئة",
|
||||||
|
"alertaApiKey": "مفتاح API",
|
||||||
|
"alertaAlertState": "حالة التنبيه",
|
||||||
|
"alertaRecoverState": "استعادة الدولة",
|
||||||
|
"auto acknowledged": "",
|
||||||
|
"auto resolve": "",
|
||||||
|
"serwersmsAPIUser": "اسم مستخدم API (بما في ذلك بادئة WebAPI_)",
|
||||||
|
"serwersmsAPIPassword": "كلمة مرور API",
|
||||||
|
"serwersmsPhoneNumber": "رقم الهاتف",
|
||||||
|
"serwersmsSenderName": "اسم مرسل الرسائل القصيرة (مسجل عبر بوابة العملاء)",
|
||||||
|
"smseagleTo": "أرقام الهواتف)",
|
||||||
|
"smseagleGroup": "اسم مجموعة كتب الهاتف (S)",
|
||||||
|
"smseagleContact": "كتاب الاتصال اسم (S)",
|
||||||
|
"smseagleRecipientType": "نوع المستلم",
|
||||||
|
"smseagleRecipient": "المتلقي (المتلقيين) (يجب فصل المتعددة مع فاصلة)",
|
||||||
|
"smseagleToken": "API وصول الرمز المميز",
|
||||||
|
"smseagleUrl": "عنوان URL لجهاز SMSEGLE الخاص بك",
|
||||||
|
"smseagleEncoding": "إرسال Unicode",
|
||||||
|
"smseaglePriority": "أولوية الرسالة (0-9 افتراضي = 0)",
|
||||||
|
"Recipient Number": "رقم المستلم",
|
||||||
|
"From Name/Number": "من الاسم/الرقم",
|
||||||
|
"Leave blank to use a shared sender number.": "اترك فارغًا لاستخدام رقم المرسل المشترك.",
|
||||||
|
"Octopush API Version": "إصدار Octopush API",
|
||||||
|
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||||
|
"ntfy Topic": "موضوع ntfy",
|
||||||
|
"onebotHttpAddress": "OneBot HTTP عنوان",
|
||||||
|
"onebotMessageType": "نوع رسالة OneBot",
|
||||||
|
"onebotGroupMessage": "مجموعة",
|
||||||
|
"onebotPrivateMessage": "خاص",
|
||||||
|
"onebotUserOrGroupId": "معرف المجموعة/المستخدم",
|
||||||
|
"onebotSafetyTips": "للسلامة يجب ضبط الرمز المميز للوصول",
|
||||||
|
"PushDeer Key": "مفتاح PushDeer",
|
||||||
|
"wayToGetClickSendSMSToken": "يمكنك الحصول على اسم مستخدم API ومفتاح API من {0}.",
|
||||||
|
"Custom Monitor Type": "نوع الشاشة المخصص",
|
||||||
|
"Google Analytics ID": "معرف Google Analytics",
|
||||||
|
"Edit Tag": "تحرير العلامة",
|
||||||
|
"Server Address": "عنوان المستقبل",
|
||||||
|
"Learn More": "يتعلم أكثر",
|
||||||
|
"apiKeyAddedMsg": "تمت إضافة مفتاح API خاص بك. يرجى تدوين ذلك لأنه لن يتم عرضه مرة أخرى.",
|
||||||
|
"No API Keys": "لا توجد مفاتيح API",
|
||||||
|
"apiKey-inactive": "غير نشط",
|
||||||
|
"disableAPIKeyMsg": "هل أنت متأكد أنك تريد تعطيل مفتاح API هذا؟",
|
||||||
|
"deleteAPIKeyMsg": "هل أنت متأكد أنك تريد حذف مفتاح API هذا؟",
|
||||||
|
"Auto Get": "الحصول التلقائي",
|
||||||
|
"Auto resolve or acknowledged": "",
|
||||||
|
"backupDescription2": "ملحوظة",
|
||||||
|
"languageName": "العربية",
|
||||||
|
"Game": "الألعاب",
|
||||||
|
"List": "قائمة",
|
||||||
|
"statusMaintenance": "الصيانة"
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"Dashboard": "დაფა",
|
||||||
|
"Help": "დახმარება",
|
||||||
|
"New Update": "განახლება",
|
||||||
|
"Language": "ენა",
|
||||||
|
"Appearance": "ვიზუალი",
|
||||||
|
"Theme": "სტილი",
|
||||||
|
"Game": "თამაში",
|
||||||
|
"Version": "ვერსია",
|
||||||
|
"Quick Stats": "თვალის გადავლება",
|
||||||
|
"Up": "მაღლა",
|
||||||
|
"Pending": "მოლოდინი",
|
||||||
|
"languageName": "Georgian",
|
||||||
|
"Settings": "კონფიგურაცია",
|
||||||
|
"General": "ძირითადი",
|
||||||
|
"Check Update On GitHub": "GitHub_ზე განახლების შემოწმება",
|
||||||
|
"List": "სია",
|
||||||
|
"Add": "დამატება",
|
||||||
|
"Add New Monitor": "ახალი მონიტორის დამატება",
|
||||||
|
"Down": "დაბლა"
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
{}
|
|
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"Settings": "ക്രമീകരണം",
|
||||||
|
"Help": "സഹായം",
|
||||||
|
"New Update": "പുതിയ നവീകരണം",
|
||||||
|
"Language": "ഭാഷ",
|
||||||
|
"Appearance": "കാണപ്പെടുക",
|
||||||
|
"Theme": "ദൃശ്യക്രമീകരണം",
|
||||||
|
"General": "പൊതുവായത്",
|
||||||
|
"Version": "പതിപ്പ്",
|
||||||
|
"List": "പട്ടിക",
|
||||||
|
"Add": "ചേർക്കുക",
|
||||||
|
"Add New Monitor": "പുതിയ മോണിറ്റർ ചേർക്കുക",
|
||||||
|
"Quick Stats": "വേഗത്തിൽ ഇപ്പോളത്തെ അവസ്ഥ നോക്കുക",
|
||||||
|
"Up": "മുകളിൽ",
|
||||||
|
"Down": "താഴെ",
|
||||||
|
"statusMaintenance": "പരിപാലനം",
|
||||||
|
"Maintenance": "പരിപാലനം",
|
||||||
|
"Unknown": "അജ്ഞാതം",
|
||||||
|
"Passive Monitor Type": "പാർശമായ തിര നോട്ടം",
|
||||||
|
"Specific Monitor Type": "പ്രത്യേക തിര നോട്ടം",
|
||||||
|
"languageName": "മലയാളം",
|
||||||
|
"Dashboard": "നിയന്ത്രണോപകരണ സജ്ജീകരണം",
|
||||||
|
"Game": "കളികൾ",
|
||||||
|
"Check Update On GitHub": "പുതിയ മാറ്റങ്ങൾക്കായി GitHub നോക്കുക",
|
||||||
|
"Pending": "തീരുമാനം പ്രതീക്ഷിച്ചിരിക്കുന്ന",
|
||||||
|
"General Monitor Type": "പൊതുവരായ തിര നോട്ടം"
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
{}
|
|
@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
"Settings": "Nastavenia",
|
||||||
|
"Help": "Nápoveda",
|
||||||
|
"New Update": "Nová aktualizácia",
|
||||||
|
"Language": "Jazyk",
|
||||||
|
"Appearance": "Vzhľad",
|
||||||
|
"Theme": "Téma",
|
||||||
|
"General": "Základné",
|
||||||
|
"Primary Base URL": "Základná URL",
|
||||||
|
"Version": "Verzia",
|
||||||
|
"List": "Zoznam",
|
||||||
|
"Add": "Pridať",
|
||||||
|
"Add New Monitor": "Pridať nové Sledovanie",
|
||||||
|
"Quick Stats": "Rýchly prehľad",
|
||||||
|
"Pending": "Čaká sa",
|
||||||
|
"statusMaintenance": "Údržba",
|
||||||
|
"Maintenance": "Údržba",
|
||||||
|
"General Monitor Type": "Základný typ Sledovania",
|
||||||
|
"Passive Monitor Type": "Pasívny typ Sledovania",
|
||||||
|
"Specific Monitor Type": "Špecifický typ Sledovania",
|
||||||
|
"pauseDashboardHome": "Pauza",
|
||||||
|
"Pause": "Pauza",
|
||||||
|
"Status": "Stav",
|
||||||
|
"Message": "Správa",
|
||||||
|
"No important events": "Žiadne dôležité udalosti",
|
||||||
|
"Edit": "Upraviť",
|
||||||
|
"Delete": "Odstrániť",
|
||||||
|
"Current": "Aktuálne",
|
||||||
|
"Cert Exp.": "Platnosť cert.",
|
||||||
|
"day": "deň | dni",
|
||||||
|
"hour": "hodina",
|
||||||
|
"Response": "Odpoveď",
|
||||||
|
"Ping": "Ping",
|
||||||
|
"Keyword": "Kľúčové slovo",
|
||||||
|
"Friendly Name": "Názov",
|
||||||
|
"Port": "Port",
|
||||||
|
"Retries": "Opakovania",
|
||||||
|
"Resend Notification if Down X times consecutively": "Poslať oznámenie znovu, ak je nedostupné X-krát za sebou",
|
||||||
|
"Advanced": "Pokročilé",
|
||||||
|
"checkEverySecond": "Skontrolovať každých {0} sekúnd",
|
||||||
|
"retryCheckEverySecond": "Zopakovať každých {0} sekúnd",
|
||||||
|
"resendEveryXTimes": "Znovu poslať každých {0} krát",
|
||||||
|
"resendDisabled": "Opakované odoslanie vypnuté",
|
||||||
|
"ignoreTLSError": "Ignorovať TLS/SSL chyby pre HTTPS stránky",
|
||||||
|
"upsideDownModeDescription": "Obrátiť stav. Pokiaľ je služba dostupná, zobrazuje sa ako NEDOSTUPNÁ.",
|
||||||
|
"Upside Down Mode": "Obrátený režim",
|
||||||
|
"Max. Redirects": "Max. počet presmerovaní",
|
||||||
|
"Accepted Status Codes": "Akceptované stavové kódy",
|
||||||
|
"Push URL": "Push URL",
|
||||||
|
"Save": "Uložiť",
|
||||||
|
"Notifications": "Notifikácie",
|
||||||
|
"Not available, please setup.": "Nedostupné, prosím nastavte.",
|
||||||
|
"Setup Notification": "Nastavenie notifikácií",
|
||||||
|
"Dark": "Tmavá",
|
||||||
|
"Light": "Svetlá",
|
||||||
|
"Auto": "Automaticky",
|
||||||
|
"Normal": "Normálna",
|
||||||
|
"Bottom": "Dole",
|
||||||
|
"None": "Žiadne",
|
||||||
|
"Timezone": "Časová zóna",
|
||||||
|
"languageName": "Slovenčina",
|
||||||
|
"Dashboard": "Dashboard",
|
||||||
|
"Check Update On GitHub": "Skontrolovať aktualizáciu na GitHub-e",
|
||||||
|
"Up": "Dostupné",
|
||||||
|
"Down": "Nedostupné",
|
||||||
|
"Unknown": "Neznáme",
|
||||||
|
"markdownSupported": "Podpora Markdown syntaxu",
|
||||||
|
"Name": "Názov",
|
||||||
|
"DateTime": "Dátum a čas",
|
||||||
|
"Resume": "Pokračovať",
|
||||||
|
"Uptime": "Doba prevádzky",
|
||||||
|
"Monitor": "Sledovanie | Sledovania",
|
||||||
|
"-day": "-dní",
|
||||||
|
"-hour": "-hodín",
|
||||||
|
"Monitor Type": "Typ Sledovania",
|
||||||
|
"URL": "URL",
|
||||||
|
"Hostname": "Adresa",
|
||||||
|
"Heartbeat Interval": "Heartbeat Interval",
|
||||||
|
"Heartbeat Retry Interval": "Interval opakovania pre Heartbeat",
|
||||||
|
"retriesDescription": "Maximálny počet opakovaní pred tým, ako je služba označená ako nedostupná a je zaslaná notifikácia",
|
||||||
|
"maxRedirectDescription": "Maximálny počet presmerovaní. Hodnota 0 vypne presmerovania.",
|
||||||
|
"needPushEvery": "Tuto adresu by ste mali volať každých {0} sekúnd.",
|
||||||
|
"pushOptionalParams": "Voliteľné parametre: {0}",
|
||||||
|
"Theme - Heartbeat Bar": "Téma - Heartbeat riadok",
|
||||||
|
"Game": "Hra",
|
||||||
|
"Search Engine Visibility": "Viditeľnosť vyhľadávačmi",
|
||||||
|
"Allow indexing": "Povoliť indexovanie",
|
||||||
|
"Change Password": "Zmeniť heslo",
|
||||||
|
"Current Password": "Aktuálne heslo",
|
||||||
|
"New Password": "Nové heslo",
|
||||||
|
"Repeat New Password": "Zopakovať nové heslo",
|
||||||
|
"Update Password": "Aktualizovať heslo",
|
||||||
|
"Disable Auth": "Vypnúť autentifikáciu",
|
||||||
|
"Enable Auth": "Zapnúť autentifikáciu",
|
||||||
|
"Please use this option carefully!": "Túto možnosť používajte opatrne!",
|
||||||
|
"Logout": "Odhlásiť sa",
|
||||||
|
"Leave": "Odísť",
|
||||||
|
"I understand, please disable": "Rozumiem, vypnite to",
|
||||||
|
"Yes": "Áno",
|
||||||
|
"No": "Nie",
|
||||||
|
"Username": "Používateľské meno",
|
||||||
|
"Password": "Heslo",
|
||||||
|
"Login": "Prihlásiť sa",
|
||||||
|
"No Monitors, please": "Žiadne sledovanie, prosím",
|
||||||
|
"add one": "pridať jeden",
|
||||||
|
"Notification Type": "Typ notifikácie",
|
||||||
|
"Email": "E-mail",
|
||||||
|
"Test": "Test",
|
||||||
|
"Certificate Info": "Informácie o certifikáte",
|
||||||
|
"Resolver Server": "DNS server",
|
||||||
|
"Last Result": "Posledný výsledok",
|
||||||
|
"Repeat Password": "Zopakovať heslo",
|
||||||
|
"Import Backup": "Importovať zálohu",
|
||||||
|
"Export Backup": "Exportovať zálohu",
|
||||||
|
"Export": "Exportovať",
|
||||||
|
"Import": "Importovať",
|
||||||
|
"respTime": "Čas odozvy (ms)",
|
||||||
|
"notAvailableShort": "Nie je číslo",
|
||||||
|
"Default enabled": "Predvolene povolené",
|
||||||
|
"Create": "Vytvoriť",
|
||||||
|
"Clear Data": "Vyčistiť dáta",
|
||||||
|
"Events": "Udalosti",
|
||||||
|
"Heartbeats": "Odpovede",
|
||||||
|
"Auto Get": "Získať automaticky",
|
||||||
|
"Schedule maintenance": "Naplánovať údržbu",
|
||||||
|
"Affected Monitors": "Dotknuté sledovania",
|
||||||
|
"Pick Affected Monitors...": "Vybrať dotknuté sledovania…",
|
||||||
|
"Start of maintenance": "Začiatok údržby",
|
||||||
|
"All Status Pages": "Všetky stavové stránky",
|
||||||
|
"Select status pages...": "Vybrať stránky stavu…",
|
||||||
|
"alertNoFile": "Vyberte súbor na import.",
|
||||||
|
"alertWrongFileType": "Vyberte súbor JSON.",
|
||||||
|
"Clear all statistics": "Vymazať všetky štatistiky",
|
||||||
|
"Skip existing": "Preskočiť existujúce",
|
||||||
|
"Overwrite": "Prepísať",
|
||||||
|
"Options": "Možnosti",
|
||||||
|
"Keep both": "Ponechať obe",
|
||||||
|
"Setup 2FA": "Nastavenie 2FA",
|
||||||
|
"Disable 2FA": "Zakázať 2FA",
|
||||||
|
"2FA Settings": "Nastavenia 2FA",
|
||||||
|
"Two Factor Authentication": "Dvojfaktorová autentifikácia",
|
||||||
|
"Inactive": "Neaktívne",
|
||||||
|
"Token": "Token",
|
||||||
|
"Show URI": "Zobraziť URI",
|
||||||
|
"Tags": "Značky",
|
||||||
|
"Add New below or Select...": "Pridať novú nižšie alebo vybrať…",
|
||||||
|
"Tag with this value already exist.": "Značka s touto hodnotou už existuje.",
|
||||||
|
"color": "Farba",
|
||||||
|
"value (optional)": "hodnota (voliteľné)",
|
||||||
|
"Gray": "Šedá",
|
||||||
|
"Red": "Červená",
|
||||||
|
"Orange": "Oranžová",
|
||||||
|
"Green": "Zelená",
|
||||||
|
"Indigo": "Indigo",
|
||||||
|
"Purple": "Fialová",
|
||||||
|
"Pink": "Ružová",
|
||||||
|
"Custom": "Vlastná",
|
||||||
|
"Avg. Ping": "Priemerný ping",
|
||||||
|
"Avg. Response": "Priemerný čas odpovede",
|
||||||
|
"Entry Page": "Vstupná stránka",
|
||||||
|
"No Services": "Žiadne služby",
|
||||||
|
"All Systems Operational": "Všetky systémy funkčné",
|
||||||
|
"Partially Degraded Service": "Čiastočne zhoršená služba",
|
||||||
|
"Degraded Service": "Degradovaná služba",
|
||||||
|
"Add Group": "Pridať skupinu",
|
||||||
|
"Add a monitor": "Pridať sledovanie",
|
||||||
|
"Edit Status Page": "Upraviť stavovú stránku",
|
||||||
|
"Go to Dashboard": "Prejdite na informačný panel",
|
||||||
|
"Status Page": "Stavová stránka",
|
||||||
|
"Status Pages": "Stavové stránky",
|
||||||
|
"defaultNotificationName": "Moje {notification} upozornenie ({number})",
|
||||||
|
"here": "tu",
|
||||||
|
"Required": "Povinné",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Druh obsahu",
|
||||||
|
"webhookJsonDesc": "{0} je vhodný pre všetky moderné servery HTTP, ako napríklad Express.js",
|
||||||
|
"webhookFormDataDesc": "{multipart} je dobré pre PHP. JSON bude potrebné analyzovať pomocou {decodeFunction}",
|
||||||
|
"Generate": "Generovať",
|
||||||
|
"Discourage search engines from indexing site": "Odradiť vyhľadávacie nástroje od indexovania stránky",
|
||||||
|
"disableauth.message1": "Ste si istý, že chcete <strong>vypnúť autentifikáciu</strong>?",
|
||||||
|
"disableauth.message2": "Je navrhnutý pre scenáre, <strong>kde máte v úmysle implementovať autentifikáciu treťou stranou</strong> pred Uptime Kuma, ako je Cloudflare Access, Authelia alebo iné autentifikačné mechanizmy.",
|
||||||
|
"Confirm": "Potvrdiť",
|
||||||
|
"Remember me": "Zapamätať si ma",
|
||||||
|
"Resource Record Type": "Typ záznamu",
|
||||||
|
"Create your admin account": "Vytvorte si účet administrátora",
|
||||||
|
"Apply on all existing monitors": "Aplikujte na všetky existujúce sledovania",
|
||||||
|
"Verify Token": "Overiť token",
|
||||||
|
"Enable 2FA": "Povoliť 2FA",
|
||||||
|
"Active": "Aktívne",
|
||||||
|
"Add New Tag": "Pridať novú značku",
|
||||||
|
"Tag with this name already exist.": "Značka s týmto názvom už existuje.",
|
||||||
|
"Blue": "Modrá",
|
||||||
|
"Search...": "Hľadať…",
|
||||||
|
"statusPageNothing": "Nič tu nie je, pridajte skupinu alebo sledovanie."
|
||||||
|
}
|
Loading…
Reference in new issue