|
|
|
@ -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>
|
|
|
|
|
|
|
|
|
|
<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 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|