fixed translation and else

This commit is contained in:
darkhorse7881 2025-05-28 23:59:07 -06:00
parent 2b586e900a
commit 11a6af1c11
6 changed files with 267 additions and 12 deletions

View file

@ -8,5 +8,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"update-language-files": "file:"
}
}

5
package-lock.json generated
View file

@ -80,6 +80,7 @@
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3",
"uptime-kuma": "file:",
"ws": "^8.13.0"
},
"devDependencies": {
@ -15129,6 +15130,10 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/uptime-kuma": {
"resolved": "",
"link": true
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",

View file

@ -145,6 +145,7 @@
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3",
"uptime-kuma": "file:",
"ws": "^8.13.0"
},
"devDependencies": {

View file

@ -348,6 +348,50 @@ module.exports.statusPageSocketHandler = (socket) => {
});
}
});
/**
* Get incident history for a status page
*/
socket.on("getStatusPageIncidentHistory", async (slug, callback) => {
try {
const statusPageBean = await R.findOne("status_page", " slug = ? ", [
slug
]);
if (!statusPageBean) {
throw new Error("Status page not found");
}
// Fetch all incidents for this status page, ordered by creation date descending
const incidents = await R.find("incident", " status_page_id = ? ORDER BY created_date DESC ", [
statusPageBean.id
]);
// Convert to public JSON format
const incidentsJSON = incidents.map(incident => {
return {
id: incident.id,
title: incident.title,
content: incident.content,
style: incident.style,
createdDate: incident.created_date,
lastUpdatedDate: incident.last_updated_date,
pin: incident.pin,
active: incident.active
};
});
callback({
ok: true,
incidents: incidentsJSON
});
} catch (error) {
callback({
ok: false,
msg: error.message
});
}
});
};
/**

6
src/languages/en.js Normal file
View file

@ -0,0 +1,6 @@
export default {
// Add translations for Incident History
"Incident History": "Incident History",
"No incident reports found.": "No incident reports found.",
"Loading": "Loading"
}

View file

@ -280,6 +280,41 @@
</div>
</template>
<!-- Incident History with improved styling -->
<div class="mb-4 incident-history">
<h2>{{ $t("Incident History") }}</h2>
<div v-if="isLoading">{{ $t("Loading") }}...</div>
<div v-else-if="incidentReports.length">
<div
v-for="report in incidentReports"
:key="report.id"
class="shadow-box alert mb-4 p-4 incident-report"
:class="'bg-' + report.style"
role="alert"
>
<h4 class="alert-heading">{{ report.title }}</h4>
<!-- eslint-disable-next-line vue/no-v-html-->
<div class="content markdown-content" v-html="formatIncidentContent(report.content)"></div>
<div class="incident-meta mt-3">
<div class="incident-date">
<font-awesome-icon icon="calendar-alt" class="me-1" />
{{ $t("Date Created") }}: {{ datetimeFormat(report.createdDate) }}
<span class="text-muted">({{ dateFromNow(report.createdDate) }})</span>
</div>
<div v-if="report.lastUpdatedDate" class="incident-updated">
<font-awesome-icon icon="clock" class="me-1" />
{{ $t("Last Updated") }}: {{ datetimeFormat(report.lastUpdatedDate) }}
<span class="text-muted">({{ dateFromNow(report.lastUpdatedDate) }})</span>
</div>
</div>
</div>
</div>
<p v-else class="text-center py-4">
<font-awesome-icon icon="info-circle" class="me-2" />
{{ $t("No incident reports found.") }}
</p>
</div>
<!-- Description -->
<strong v-if="editMode">{{ $t("Description") }}:</strong>
<Editable v-if="enableEditMode" v-model="config.description" :contenteditable="editMode" tag="div" class="mb-4 description" />
@ -829,20 +864,31 @@ export default {
}
},
async fetchIncidentReports() {
const socket = io();
this.isLoading = true;
socket.emit("fetchIncidentReports");
socket.on("incidentReports", (data) => {
this.incidentReports = data;
this.isLoading = false;
});
socket.on("incidentReportsError", (error) => {
try {
const socket = this.$root.getSocket();
socket.emit("getStatusPageIncidentHistory", this.slug, (data) => {
if (data.ok) {
this.incidentReports = data.incidents;
} else {
this.error = data.msg;
console.error("Error fetching incident reports:", data.msg);
}
this.isLoading = false;
});
} catch (error) {
this.error = error;
console.error("", error);
console.error("Error fetching incident reports:", error);
this.isLoading = false;
});
}
},
formatIncidentContent(content) {
// Convert markdown to HTML and sanitize
if (!content) {
return "";
}
return DOMPurify.sanitize(marked(content));
},
/**
* Setup timer to display countdown to refresh
@ -1314,4 +1360,154 @@ footer {
opacity: 0.7;
}
.incident-history {
.incident-report {
transition: all 0.3s ease;
border-left: 5px solid;
&.bg-info {
border-left-color: $info;
}
&.bg-warning {
border-left-color: $warning;
}
&.bg-danger {
border-left-color: $danger;
}
&.bg-primary {
border-left-color: $primary;
}
&.bg-light {
border-left-color: #ccc;
}
&.bg-dark {
border-left-color: #333;
}
&.bg-maintenance {
border-left-color: $maintenance;
}
.alert-heading {
font-weight: bold;
margin-bottom: 1rem;
}
.incident-meta {
font-size: 0.85rem;
opacity: 0.8;
border-top: 1px solid rgba(0, 0, 0, 0.1);
padding-top: 0.75rem;
margin-top: 1rem;
.incident-date, .incident-updated {
margin-bottom: 0.25rem;
}
}
}
/* Ensure markdown content is properly styled */
:deep(.markdown-content) {
h1, h2, h3, h4, h5, h6 {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
p {
margin-bottom: 1rem;
}
ul, ol {
margin-bottom: 1rem;
padding-left: 2rem;
}
code {
background-color: rgba(0, 0, 0, 0.05);
padding: 0.2rem 0.4rem;
border-radius: 3px;
}
pre {
background-color: rgba(0, 0, 0, 0.05);
padding: 1rem;
border-radius: 5px;
overflow-x: auto;
}
blockquote {
border-left: 4px solid rgba(0, 0, 0, 0.1);
padding-left: 1rem;
margin-left: 0;
color: rgba(0, 0, 0, 0.6);
}
img {
max-width: 100%;
height: auto;
}
a {
text-decoration: underline;
}
table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
th, td {
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 0.5rem;
}
th {
background-color: rgba(0, 0, 0, 0.05);
}
}
}
/* Dark mode adjustments */
.dark & {
.incident-report {
&.bg-light {
color: $dark-bg;
}
.incident-meta {
border-top-color: rgba(255, 255, 255, 0.1);
}
}
:deep(.markdown-content) {
code, pre {
background-color: rgba(255, 255, 255, 0.05);
}
blockquote {
border-left-color: rgba(255, 255, 255, 0.2);
color: rgba(255, 255, 255, 0.7);
}
table {
th, td {
border-color: rgba(255, 255, 255, 0.1);
}
th {
background-color: rgba(255, 255, 255, 0.05);
}
}
}
}
}
</style>