pull/1836/head
commit
f091e92c70
@ -0,0 +1,5 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
ALTER TABLE monitor_group
|
||||||
|
ADD send_url BOOLEAN DEFAULT 0 NOT NULL;
|
||||||
|
COMMIT;
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 893 B |
@ -0,0 +1,54 @@
|
|||||||
|
const https = require("https");
|
||||||
|
const http = require("http");
|
||||||
|
const CacheableLookup = require("cacheable-lookup");
|
||||||
|
|
||||||
|
class CacheableDnsHttpAgent {
|
||||||
|
|
||||||
|
static cacheable = new CacheableLookup();
|
||||||
|
|
||||||
|
static httpAgentList = {};
|
||||||
|
static httpsAgentList = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register cacheable to global agents
|
||||||
|
*/
|
||||||
|
static registerGlobalAgent() {
|
||||||
|
this.cacheable.install(http.globalAgent);
|
||||||
|
this.cacheable.install(https.globalAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static install(agent) {
|
||||||
|
this.cacheable.install(agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var {https.AgentOptions} agentOptions
|
||||||
|
* @return {https.Agent}
|
||||||
|
*/
|
||||||
|
static getHttpsAgent(agentOptions) {
|
||||||
|
let key = JSON.stringify(agentOptions);
|
||||||
|
if (!(key in this.httpsAgentList)) {
|
||||||
|
this.httpsAgentList[key] = new https.Agent(agentOptions);
|
||||||
|
this.cacheable.install(this.httpsAgentList[key]);
|
||||||
|
}
|
||||||
|
return this.httpsAgentList[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var {http.AgentOptions} agentOptions
|
||||||
|
* @return {https.Agents}
|
||||||
|
*/
|
||||||
|
static getHttpAgent(agentOptions) {
|
||||||
|
let key = JSON.stringify(agentOptions);
|
||||||
|
if (!(key in this.httpAgentList)) {
|
||||||
|
this.httpAgentList[key] = new http.Agent(agentOptions);
|
||||||
|
this.cacheable.install(this.httpAgentList[key]);
|
||||||
|
}
|
||||||
|
return this.httpAgentList[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
CacheableDnsHttpAgent,
|
||||||
|
};
|
@ -0,0 +1,50 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { setting } = require("../util-server");
|
||||||
|
const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util");
|
||||||
|
|
||||||
|
class AlertNow extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "AlertNow";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
try {
|
||||||
|
let textMsg = "";
|
||||||
|
let status = "open";
|
||||||
|
let eventType = "ERROR";
|
||||||
|
let eventId = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
||||||
|
|
||||||
|
if (heartbeatJSON && heartbeatJSON.status === UP) {
|
||||||
|
textMsg = `[${heartbeatJSON.name}] ✅ Application is back online`;
|
||||||
|
status = "close";
|
||||||
|
eventType = "INFO";
|
||||||
|
eventId += `_${heartbeatJSON.name.replace(/\s/g, "")}`;
|
||||||
|
} else if (heartbeatJSON && heartbeatJSON.status === DOWN) {
|
||||||
|
textMsg = `[${heartbeatJSON.name}] 🔴 Application went down`;
|
||||||
|
}
|
||||||
|
|
||||||
|
textMsg += ` - ${msg}`;
|
||||||
|
|
||||||
|
const baseURL = await setting("primaryBaseURL");
|
||||||
|
if (baseURL && monitorJSON) {
|
||||||
|
textMsg += ` >> ${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
"summary": textMsg,
|
||||||
|
"status": status,
|
||||||
|
"event_type": eventType,
|
||||||
|
"event_id": eventId,
|
||||||
|
};
|
||||||
|
|
||||||
|
await axios.post(notification.alertNowWebhookURL, data);
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AlertNow;
|
@ -0,0 +1,43 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const qs = require("qs");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class LineNotify extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "LineNotify";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
try {
|
||||||
|
let lineAPIUrl = "https://notify-api.line.me/api/notify";
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Authorization": "Bearer " + notification.lineNotifyAccessToken
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testMessage = {
|
||||||
|
"message": msg,
|
||||||
|
};
|
||||||
|
await axios.post(lineAPIUrl, qs.stringify(testMessage), config);
|
||||||
|
} else if (heartbeatJSON["status"] === DOWN) {
|
||||||
|
let downMessage = {
|
||||||
|
"message": "\n[🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
};
|
||||||
|
await axios.post(lineAPIUrl, qs.stringify(downMessage), config);
|
||||||
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
|
let upMessage = {
|
||||||
|
"message": "\n[✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
};
|
||||||
|
await axios.post(lineAPIUrl, qs.stringify(upMessage), config);
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LineNotify;
|
@ -0,0 +1,165 @@
|
|||||||
|
const { R } = require("redbean-node");
|
||||||
|
const { log } = require("../src/util");
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example:
|
||||||
|
* {
|
||||||
|
* key1: {
|
||||||
|
* value: "value2",
|
||||||
|
* timestamp: 12345678
|
||||||
|
* },
|
||||||
|
* key2: {
|
||||||
|
* value: 2,
|
||||||
|
* timestamp: 12345678
|
||||||
|
* },
|
||||||
|
* }
|
||||||
|
* @type {{}}
|
||||||
|
*/
|
||||||
|
static cacheList = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static cacheCleaner = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve value of setting based on key
|
||||||
|
* @param {string} key Key of setting to retrieve
|
||||||
|
* @returns {Promise<any>} Value
|
||||||
|
*/
|
||||||
|
static async get(key) {
|
||||||
|
|
||||||
|
// Start cache clear if not started yet
|
||||||
|
if (!Settings.cacheCleaner) {
|
||||||
|
Settings.cacheCleaner = setInterval(() => {
|
||||||
|
log.debug("settings", "Cache Cleaner is just started.");
|
||||||
|
for (key in Settings.cacheList) {
|
||||||
|
if (Date.now() - Settings.cacheList[key].timestamp > 60 * 1000) {
|
||||||
|
log.debug("settings", "Cache Cleaner deleted: " + key);
|
||||||
|
delete Settings.cacheList[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query from cache
|
||||||
|
if (key in Settings.cacheList) {
|
||||||
|
const v = Settings.cacheList[key].value;
|
||||||
|
log.debug("settings", `Get Setting (cache): ${key}: ${v}`);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
||||||
|
key,
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const v = JSON.parse(value);
|
||||||
|
log.debug("settings", `Get Setting: ${key}: ${v}`);
|
||||||
|
|
||||||
|
Settings.cacheList[key] = {
|
||||||
|
value: v,
|
||||||
|
timestamp: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
return v;
|
||||||
|
} catch (e) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the specified setting to specified value
|
||||||
|
* @param {string} key Key of setting to set
|
||||||
|
* @param {any} value Value to set to
|
||||||
|
* @param {?string} type Type of setting
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async set(key, value, type = null) {
|
||||||
|
|
||||||
|
let bean = await R.findOne("setting", " `key` = ? ", [
|
||||||
|
key,
|
||||||
|
]);
|
||||||
|
if (!bean) {
|
||||||
|
bean = R.dispense("setting");
|
||||||
|
bean.key = key;
|
||||||
|
}
|
||||||
|
bean.type = type;
|
||||||
|
bean.value = JSON.stringify(value);
|
||||||
|
await R.store(bean);
|
||||||
|
|
||||||
|
Settings.deleteCache([ key ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings based on type
|
||||||
|
* @param {string} type The type of setting
|
||||||
|
* @returns {Promise<Bean>}
|
||||||
|
*/
|
||||||
|
static async getSettings(type) {
|
||||||
|
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
|
||||||
|
type,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let result = {};
|
||||||
|
|
||||||
|
for (let row of list) {
|
||||||
|
try {
|
||||||
|
result[row.key] = JSON.parse(row.value);
|
||||||
|
} catch (e) {
|
||||||
|
result[row.key] = row.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set settings based on type
|
||||||
|
* @param {string} type Type of settings to set
|
||||||
|
* @param {Object} data Values of settings
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async setSettings(type, data) {
|
||||||
|
let keyList = Object.keys(data);
|
||||||
|
|
||||||
|
let promiseList = [];
|
||||||
|
|
||||||
|
for (let key of keyList) {
|
||||||
|
let bean = await R.findOne("setting", " `key` = ? ", [
|
||||||
|
key
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (bean == null) {
|
||||||
|
bean = R.dispense("setting");
|
||||||
|
bean.type = type;
|
||||||
|
bean.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bean.type === type) {
|
||||||
|
bean.value = JSON.stringify(data[key]);
|
||||||
|
promiseList.push(R.store(bean));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promiseList);
|
||||||
|
|
||||||
|
Settings.deleteCache(keyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string[]} keyList
|
||||||
|
*/
|
||||||
|
static deleteCache(keyList) {
|
||||||
|
for (let key of keyList) {
|
||||||
|
delete Settings.cacheList[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Settings,
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="alertnow-webhook-url" class="form-label">{{ $t("Webhook URL") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="alertnow-webhook-url" v-model="$parent.notification.alertNowWebhookURL" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<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://service.opsnow.com/docs/alertnow/en/user-guide-alertnow-en.html#standard" target="_blank">{{ $t("here") }}</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="line-notify-access-token" class="form-label">{{ $t("Access Token") }}</label>
|
||||||
|
<input id="line-notify-access-token" v-model="$parent.notification.lineNotifyAccessToken" type="text" class="form-control" :required="true">
|
||||||
|
</div>
|
||||||
|
<i18n-t tag="div" keypath="wayToGetLineNotifyToken" class="form-text" style="margin-top: 8px;">
|
||||||
|
<a href="https://notify-bot.line.me/" target="_blank">https://notify-bot.line.me/</a>
|
||||||
|
</i18n-t>
|
||||||
|
</template>
|
@ -0,0 +1,203 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Português (Portugal)",
|
||||||
|
checkEverySecond: "Verificar a cada {0} segundos.",
|
||||||
|
retryCheckEverySecond: "Tentar novamente a cada {0} segundos.",
|
||||||
|
retriesDescription: "Máximo de tentativas antes que o serviço seja marcado como inativo e uma notificação seja enviada",
|
||||||
|
ignoreTLSError: "Ignorar erros TLS/SSL para sites HTTPS",
|
||||||
|
upsideDownModeDescription: "Inverte o status de cabeça para baixo. Se o serviço estiver acessível, ele está OFFLINE.",
|
||||||
|
maxRedirectDescription: "Número máximo de redirecionamentos a seguir. Define como 0 para desativar redirecionamentos.",
|
||||||
|
acceptedStatusCodesDescription: "Seleciona os códigos de status que são considerados uma resposta bem-sucedida.",
|
||||||
|
passwordNotMatchMsg: "A senha repetida não corresponde.",
|
||||||
|
notificationDescription: "Atribuir uma notificação ao (s) monitor (es) para que funcione.",
|
||||||
|
keywordDescription: "Pesquisa a palavra-chave em HTML simples ou resposta JSON e diferencia maiúsculas de minúsculas",
|
||||||
|
pauseDashboardHome: "Pausa",
|
||||||
|
deleteMonitorMsg: "Tens a certeza de que queres excluir este monitor?",
|
||||||
|
deleteNotificationMsg: "Tens a certeza de que queres excluir esta notificação para todos os monitores?",
|
||||||
|
resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor 'resolvedor' a qualquer momento.",
|
||||||
|
rrtypeDescription: "Seleciona o RR-Type que queres monitorizar",
|
||||||
|
pauseMonitorMsg: "Tens a certeza que queres fazer uma pausa?",
|
||||||
|
enableDefaultNotificationDescription: "Para cada monitor novo esta notificação vai estar activa por padrão. Podes também desativar a notificação separadamente para cada monitor.",
|
||||||
|
clearEventsMsg: "Tens a certeza que queres excluir todos os eventos deste monitor?",
|
||||||
|
clearHeartbeatsMsg: "Tens a certeza de que queres excluir todos os heartbeats deste monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Tens a certeza que queres excluir TODAS as estatísticas?",
|
||||||
|
importHandleDescription: "Escolhe 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.",
|
||||||
|
confirmImportMsg: "Tens a certeza que queres importar o backup? Certifica-te que selecionaste a opção de importação correta.",
|
||||||
|
twoFAVerifyLabel: "Insire o teu token para verificares se o 2FA está a funcionar",
|
||||||
|
tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações do 2FA.",
|
||||||
|
confirmEnableTwoFAMsg: "Tens a certeza de que queres habilitar 2FA?",
|
||||||
|
confirmDisableTwoFAMsg: "Tens a certeza de que queres desativar 2FA?",
|
||||||
|
Settings: "Configurações",
|
||||||
|
Dashboard: "Dashboard",
|
||||||
|
"New Update": "Nova Atualização",
|
||||||
|
Language: "Linguagem",
|
||||||
|
Appearance: "Aparência",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Geral",
|
||||||
|
Version: "Versão",
|
||||||
|
"Check Update On GitHub": "Verificar atualização no Github",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Adicionar",
|
||||||
|
"Add New Monitor": "Adicionar novo monitor",
|
||||||
|
"Quick Stats": "Estatísticas rápidas",
|
||||||
|
Up: "On",
|
||||||
|
Down: "Off",
|
||||||
|
Pending: "Pendente",
|
||||||
|
Unknown: "Desconhecido",
|
||||||
|
Pause: "Pausa",
|
||||||
|
Name: "Nome",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Data hora",
|
||||||
|
Message: "Mensagem",
|
||||||
|
"No important events": "Nenhum evento importante",
|
||||||
|
Resume: "Resumo",
|
||||||
|
Edit: "Editar",
|
||||||
|
Delete: "Apagar",
|
||||||
|
Current: "Atual",
|
||||||
|
Uptime: "Tempo de atividade",
|
||||||
|
"Cert Exp.": "Cert Exp.",
|
||||||
|
day: "dia | dias",
|
||||||
|
"-day": "-dia",
|
||||||
|
hour: "hora",
|
||||||
|
"-hour": "-hora",
|
||||||
|
Response: "Resposta",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Tipo de Monitor",
|
||||||
|
Keyword: "Palavra-Chave",
|
||||||
|
"Friendly Name": "Nome Amigável",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Hostname",
|
||||||
|
Port: "Porta",
|
||||||
|
"Heartbeat Interval": "Intervalo de Heartbeats",
|
||||||
|
Retries: "Novas tentativas",
|
||||||
|
"Heartbeat Retry Interval": "Intervalo de repetição de Heartbeats",
|
||||||
|
Advanced: "Avançado",
|
||||||
|
"Upside Down Mode": "Modo de cabeça para baixo",
|
||||||
|
"Max. Redirects": "Redirecionamento Máx.",
|
||||||
|
"Accepted Status Codes": "Status Code Aceitáveis",
|
||||||
|
Save: "Guardar",
|
||||||
|
Notifications: "Notificações",
|
||||||
|
"Not available, please setup.": "Não disponível, por favor configura.",
|
||||||
|
"Setup Notification": "Configurar Notificação",
|
||||||
|
Light: "Claro",
|
||||||
|
Dark: "Escuro",
|
||||||
|
Auto: "Auto",
|
||||||
|
"Theme - Heartbeat Bar": "Tema - Barra de Heartbeat",
|
||||||
|
Normal: "Normal",
|
||||||
|
Bottom: "Inferior",
|
||||||
|
None: "Nenhum",
|
||||||
|
Timezone: "Fuso horário",
|
||||||
|
"Search Engine Visibility": "Visibilidade do mecanismo de pesquisa",
|
||||||
|
"Allow indexing": "Permitir Indexação",
|
||||||
|
"Discourage search engines from indexing site": "Desencorajar que motores de busca indexem o site",
|
||||||
|
"Change Password": "Mudar senha",
|
||||||
|
"Current Password": "Senha atual",
|
||||||
|
"New Password": "Nova Senha",
|
||||||
|
"Repeat New Password": "Repetir Nova Senha",
|
||||||
|
"Update Password": "Atualizar Senha",
|
||||||
|
"Disable Auth": "Desativar Autenticação",
|
||||||
|
"Enable Auth": "Ativar Autenticação",
|
||||||
|
"disableauth.message1": "Tens a certeza que queres <strong>desativar a autenticação</strong>?",
|
||||||
|
"disableauth.message2": "Isso é para <strong>alguém que tem autenticação de terceiros</strong> em frente ao 'UpTime Kuma' como o Cloudflare Access.",
|
||||||
|
"Please use this option carefully!": "Por favor, utiliza esta opção com cuidado.",
|
||||||
|
Logout: "Logout",
|
||||||
|
Leave: "Sair",
|
||||||
|
"I understand, please disable": "Eu entendo, por favor desativa.",
|
||||||
|
Confirm: "Confirmar",
|
||||||
|
Yes: "Sim",
|
||||||
|
No: "Não",
|
||||||
|
Username: "Utilizador",
|
||||||
|
Password: "Senha",
|
||||||
|
"Remember me": "Lembra-me",
|
||||||
|
Login: "Autenticar",
|
||||||
|
"No Monitors, please": "Nenhum monitor, por favor",
|
||||||
|
"add one": "adicionar um",
|
||||||
|
"Notification Type": "Tipo de Notificação",
|
||||||
|
Email: "Email",
|
||||||
|
Test: "Testar",
|
||||||
|
"Certificate Info": "Info. do Certificado ",
|
||||||
|
"Resolver Server": "Resolver Servidor",
|
||||||
|
"Resource Record Type": "Tipo de registro de aplicação",
|
||||||
|
"Last Result": "Último resultado",
|
||||||
|
"Create your admin account": "Cria a tua conta de admin",
|
||||||
|
"Repeat Password": "Repete a senha",
|
||||||
|
"Import Backup": "Importar Backup",
|
||||||
|
"Export Backup": "Exportar Backup",
|
||||||
|
Export: "Exportar",
|
||||||
|
Import: "Importar",
|
||||||
|
respTime: "Tempo de Resp. (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Padrão habilitado",
|
||||||
|
"Apply on all existing monitors": "Aplicar em todos os monitores existentes",
|
||||||
|
Create: "Criar",
|
||||||
|
"Clear Data": "Limpar Dados",
|
||||||
|
Events: "Eventos",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Obter Automático",
|
||||||
|
backupDescription: "Podes fazer backup de todos os monitores e todas as notificações num arquivo JSON.",
|
||||||
|
backupDescription2: "OBS: Os dados do histórico e do evento não estão incluídos.",
|
||||||
|
backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantem-no com cuidado.",
|
||||||
|
alertNoFile: "Seleciona um arquivo para importar.",
|
||||||
|
alertWrongFileType: "Seleciona um arquivo JSON.",
|
||||||
|
"Clear all statistics": "Limpar todas as estatísticas",
|
||||||
|
"Skip existing": "Saltar existente",
|
||||||
|
Overwrite: "Sobrescrever",
|
||||||
|
Options: "Opções",
|
||||||
|
"Keep both": "Manter os dois",
|
||||||
|
"Verify Token": "Verificar Token",
|
||||||
|
"Setup 2FA": "Configurar 2FA",
|
||||||
|
"Enable 2FA": "Ativar 2FA",
|
||||||
|
"Disable 2FA": "Desativar 2FA",
|
||||||
|
"2FA Settings": "Configurações do 2FA ",
|
||||||
|
"Two Factor Authentication": "Autenticação de Dois Fatores",
|
||||||
|
Active: "Ativo",
|
||||||
|
Inactive: "Inativo",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Mostrar URI",
|
||||||
|
Tags: "Tag",
|
||||||
|
"Add New below or Select...": "Adicionar Novo abaixo ou Selecionar ...",
|
||||||
|
"Tag with this name already exist.": "Já existe uma etiqueta com este nome.",
|
||||||
|
"Tag with this value already exist.": "Já existe uma etiqueta com este valor.",
|
||||||
|
color: "cor",
|
||||||
|
"value (optional)": "valor (opcional)",
|
||||||
|
Gray: "Cinza",
|
||||||
|
Red: "Vermelho",
|
||||||
|
Orange: "Laranja",
|
||||||
|
Green: "Verde",
|
||||||
|
Blue: "Azul",
|
||||||
|
Indigo: "Índigo",
|
||||||
|
Purple: "Roxo",
|
||||||
|
Pink: "Rosa",
|
||||||
|
"Search...": "Pesquisa...",
|
||||||
|
"Avg. Ping": "Ping Médio.",
|
||||||
|
"Avg. Response": "Resposta Média. ",
|
||||||
|
"Status Page": "Página de Status",
|
||||||
|
"Status Pages": "Página de Status",
|
||||||
|
"Entry Page": "Página de entrada",
|
||||||
|
statusPageNothing: "Nada aqui, por favor, adiciona um grupo ou monitor.",
|
||||||
|
"No Services": "Nenhum Serviço",
|
||||||
|
"All Systems Operational": "Todos os Serviços Operacionais",
|
||||||
|
"Partially Degraded Service": "Serviço parcialmente degradados",
|
||||||
|
"Degraded Service": "Serviço Degradado",
|
||||||
|
"Add Group": "Adicionar Grupo",
|
||||||
|
"Add a monitor": "Adicionar um monitor",
|
||||||
|
"Edit Status Page": "Editar Página de Status",
|
||||||
|
"Go to Dashboard": "Ir para o dashboard",
|
||||||
|
telegram: "Telegram",
|
||||||
|
webhook: "Webhook",
|
||||||
|
smtp: "Email (SMTP)",
|
||||||
|
discord: "Discord",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
signal: "Signal",
|
||||||
|
gotify: "Gotify",
|
||||||
|
slack: "Slack",
|
||||||
|
"rocket.chat": "Rocket.chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (Support 50+ Notification services)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "Line Messenger",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
};
|
Loading…
Reference in new issue