mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-11-04 13:46:13 +08:00 
			
		
		
		
	Feat: Toast notification timeout settings (#3441)
* Add toast timeout to the settings Changing gui, adding timeout with a fix value memo rc rollback readme cleanup code cleanup code Review fixes review fix 2 * Feat: Add clearAll button below toastContainer * Feat: Load & Apply defaults, improve wording Chore: Remove unused * Feat: Change setting to affect monitor notif. only * Apply suggestions from code review Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> * Chore: Fix JSDoc --------- Co-authored-by: Berczi Sandor <sandor.berczi@urss.hu> Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
This commit is contained in:
		@@ -609,6 +609,18 @@ $shadow-box-padding: 20px;
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 770px) {
 | 
				
			||||||
 | 
					    .toast-container {
 | 
				
			||||||
 | 
					        margin-bottom: 100px !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 550px) {
 | 
				
			||||||
 | 
					    .toast-container {
 | 
				
			||||||
 | 
					        margin-bottom: 126px !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Localization
 | 
					// Localization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import "localization.scss";
 | 
					@import "localization.scss";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,39 @@
 | 
				
			|||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="my-4 pt-4">
 | 
				
			||||||
 | 
					            <h5 class="my-4 settings-subheading">{{ $t("monitorToastMessagesLabel") }}</h5>
 | 
				
			||||||
 | 
					            <p>{{ $t("monitorToastMessagesDescription") }}</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="my-4">
 | 
				
			||||||
 | 
					                <label for="toastErrorTimeoutSecs" class="form-label">
 | 
				
			||||||
 | 
					                    {{ $t("toastErrorTimeout") }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                    id="toastErrorTimeoutSecs"
 | 
				
			||||||
 | 
					                    v-model="toastErrorTimeoutSecs"
 | 
				
			||||||
 | 
					                    type="number"
 | 
				
			||||||
 | 
					                    class="form-control"
 | 
				
			||||||
 | 
					                    min="-1"
 | 
				
			||||||
 | 
					                    step="1"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="my-4">
 | 
				
			||||||
 | 
					                <label for="toastSuccessTimeoutSecs" class="form-label">
 | 
				
			||||||
 | 
					                    {{ $t("toastSuccessTimeout") }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                    id="toastSuccessTimeoutSecs"
 | 
				
			||||||
 | 
					                    v-model="toastSuccessTimeoutSecs"
 | 
				
			||||||
 | 
					                    type="number"
 | 
				
			||||||
 | 
					                    class="form-control"
 | 
				
			||||||
 | 
					                    min="-1"
 | 
				
			||||||
 | 
					                    step="1"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="my-4 pt-4">
 | 
					        <div class="my-4 pt-4">
 | 
				
			||||||
            <h5 class="my-4 settings-subheading">{{ $t("settingsCertificateExpiry") }}</h5>
 | 
					            <h5 class="my-4 settings-subheading">{{ $t("settingsCertificateExpiry") }}</h5>
 | 
				
			||||||
            <p>{{ $t("certificationExpiryDescription") }}</p>
 | 
					            <p>{{ $t("certificationExpiryDescription") }}</p>
 | 
				
			||||||
@@ -58,6 +91,8 @@ export default {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 | 
					            toastSuccessTimeoutSecs: 20,
 | 
				
			||||||
 | 
					            toastErrorTimeoutSecs: -1,
 | 
				
			||||||
            /**
 | 
					            /**
 | 
				
			||||||
             * Variable to store the input for new certificate expiry day.
 | 
					             * Variable to store the input for new certificate expiry day.
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
@@ -77,6 +112,26 @@ export default {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        // Parse, store and apply new timeout settings.
 | 
				
			||||||
 | 
					        toastSuccessTimeoutSecs(newTimeout) {
 | 
				
			||||||
 | 
					            const parsedTimeout = parseInt(newTimeout);
 | 
				
			||||||
 | 
					            if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					                localStorage.toastSuccessTimeout = newTimeout > 0 ? newTimeout * 1000 : newTimeout;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        toastErrorTimeoutSecs(newTimeout) {
 | 
				
			||||||
 | 
					            const parsedTimeout = parseInt(newTimeout);
 | 
				
			||||||
 | 
					            if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					                localStorage.toastErrorTimeout = newTimeout > 0 ? newTimeout * 1000 : newTimeout;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mounted() {
 | 
				
			||||||
 | 
					        this.loadToastTimeoutSettings();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    methods: {
 | 
					    methods: {
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Remove a day from expiry notification days.
 | 
					         * Remove a day from expiry notification days.
 | 
				
			||||||
@@ -108,6 +163,27 @@ export default {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Loads toast timeout settings from storage to component data.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        loadToastTimeoutSettings() {
 | 
				
			||||||
 | 
					            const successTimeout = localStorage.toastSuccessTimeout;
 | 
				
			||||||
 | 
					            if (successTimeout !== undefined) {
 | 
				
			||||||
 | 
					                const parsedTimeout = parseInt(successTimeout);
 | 
				
			||||||
 | 
					                if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					                    this.toastSuccessTimeoutSecs = parsedTimeout > 0 ? parsedTimeout / 1000 : parsedTimeout;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const errorTimeout = localStorage.toastErrorTimeout;
 | 
				
			||||||
 | 
					            if (errorTimeout !== undefined) {
 | 
				
			||||||
 | 
					                const parsedTimeout = parseInt(errorTimeout);
 | 
				
			||||||
 | 
					                if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					                    this.toastErrorTimeoutSecs = parsedTimeout > 0 ? parsedTimeout / 1000 : parsedTimeout;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -785,6 +785,10 @@
 | 
				
			|||||||
    "Badge URL": "Badge URL",
 | 
					    "Badge URL": "Badge URL",
 | 
				
			||||||
    "Group": "Group",
 | 
					    "Group": "Group",
 | 
				
			||||||
    "Monitor Group": "Monitor Group",
 | 
					    "Monitor Group": "Monitor Group",
 | 
				
			||||||
 | 
					    "monitorToastMessagesLabel": "Monitor Toast notifications",
 | 
				
			||||||
 | 
					    "monitorToastMessagesDescription": "Toast notifications for monitors disappear after given time in seconds. Set to -1 disables timeout. Set to 0 disables toast notifications.",
 | 
				
			||||||
 | 
					    "toastErrorTimeout": "Timeout for Error Notifications",
 | 
				
			||||||
 | 
					    "toastSuccessTimeout": "Timeout for Success Notifications",
 | 
				
			||||||
    "Kafka Brokers": "Kafka Brokers",
 | 
					    "Kafka Brokers": "Kafka Brokers",
 | 
				
			||||||
    "Enter the list of brokers": "Enter the list of brokers",
 | 
					    "Enter the list of brokers": "Enter the list of brokers",
 | 
				
			||||||
    "Press Enter to add broker": "Press Enter to add broker",
 | 
					    "Press Enter to add broker": "Press Enter to add broker",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,12 +117,23 @@
 | 
				
			|||||||
                {{ $t("Settings") }}
 | 
					                {{ $t("Settings") }}
 | 
				
			||||||
            </router-link>
 | 
					            </router-link>
 | 
				
			||||||
        </nav>
 | 
					        </nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					            v-if="numActiveToasts != 0"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            class="btn btn-normal clear-all-toast-btn"
 | 
				
			||||||
 | 
					            @click="clearToasts"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <font-awesome-icon icon="times" />
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import Login from "../components/Login.vue";
 | 
					import Login from "../components/Login.vue";
 | 
				
			||||||
import compareVersions from "compare-versions";
 | 
					import compareVersions from "compare-versions";
 | 
				
			||||||
 | 
					import { useToast } from "vue-toastification";
 | 
				
			||||||
 | 
					const toast = useToast();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,7 +142,11 @@ export default {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {};
 | 
					        return {
 | 
				
			||||||
 | 
					            toastContainer: null,
 | 
				
			||||||
 | 
					            numActiveToasts: 0,
 | 
				
			||||||
 | 
					            toastContainerObserver: null,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    computed: {
 | 
					    computed: {
 | 
				
			||||||
@@ -159,11 +174,33 @@ export default {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mounted() {
 | 
					    mounted() {
 | 
				
			||||||
 | 
					        this.toastContainer = document.querySelector(".bottom-right.toast-container");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Watch the number of active toasts
 | 
				
			||||||
 | 
					        this.toastContainerObserver = new MutationObserver((mutations) => {
 | 
				
			||||||
 | 
					            for (const mutation of mutations) {
 | 
				
			||||||
 | 
					                if (mutation.type === "childList") {
 | 
				
			||||||
 | 
					                    this.numActiveToasts = mutation.target.children.length;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.toastContainer != null) {
 | 
				
			||||||
 | 
					            this.toastContainerObserver.observe(this.toastContainer, { childList: true });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beforeUnmount() {
 | 
				
			||||||
 | 
					        this.toastContainerObserver.disconnect();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    methods: {
 | 
					    methods: {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Clear all toast notifications.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        clearToasts() {
 | 
				
			||||||
 | 
					            toast.clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -323,4 +360,22 @@ main {
 | 
				
			|||||||
        background-color: $dark-bg;
 | 
					        background-color: $dark-bg;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.clear-all-toast-btn {
 | 
				
			||||||
 | 
					    position: fixed;
 | 
				
			||||||
 | 
					    right: 1em;
 | 
				
			||||||
 | 
					    bottom: 1em;
 | 
				
			||||||
 | 
					    font-size: 1.2em;
 | 
				
			||||||
 | 
					    padding: 9px 15px;
 | 
				
			||||||
 | 
					    width: 48px;
 | 
				
			||||||
 | 
					    box-shadow: 2px 2px 30px rgba(0, 0, 0, 0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 770px) {
 | 
				
			||||||
 | 
					    .clear-all-toast-btn {
 | 
				
			||||||
 | 
					        bottom: 72px;
 | 
				
			||||||
 | 
					        z-index: 100;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import dayjs from "dayjs";
 | 
				
			|||||||
import timezone from "./modules/dayjs/plugin/timezone";
 | 
					import timezone from "./modules/dayjs/plugin/timezone";
 | 
				
			||||||
import utc from "dayjs/plugin/utc";
 | 
					import utc from "dayjs/plugin/utc";
 | 
				
			||||||
import relativeTime from "dayjs/plugin/relativeTime";
 | 
					import relativeTime from "dayjs/plugin/relativeTime";
 | 
				
			||||||
 | 
					import { loadToastSettings } from "./util-frontend";
 | 
				
			||||||
dayjs.extend(utc);
 | 
					dayjs.extend(utc);
 | 
				
			||||||
dayjs.extend(timezone);
 | 
					dayjs.extend(timezone);
 | 
				
			||||||
dayjs.extend(relativeTime);
 | 
					dayjs.extend(relativeTime);
 | 
				
			||||||
@@ -44,11 +45,7 @@ const app = createApp({
 | 
				
			|||||||
app.use(router);
 | 
					app.use(router);
 | 
				
			||||||
app.use(i18n);
 | 
					app.use(i18n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const options = {
 | 
					app.use(Toast, loadToastSettings());
 | 
				
			||||||
    position: "bottom-right",
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
app.use(Toast, options);
 | 
					 | 
				
			||||||
app.component("Editable", contenteditable);
 | 
					app.component("Editable", contenteditable);
 | 
				
			||||||
app.component("FontAwesomeIcon", FontAwesomeIcon);
 | 
					app.component("FontAwesomeIcon", FontAwesomeIcon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import jwtDecode from "jwt-decode";
 | 
				
			|||||||
import Favico from "favico.js";
 | 
					import Favico from "favico.js";
 | 
				
			||||||
import dayjs from "dayjs";
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
import { DOWN, MAINTENANCE, PENDING, UP } from "../util.ts";
 | 
					import { DOWN, MAINTENANCE, PENDING, UP } from "../util.ts";
 | 
				
			||||||
import { getDevContainerServerHostname, isDevContainer } from "../util-frontend.js";
 | 
					import { getDevContainerServerHostname, isDevContainer, getToastSuccessTimeout, getToastErrorTimeout } from "../util-frontend.js";
 | 
				
			||||||
const toast = useToast();
 | 
					const toast = useToast();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let socket;
 | 
					let socket;
 | 
				
			||||||
@@ -190,11 +190,11 @@ export default {
 | 
				
			|||||||
                    if (this.monitorList[data.monitorID] !== undefined) {
 | 
					                    if (this.monitorList[data.monitorID] !== undefined) {
 | 
				
			||||||
                        if (data.status === 0) {
 | 
					                        if (data.status === 0) {
 | 
				
			||||||
                            toast.error(`[${this.monitorList[data.monitorID].name}] [DOWN] ${data.msg}`, {
 | 
					                            toast.error(`[${this.monitorList[data.monitorID].name}] [DOWN] ${data.msg}`, {
 | 
				
			||||||
                                timeout: false,
 | 
					                                timeout: getToastErrorTimeout(),
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                        } else if (data.status === 1) {
 | 
					                        } else if (data.status === 1) {
 | 
				
			||||||
                            toast.success(`[${this.monitorList[data.monitorID].name}] [Up] ${data.msg}`, {
 | 
					                            toast.success(`[${this.monitorList[data.monitorID].name}] [Up] ${data.msg}`, {
 | 
				
			||||||
                                timeout: 20000,
 | 
					                                timeout: getToastSuccessTimeout(),
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
                            toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`);
 | 
					                            toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`);
 | 
				
			||||||
@@ -683,7 +683,7 @@ export default {
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        getMonitorBeats(monitorID, period, callback) {
 | 
					        getMonitorBeats(monitorID, period, callback) {
 | 
				
			||||||
            socket.emit("getMonitorBeats", monitorID, period, callback);
 | 
					            socket.emit("getMonitorBeats", monitorID, period, callback);
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    computed: {
 | 
					    computed: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import dayjs from "dayjs";
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
import timezones from "timezones-list";
 | 
					import timezones from "timezones-list";
 | 
				
			||||||
import { localeDirection, currentLocale } from "./i18n";
 | 
					import { localeDirection, currentLocale } from "./i18n";
 | 
				
			||||||
 | 
					import { POSITION } from "vue-toastification";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns the offset from UTC in hours for the current locale.
 | 
					 * Returns the offset from UTC in hours for the current locale.
 | 
				
			||||||
@@ -149,3 +150,65 @@ export function colorOptions(self) {
 | 
				
			|||||||
            color: "#DB2777" },
 | 
					            color: "#DB2777" },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Loads the toast timeout settings from storage.
 | 
				
			||||||
 | 
					 * @returns {object} The toast plugin options object.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function loadToastSettings() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        position: POSITION.BOTTOM_RIGHT,
 | 
				
			||||||
 | 
					        containerClassName: "toast-container mb-5",
 | 
				
			||||||
 | 
					        showCloseButtonOnHover: true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        filterBeforeCreate: (toast, toasts) => {
 | 
				
			||||||
 | 
					            if (toast.timeout === 0) {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return toast;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get timeout for success toasts
 | 
				
			||||||
 | 
					 * @returns {(number|boolean)} Timeout in ms. If false timeout disabled.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function getToastSuccessTimeout() {
 | 
				
			||||||
 | 
					    let successTimeout = 20000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (localStorage.toastSuccessTimeout !== undefined) {
 | 
				
			||||||
 | 
					        const parsedTimeout = parseInt(localStorage.toastSuccessTimeout);
 | 
				
			||||||
 | 
					        if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					            successTimeout = parsedTimeout;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (successTimeout === -1) {
 | 
				
			||||||
 | 
					        successTimeout = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return successTimeout;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get timeout for error toasts
 | 
				
			||||||
 | 
					 * @returns {(number|boolean)} Timeout in ms. If false timeout disabled.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function getToastErrorTimeout() {
 | 
				
			||||||
 | 
					    let errorTimeout = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (localStorage.toastErrorTimeout !== undefined) {
 | 
				
			||||||
 | 
					        const parsedTimeout = parseInt(localStorage.toastErrorTimeout);
 | 
				
			||||||
 | 
					        if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
 | 
				
			||||||
 | 
					            errorTimeout = parsedTimeout;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (errorTimeout === -1) {
 | 
				
			||||||
 | 
					        errorTimeout = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return errorTimeout;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user