Compare commits

..

56 Commits

Author SHA1 Message Date
Raj Nandan Sharma ebc30b674f Merge pull request #476 from rajnandan1/fix/475
refactor(users): change plain password input type to password for sec…
2025-08-06 07:31:22 +05:30
Raj Nandan Sharma bf079798d3 refactor(users): change plain password input type to password for security #475 2025-08-06 07:30:49 +05:30
Raj Nandan Sharma 480cf64738 Merge pull request #474 from rajnandan1/fix/429
refactor(docker): enhance build process and organize template files f…
2025-08-05 22:37:47 +05:30
Raj Nandan Sharma 65f039b7bd refactor(docker): enhance build process and organize template files fixes #429 2025-08-05 22:36:31 +05:30
Raj Nandan Sharma 5c7b62e9f7 Merge pull request #451 from moaazbhnas228/fix/heartbeat-grace-period
Fix: Heartbeat monitor respects cron-based grace periods
2025-08-05 22:21:37 +05:30
Raj Nandan Sharma 5e6e891ea6 Merge pull request #473 from rajnandan1/fix/441
Fix/441
2025-08-05 22:00:06 +05:30
Raj Nandan Sharma 82c904608b refactor(subscriptions): simplify condition for subscription trigger ID check 2025-08-05 21:59:22 +05:30
Raj Nandan Sharma f5260ceb86 chore(package): update version to 3.2.19 2025-08-05 21:18:32 +05:30
Raj Nandan Sharma abb32fdd6f fix(subscriptions): improve status toggle handling
Refactors the subscription status toggle to use a dedicated handler, ensuring correct behavior when toggling status for both new and existing triggers. Enhances user experience by automatically saving and reloading data when needed.
2025-08-05 21:17:09 +05:30
Raj Nandan Sharma 97aef5c5f5 Merge pull request #461 from antonio-sessa/fix/issue_456
fix: enhance monitor rearrangement with scrollable container
2025-08-05 11:06:47 +05:30
Raj Nandan Sharma c3eb8ae7f4 Merge pull request #467 from Baw-Appie/patch-1
Update Korean translations for clarity and consistency
2025-08-05 11:06:15 +05:30
Raj Nandan Sharma 72f74f9164 Merge pull request #469 from faridvatani/feature/persian-support
feat(i18n): add Persian language support
2025-08-05 11:05:50 +05:30
Farid Vatani 958676e5a7 feat(i18n): add Persian language support 2025-07-21 14:27:42 +03:30
JiHun Oh 51134670e5 Update Korean translations for clarity and consistency 2025-07-19 11:02:39 +00:00
JiHun Oh ecea2b220d Update ko.json 2025-07-19 19:51:27 +09:00
antonio-sessa 212f4d5e7a fix: enhance monitor rearrangement with scrollable container 2025-07-14 09:30:41 +02:00
Raj Nandan Sharma 2edb09bd13 Merge pull request #455 from xgenos/fix-issue-332
fixed the issue#332 with more optimized ORIGIN env calls
2025-07-11 10:10:07 +05:30
Biswa Kalyan Bhuyan 6b9f073cb7 fix: fixed the issue#332 with more optimized ORIGIN env calls 2025-07-02 19:15:52 +05:30
Moaaz Bhnas 9f933a0f1c Fixed returned status/type on heartbeat error 2025-07-02 09:21:58 +03:00
Moaaz Bhnas 8a6f721bb4 previousRun() 2025-07-01 09:03:50 +03:00
Moaaz Bhnas eeadcca6ed Used croner instead of cron-parser 2025-07-01 08:59:04 +03:00
Moaaz Bhnas 8e89c10906 Small change 2025-07-01 08:53:46 +03:00
Moaaz Bhnas 833d16351c FIX: heartbeat latency 2025-07-01 08:49:32 +03:00
Raj Nandan Sharma 0c10552fa7 Merge pull request #448 from federico-it/main
feat(i18n): add Italian language support
2025-06-30 21:30:05 +05:30
Raj Nandan Sharma 443afe2f6e Merge pull request #447 from sendmiche/patch-1
The translation has been made more suitable for the Russian language.
2025-06-30 21:29:33 +05:30
Federico db48d98da7 feat(i18n): add Italian language support 2025-06-20 17:44:28 +02:00
sendmiche bf3150434a The translation has been made more suitable for the Russian language. 2025-06-20 12:30:59 +03:00
github-actions 71c4bd26d2 Auto-generate README.md with release versions 2025-06-12 04:47:55 +00:00
Raj Nandan Sharma ca4f7040e8 refactor(themeInfo): remove maintenance status migration and update default value handling 2025-06-12 09:54:03 +05:30
Raj Nandan Sharma 1cfa861d7e Merge pull request #431 from rajnandan1/release/18
Release/18
2025-06-12 09:21:40 +05:30
Raj Nandan Sharma 007baefe80 Merge pull request #426 from ToxykAuBleu/feat/scheduled-downtime
Add maintenance visibility to monitor' status
2025-06-02 09:31:36 +05:30
Raj Nandan Sharma 7d77f4d996 chore: update version to 3.2.18 2025-05-28 10:01:15 +05:30
Raj Nandan Sharma 3d5a62c085 feat(subscription): add status toggle and restrict config editing #418
Adds support for toggling the subscription trigger's active/inactive status from the UI and updates backend/controller logic to allow dynamic status changes. Restricts editing of subscription event configuration and user subscriptions to when the trigger is active, improving admin control and preventing unintended changes when subscriptions are inactive.
2025-05-28 10:00:32 +05:30
Raj Nandan Sharma 24ffef997b feat(docker): copy server templates to build output #429 2025-05-28 08:52:37 +05:30
ToxykAuBleu 7d5275152c Fixing responsiveness of "Availability per Component", above monitors. 2025-05-26 12:08:03 +00:00
ToxykAuBleu 93167c2358 Reverting commit about recurring maintenance (forgotten). 2025-05-26 11:22:30 +00:00
ToxykAuBleu 734d3ad280 Adding translations for all translations. 2025-05-26 09:57:59 +00:00
ToxykAuBleu 753668dfa5 Adding documentation related to new maintenance status. 2025-05-26 06:58:03 +00:00
ToxykAuBleu 351817338d Reverting commits about recurring maintenance (moved to new branch). 2025-05-26 06:47:17 +00:00
ToxykAuBleu 7c12218489 Changing default color of maintenance' status. 2025-05-22 06:50:24 +00:00
ToxykAuBleu 7c71298227 Adding maintenance calculation & message to system data. 2025-05-22 06:41:10 +00:00
ToxykAuBleu 167db6d7e6 Adding visibility of this new status to Home page.
Adding MAINTENANCE to affected monitors (Events page).
2025-05-21 07:08:35 +00:00
Raj Nandan Sharma 74834f3559 Merge pull request #417 from chunchet-ng/main
fix: remove VOLUME declarations to prevent unintended anonymous volumes
2025-05-21 09:24:23 +05:30
ToxykAuBleu e13ca5c639 Adding visibility of this new type of maintenance into Events page. 2025-05-15 12:08:29 +00:00
Chun Chet a51806d62b fix: remove VOLUME declarations to prevent unintended anonymous volumes 2025-05-15 11:18:23 +08:00
ToxykAuBleu 57238dfb72 Adding input validation for maintenance duration.
Fixing some labels + flex layout.
2025-05-13 07:02:42 +00:00
ToxykAuBleu a2be642af0 Updating controller to accept new input data from Incident creation page.
Updating last migration to create new columns.
2025-05-13 07:01:14 +00:00
Raj Nandan Sharma aec2d23c2f Merge pull request #416 from OzkrOssa/feature/spanish-support
feat(i18n): add Spanish language support
2025-05-13 09:56:31 +05:30
Oscar Ossa 11a11162da feat(i18n): add Spanish language support 2025-05-12 09:48:06 -05:00
ToxykAuBleu 12a7be497e Editing incident creation page to include maintenance strategy option.
Removing unused properties inside newIncident.
2025-05-12 08:25:26 +00:00
github-actions 9b69da66a5 Auto-generate README.md with release versions 2025-05-06 17:27:39 +00:00
Raj Nandan Sharma ee831f96bb Merge pull request #413 from rajnandan1/css-fix-1
chore: update version to 3.2.17 and adjust layout properties in monit…
2025-05-06 22:40:06 +05:30
Raj Nandan Sharma 5542790145 chore: update version to 3.2.17 and adjust layout properties in monitor component 2025-05-06 22:39:09 +05:30
github-actions 3b1091a34f Auto-generate README.md with release versions 2025-05-06 01:54:32 +00:00
ToxykAuBleu 3b05ca73e5 Adding validation to this new status.
Adding migration + seed for this new status.
2025-05-05 09:05:16 +00:00
ToxykAuBleu 236d7ea585 Adding new maintenance status to theme page. 2025-05-05 09:04:37 +00:00
48 changed files with 651 additions and 147 deletions
+4 -4
View File
@@ -63,8 +63,10 @@ RUN rm -rf src/routes/\(docs\) \
mkdir -p uploads database && \
chmod -R 750 uploads database
# Build the application and remove `devDependencies`
# Build the application and copy templates to build directory
RUN npm run build && \
mkdir -p build/server/templates && \
cp -r src/lib/server/templates/* build/server/templates/ && \
npm prune --omit=dev
#==========================================================#
@@ -108,6 +110,7 @@ COPY --chown=node:node --from=builder /app/src/lib/ ./src/lib/
COPY --chown=node:node --from=builder /app/build ./build
COPY --chown=node:node --from=builder /app/uploads ./uploads
COPY --chown=node:node --from=builder /app/database ./database
COPY --chown=node:node --from=builder /app/src/lib/server/templates ./build/server/templates
# TODO: Consider changing from copying `node_modules` to instead letting `npm ci --omit=dev` handle production dependencies. Right now, copying `node_modules` is leading to a smaller image, whereas letting `npm ci` handle the install in final image is slightly faster, but leads to larger image size. IMO, having a slightly longer build time (e.g. ~10 sec.) is better in the end to have a smaller image.
COPY --chown=node:node --from=builder /app/node_modules ./node_modules
COPY --chown=node:node --from=builder /app/migrations ./migrations
@@ -120,9 +123,6 @@ COPY --chown=node:node --from=builder /app/openapi.json ./openapi.json
COPY --chown=node:node --from=builder /app/openapi.yaml ./openapi.yaml
COPY --chown=node:node --from=builder /app/package.json ./package.json
# Ensure necessary directories are writable
VOLUME ["/uploads", "/database"]
# Set container timezone and make entrypoint script executable
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
chmod +x ./entrypoint.sh
+9 -9
View File
@@ -79,7 +79,7 @@ npm run dev
Official Docker images for **Kener** are available on [Docker Hub](https://hub.docker.com/r/rajnandan1/kener). Multiple versions are maintained to support different use cases.
<a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.15"><img src="https://img.shields.io/badge/Latest_Stable_Release-3.2.15-blue" alt="Kener latest stable version: 3.2.15" /></a>
<a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.18"><img src="https://img.shields.io/badge/Latest_Stable_Release-3.2.18-blue" alt="Kener latest stable version: 3.2.18" /></a>
#### Available Tags
@@ -93,38 +93,38 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=latest" target="_blank"><code>latest</code></td>
<td>Latest stable release (aka 3.2.15)</td>
<td>Latest stable release (aka 3.2.18)</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.15" target="_blank"><code>3.2.15</code></a></td>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.18" target="_blank"><code>3.2.18</code></a></td>
<td>Specific release version</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2" target="_blank"><code>3.2</code></a></td>
<td>Major-minor version tag pointing to the latest patch (3.2.15) release within that minor version (3.2.x)</td>
<td>Major-minor version tag pointing to the latest patch (3.2.18) release within that minor version (3.2.x)</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3" target="_blank"><code>3</code></a></td>
<td>Major version tag pointing to the latest stable (3.2.15) release within that major version (3.x.x)</td>
<td>Major version tag pointing to the latest stable (3.2.18) release within that major version (3.x.x)</td>
</tr>
<tr>
<td align="left" colspan="2" style="color:#0D597F;text-align:left;">Alpine Linux 3.21 w/ Node.js v23.7.0 &nbsp;<strong><em>(smallest image size)</em></strong></td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=alpine" target="_blank"><code>alpine</code></td>
<td>Latest stable release (aka 3.2.15)</td>
<td>Latest stable release (aka 3.2.18)</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.15-alpine" target="_blank"><code>3.2.15-alpine</code></a></td>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2.18-alpine" target="_blank"><code>3.2.18-alpine</code></a></td>
<td>Specific release version</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3.2-alpine" target="_blank"><code>3.2-alpine</code></a></td>
<td>Major-minor version tag pointing to the latest patch (3.2.15) release within that minor version (3.2.x)</td>
<td>Major-minor version tag pointing to the latest patch (3.2.18) release within that minor version (3.2.x)</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=3-alpine" target="_blank"><code>3-alpine</code></a></td>
<td>Major version tag pointing to the latest stable (3.2.15) release within that major version (3.x.x)</td>
<td>Major version tag pointing to the latest stable (3.2.18) release within that major version (3.x.x)</td>
</tr>
</table>
+2
View File
@@ -41,6 +41,7 @@ Copy and update the translation file in the `locales` folder. The translation fi
"All Systems are Degraded": "All Systems are Degraded",
"All Systems are Down": "All Systems are Down",
"All Systems are Operational": "All Systems are Operational",
"All Systems are in Maintenance": "All Systems are in Maintenance",
"Back": "Back",
"Badge Copied": "Badge Copied",
"Badge": "Badge",
@@ -91,6 +92,7 @@ Copy and update the translation file in the `locales` folder. The translation fi
"Some Systems are not working as expected": "Some Systems are not working as expected",
"Some Systems Degraded": "Some Systems Degraded",
"Some Systems Down": "Some Systems Down",
"Some Systems in Maintenance": "Some Systems in Maintenance",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Started %startedAt, lasted for %lastedFor",
"Started %startedAt, still ongoing": "Started %startedAt, still ongoing",
+1 -1
View File
@@ -73,7 +73,7 @@ To close an incident, you need to add a message and set the status to `RESOLVED`
## Add Monitors
To add monitors to the incident, you need to add the monitor tag to the incident. This will automatically add the monitor to the incident. You will also get the status of the monitor in the incident. This can be `DEGRADED` or `DOWN`.
To add monitors to the incident, you need to add the monitor tag to the incident. This will automatically add the monitor to the incident. You will also get the status of the monitor in the incident. For any event type, this can be `DEGRADED` or `DOWN`. For maintenance event type, this can also be `MAINTENANCE`.
## Maintenance
+1 -1
View File
@@ -75,7 +75,7 @@ Shows the day's impact. Example: If it was down at 10:00 AM and it is 11:00 AM,
## Colors
You can change the colors of UP/DEGRADED/DOWN states of the monitor. You show have a shade of green, yellow, and red respectively.
You can change the colors of UP/DEGRADED/DOWN/MAINTENANCE states of the monitor. By default, it shows a shade of green, yellow, red and blue respectively.
---
+4
View File
@@ -15,6 +15,10 @@ const base = process.env.KENER_BASE_PATH || "";
const app = express();
const db = knex(knexOb);
if (process.env.ORIGIN) {
process.env.SVELTEKIT_ORIGIN = process.env.ORIGIN;
}
app.use((req, res, next) => {
if (req.path.startsWith("/embed")) {
res.setHeader("Content-Security-Policy", "frame-ancestors *");
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "kener",
"version": "3.2.16",
"version": "3.2.19",
"private": false,
"license": "MIT",
"description": "Kener is a modern, open-source status page application built with Node.js. It provides real-time monitoring, uptime tracking, incident management, and beautiful dashboards. Perfect for DevOps teams, SaaS providers, and businesses needing reliable service status communication with minimal setup.",
+28
View File
@@ -10,6 +10,7 @@ section {
--up-color: #4ead94;
--down-color: #ca3038;
--degraded-color: #e6ca61;
--maintenance-color: #6679cc;
}
/*Colors for something UP*/
@@ -82,6 +83,33 @@ section {
background: linear-gradient(0deg, var(--degraded-color) 90%, var(--up-color) 1%);
}
/*Colors for something in maintenance*/
.bg-api-maintenance {
background-color: var(--maintenance-color);
}
.text-api-maintenance {
color: var(--maintenance-color);
}
.bg-api-maintenance-10 {
background: linear-gradient(0deg, var(--maintenance-color) 10%, var(--up-color) 1%);
}
.bg-api-maintenance-20 {
background: linear-gradient(0deg, var(--maintenance-color) 20%, var(--up-color) 1%);
}
.bg-api-maintenance-40 {
background: linear-gradient(0deg, var(--maintenance-color) 40%, var(--up-color) 1%);
}
.bg-api-maintenance-60 {
background: linear-gradient(0deg, var(--maintenance-color) 60%, var(--up-color) 1%);
}
.bg-api-maintenance-80 {
background: linear-gradient(0deg, var(--maintenance-color) 80%, var(--up-color) 1%);
}
.bg-api-maintenance-90 {
background: linear-gradient(0deg, var(--maintenance-color) 90%, var(--up-color) 1%);
}
/*Needed to show markdown properly*/
.prose :where(code):not(:where([class~="not-prose"], [class~="not-prose"] *))::before {
content: "";
+1
View File
@@ -7,6 +7,7 @@ async function StatusColor(status) {
UP: site.colors?.UP || "#00dfa2",
DEGRADED: site.colors?.DEGRADED || "#e6ca61",
DOWN: site.colors?.DOWN || "#ca3038",
MAINTENANCE: site.colors?.MAINTENANCE || "#6679cc",
NO_DATA: "#f1f5f8"
};
}
+1 -1
View File
@@ -481,7 +481,7 @@
<div class="content px-4 py-4">
<h2 class="text-lg font-semibold">Rearrange Monitors</h2>
<div
class="mt-4"
class="mt-4 max-h-[80vh] overflow-y-auto"
use:dndzone={{ items: monitors, flipDurationMs, dropTargetStyle }}
on:consider={handleSort}
on:finalize={handleSort}
+21 -3
View File
@@ -35,7 +35,8 @@
colorsJ: {
UP: "#4ead94",
DOWN: "#ca3038",
DEGRADED: "#e6ca61"
DEGRADED: "#e6ca61",
MAINTENANCE: "#6679cc"
},
fontJ: {
cssSrc:
@@ -50,7 +51,10 @@
themeData = siteDataExtractFromDb(data.siteData, themeData);
if (data.siteData.colors) {
themeData.colorsJ = data.siteData.colors;
if (data.siteData.colors.MAINTENANCE === undefined) {
data.siteData.colors.MAINTENANCE = "#6679cc"; // default value for MAINTENANCE
}
themeData.colorsJ = JSON.parse(JSON.stringify(data.siteData.colors));
}
if (data.siteData.font) {
themeData.fontJ = data.siteData.font;
@@ -296,7 +300,7 @@
<div>
<p class="font-medium">Status Colors</p>
<p class=" text-xs font-semibold text-muted-foreground">
Choose the colors for the monitor. You can choose between UP, DEGRADED, and DOWN.
Choose the colors for the monitor. You can choose between UP, DEGRADED, DOWN and MAINTENANCE.
</p>
</div>
@@ -343,6 +347,20 @@
}}
/>
</div>
<div class="relative">
<ColorPicker
bind:hex={themeData.colorsJ.MAINTENANCE}
position="responsive"
isAlpha={false}
isDark={$mode == "dark"}
--input-size="16px"
isTextInput={true}
label="MAINTENANCE"
on:input={(event) => {
themeData.colorsJ.MAINTENANCE = event.detail.hex;
}}
/>
</div>
</div>
<hr />
<p class="font-medium">
+2 -2
View File
@@ -211,7 +211,7 @@
}
</script>
<div class="monitor relative grid w-full grid-cols-12 gap-2 pb-2 pt-0 md:w-[655px]">
<div class="monitor relative grid w-full max-w-[655px] grid-cols-12 gap-2 pb-2 pt-0">
{#if !!!embed}
<div class="col-span-12 md:w-[546px]">
<div class="pt-0">
@@ -312,7 +312,7 @@
showDailyDataModal = false;
}}
>
<div class="daygrid90 flex min-h-[60px] justify-start overflow-x-auto overflow-y-hidden py-1">
<div class="daygrid90 flex min-h-[60px] justify-between overflow-x-auto overflow-y-hidden py-1">
{#each Object.entries(_90Day) as [ts, bar]}
<button
data-ts={ts}
+4 -1
View File
@@ -1,7 +1,7 @@
// @ts-nocheck
import { format, formatDistance, formatDistanceToNow, formatDuration } from "date-fns";
import { ru, enUS, hi, de, zhCN, vi, ja, nl, da, fr, ko, ptBR, tr, nb, pl } from "date-fns/locale";
import { ru, enUS, hi, de, zhCN, vi, ja, nl, da, fr, ko, ptBR, tr, nb, pl, es, it, faIR } from "date-fns/locale";
import { formatInTimeZone } from "date-fns-tz";
const locales = {
@@ -20,6 +20,9 @@ const locales = {
tr,
"nb-NO": nb,
pl,
es,
it,
fa: faIR,
};
const f = function (date, formatStr, locale, tz) {
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Alle Systeme sind eingeschränkt",
"All Systems are Down": "Alle Systeme sind ausgefallen",
"All Systems are Operational": "Alle Systeme sind betriebsbereit",
"All Systems are in Maintenance": "Alle Systeme sind in Wartung",
"Back": "Zurück",
"Badge Copied": "Abzeichen kopiert",
"Badge": "Abzeichen",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Einige Systeme funktionieren nicht wie erwartet",
"Some Systems Degraded": "Einige Systeme eingeschränkt",
"Some Systems Down": "Einige Systeme ausgefallen",
"Some Systems in Maintenance": "Einige Systeme sind in Wartung",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Begann vor etwa %startedAt und dauerte etwa %lastedFor",
"Started %startedAt, still ongoing": "Begann vor etwa %startedAt und dauert noch an",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Alle Systemer er Forringet",
"All Systems are Down": "Alle Systemer er Nede",
"All Systems are Operational": "Alle Systemer er Operationelle",
"All Systems are in Maintenance": "Alle systemer er i vedligeholdelse",
"Back": "Tilbage",
"Badge Copied": "Mærke Kopieret",
"Badge": "Mærke",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Nogle Systemer fungerer ikke som forventet",
"Some Systems Degraded": "Nogle Systemer er Forringet",
"Some Systems Down": "Nogle Systemer er Nede",
"Some Systems in Maintenance": "Nogle Systemer er i Vedligeholdelse",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Startede for cirka %startedAt siden, varede i cirka %lastedFor",
"Started %startedAt, still ongoing": "Startede for cirka %startedAt siden, stadig igangværende",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "All Systems are Degraded",
"All Systems are Down": "All Systems are Down",
"All Systems are Operational": "All Systems are Operational",
"All Systems are in Maintenance": "All Systems are in Maintenance",
"Back": "Back",
"Badge Copied": "Badge Copied",
"Badge": "Badge",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Some Systems are not working as expected",
"Some Systems Degraded": "Some Systems Degraded",
"Some Systems Down": "Some Systems Down",
"Some Systems in Maintenance": "Some Systems in Maintenance",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Started %startedAt, lasted for %lastedFor",
"Started %startedAt, still ongoing": "Started %startedAt, still ongoing",
+90
View File
@@ -0,0 +1,90 @@
{
"%status for %duration": "%status durante %duration",
"120 Days": "120 Días",
"14 Days": "14 Días",
"150 Days": "150 Días",
"180 Days": "180 Días",
"30 Days": "30 Días",
"60 Days": "60 Días",
"7 Days": "7 Días",
"90 Days": "90 Días",
"Availability per Component": "Disponibilidad por componente",
"All Systems are Degraded": "Todos los sistemas están degradados",
"All Systems are Down": "Todos los sistemas están caídos",
"All Systems are Operational": "Todos los sistemas están operativos",
"Back": "Volver",
"Badge Copied": "Distintivo copiado",
"Badge": "Distintivo",
"Browse Events": "Ver eventos",
"Change Email": "Cambiar correo electrónico",
"Code Copied": "Código copiado",
"Confirm Login": "Confirmar inicio de sesión",
"Copy Code": "Copiar código",
"Copy Link": "Copiar enlace",
"DEGRADED": "DEGRADADO",
"DOWN": "CAÍDO",
"Dark": "Oscuro",
"Days": "Días",
"Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.": "Incrusta este monitor usando <script> o <iframe> en tu aplicación.",
"Embed": "Incrustar",
"Enter the code": "Ingresa el código",
"Enter your email": "Ingresa tu correo electrónico",
"Enter your email to log in. If you are not subscribed, you will be prompted to subscribe.": "Ingresa tu correo electrónico para iniciar sesión. Si no estás suscrito, se te pedirá que te suscribas.",
"Get SVG badge for this monitor": "Obtener distintivo SVG para este monitor",
"Get a LIVE Status for this monitor": "Obtener estado EN VIVO para este monitor",
"IDENTIFIED": "IDENTIFICADO",
"INVESTIGATING": "INVESTIGANDO",
"Incident Updates": "Actualizaciones de incidentes",
"LIVE Status": "Estado EN VIVO",
"Lasted for about %lastedFor": "Duró aproximadamente %lastedFor",
"Light": "Claro",
"Link Copied": "Enlace copiado",
"Login": "Iniciar sesión",
"MAINTENANCE": "MANTENIMIENTO",
"MONITORING": "MONITOREANDO",
"Maintenance Completed": "Mantenimiento completado",
"Maintenance in Progress": "Mantenimiento en progreso",
"Manage Subscription": "Gestionar suscripción",
"Mode": "Modo",
"No Data": "Sin datos",
"No Incident in %date": "Sin incidentes en %date",
"No Incidents": "Sin incidentes",
"No Monitor Found": "No se encontró monitor",
"No Updates Yet": "Aún no hay actualizaciones",
"Ongoing Incidents": "Incidentes en curso",
"Pinging": "Haciendo ping",
"Please select specific monitors to receive updates from.": "Por favor selecciona monitores específicos para recibir actualizaciones.",
"RESOLVED": "RESUELTO",
"Recent Incidents": "Incidentes recientes",
"Recent Maintenances": "Mantenimientos recientes",
"Share this monitor using a link with others": "Comparte este monitor mediante un enlace con otros",
"Share": "Compartir",
"Some Systems are not working as expected": "Algunos sistemas no funcionan como se espera",
"Some Systems Degraded": "Algunos sistemas degradados",
"Some Systems Down": "Algunos sistemas caídos",
"Standard": "Estándar",
"Started %startedAt, lasted for %lastedFor": "Comenzó el %startedAt, duró %lastedFor",
"Started %startedAt, still ongoing": "Comenzó el %startedAt, aún en curso",
"Started %startedAt, will last for %lastedFor more": "Comenzó el %startedAt, durará %lastedFor más",
"Starts %startedAt, will last for %lastedFor": "Empieza el %startedAt, durará %lastedFor",
"Starts %startedAt": "Empieza el %startedAt",
"Status OK": "Estado OK",
"Status": "Estado",
"Subscribe": "Suscribirse",
"Subscribe to Updates": "Suscribirse a actualizaciones",
"Subscribe to all monitors": "Suscribirse a todos los monitores",
"Switch to your timezone": "Cambiar a tu zona horaria",
"Theme": "Tema",
"There are no upcoming maintenances": "No hay mantenimientos próximos",
"Timezone set to %tz": "Zona horaria configurada a %tz",
"Today": "Hoy",
"UP": "ACTIVO",
"Update Subscription": "Actualizar suscripción",
"Upcoming Maintenance": "Mantenimiento próximo",
"Upcoming Maintenances": "Mantenimientos próximos",
"Updates": "Actualizaciones",
"Uptime": "Tiempo en línea",
"View in detail": "Ver en detalle",
"We have sent a code to your email. Please enter it below to confirm your login": "Hemos enviado un código a tu correo. Por favor, ingrésalo abajo para confirmar tu inicio de sesión",
"You are logged in as %email": "Has iniciado sesión como %email"
}
+92
View File
@@ -0,0 +1,92 @@
{
"%status for %duration": "%status به مدت %duration",
"120 Days": "۱۲۰ روزه",
"14 Days": "۱۴ روزه",
"150 Days": "۱۵۰ روزه",
"180 Days": "۱۸۰ روزه",
"30 Days": "۳۰ روزه",
"60 Days": "۶۰ روزه",
"7 Days": "۷ روزه",
"90 Days": "۹۰ روزه",
"Availability per Component": "دسترس‌پذیری هر کامپوننت",
"All Systems are Degraded": "همه سامانه‌ها دچار اختلال‌اند",
"All Systems are Down": "همه سامانه‌ها از کار افتاده‌اند",
"All Systems are Operational": "همه سامانه‌ها در حال کار هستند",
"All Systems are in Maintenance": "همه سامانه‌ها در حال تعمیر هستند",
"Back": "بازگشت",
"Badge Copied": "نشان کپی شد",
"Badge": "نشان",
"Browse Events": "مشاهده رویدادها",
"Change Email": "تغییر ایمیل",
"Code Copied": "کد کپی شد",
"Confirm Login": "تأیید ورود",
"Copy Code": "کپی کد",
"Copy Link": "کپی لینک",
"DEGRADED": "اختلال",
"DOWN": "از کار افتاده",
"Dark": "تاریک",
"Days": "روزها",
"Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.": "این مانیتور را با استفاده از <script> یا <iframe> در برنامه‌تان قرار دهید.",
"Embed": "درج",
"Enter the code": "کد را وارد کنید",
"Enter your email": "ایمیل خود را وارد کنید",
"Enter your email to log in. If you are not subscribed, you will be prompted to subscribe.": "برای ورود، ایمیل خود را وارد کنید. اگر عضو نیستید، از شما خواسته می‌شود عضو شوید.",
"Get SVG badge for this monitor": "دریافت نشان SVG برای این مانیتور",
"Get a LIVE Status for this monitor": "دریافت وضعیت زنده این مانیتور",
"IDENTIFIED": "شناسایی شده",
"INVESTIGATING": "در حال بررسی",
"Incident Updates": "به‌روزرسانی‌های حادثه",
"LIVE Status": "وضعیت زنده",
"Lasted for about %lastedFor": "حدوداً به مدت %lastedFor ادامه داشت",
"Light": "روشن",
"Link Copied": "لینک کپی شد",
"Login": "ورود",
"MAINTENANCE": "تعمیر و نگهداری",
"MONITORING": "در حال پایش",
"Maintenance Completed": "تعمیرات به پایان رسید",
"Maintenance in Progress": "تعمیرات در حال انجام است",
"Manage Subscription": "مدیریت اشتراک",
"Mode": "حالت",
"No Data": "بدون داده",
"No Incident in %date": "هیچ حادثه‌ای در %date وجود ندارد",
"No Incidents": "هیچ حادثه‌ای وجود ندارد",
"No Monitor Found": "هیچ مانیتوری یافت نشد",
"No Updates Yet": "هنوز به‌روزرسانی‌ای وجود ندارد",
"Ongoing Incidents": "حوادث در حال وقوع",
"Pinging": "در حال پینگ گرفتن",
"Please select specific monitors to receive updates from.": "لطفاً مانیتورهای خاصی را برای دریافت به‌روزرسانی انتخاب کنید.",
"RESOLVED": "حل شده",
"Recent Incidents": "حوادث اخیر",
"Recent Maintenances": "تعمیرات اخیر",
"Share this monitor using a link with others": "این مانیتور را با لینک با دیگران به اشتراک بگذارید",
"Share": "اشتراک‌گذاری",
"Some Systems are not working as expected": "برخی سامانه‌ها به‌درستی کار نمی‌کنند",
"Some Systems Degraded": "برخی سامانه‌ها دچار اختلال‌اند",
"Some Systems Down": "برخی سامانه‌ها از کار افتاده‌اند",
"Some Systems in Maintenance": "برخی سامانه‌ها در حال تعمیر هستند",
"Standard": "معمولی",
"Started %startedAt, lasted for %lastedFor": "شروع در %startedAt، به مدت %lastedFor ادامه داشت",
"Started %startedAt, still ongoing": "شروع در %startedAt، هنوز ادامه دارد",
"Started %startedAt, will last for %lastedFor more": "شروع در %startedAt، تا %lastedFor دیگر ادامه خواهد داشت",
"Starts %startedAt, will last for %lastedFor": "شروع در %startedAt، به مدت %lastedFor ادامه دارد",
"Starts %startedAt": "شروع در %startedAt",
"Status OK": "وضعیت خوب",
"Status": "وضعیت",
"Subscribe": "اشتراک",
"Subscribe to Updates": "مشترک شدن در به‌روزرسانی‌ها",
"Subscribe to all monitors": "اشتراک همه مانیتورها",
"Switch to your timezone": "تغییر به منطقه زمانی شما",
"Theme": "تم",
"There are no upcoming maintenances": "هیچ تعمیر آینده‌ای وجود ندارد",
"Timezone set to %tz": "منطقه زمانی روی %tz تنظیم شد",
"Today": "امروز",
"UP": "فعال",
"Update Subscription": "به‌روزرسانی اشتراک",
"Upcoming Maintenance": "تعمیر آینده",
"Upcoming Maintenances": "تعمیرات آینده",
"Updates": "به‌روزرسانی‌ها",
"Uptime": "زمان کارکرد",
"View in detail": "مشاهده جزئیات",
"We have sent a code to your email. Please enter it below to confirm your login": "کدی به ایمیل شما ارسال کردیم. لطفاً برای تأیید ورود آن را وارد کنید.",
"You are logged in as %email": "شما با ایمیل %email وارد شده‌اید"
}
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Tous les systèmes sont dégradés",
"All Systems are Down": "Tous les systèmes sont hors ligne",
"All Systems are Operational": "Tous les systèmes sont opérationnels",
"All Systems are in Maintenance": "Tous les systèmes sont en maintenance",
"Back": "Retour",
"Badge Copied": "Badge copié",
"Badge": "Badge",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Certains systèmes ne fonctionnent pas comme prévu",
"Some Systems Degraded": "Certains systèmes sont dégradés",
"Some Systems Down": "Certains systèmes sont hors ligne",
"Some Systems in Maintenance": "Certains systèmes sont en maintenance",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Commencé il y a environ %startedAt, a duré environ %lastedFor",
"Started %startedAt, still ongoing": "Commencé il y a environ %startedAt, toujours en cours",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "सभी सिस्टम क्षीण हैं",
"All Systems are Down": "सभी सिस्टम डाउन हैं",
"All Systems are Operational": "सभी सिस्टम कार्यरत हैं",
"All Systems are in Maintenance": "सभी सिस्टम रखरखाव में हैं",
"Back": "वापस",
"Badge Copied": "बैज कॉपी किया गया",
"Badge": "बैज",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "कुछ सिस्टम अपेक्षित रूप से काम नहीं कर रहे हैं",
"Some Systems Degraded": "कुछ सिस्टम क्षीण हैं",
"Some Systems Down": "कुछ सिस्टम डाउन हैं",
"Some Systems in Maintenance": "कुछ सिस्टम रखरखाव में हैं",
"Standard": "मानक",
"Started %startedAt, lasted for %lastedFor": "%startedAt शुरू हुआ, %lastedFor तक चला",
"Started %startedAt, still ongoing": "%startedAt शुरू हुआ, अभी भी जारी है",
+93
View File
@@ -0,0 +1,93 @@
{
"%status for %duration": "%status per %duration",
"120 Days": "120 Giorni",
"14 Days": "14 Giorni",
"150 Days": "150 Giorni",
"180 Days": "180 Giorni",
"30 Days": "30 Giorni",
"60 Days": "60 Giorni",
"7 Days": "7 Giorni",
"90 Days": "90 Giorni",
"Availability per Component": "Disponibilità per componente",
"All Systems are Degraded": "Tutti i sistemi sono degradati",
"All Systems are Down": "Tutti i sistemi sono inattivi",
"All Systems are Operational": "Tutti i sistemi sono operativi",
"All Systems are in Maintenance": "Tutti i sistemi sono in manutenzione",
"Back": "Indietro",
"Badge Copied": "Badge copiato",
"Badge": "Badge",
"Browse Events": "Sfoglia eventi",
"Change Email": "Cambia email",
"Code Copied": "Codice copiato",
"Confirm Login": "Conferma accesso",
"Copy Code": "Copia codice",
"Copy Link": "Copia link",
"DEGRADED": "DEGRADATO",
"DOWN": "NON DISPONIBILE",
"Dark": "Scuro",
"Days": "Giorni",
"Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.": "Incorpora questo monitor usando <script> o <iframe> nella tua app.",
"Embed": "Incorpora",
"Enter the code": "Inserisci il codice",
"Enter your email": "Inserisci la tua email",
"Enter your email to log in. If you are not subscribed, you will be prompted to subscribe.": "Inserisci la tua email per accedere. Se non sei iscritto, ti verrà chiesto di iscriverti.",
"Get SVG badge for this monitor": "Ottieni badge SVG per questo monitor",
"Get a LIVE Status for this monitor": "Ottieni lo stato LIVE per questo monitor",
"IDENTIFIED": "IDENTIFICATO",
"INVESTIGATING": "IN ANALISI",
"Incident Updates": "Aggiornamenti incidenti",
"LIVE Status": "Stato LIVE",
"Lasted for about %lastedFor": "Durato circa %lastedFor",
"Light": "Chiaro",
"Link Copied": "Link copiato",
"Login": "Accedi",
"MAINTENANCE": "MANUTENZIONE",
"MONITORING": "MONITORAGGIO",
"Maintenance Completed": "Manutenzione completata",
"Maintenance in Progress": "Manutenzione in corso",
"Manage Subscription": "Gestisci iscrizione",
"Mode": "Modalità",
"No Data": "Nessun dato",
"No Incident in %date": "Nessun incidente in %date",
"No Incidents": "Nessun incidente",
"No Monitor Found": "Nessun monitor trovato",
"No Updates Yet": "Nessun aggiornamento ancora",
"Ongoing Incidents": "Incidenti in corso",
"Pinging": "Ping in corso",
"Please select specific monitors to receive updates from.": "Seleziona i monitor specifici da cui ricevere aggiornamenti.",
"RESOLVED": "RISOLTO",
"Recent Incidents": "Incidenti recenti",
"Recent Maintenances": "Manutenzioni recenti",
"Share this monitor using a link with others": "Condividi questo monitor tramite un link con altri",
"Share": "Condividi",
"Some Systems are not working as expected": "Alcuni sistemi non funzionano come previsto",
"Some Systems Degraded": "Alcuni sistemi degradati",
"Some Systems Down": "Alcuni sistemi inattivi",
"Some Systems in Maintenance": "Alcuni sistemi in manutenzione",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Iniziato il %startedAt, durato %lastedFor",
"Started %startedAt, still ongoing": "Iniziato il %startedAt, ancora in corso",
"Started %startedAt, will last for %lastedFor more": "Iniziato il %startedAt, durerà ancora %lastedFor",
"Starts %startedAt, will last for %lastedFor": "Inizia il %startedAt, durerà %lastedFor",
"Starts %startedAt": "Inizia il %startedAt",
"Status OK": "Stato OK",
"Status": "Stato",
"Subscribe": "Iscriviti",
"Subscribe to Updates": "Iscriviti agli aggiornamenti",
"Subscribe to all monitors": "Iscriviti a tutti i monitor",
"Switch to your timezone": "Passa al tuo fuso orario",
"Theme": "Tema",
"There are no upcoming maintenances": "Non ci sono manutenzioni imminenti",
"Timezone set to %tz": "Fuso orario impostato su %tz",
"Today": "Oggi",
"UP": "ATTIVO",
"Update Subscription": "Aggiorna iscrizione",
"Upcoming Maintenance": "Manutenzione imminente",
"Upcoming Maintenances": "Manutenzioni imminenti",
"Updates": "Aggiornamenti",
"Uptime": "Tempo di attività",
"View in detail": "Visualizza nel dettaglio",
"We have sent a code to your email. Please enter it below to confirm your login": "Abbiamo inviato un codice alla tua email. Inseriscilo qui sotto per confermare l'accesso",
"You are logged in as %email": "Sei connesso come %email"
}
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "すべてのシステムが劣化しています",
"All Systems are Down": "すべてのシステムがダウンしています",
"All Systems are Operational": "すべてのシステムが正常に稼働しています",
"All Systems are in Maintenance": "すべてのシステムがメンテナンス中です",
"Back": "戻る",
"Badge Copied": "バッジがコピーされました",
"Badge": "バッジ",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "一部のシステムが期待通りに動作していません",
"Some Systems Degraded": "一部のシステムが劣化しています",
"Some Systems Down": "一部のシステムがダウンしています",
"Some Systems in Maintenance": "いくつかのシステムがメンテナンス中です",
"Standard": "標準",
"Started %startedAt, lasted for %lastedFor": "%startedAt 前に開始し、約 %lastedFor 続きました",
"Started %startedAt, still ongoing": "%startedAt 前に開始し、まだ進行中です",
+36 -34
View File
@@ -1,25 +1,26 @@
{
"%status for %duration": "%duration 동안 %status 상태였음",
"120 Days": "120 일",
"14 Days": "14 일",
"150 Days": "150 일",
"180 Days": "180 일",
"30 Days": "30 일",
"60 Days": "60 일",
"7 Days": "7 일",
"90 Days": "90 일",
"Availability per Component": "항목당 가용성",
"%status for %duration": "%duration 동안 %status 상태",
"120 Days": "120일",
"14 Days": "14일",
"150 Days": "150일",
"180 Days": "180일",
"30 Days": "30일",
"60 Days": "60일",
"7 Days": "7일",
"90 Days": "90일",
"Availability per Component": "항목 당 가용성",
"All Systems are Degraded": "모든 시스템이 성능 저하 상태입니다",
"All Systems are Down": "모든 시스템이 중단되었습니다",
"All Systems are Operational": "모든 시스템이 정상 작동 중입니다",
"All Systems are in Maintenance": "모든 시스템이 유지 보수 중입니다",
"Back": "뒤로",
"Badge Copied": "배지 복사됨",
"Badge Copied": "배지 복사 됨",
"Badge": "배지",
"Browse Events": "이벤트 찾아보기",
"Change Email": "이메일 변경",
"Code Copied": "소스코드 복사됨",
"Code Copied": "소스 코드 복사됨",
"Confirm Login": "로그인 확인",
"Copy Code": "소스코드 복사",
"Copy Code": "소스 코드 복사",
"Copy Link": "링크 복사",
"DEGRADED": "성능 저하됨",
"DOWN": "중단",
@@ -30,58 +31,59 @@
"Enter the code": "코드를 입력하세요",
"Enter your email": "이메일을 입력하세요",
"Enter your email to log in. If you are not subscribed, you will be prompted to subscribe.": "로그인하려면 이메일을 입력하세요. 구독하지 않은 경우 구독 요청이 표시됩니다.",
"Get SVG badge for this monitor": "이 모니터링 항목에 대한 SVG 배지를 구해보세요.",
"Get a LIVE Status for this monitor": "이 모니터링 항목에 대한 실시간 상태를 구해보세요.",
"IDENTIFIED": "확인됨",
"Get SVG badge for this monitor": "이 모니터링 항목에 대한 SVG 배지를 얻어보세요.",
"Get a LIVE Status for this monitor": "이 모니터링 항목에 대한 실시간 상태를 얻어보세요.",
"IDENTIFIED": "확인 됨",
"INVESTIGATING": "조사 중",
"Incident Updates": "사건 보고서",
"LIVE Status": "실시간 상태",
"Lasted for about %lastedFor": "%lastedFor 동안 지속",
"Light": "라이트",
"Link Copied": "링크 복사됨",
"Light": "밝게",
"Link Copied": "링크 복사 됨",
"Login": "로그인",
"MAINTENANCE": "유지보수",
"MONITORING": "감시 중",
"Maintenance Completed": "유지보수 완료",
"Maintenance in Progress": "유지보수 진행 중",
"Maintenance Completed": "유지 보수 완료",
"Maintenance in Progress": "유지 보수 진행 중",
"Manage Subscription": "구독 관리",
"Mode": "모드",
"No Data": "데이터 없음",
"No Incident in %date": "%date 에는 아무 사건도 없었음",
"No Incident in %date": "%date에는 아무 사건도 없었음",
"No Incidents": "사건 없음",
"No Monitor Found": "모니터링 항목을 찾을 수 없음",
"No Updates Yet": "아직 아무 업데이트도 없음",
"Ongoing Incidents": "진행중 사건",
"Ongoing Incidents": "진행 중 사건",
"Pinging": "핑 요청",
"Please select specific monitors to receive updates from.": "업데이트를 받을 특정 모니터를 선택하세요.",
"RESOLVED": "해결됨",
"RESOLVED": "해결 됨",
"Recent Incidents": "최근 사건",
"Recent Maintenances": "최근 유지보수",
"Recent Maintenances": "최근 유지 보수",
"Share this monitor using a link with others": "링크를 사용하여 다른 사람들과 이 모니터링 데이터를 공유해보세요",
"Share": "공유",
"Some Systems are not working as expected": "일부 시스템이 예상대로 작동하지 않습니다",
"Some Systems Degraded": "일부 시스템이 성능 저하 상태입니다",
"Some Systems Down": "일부 시스템이 중단되었습니다",
"Some Systems in Maintenance": "일부 시스템이 유지 보수 중입니다",
"Standard": "기본",
"Started %startedAt, lasted for %lastedFor": "%startedAt에 시작되었으며, %lastedFor 동안 지속되습니다",
"Started %startedAt, still ongoing": "%startedAt에 시작되었으며, 아직 진행중입니다",
"Started %startedAt, will last for %lastedFor more": "%startedAt에 시작되었으며, %lastedFor 더 지속될 예정입니다",
"Starts %startedAt, will last for %lastedFor": "%startedAt에 시작되었으며, %lastedFor 까지 지속될 예정입니다",
"Starts %startedAt": "%startedAt 에 시작되었습니다",
"Started %startedAt, lasted for %lastedFor": "%startedAt에 시작되었으며, %lastedFor 동안 지속되고 있습니다",
"Started %startedAt, still ongoing": "%startedAt에 시작되었으며, 아직 진행 중입니다",
"Started %startedAt, will last for %lastedFor more": "%startedAt에 시작되었으며, %lastedFor 더 지속될 예정입니다",
"Starts %startedAt, will last for %lastedFor": "%startedAt에 시작되며, %lastedFor 지속될 예정입니다",
"Starts %startedAt": "%startedAt에 시작되었습니다",
"Status OK": "양호",
"Status": "상태",
"Subscribe": "구독",
"Subscribe to Updates": "업데이트 구독하기",
"Subscribe to all monitors": "모든 모니터 구독",
"Switch to your timezone": "귀하의 시간대로 변경",
"Switch to your timezone": " 시간대로 변경",
"Theme": "테마",
"There are no upcoming maintenances": "예정된 유지보수가 없습니다",
"Timezone set to %tz": "시간대 설정 %tz",
"There are no upcoming maintenances": "예정된 유지 보수가 없습니다",
"Timezone set to %tz": "%tz(으)로 시간대 설정",
"Today": "오늘",
"UP": "작동 중",
"Update Subscription": "구독 업데이트",
"Upcoming Maintenance": "예정된 유지보수",
"Upcoming Maintenances": "예정된 유지보수 목록",
"Upcoming Maintenance": "예정된 유지 보수",
"Upcoming Maintenances": "예정된 유지 보수 목록",
"Updates": "업데이트",
"Uptime": "업타임",
"View in detail": "자세히 보기",
+12
View File
@@ -58,5 +58,17 @@
{
"code": "pl",
"name": "Polski"
},
{
"code": "es",
"name": "Español"
},
{
"code": "it",
"name": "Italiano"
},
{
"code": "fa",
"name": "Persian (فارسی)"
}
]
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Alle systemer har nedsatt ytelse",
"All Systems are Down": "Alle systemer er nede",
"All Systems are Operational": "Alle systemer er operative",
"All Systems are in Maintenance": "Alle systemer er til vedlikehold",
"Back": "Tilbake",
"Badge Copied": "Merke kopiert",
"Badge": "Merke",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Noen systemer fungerer ikke som forventet",
"Some Systems Degraded": "Noen systemer har nedsatt ytelse",
"Some Systems Down": "Noen systemer er nede",
"Some Systems in Maintenance": "Noen systemer er til vedlikehold",
"Standard": "Standard",
"Started %startedAt, lasted for %lastedFor": "Startet %startedAt, varte i %lastedFor",
"Started %startedAt, still ongoing": "Startet %startedAt, fortsatt pågår",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Alle systemen werken met beperkte functionaliteit",
"All Systems are Down": "Alle systemen zijn niet bereikbaar",
"All Systems are Operational": "Alle systemen zijn operationeel",
"All Systems are in Maintenance": "Alle systemen zijn in onderhoud",
"Back": "Terug",
"Badge Copied": "Badge gekopieerd",
"Badge": "Badge",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Sommige systemen werken niet zoals verwacht",
"Some Systems Degraded": "Sommige systemen werken met beperkte functionaliteit",
"Some Systems Down": "Sommige systemen zijn niet bereikbaar",
"Some Systems in Maintenance": "Sommige systemen zijn in onderhoud",
"Standard": "Standaard",
"Started %startedAt, lasted for %lastedFor": "Begonnen ongeveer %startedAt geleden, duurde ongeveer %lastedFor",
"Started %startedAt, still ongoing": "Begonnen ongeveer %startedAt geleden, nog steeds bezig",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Wszystkie systemy działają z ograniczeniami",
"All Systems are Down": "Wszystkie systemy są niedostępne",
"All Systems are Operational": "Wszystkie systemy działają poprawnie",
"All Systems are in Maintenance": "Wszystkie systemy są w konserwacji",
"Back": "Wstecz",
"Badge Copied": "Odznaka skopiowana",
"Badge": "Odznaka",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Niektóre systemy nie działają zgodnie z oczekiwaniami",
"Some Systems Degraded": "Niektóre systemy działają z ograniczeniami",
"Some Systems Down": "Niektóre systemy są niedostępne",
"Some Systems in Maintenance": "Niektóre systemy są w konserwacji",
"Standard": "Standardowy",
"Started %startedAt, lasted for %lastedFor": "Rozpoczęto %startedAt, trwało %lastedFor",
"Started %startedAt, still ongoing": "Rozpoczęto %startedAt, nadal trwa",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Todos os Sistemas estão com Falhas",
"All Systems are Down": "Todos os Sistemas estão Indisponíveis",
"All Systems are Operational": "Todos os Sistemas estão Operacionais",
"All Systems are in Maintenance": "Todos os Sistemas estão em Manutenção",
"Back": "Voltar",
"Badge Copied": "Emblema Copiado",
"Badge": "Emblema",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Alguns Sistemas não estão funcionando como esperado",
"Some Systems Degraded": "Alguns Sistemas estão com Falhas",
"Some Systems Down": "Alguns Sistemas estão Indisponíveis",
"Some Systems in Maintenance": "Alguns Sistemas estão em Manutenção",
"Standard": "Padrão",
"Started %startedAt, lasted for %lastedFor": "Ocorreu faz %startedAt e durou %lastedFor",
"Started %startedAt, still ongoing": "Iniciou faz %startedAt, ainda em andamento",
+49 -47
View File
@@ -1,73 +1,75 @@
{
"%status for %duration": "%status в течение %duration",
"14 Days": "14 Дней",
"30 Days": "30 Дней",
"60 Days": "60 Дней",
"7 Days": "7 Дней",
"90 Days": "90 Дней",
"120 Days": "120 Дней",
"150 Days": "150 Дней",
"180 Days": "180 Дней",
"120 Days": "120 дней",
"14 Days": "14 дней",
"150 Days": "150 дней",
"180 Days": "180 дней",
"30 Days": "30 дней",
"60 Days": "60 дней",
"7 Days": "7 дней",
"90 Days": "90 дней",
"Availability per Component": "Доступность по компонентам",
"All Systems are Degraded": "Все системы работают с ухудшенной производительностью",
"All Systems are Down": "Все системы недоступны",
"All Systems are Operational": "Все системы работают нормально",
"All Systems are Degraded": "Системы работают нестабильно",
"All Systems are Down": "Системы не работают",
"All Systems are Operational": "Системы работают нормально",
"All Systems are in Maintenance": "Системы на обслуживании",
"Back": "Назад",
"Badge Copied": "Значок скопирован",
"Badge": "Значок",
"Browse Events": "Просмотр событий",
"Change Email": "Изменить email",
"Change Email": "Изменить электронную почту",
"Code Copied": "Код скопирован",
"Confirm Login": "Подтвердить вход",
"Copy Code": "Копировать код",
"Copy Link": "Копировать ссылку",
"DEGRADED": "УХУДШЕНО",
"DOWN": "НЕДОСТУПНО",
"Dark": "Темная",
"Days": "Дней",
"Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.": "Встройте этот монитор используя <script> или <iframe> в ваше приложение.",
"Embed": "Встроить",
"Confirm Login": "Подтвердите вход",
"Copy Code": "Скопировать код",
"Copy Link": "Скопировать ссылку",
"DEGRADED": "НЕСТАБИЛЬНО",
"DOWN": "НЕ РАБОТАЕТ",
"Dark": "Тёмная",
"Days": "дней",
"Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.": "Встройте этот монитор с помощью <script> или <iframe> в ваше приложение.",
"Embed": "Вставить",
"Enter the code": "Введите код",
"Enter your email": "Введите ваш email",
"Enter your email to log in. If you are not subscribed, you will be prompted to subscribe.": "Введите ваш email для входа. Если вы не подписаны, вам будет предложено подписаться.",
"Get SVG badge for this monitor": "Получить SVG значок для этого монитора",
"Get a LIVE Status for this monitor": "Получить ЖИВОЙ статус для этого монитора",
"Get a LIVE Status for this monitor": "Получить текущий статус для этого монитора",
"IDENTIFIED": "ВЫЯВЛЕНО",
"INVESTIGATING": ССЛЕДУЕТСЯ",
"Incident Updates": "Обновления инцидента",
"LIVE Status": "ЖИВОЙ статус",
"Lasted for about %lastedFor": "Длилось около %lastedFor",
"INVESTIGATING": ЗУЧАЕТСЯ",
"Incident Updates": "Обновления инцидентов",
"LIVE Status": "Текущий статус",
"Lasted for about %lastedFor": "Продолжалось около %lastedFor",
"Light": "Светлая",
"Link Copied": "Ссылка скопирована",
"Login": "Войти",
"MAINTENANCE": "ОБСЛУЖИВАНИЕ",
"MONITORING": "МОНИТОРИНГ",
"Maintenance Completed": "Техническое обслуживание завершено",
"Maintenance in Progress": "Техническое обслуживание",
"Maintenance Completed": "Обслуживание завершено",
"Maintenance in Progress": "Обслуживание в процессе",
"Manage Subscription": "Управление подпиской",
"Mode": "Режим",
"No Data": "Нет данных",
"No Incident in %date": "Нет инцидентов на %date",
"No Incidents": "Нет инцидентов",
"No Incident in %date": "Нет инцидентов за %date",
"No Incidents": "Инцидентов нет",
"No Monitor Found": "Монитор не найден",
"No Updates Yet": "Пока нет обновлений",
"No Updates Yet": "Обновлений пока нет",
"Ongoing Incidents": "Текущие инциденты",
"Pinging": ингуется",
"Please select specific monitors to receive updates from.": "Выберите конкретные мониторы для получения обновлений.",
"Pinging": роверка доступности",
"Please select specific monitors to receive updates from.": "Пожалуйста, выберите мониторы для получения обновлений.",
"RESOLVED": "РЕШЕНО",
"Recent Incidents": "Недавние инциденты",
"Recent Maintenances": "Последние обслуживания",
"Share this monitor using a link with others": "Поделитесь этим монитором с другими по ссылке",
"Share": "Поделиться",
"Some Systems are not working as expected": "Некоторые системы работают не так, как ожидалось",
"Some Systems Degraded": "Некоторые системы работают с ухудшенной производительностью",
"Some Systems are not working as expected": "Некоторые системы работают нестабильно",
"Some Systems Degraded": "Некоторые системы работают нестабильно",
"Some Systems Down": "Некоторые системы недоступны",
"Some Systems in Maintenance": "Некоторые системы на обслуживании",
"Standard": "Стандартная",
"Started %startedAt, lasted for %lastedFor": "Началось около %startedAt назад, длилось около %lastedFor",
"Started %startedAt, still ongoing": "Началось около %startedAt назад, все еще продолжается",
"Started %startedAt, will last for %lastedFor more": "Начнется около %startedAt, продлится еще около %lastedFor",
"Starts %startedAt, will last for %lastedFor": "Начнется через %startedAt, продлится около %lastedFor",
"Starts %startedAt": "Начнется через %startedAt",
"Started %startedAt, lasted for %lastedFor": "Началось %startedAt, продолжалось %lastedFor",
"Started %startedAt, still ongoing": "Началось %startedAt, всё ещё продолжается",
"Started %startedAt, will last for %lastedFor more": "Началось %startedAt, продлится ещё около %lastedFor",
"Starts %startedAt, will last for %lastedFor": "Начнётся %startedAt, продлится %lastedFor",
"Starts %startedAt": "Начнётся %startedAt",
"Status OK": "Статус ОК",
"Status": "Статус",
"Subscribe": "Подписаться",
@@ -75,16 +77,16 @@
"Subscribe to all monitors": "Подписаться на все мониторы",
"Switch to your timezone": "Переключиться на ваш часовой пояс",
"Theme": "Тема",
"There are no upcoming maintenances": "Нет предстоящих технических обслуживаний",
"Timezone set to %tz": "Часовой пояс установлен на %tz",
"There are no upcoming maintenances": "Предстоящих обслуживаний нет",
"Timezone set to %tz": "Часовой пояс установлен: %tz",
"Today": "Сегодня",
"UP": "РАБОТАЕТ",
"Update Subscription": "Обновить подписку",
"Upcoming Maintenance": "Предстоящее техническое обслуживание",
"Upcoming Maintenances": "Предстоящие технические обслуживания",
"Upcoming Maintenance": "Предстоящее обслуживание",
"Upcoming Maintenances": "Предстоящие обслуживания",
"Updates": "Обновления",
"Uptime": "Время работы",
"View in detail": "Подробный просмотр",
"We have sent a code to your email. Please enter it below to confirm your login": "Мы отправили код на ваш email. Пожалуйста, введите его ниже для подтверждения входа",
"Uptime": "Время безотказной работы",
"View in detail": "Подробнее",
"We have sent a code to your email. Please enter it below to confirm your login": "Мы отправили код на вашу почту. Введите его ниже для подтверждения входа",
"You are logged in as %email": "Вы вошли как %email"
}
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Tüm Sistemler Bozuk Durumda",
"All Systems are Down": "Tüm Sistemler Çalışmıyor",
"All Systems are Operational": "Tüm Sistemler Çalışıyor",
"All Systems are in Maintenance": "Tüm Sistemler Bakımda",
"Back": "Geri",
"Badge Copied": "Rozet Kopyalandı",
"Badge": "Rozet",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Bazı Sistemler Beklendiği Gibi Çalışmıyor",
"Some Systems Degraded": "Bazı Sistemler Bozuk Durumda",
"Some Systems Down": "Bazı Sistemler Çalışmıyor",
"Some Systems in Maintenance": "Bazı Sistemler Bakımda",
"Standard": "Standart",
"Started %startedAt, lasted for %lastedFor": "%startedAt başladı, %lastedFor sürdü",
"Started %startedAt, still ongoing": "%startedAt başladı, devam ediyor",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "Tất cả hệ thống đang suy giảm hiệu suất",
"All Systems are Down": "Tất cả hệ thống đang ngừng hoạt động",
"All Systems are Operational": "Tất cả hệ thống đang hoạt động bình thường",
"All Systems are in Maintenance": "Tất cả hệ thống đang bảo trì",
"Back": "Quay lại",
"Badge Copied": "Huy hiệu đã được sao chép",
"Badge": "Huy hiệu",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "Một số hệ thống không hoạt động như mong đợi",
"Some Systems Degraded": "Một số hệ thống đang suy giảm hiệu suất",
"Some Systems Down": "Một số hệ thống đang ngừng hoạt động",
"Some Systems in Maintenance": "Một số hệ thống đang bảo trì",
"Standard": "Tiêu chuẩn",
"Started %startedAt, lasted for %lastedFor": "Bắt đầu khoảng %startedAt trước, kéo dài khoảng %lastedFor",
"Started %startedAt, still ongoing": "Bắt đầu khoảng %startedAt trước, vẫn đang diễn ra",
+2
View File
@@ -12,6 +12,7 @@
"All Systems are Degraded": "所有系统性能下降",
"All Systems are Down": "所有系统不可用",
"All Systems are Operational": "所有系统运行正常",
"All Systems are in Maintenance": "所有系统正在维护",
"Back": "返回",
"Badge Copied": "徽章已复制",
"Badge": "徽章",
@@ -62,6 +63,7 @@
"Some Systems are not working as expected": "部分系统运行异常",
"Some Systems Degraded": "部分系统性能下降",
"Some Systems Down": "部分系统不可用",
"Some Systems in Maintenance": "部分系统正在维护",
"Standard": "标准",
"Started %startedAt, lasted for %lastedFor": "大约 %startedAt 前开始,持续了约 %lastedFor",
"Started %startedAt, still ongoing": "大约 %startedAt 前开始,目前仍在进行中",
+1
View File
@@ -8,6 +8,7 @@ const SITE = "./config/site.yaml";
const UP = "UP";
const DOWN = "DOWN";
const DEGRADED = "DEGRADED";
const MAINTENANCE = "MAINTENANCE";
const NO_DATA = "NO_DATA";
const API_TIMEOUT = 10 * 1000; // 10 seconds
const AnalyticsProviders = {
+38 -20
View File
@@ -206,6 +206,7 @@ export const SystemDataMessage = async () => {
let upsCount = 0;
let degradedCount = 0;
let downCount = 0;
let maintenanceCount = 0;
for (let i = 0; i < monitors.length; i++) {
let status = await db.getLatestMonitoringData(monitors[i].tag);
if (status) {
@@ -215,11 +216,13 @@ export const SystemDataMessage = async () => {
degradedCount++;
} else if (status.status === "DOWN") {
downCount++;
} else if (status.status === "MAINTENANCE") {
maintenanceCount++;
}
}
}
const total = upsCount + degradedCount + downCount;
const total = upsCount + degradedCount + downCount + maintenanceCount;
if (total === 0) {
return {
@@ -227,48 +230,56 @@ export const SystemDataMessage = async () => {
upsPercentage: 0,
degradedPercentage: 0,
downsPercentage: 0,
maintenancePercentage: 0,
};
}
let upsPercentage = Math.round((upsCount / total) * 100);
let degradedPercentage = Math.round((degradedCount / total) * 100);
let downsPercentage = Math.round((downCount / total) * 100);
let maintenancePercentage = Math.round((maintenanceCount / total) * 100);
let message = "";
// Determine message based on the combination of system states
if (upsCount > 0 && degradedCount === 0 && downCount === 0) {
// UP=1|DOWN=0|DEGRADED=0
if (upsCount > 0 && degradedCount === 0 && downCount === 0 && maintenanceCount == 0) {
// UP=1|DOWN=0|DEGRADED=0|MAINTENANCE=0
message = "All Systems are Operational";
} else if (upsCount === 0 && degradedCount > 0 && downCount === 0) {
// UP=0|DOWN=0|DEGRADED=1
} else if (upsCount === 0 && degradedCount > 0 && downCount === 0 && maintenanceCount == 0) {
// UP=0|DOWN=0|DEGRADED=1|MAINTENANCE=0
message = "All Systems are Degraded";
} else if (upsCount === 0 && degradedCount === 0 && downCount > 0) {
// UP=0|DOWN=1|DEGRADED=0
} else if (upsCount === 0 && degradedCount === 0 && downCount > 0 && maintenanceCount == 0) {
// UP=0|DOWN=1|DEGRADED=0|MAINTENANCE=0
message = "All Systems are Down";
} else if (upsCount === 0 && degradedCount === 0 && downCount === 0 && maintenanceCount > 0) {
message = "All Systems are in Maintenance";
} else if (
(upsCount > 0 && degradedCount > 0 && downCount > 0) ||
(upsCount === 0 && degradedCount > 0 && downCount > 0)
(upsCount > 0 && degradedCount > 0 && downCount > 0 && maintenanceCount > 0) ||
(upsCount === 0 && degradedCount > 0 && downCount > 0 && maintenanceCount > 0)
) {
// UP=1|DOWN=1|DEGRADED=1 or UP=0|DOWN=1|DEGRADED=1
// UP=1|DOWN=1|DEGRADED=1|MAINTENANCE=1 or UP=0|DOWN=1|DEGRADED=1|MAINTENANCE=1
message = "Some Systems are not working as expected";
} else if (upsCount > 0 && degradedCount === 0 && downCount > 0) {
// UP=1|DOWN=1|DEGRADED=0
} else if (upsCount > 0 && degradedCount === 0 && downCount > 0 && maintenanceCount == 0) {
// UP=1|DOWN=1|DEGRADED=0|MAINTENANCE=0
message = "Some Systems Down";
} else if (upsCount > 0 && degradedCount > 0 && downCount === 0) {
// UP=1|DOWN=0|DEGRADED=1
} else if (upsCount > 0 && degradedCount > 0 && downCount === 0 && maintenanceCount == 0) {
// UP=1|DOWN=0|DEGRADED=1|MAINTENANCE=0
message = "Some Systems Degraded";
} else if (upsCount > 0 && degradedCount === 0 && downCount === 0 && maintenanceCount > 0) {
// UP=1|DOWN=0|DEGRADED=0|MAINTENANCE=1
message = "Some Systems in Maintenance";
}
//if percentage is not 100 sum, then add remaining to up
if (upsPercentage + degradedPercentage + downsPercentage < 100) {
upsPercentage = 100 - (degradedPercentage + downsPercentage);
if (upsPercentage + degradedPercentage + downsPercentage + maintenancePercentage < 100) {
upsPercentage = 100 - (degradedPercentage + downsPercentage + maintenancePercentage);
}
return {
text: message,
upsPercentage,
degradedPercentage,
downsPercentage,
maintenancePercentage
};
};
@@ -722,6 +733,7 @@ export const GetDataGroupByDayAlternative = async (monitor_tag, start, end, time
UP: 0,
DOWN: 0,
DEGRADED: 0,
MAINTENANCE: 0,
NO_DATA: 0,
};
}
@@ -740,6 +752,7 @@ export const GetDataGroupByDayAlternative = async (monitor_tag, start, end, time
UP: group.UP,
DOWN: group.DOWN,
DEGRADED: group.DEGRADED,
MAINTENANCE: group.MAINTENANCE,
NO_DATA: group.NO_DATA,
}));
};
@@ -863,9 +876,9 @@ export const RemoveIncidentMonitor = async (incident_id, monitor_tag) => {
};
export const AddIncidentMonitor = async (incident_id, monitor_tag, monitor_impact) => {
//monitor_impact must be DOWN or DEGRADED or NONE
if (!["DOWN", "DEGRADED"].includes(monitor_impact)) {
throw new Error("Monitor impact must be either DOWN, DEGRADED ");
//monitor_impact must be DOWN or DEGRADED or MAINTENANCE or NONE
if (!["DOWN", "DEGRADED", "MAINTENANCE"].includes(monitor_impact)) {
throw new Error("Monitor impact must be either DOWN, DEGRADED, MAINTENANCE");
}
//check if monitor exists
@@ -1616,7 +1629,7 @@ export const CreateSubscriptionTrigger = async (data) => {
} else {
await db.updateSubscriptionTrigger({
id: subscriptionTrigger.id,
subscription_trigger_status: "ACTIVE",
subscription_trigger_status: data.subscription_trigger_status || "ACTIVE",
subscription_trigger_type: subscriptionTrigger.subscription_trigger_type,
config: data.config,
});
@@ -1629,6 +1642,11 @@ export const CreateSubscriptionTrigger = async (data) => {
};
};
//updateSubscriptionTriggerStatus
export const UpdateSubscriptionTriggerStatus = async (id, status) => {
return await db.updateSubscriptionTriggerStatus(id, status);
};
// Get subscribers paginated
export const GetSubscribersPaginated = async (data) => {
const page = parseInt(data.page) || 1;
+1 -1
View File
@@ -109,7 +109,7 @@ export function IsValidColors(colors) {
return false;
}
if (typeof colors !== "object") return false;
const validColorKeys = ["UP", "DOWN", "DEGRADED"];
const validColorKeys = ["UP", "DOWN", "DEGRADED", "MAINTENANCE"];
for (const key of validColorKeys) {
if (typeof colors[key] !== "string" || !/^#[0-9A-Fa-f]{6}$/.test(colors[key])) return false;
}
+4
View File
@@ -42,6 +42,10 @@ async function manualIncident(monitor) {
for (let i = 0; i < impactArr.length; i++) {
const element = impactArr[i];
if (element.monitor_impact === "MAINTENANCE") {
impact = "MAINTENANCE";
break;
}
if (element.monitor_impact === "DOWN") {
impact = "DOWN";
break;
+1
View File
@@ -92,6 +92,7 @@ const seedSiteData = {
UP: "#67ab95",
DOWN: "#ca3038",
DEGRADED: "#e6ca61",
MAINTENANCE: "#6679cc",
},
font: {
cssSrc: "",
+10
View File
@@ -125,6 +125,11 @@ const FetchData = async function (site, monitor, localTz, selectedLang, lang, is
summaryDuration = getSummaryDuration(dayData.DOWN, selectedLang);
summaryStatus = "DOWN";
}
if (dayData.MAINTENANCE > 0) {
cssClass = returnStatusClass(dayData.MAINTENANCE, dayData.total, StatusObj.MAINTENANCE, site.barStyle);
summaryDuration = getSummaryDuration(dayData.MAINTENANCE, selectedLang);
summaryStatus = "MAINTENANCE";
}
if (dayData.NO_DATA === dayData.total) {
cssClass = StatusObj.NO_DATA;
summaryStatus = NO_DATA;
@@ -178,6 +183,11 @@ const FetchData = async function (site, monitor, localTz, selectedLang, lang, is
summaryStatus = "DOWN";
summaryColorClass = "api-down";
}
if (!!lastRow && lastRow.status == "MAINTENANCE") {
summaryDuration = getSummaryDuration(getCountOfSimilarStatuesEnd(todayDataDb, "MAINTENANCE"), selectedLang);
summaryStatus = "MAINTENANCE";
summaryColorClass = "api-maintenance";
}
if (lastRow.status === "NO_DATA") {
summaryStatus = NO_DATA;
summaryColorClass = "api-nodata";
+30 -2
View File
@@ -2,6 +2,7 @@
import { UP, DOWN, DEGRADED, REALTIME, TIMEOUT, ERROR, MANUAL } from "../constants.js";
import { GetMinuteStartNowTimestampUTC } from "../tool.js";
import { GetLastHeartbeat } from "../controllers/controller.js";
import { Cron } from "croner";
class HeartbeatCall {
monitor;
@@ -11,12 +12,37 @@ class HeartbeatCall {
}
async execute() {
let nowMinute = GetMinuteStartNowTimestampUTC();
let nowMinute = GetMinuteStartNowTimestampUTC(); // current time in seconds (minute start)
let latestData = await GetLastHeartbeat(this.monitor.tag);
if (!latestData) {
return {};
}
let latency = nowMinute - latestData.timestamp;
// Use croner to calculate expected heartbeat time
let expectedTime;
try {
const cronJob = Cron(this.monitor.cron);
const prevDate = cronJob.previousRun();
expectedTime = Math.floor(prevDate.getTime() / 1000); // seconds
} catch (err) {
return {
status: DOWN,
latency: 0,
type: ERROR,
};
}
// If heartbeat was received after or at expected time, it's UP
if (latestData.timestamp >= expectedTime) {
return {
status: UP,
latency: nowMinute - latestData.timestamp,
type: REALTIME,
};
}
// Calculate how late the expected heartbeat is
let latency = nowMinute - expectedTime;
let downRemainingMinutes = Number(this.monitor.type_data.downRemainingMinutes);
if (latency > downRemainingMinutes * 60) {
return {
@@ -25,6 +51,7 @@ class HeartbeatCall {
type: REALTIME,
};
}
let degradedRemainingMinutes = Number(this.monitor.type_data.degradedRemainingMinutes);
if (latency > degradedRemainingMinutes * 60) {
return {
@@ -33,6 +60,7 @@ class HeartbeatCall {
type: REALTIME,
};
}
return {
status: UP,
latency: latency,
+1
View File
@@ -149,6 +149,7 @@ const StatusObj = {
UP: "api-up",
DEGRADED: "api-degraded",
DOWN: "api-down",
MAINTENANCE: "api-maintenance",
NO_DATA: "api-nodata",
};
// @ts-ignore
+4
View File
@@ -10,6 +10,7 @@ import {
IsLoggedInSession,
GetLocaleFromCookie,
IsEmailSetup,
GetSubscriptionTriggerByEmail,
} from "$lib/server/controllers/controller.js";
export async function load({ params, route, url, cookies, request }) {
@@ -47,6 +48,8 @@ export async function load({ params, route, url, cookies, request }) {
const query = url.searchParams;
const bgc = query.get("bgc") ? "#" + query.get("bgc") : "";
const emailSubscriptionTrigger = await GetSubscriptionTriggerByEmail();
return {
site: site,
localTz: localTz,
@@ -55,6 +58,7 @@ export async function load({ params, route, url, cookies, request }) {
selectedLang: selectedLang,
isLoggedIn: !!isLoggedIn.user,
canSendEmail: IsEmailSetup(),
canUsersSubscribe: !!emailSubscriptionTrigger && emailSubscriptionTrigger.subscription_trigger_status == "ACTIVE",
isMobile: isMobile,
};
}
+2 -1
View File
@@ -109,7 +109,8 @@
--bg-custom: {data.bgc};
--up-color: {data.site.colors.UP};
--down-color: {data.site.colors.DOWN};
--degraded-color: {data.site.colors.DEGRADED}
--degraded-color: {data.site.colors.DEGRADED};
--maintenance-color: {data.site.colors.MAINTENANCE};
"
class="kener-theme-{kenerTheme}"
>
+19 -11
View File
@@ -117,12 +117,15 @@
<div class="bg-api-up h-4" style="width: {data.systemDataMessage.upsPercentage}%;"></div>
<div class="bg-api-degraded h-4" style="width: {data.systemDataMessage.degradedPercentage}%;"></div>
<div class="bg-api-down h-4" style="width: {data.systemDataMessage.downsPercentage}%;"></div>
<div class="bg-api-maintenance h-4" style="width: {data.systemDataMessage.maintenancePercentage}%;"></div>
</div>
</div>
{/if}
<div class="section-actions mx-auto mb-8 flex w-full max-w-[655px] flex-1 flex-col items-center justify-center">
<div class="flex w-full flex-wrap rounded-md border shadow-sm">
{#if data.canSendEmail}
<div
class="section-actions relative mx-auto mb-8 flex w-full max-w-[655px] flex-1 flex-col items-center justify-center"
>
<div class="flex w-full flex-wrap rounded-md border bg-background shadow-sm">
{#if data.canSendEmail && data.canUsersSubscribe}
<Button
variant="ghost"
class="dash-after relative h-10 rounded-md text-sm font-medium"
@@ -216,13 +219,13 @@
class="section-legend mx-auto mb-2 flex w-full flex-1 flex-col items-start justify-center bg-transparent md:w-[655px]"
id=""
>
<div class="grid w-full grid-cols-2 gap-4">
<div class="col-span-2 text-center md:col-span-1 md:text-left">
<div class="flex w-full flex-col justify-between gap-4 md:flex-row">
<div class="md:content-left flex justify-center">
<Badge class="border-0 md:pl-0" variant="outline">
{l(data.lang, "Availability per Component")}
</Badge>
</div>
<div class="col-span-2 text-center md:col-span-1 md:text-right">
<div class="flex justify-center md:justify-end">
<Badge variant="outline" class="border-0 md:pr-0">
<span class="bg-api-up mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
<span class="mr-3">
@@ -235,18 +238,23 @@
</span>
<span class="bg-api-down mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
<span class="">
<span class="mr-3">
{l(data.lang, "DOWN")}
</span>
<span class="bg-api-maintenance mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
<span class="">
{l(data.lang, "MAINTENANCE")}
</span>
</Badge>
</div>
</div>
</section>
<section
class="section-monitors z-20 mx-auto mb-8 flex w-full flex-1 flex-col items-start justify-center backdrop-blur-[2px] md:w-[655px]"
class="section-monitors z-20 mx-auto mb-8 flex w-full max-w-[655px] flex-1 flex-col items-center justify-center"
>
<Card.Root class="monitor-root">
<Card.Content class="monitors-card p-0">
<Card.Root class="monitor-root w-full">
<Card.Content class="monitors-card p-0 ">
{#each data.monitors as monitor}
<Monitor
on:show_shareMenu={showShareMenu}
@@ -262,7 +270,7 @@
{/if}
{#if data.site.categories && data.pageType == "home"}
<section
class="section-categories relative z-10 mx-auto mb-8 w-full max-w-[890px] flex-1 flex-col items-start backdrop-blur-[2px] md:w-[655px]"
class="section-categories relative z-10 mx-auto mb-8 w-full max-w-[655px] flex-1 flex-col items-start backdrop-blur-[2px] md:w-[655px]"
>
{#each data.site.categories.filter((category) => category.name != "Home" && (!!!category.isHidden || $page.data.isLoggedIn)) as category}
<a href={`?category=${category.name}`} rel="external">
@@ -13,6 +13,7 @@ import {
InsertKeyValue,
GetMonitors,
CreateUpdateTrigger,
UpdateSubscriptionTriggerStatus,
GetAllTriggers,
UpdateTriggerData,
GetSubscriptionTriggerByEmail,
@@ -254,6 +255,8 @@ export async function POST({ request, cookies }) {
resp = await GetSubscribersPaginated(data);
} else if (action == "updateSubscriptionStatus") {
resp = await UpdateSubscriptionStatus(data.id, data.status);
} else if (action == "updateSubscriptionTriggerStatus") {
resp = await UpdateSubscriptionTriggerStatus(data.id, data.status);
}
} catch (error) {
console.log(error);
@@ -1092,6 +1092,11 @@
<Select.Content>
<Select.Group>
<Select.Label>Impact</Select.Label>
{#if currentIncident.incident_type == "MAINTENANCE"}
<Select.Item value="MAINTENANCE" label="MAINTENANCE" class="text-api-maintenance text-sm font-medium">
MAINTENANCE
</Select.Item>
{/if}
<Select.Item value="DOWN" label="DOWN" class="text-api-down text-sm font-medium">
DOWN
</Select.Item>
@@ -16,7 +16,7 @@
let total = 0; // Initialize total to 0
let totalPages = 0; // Initialize totalPages
let subscriptionTrigger = {
subscription_trigger_id: null,
id: null,
subscription_trigger_status: "INACTIVE",
subscription_trigger_type: "email",
config: {
@@ -122,6 +122,34 @@
});
}
function updateSubscriptionTriggerStatus(id, status) {
// Call the API to update the subscription status
fetch(base + "/manage/app/api/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
action: "updateSubscriptionTriggerStatus",
data: {
id: id,
status: status
}
})
});
}
async function handleActiveInactive(e) {
if (subscriptionTrigger.id) {
subscriptionTrigger.subscription_trigger_status = e.target.checked ? "ACTIVE" : "INACTIVE";
updateSubscriptionTriggerStatus(subscriptionTrigger.id, subscriptionTrigger.subscription_trigger_status);
} else {
await saveSubscriptionTrigger();
pageLoading = true;
await loadSubscriptionTrigger();
await loadSubscribers();
pageLoading = false;
}
}
// Reactive statement to calculate totalPages
</script>
@@ -132,6 +160,23 @@
Events Subscription
{#if pageLoading}
<Loader size="16" class="absolute right-0 top-0 animate-spin text-gray-500" />
{:else if canSendEmail}
<label class="absolute right-0 top-0 flex cursor-pointer items-center justify-between gap-2 text-sm">
<Label class="text-xs font-medium ">
{subscriptionTrigger.subscription_trigger_status == "ACTIVE" ? "Active" : "Inactive"}
</Label>
<input
type="checkbox"
value=""
disabled={!canSendEmail}
class="peer sr-only"
checked={subscriptionTrigger.subscription_trigger_status == "ACTIVE"}
on:change={handleActiveInactive}
/>
<div
class="peer relative h-6 w-11 rounded-full bg-gray-200 after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:bg-blue-600 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:peer-focus:ring-blue-800 rtl:peer-checked:after:-translate-x-full"
></div>
</label>
{/if}
</Card.Title>
<Card.Description>Configure and view who have subscribed to updates for your status page.</Card.Description>
@@ -163,7 +208,7 @@
class="mr-1"
type="checkbox"
checked={subscriptionTrigger.config.createIncident}
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
/>
Event Triggered
</label>
@@ -181,7 +226,7 @@
class="mr-1"
type="checkbox"
checked={subscriptionTrigger.config.updateIncident}
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
/>
Event Updated
</label>
@@ -197,7 +242,7 @@
class="mr-1"
type="checkbox"
checked={subscriptionTrigger.config.insertIncidentMonitor}
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
/>
Update Monitor in Event
</label>
@@ -215,7 +260,7 @@
class="mr-1"
type="checkbox"
checked={subscriptionTrigger.config.updateIncidentComment}
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
/>
Update Incident Comment
</label>
@@ -233,7 +278,7 @@
class="mr-1"
type="checkbox"
checked={subscriptionTrigger.config.insertIncidentComment}
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
/>
Insert Incident Comment
</label>
@@ -363,7 +408,7 @@
<input
type="checkbox"
value=""
disabled={!canSendEmail}
disabled={!canSendEmail || subscriptionTrigger.subscription_trigger_status != "ACTIVE"}
class="peer sr-only"
checked={user.subscriptions_status == "ACTIVE"}
on:change={(e) => {
@@ -431,7 +431,7 @@
<div class="flex flex-col gap-y-2">
<Label for="plainPassword">Confirm Password</Label>
<Input
type="text"
type="password"
name="plainPassword"
id="plainPassword"
bind:value={newUser.plainPassword}
+2
View File
@@ -10,6 +10,7 @@ const PORT = Number(process.env.PORT) || 3000;
const base = process.env.KENER_BASE_PATH || "";
const VITE_BUILD_ENV = process.env.VITE_BUILD_ENV || "development"; // Default to "development"
const isProduction = VITE_BUILD_ENV === "production";
const ORIGIN = process.env.ORIGIN || `http://localhost:${PORT}`;
export default defineConfig(({ mode }) => ({
optimizeDeps: {
@@ -49,6 +50,7 @@ export default defineConfig(({ mode }) => ({
version(),
],
server: {
allowedHosts: [new URL(ORIGIN).hostname],
port: PORT,
watch: {
ignored: ["**/src/lib/server/data/**"], // Adjust the path to the file you want to ignore