Merge branch 'louislam:master' into master

This commit is contained in:
Moritz R
2022-04-13 15:58:17 +02:00
committed by GitHub
48 changed files with 1168 additions and 247 deletions

View File

@@ -21,7 +21,9 @@
<div class="form-text">
<ul>
<li>{{ $t("Accept characters:") }} <mark>a-z</mark> <mark>0-9</mark> <mark>-</mark></li>
<li>{{ $t("Start or end with") }} <mark>a-z</mark> <mark>0-9</mark> only</li>
<i18n-t tag="li" keypath="startOrEndWithOnly">
<mark>a-z</mark> <mark>0-9</mark>
</i18n-t>
<li>{{ $t("No consecutive dashes") }} <mark>--</mark></li>
</ul>
</div>

View File

@@ -170,6 +170,15 @@
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
<div class="my-3 form-check">
<input id="expiry-notification" v-model="monitor.expiryNotification" class="form-check-input" type="checkbox">
<label class="form-check-label" for="expiry-notification">
{{ $t("Domain Name Expiry Notification") }}
</label>
<div class="form-text">
</div>
</div>
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' " class="my-3 form-check">
<input id="ignore-tls" v-model="monitor.ignoreTls" class="form-check-input" type="checkbox" value="">
<label class="form-check-label" for="ignore-tls">
@@ -254,31 +263,33 @@
</button>
<!-- Proxies -->
<h2 class="mt-5 mb-2">{{ $t("Proxies") }}</h2>
<p v-if="$root.proxyList.length === 0">
{{ $t("Not available, please setup.") }}
</p>
<div v-if="monitor.type === 'http' || monitor.type === 'keyword'">
<h2 class="mt-5 mb-2">{{ $t("Proxy") }}</h2>
<p v-if="$root.proxyList.length === 0">
{{ $t("Not available, please setup.") }}
</p>
<div v-if="$root.proxyList.length > 0" class="form-check form-switch my-3">
<input id="proxy-disable" v-model="monitor.proxyId" :value="null" name="proxy" class="form-check-input" type="radio">
<label class="form-check-label" for="proxy-disable">{{ $t("No Proxy") }}</label>
<div v-if="$root.proxyList.length > 0" class="form-check my-3">
<input id="proxy-disable" v-model="monitor.proxyId" :value="null" name="proxy" class="form-check-input" type="radio">
<label class="form-check-label" for="proxy-disable">{{ $t("No Proxy") }}</label>
</div>
<div v-for="proxy in $root.proxyList" :key="proxy.id" class="form-check my-3">
<input :id="`proxy-${proxy.id}`" v-model="monitor.proxyId" :value="proxy.id" name="proxy" class="form-check-input" type="radio">
<label class="form-check-label" :for="`proxy-${proxy.id}`">
{{ proxy.host }}:{{ proxy.port }} ({{ proxy.protocol }})
<a href="#" @click="$refs.proxyDialog.show(proxy.id)">{{ $t("Edit") }}</a>
</label>
<span v-if="proxy.default === true" class="badge bg-primary ms-2">{{ $t("default") }}</span>
</div>
<button class="btn btn-primary me-2" type="button" @click="$refs.proxyDialog.show()">
{{ $t("Setup Proxy") }}
</button>
</div>
<div v-for="proxy in $root.proxyList" :key="proxy.id" class="form-check form-switch my-3">
<input :id="`proxy-${proxy.id}`" v-model="monitor.proxyId" :value="proxy.id" name="proxy" class="form-check-input" type="radio">
<label class="form-check-label" :for="`proxy-${proxy.id}`">
{{ proxy.host }}:{{ proxy.port }} ({{ proxy.protocol }})
<a href="#" @click="$refs.proxyDialog.show(proxy.id)">{{ $t("Edit") }}</a>
</label>
<span v-if="proxy.default === true" class="badge bg-primary ms-2">{{ $t("default") }}</span>
</div>
<button class="btn btn-primary me-2" type="button" @click="$refs.proxyDialog.show()">
{{ $t("Setup Proxy") }}
</button>
<!-- HTTP Options -->
<template v-if="monitor.type === 'http' || monitor.type === 'keyword' ">
<h2 class="mt-5 mb-2">{{ $t("HTTP Options") }}</h2>
@@ -506,6 +517,7 @@ export default {
notificationIDList: {},
ignoreTls: false,
upsideDown: false,
expiryNotification: false,
maxredirects: 10,
accepted_statuscodes: ["200-299"],
dns_resolve_type: "A",

View File

@@ -1,19 +1,45 @@
<template>
<div></div>
<div>
<StatusPage v-if="statusPageSlug" :override-slug="statusPageSlug" />
</div>
</template>
<script>
import axios from "axios";
import StatusPage from "./StatusPage.vue";
export default {
components: {
StatusPage,
},
data() {
return {
statusPageSlug: null,
};
},
async mounted() {
let entryPage = (await axios.get("/api/entry-page")).data;
if (entryPage === "statusPage") {
this.$router.push("/status");
// There are only 2 cases that could come in here.
// 1. Matched status Page domain name
// 2. Vue Frontend Dev
let res = (await axios.get("/api/entry-page")).data;
if (res.type === "statusPageMatchedDomain") {
this.statusPageSlug = res.statusPageSlug;
this.$root.forceStatusPageTheme = true;
} else if (res.type === "entryPage") { // Dev only. For production, the logic is in the server side
const entryPage = res.entryPage;
if (entryPage === "statusPage") {
this.$router.push("/status");
} else {
this.$router.push("/dashboard");
}
} else {
this.$router.push("/dashboard");
}
},
};

View File

@@ -12,7 +12,7 @@
<div class="shadow-box">
<template v-if="$root.statusPageListLoaded">
<span v-if="Object.keys($root.statusPageList).length === 0" class="d-flex align-items-center justify-content-center my-3">
No status pages
{{ $t("No status pages") }}
</span>
<!-- use <a> instead of <router-link>, because the heartbeat won't load. -->

View File

@@ -121,6 +121,10 @@ export default {
this.$root.getSocket().emit("getSettings", (res) => {
this.settings = res.data;
if (this.settings.checkUpdate === undefined) {
this.settings.checkUpdate = true;
}
if (this.settings.searchEngineIndex === undefined) {
this.settings.searchEngineIndex = false;
}

View File

@@ -2,49 +2,61 @@
<div v-if="loadedTheme" class="container mt-3">
<!-- Sidebar for edit mode -->
<div v-if="enableEditMode" class="sidebar">
<div class="my-3">
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
<div class="input-group">
<span id="basic-addon3" class="input-group-text">/status/</span>
<input id="slug" v-model="config.slug" type="text" class="form-control">
<div class="sidebar-body">
<div class="my-3">
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
<div class="input-group">
<span id="basic-addon3" class="input-group-text">/status/</span>
<input id="slug" v-model="config.slug" type="text" class="form-control">
</div>
</div>
</div>
<div class="my-3">
<label for="title" class="form-label">{{ $t("Title") }}</label>
<input id="title" v-model="config.title" type="text" class="form-control">
</div>
<div class="my-3">
<label for="title" class="form-label">{{ $t("Title") }}</label>
<input id="title" v-model="config.title" type="text" class="form-control">
</div>
<div class="my-3">
<label for="description" class="form-label">{{ $t("Description") }}</label>
<textarea id="description" v-model="config.description" class="form-control"></textarea>
</div>
<div class="my-3">
<label for="description" class="form-label">{{ $t("Description") }}</label>
<textarea id="description" v-model="config.description" class="form-control"></textarea>
</div>
<div class="my-3 form-check form-switch">
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
</div>
<div class="my-3 form-check form-switch">
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
</div>
<div class="my-3 form-check form-switch">
<input id="showTags" v-model="config.showTags" class="form-check-input" type="checkbox">
<label class="form-check-label" for="showTags">{{ $t("Show Tags") }}</label>
</div>
<div class="my-3 form-check form-switch">
<input id="showTags" v-model="config.showTags" class="form-check-input" type="checkbox">
<label class="form-check-label" for="showTags">{{ $t("Show Tags") }}</label>
</div>
<div v-if="false" class="my-3">
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
</div>
<div v-if="false" class="my-3">
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
</div>
<div v-if="false" class="my-3">
<label for="cname" class="form-label">Domain Names <sup>Coming Soon</sup></label>
<textarea id="cname" v-model="config.domanNames" rows="3" disabled class="form-control" :placeholder="domainNamesPlaceholder"></textarea>
</div>
<!-- Domain Name List -->
<div class="my-3">
<label class="form-label">
Domain Names
<font-awesome-icon icon="plus-circle" class="btn-add-domain action text-primary" @click="addDomainField" />
</label>
<div class="danger-zone">
<button class="btn btn-danger me-2" @click="deleteDialog">
<font-awesome-icon icon="trash" />
{{ $t("Delete") }}
</button>
<ul class="list-group domain-name-list">
<li v-for="(domain, index) in config.domainNameList" :key="index" class="list-group-item">
<input v-model="config.domainNameList[index]" type="text" class="no-bg domain-input" placeholder="example.com" />
<font-awesome-icon icon="times" class="action remove ms-2 me-3 text-danger" @click="removeDomain(index)" />
</li>
</ul>
</div>
<div class="danger-zone">
<button class="btn btn-danger me-2" @click="deleteDialog">
<font-awesome-icon icon="trash" />
{{ $t("Delete") }}
</button>
</div>
</div>
<!-- Sidebar Footer -->
@@ -55,7 +67,7 @@
</button>
<button class="btn btn-danger me-2" @click="discard">
<font-awesome-icon icon="save" />
<font-awesome-icon icon="undo" />
{{ $t("Discard") }}
</button>
</div>
@@ -120,7 +132,7 @@
<!-- Incident Date -->
<div class="date mt-3">
{{ $t("Created") }}: {{ $root.datetime(incident.createdDate) }} ({{ dateFromNow(incident.createdDate) }})<br />
{{ $t("Date Created") }}: {{ $root.datetime(incident.createdDate) }} ({{ dateFromNow(incident.createdDate) }})<br />
<span v-if="incident.lastUpdatedDate">
{{ $t("Last Updated") }}: {{ $root.datetime(incident.lastUpdatedDate) }} ({{ dateFromNow(incident.lastUpdatedDate) }})
</span>
@@ -259,6 +271,7 @@ const favicon = new Favico({
});
export default {
components: {
PublicGroupList,
ImageCropUpload,
@@ -278,6 +291,14 @@ export default {
next();
},
props: {
overrideSlug: {
type: String,
required: false,
default: null,
},
},
data() {
return {
slug: null,
@@ -294,7 +315,6 @@ export default {
loadedData: false,
baseURL: "",
clickedEditButton: false,
domainNamesPlaceholder: "domain1.com\ndomain2.com\n..."
};
},
computed: {
@@ -389,6 +409,22 @@ export default {
},
watch: {
/**
* If connected to the socket and logged in, request private data of this statusPage
* @param connected
*/
"$root.loggedIn"(loggedIn) {
if (loggedIn) {
this.$root.getSocket().emit("getStatusPage", this.slug, (res) => {
if (res.ok) {
this.config = res.config;
} else {
toast.error(res.msg);
}
});
}
},
/**
* Selected a monitor and add to the list.
*/
@@ -449,7 +485,7 @@ export default {
this.baseURL = getResBaseURL();
},
async mounted() {
this.slug = this.$route.params.slug;
this.slug = this.overrideSlug || this.$route.params.slug;
if (!this.slug) {
this.slug = "default";
@@ -458,6 +494,10 @@ export default {
axios.get("/api/status-page/" + this.slug).then((res) => {
this.config = res.data.config;
if (!this.config.domainNameList) {
this.config.domainNameList = [];
}
if (this.config.icon) {
this.imgDataUrl = this.config.icon;
}
@@ -575,6 +615,10 @@ export default {
});
},
addDomainField() {
this.config.domainNameList.push("");
},
discard() {
location.href = "/status/" + this.slug;
},
@@ -657,6 +701,10 @@ export default {
return dayjs.utc(date).fromNow();
},
removeDomain(index) {
this.config.domainNameList.splice(index, 1);
},
}
};
</script>
@@ -705,9 +753,7 @@ h1 {
top: 0;
width: 300px;
height: 100vh;
padding: 15px 15px 68px 15px;
overflow-x: hidden;
overflow-y: auto;
border-right: 1px solid #ededed;
.danger-zone {
@@ -715,13 +761,25 @@ h1 {
padding-top: 15px;
}
.sidebar-body {
padding: 0 10px 10px 10px;
overflow-x: hidden;
overflow-y: auto;
height: calc(100% - 70px);
}
.sidebar-footer {
width: 100%;
bottom: 0;
left: 0;
padding: 15px;
position: absolute;
border-top: 1px solid #ededed;
border-right: 1px solid #ededed;
padding: 10px;
width: 300px;
height: 70px;
position: fixed;
left: 0;
bottom: 0;
background-color: white;
display: flex;
align-items: center;
}
}
@@ -808,7 +866,29 @@ footer {
}
.sidebar-footer {
border-right-color: $dark-border-color;
border-top-color: $dark-border-color;
background-color: $dark-header-bg;
}
}
}
.domain-name-list {
li {
display: flex;
align-items: center;
padding: 10px 0 10px 10px;
.domain-input {
flex-grow: 1;
background-color: transparent;
border: none;
color: $dark-font-color;
outline: none;
&::placeholder {
color: #1d2634;
}
}
}
}