diff --git a/src/lang/en.json b/src/lang/en.json index 09a99998d..7463c89d1 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -646,7 +646,8 @@ "recurringIntervalMessage": "Run once every day | Run once every {0} days", "affectedMonitorsDescription": "Select monitors that are affected by current maintenance", "affectedStatusPages": "Show this maintenance message on selected status pages", - "atLeastOneMonitor": "Select at least one affected monitor", + "noMonitorsSelectedWarning": "You are creating a maintenance without any affected monitors. Are you sure you want to continue?", + "noMonitorsOrStatusPagesSelectedError": "Cannot create maintenance without affected monitors or status pages", "passwordNotMatchMsg": "The repeat password does not match.", "notificationDescription": "Notifications must be assigned to a monitor to function.", "keywordDescription": "Search keyword in plain HTML or JSON response. The search is case-sensitive.", diff --git a/src/pages/EditMaintenance.vue b/src/pages/EditMaintenance.vue index 3833aeb49..928199f38 100644 --- a/src/pages/EditMaintenance.vue +++ b/src/pages/EditMaintenance.vue @@ -341,6 +341,10 @@ + + + {{ $t("noMonitorsSelectedWarning") }} + @@ -350,11 +354,13 @@ import VueMultiselect from "vue-multiselect"; import Datepicker from "@vuepic/vue-datepicker"; import { timezoneList } from "../util-frontend"; import cronstrue from "cronstrue/i18n"; +import Confirm from "../components/Confirm.vue"; export default { components: { VueMultiselect, Datepicker, + Confirm, }, data() { @@ -489,6 +495,22 @@ export default { isClone() { return this.$route.path.startsWith("/maintenance/clone"); }, + + /** + * Check if maintenance has monitors + * @returns {boolean} True if maintenance has monitors + */ + hasMonitors() { + return this.affectedMonitors.length > 0; + }, + + /** + * Check if maintenance status pages assigned + * @returns {boolean} True if maintenance status pages + */ + hasStatusPages() { + return this.showOnAllPages || this.selectedStatusPages.length > 0; + }, }, watch: { "$route.fullPath"() { @@ -633,16 +655,30 @@ export default { } }, + /** + * Handle form submission - show confirmation if no monitors selected + * @returns {void} + */ + submit() { + // While unusual, not requiring montiors can allow showing on status pages if a "currently unmonitored" service goes down + if (!this.hasMonitors && this.hasStatusPages) { + this.$refs.confirmNoMonitors.show(); + return; + } + this.doSubmit(); + }, + /** * Create new maintenance * @returns {Promise} */ - async submit() { + async doSubmit() { this.processing = true; - if (this.affectedMonitors.length === 0) { - this.$root.toastError(this.$t("atLeastOneMonitor")); - return (this.processing = false); + if (!this.hasMonitors && !this.hasStatusPages) { + this.$root.toastError(this.$t("noMonitorsOrStatusPagesSelectedError")); + this.processing = false; + return; } if (this.isAdd || this.isClone) {