mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-18 12:14:41 -05:00
Merge pull request #2570 from Computroniks/feature/#2365-allow-markdown-in-status-page-footer
Add support for markdown on status page
This commit is contained in:
commit
b0673ba9ce
32
package-lock.json
generated
32
package-lock.json
generated
@ -89,10 +89,12 @@
|
|||||||
"cypress": "^10.1.0",
|
"cypress": "^10.1.0",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
"dns2": "~2.0.1",
|
"dns2": "~2.0.1",
|
||||||
|
"dompurify": "~2.4.3",
|
||||||
"eslint": "~8.14.0",
|
"eslint": "~8.14.0",
|
||||||
"eslint-plugin-vue": "~8.7.1",
|
"eslint-plugin-vue": "~8.7.1",
|
||||||
"favico.js": "~0.3.10",
|
"favico.js": "~0.3.10",
|
||||||
"jest": "~27.2.5",
|
"jest": "~27.2.5",
|
||||||
|
"marked": "~4.2.5",
|
||||||
"postcss-html": "~1.5.0",
|
"postcss-html": "~1.5.0",
|
||||||
"postcss-rtlcss": "~3.7.2",
|
"postcss-rtlcss": "~3.7.2",
|
||||||
"postcss-scss": "~4.0.4",
|
"postcss-scss": "~4.0.4",
|
||||||
@ -7801,6 +7803,12 @@
|
|||||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dompurify": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/domutils": {
|
"node_modules/domutils": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||||
@ -13622,6 +13630,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "4.2.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
|
||||||
|
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mathml-tag-names": {
|
"node_modules/mathml-tag-names": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
|
||||||
@ -24880,6 +24900,12 @@
|
|||||||
"domelementtype": "^2.3.0"
|
"domelementtype": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dompurify": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"domutils": {
|
"domutils": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||||
@ -29114,6 +29140,12 @@
|
|||||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"marked": {
|
||||||
|
"version": "4.2.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
|
||||||
|
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"mathml-tag-names": {
|
"mathml-tag-names": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
|
||||||
|
@ -146,9 +146,11 @@
|
|||||||
"cypress": "^10.1.0",
|
"cypress": "^10.1.0",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
"dns2": "~2.0.1",
|
"dns2": "~2.0.1",
|
||||||
|
"dompurify": "~2.4.3",
|
||||||
"eslint": "~8.14.0",
|
"eslint": "~8.14.0",
|
||||||
"eslint-plugin-vue": "~8.7.1",
|
"eslint-plugin-vue": "~8.7.1",
|
||||||
"favico.js": "~0.3.10",
|
"favico.js": "~0.3.10",
|
||||||
|
"marked": "~4.2.5",
|
||||||
"jest": "~27.2.5",
|
"jest": "~27.2.5",
|
||||||
"postcss-html": "~1.5.0",
|
"postcss-html": "~1.5.0",
|
||||||
"postcss-rtlcss": "~3.7.2",
|
"postcss-rtlcss": "~3.7.2",
|
||||||
|
@ -35,6 +35,11 @@ textarea.form-control {
|
|||||||
color: $maintenance !important;
|
color: $maintenance !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.incident a,
|
||||||
|
.bg-maintenance a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.list-group {
|
.list-group {
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
|
|
||||||
@ -248,6 +253,11 @@ optgroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.incident a,
|
||||||
|
.bg-maintenance a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.form-control,
|
.form-control,
|
||||||
.form-control:focus,
|
.form-control:focus,
|
||||||
.form-select,
|
.form-select,
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"General Monitor Type": "General Monitor Type",
|
"General Monitor Type": "General Monitor Type",
|
||||||
"Passive Monitor Type": "Passive Monitor Type",
|
"Passive Monitor Type": "Passive Monitor Type",
|
||||||
"Specific Monitor Type": "Specific Monitor Type",
|
"Specific Monitor Type": "Specific Monitor Type",
|
||||||
|
"markdownSupported": "Markdown syntax supported",
|
||||||
"pauseDashboardHome": "Pause",
|
"pauseDashboardHome": "Pause",
|
||||||
"Pause": "Pause",
|
"Pause": "Pause",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
<textarea
|
<textarea
|
||||||
id="description" v-model="maintenance.description" class="form-control"
|
id="description" v-model="maintenance.description" class="form-control"
|
||||||
></textarea>
|
></textarea>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("markdownSupported") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Affected Monitors -->
|
<!-- Affected Monitors -->
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="footer-text" class="form-label">{{ $t("Footer Text") }}</label>
|
<label for="footer-text" class="form-label">{{ $t("Footer Text") }}</label>
|
||||||
<textarea id="footer-text" v-model="config.footerText" class="form-control"></textarea>
|
<textarea id="footer-text" v-model="config.footerText" class="form-control"></textarea>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("markdownSupported") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3 form-check form-switch">
|
<div class="my-3 form-check form-switch">
|
||||||
@ -148,7 +151,12 @@
|
|||||||
<Editable v-model="incident.title" tag="h4" :contenteditable="editIncidentMode" :noNL="true" class="alert-heading" />
|
<Editable v-model="incident.title" tag="h4" :contenteditable="editIncidentMode" :noNL="true" class="alert-heading" />
|
||||||
|
|
||||||
<strong v-if="editIncidentMode">{{ $t("Content") }}:</strong>
|
<strong v-if="editIncidentMode">{{ $t("Content") }}:</strong>
|
||||||
<Editable v-model="incident.content" tag="div" :contenteditable="editIncidentMode" class="content" />
|
<Editable v-if="editIncidentMode" v-model="incident.content" tag="div" :contenteditable="editIncidentMode" class="content" />
|
||||||
|
<div v-if="editIncidentMode" class="form-text">
|
||||||
|
{{ $t("markdownSupported") }}
|
||||||
|
</div>
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html-->
|
||||||
|
<div v-if="! editIncidentMode" class="content" v-html="incidentHTML"></div>
|
||||||
|
|
||||||
<!-- Incident Date -->
|
<!-- Incident Date -->
|
||||||
<div class="date mt-3">
|
<div class="date mt-3">
|
||||||
@ -236,7 +244,8 @@
|
|||||||
class="shadow-box alert mb-4 p-3 bg-maintenance mt-4 position-relative" role="alert"
|
class="shadow-box alert mb-4 p-3 bg-maintenance mt-4 position-relative" role="alert"
|
||||||
>
|
>
|
||||||
<h4 class="alert-heading">{{ maintenance.title }}</h4>
|
<h4 class="alert-heading">{{ maintenance.title }}</h4>
|
||||||
<div class="content">{{ maintenance.description }}</div>
|
<!-- eslint-disable-next-line vue/no-v-html-->
|
||||||
|
<div class="content" v-html="maintenanceHTML(maintenance.description)"></div>
|
||||||
<MaintenanceTime :maintenance="maintenance" />
|
<MaintenanceTime :maintenance="maintenance" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -279,7 +288,9 @@
|
|||||||
<div class="custom-footer-text text-start">
|
<div class="custom-footer-text text-start">
|
||||||
<strong v-if="enableEditMode">{{ $t("Custom Footer") }}:</strong>
|
<strong v-if="enableEditMode">{{ $t("Custom Footer") }}:</strong>
|
||||||
</div>
|
</div>
|
||||||
<Editable v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" />
|
<Editable v-if="enableEditMode" v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" />
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html-->
|
||||||
|
<div v-if="! enableEditMode" class="alert-heading p-2" v-html="footerHTML"></div>
|
||||||
|
|
||||||
<p v-if="config.showPoweredBy">
|
<p v-if="config.showPoweredBy">
|
||||||
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
||||||
@ -310,6 +321,8 @@ import ImageCropUpload from "vue-image-crop-upload";
|
|||||||
import { PrismEditor } from "vue-prism-editor";
|
import { PrismEditor } from "vue-prism-editor";
|
||||||
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
|
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
|
import { marked } from "marked";
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
import Confirm from "../components/Confirm.vue";
|
import Confirm from "../components/Confirm.vue";
|
||||||
import PublicGroupList from "../components/PublicGroupList.vue";
|
import PublicGroupList from "../components/PublicGroupList.vue";
|
||||||
import MaintenanceTime from "../components/MaintenanceTime.vue";
|
import MaintenanceTime from "../components/MaintenanceTime.vue";
|
||||||
@ -477,6 +490,13 @@ export default {
|
|||||||
return this.overallStatus === STATUS_PAGE_MAINTENANCE;
|
return this.overallStatus === STATUS_PAGE_MAINTENANCE;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
incidentHTML() {
|
||||||
|
return DOMPurify.sanitize(marked(this.incident.content));
|
||||||
|
},
|
||||||
|
|
||||||
|
footerHTML() {
|
||||||
|
return DOMPurify.sanitize(marked(this.config.footerText));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
||||||
@ -836,6 +856,15 @@ export default {
|
|||||||
this.config.domainNameList.splice(index, 1);
|
this.config.domainNameList.splice(index, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate sanitized HTML from maintenance description
|
||||||
|
* @param {string} description
|
||||||
|
* @returns {string} Sanitized HTML
|
||||||
|
*/
|
||||||
|
maintenanceHTML(description) {
|
||||||
|
return DOMPurify.sanitize(marked(description));
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user