feat: allow maintenance without affected monitors (#6606)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
This commit is contained in:
MkDev11 2026-01-08 21:04:39 -08:00 committed by GitHub
parent 75a2329684
commit 680f0f4584
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 5 deletions

View File

@ -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.",

View File

@ -341,6 +341,10 @@
</div>
</div>
</form>
<Confirm ref="confirmNoMonitors" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="doSubmit">
{{ $t("noMonitorsSelectedWarning") }}
</Confirm>
</div>
</transition>
</template>
@ -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<void>}
*/
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) {