288 lines
8.8 KiB
HTML
288 lines
8.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" data-bs-theme="auto">
|
|
|
|
<head>
|
|
<%- header %>
|
|
<style>
|
|
.troubleshooting-logs {
|
|
white-space: pre;
|
|
font-family: monospace;
|
|
overflow: auto;
|
|
max-height: 500px;
|
|
min-height: 500px;
|
|
font-size: 16px;
|
|
position: relative;
|
|
}
|
|
|
|
.copy-icon {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
padding: 8px;
|
|
cursor: pointer;
|
|
color: rgba(0, 0, 0, 1);
|
|
appearance: none;
|
|
border: none;
|
|
background: none;
|
|
}
|
|
|
|
.copy-icon:hover {
|
|
color: rgba(0, 0, 0, 0.75);
|
|
}
|
|
|
|
.copy-icon:active {
|
|
color: rgba(0, 0, 0, 1);
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body id="app" v-cloak>
|
|
<Navbar></Navbar>
|
|
<div class="container">
|
|
<h1 class="my-4">{{ $t('troubleshooting.troubleshooting') }}</h1>
|
|
<!-- Force Close App -->
|
|
<div class="card p-2 my-4">
|
|
<div class="card-body">
|
|
<h2 id="close_apps">{{ $t('troubleshooting.force_close') }}</h2>
|
|
<br>
|
|
<p>{{ $t('troubleshooting.force_close_desc') }}</p>
|
|
<div class="alert alert-success" v-if="closeAppStatus === true">
|
|
{{ $t('troubleshooting.force_close_success') }}
|
|
</div>
|
|
<div class="alert alert-danger" v-if="closeAppStatus === false">
|
|
{{ $t('troubleshooting.force_close_error') }}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-warning" :disabled="closeAppPressed" @click="closeApp">
|
|
{{ $t('troubleshooting.force_close') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Restart Apollo -->
|
|
<div class="card p-2 my-4">
|
|
<div class="card-body">
|
|
<h2 id="restart">{{ $t('troubleshooting.restart_apollo') }}</h2>
|
|
<br>
|
|
<p>{{ $t('troubleshooting.restart_apollo_desc') }}</p>
|
|
<div class="alert alert-success" v-if="serverRestarting">
|
|
{{ $t('troubleshooting.restart_apollo_success') }}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-warning" :disabled="serverQuitting || serverRestarting" @click="restart">
|
|
{{ $t('troubleshooting.restart_apollo') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Quit Apollo -->
|
|
<div class="card p-2 my-4">
|
|
<div class="card-body">
|
|
<h2 id="quit">{{ $t('troubleshooting.quit_apollo') }}</h2>
|
|
<br>
|
|
<p>{{ $t('troubleshooting.quit_apollo_desc') }}</p>
|
|
<div class="alert alert-success" v-if="serverQuit">
|
|
{{ $t('troubleshooting.quit_apollo_success') }}
|
|
</div>
|
|
<div class="alert alert-success" v-if="serverQuitting">
|
|
{{ $t('troubleshooting.quit_apollo_success_ongoing') }}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-warning" :disabled="serverQuitting || serverRestarting" @click="quit">
|
|
{{ $t('troubleshooting.quit_apollo') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Reset persistent display device settings -->
|
|
<div class="card p-2 my-4" v-if="platform === 'windows'">
|
|
<div class="card-body">
|
|
<h2 id="dd_reset">{{ $t('troubleshooting.dd_reset') }}</h2>
|
|
<br>
|
|
<p style="white-space: pre-line">{{ $t('troubleshooting.dd_reset_desc') }}</p>
|
|
<div class="alert alert-success" v-if="ddResetStatus === true">
|
|
{{ $t('troubleshooting.dd_reset_success') }}
|
|
</div>
|
|
<div class="alert alert-danger" v-if="ddResetStatus === false">
|
|
{{ $t('troubleshooting.dd_reset_error') }}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-warning" :disabled="ddResetPressed" @click="ddResetPersistence">
|
|
{{ $t('troubleshooting.dd_reset') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Logs -->
|
|
<div class="card p-2 my-4">
|
|
<div class="card-body">
|
|
<h2 id="logs">{{ $t('troubleshooting.logs') }}</h2>
|
|
<br>
|
|
<div class="d-flex justify-content-between align-items-baseline py-2">
|
|
<p>{{ $t('troubleshooting.logs_desc') }}</p>
|
|
<input type="text" class="form-control" v-model="logFilter" :placeholder="$t('troubleshooting.logs_find')" style="width: 300px">
|
|
</div>
|
|
<div>
|
|
<div class="troubleshooting-logs">
|
|
<button class="copy-icon"><i class="fas fa-copy " @click="copyLogs"></i></button>{{actualLogs}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import { createApp } from 'vue'
|
|
import { initApp } from './init'
|
|
import Navbar from './Navbar.vue'
|
|
|
|
const app = createApp({
|
|
components: {
|
|
Navbar
|
|
},
|
|
inject: ['i18n'],
|
|
data() {
|
|
return {
|
|
clients: [],
|
|
closeAppPressed: false,
|
|
closeAppStatus: null,
|
|
ddResetPressed: false,
|
|
ddResetStatus: null,
|
|
logs: 'Loading...',
|
|
logFilter: null,
|
|
logInterval: null,
|
|
serverRestarting: false,
|
|
serverQuitting: false,
|
|
serverQuit: false,
|
|
platform: "",
|
|
};
|
|
},
|
|
computed: {
|
|
actualLogs() {
|
|
if (!this.logFilter) return this.logs;
|
|
let lines = this.logs.split("\n");
|
|
lines = lines.filter(x => x.indexOf(this.logFilter) !== -1);
|
|
return lines.join("\n");
|
|
}
|
|
},
|
|
created() {
|
|
fetch("/api/config")
|
|
.then((r) => r.json())
|
|
.then((r) => {
|
|
this.platform = r.platform;
|
|
});
|
|
|
|
this.logInterval = setInterval(() => {
|
|
this.refreshLogs();
|
|
}, 5000);
|
|
this.refreshLogs();
|
|
},
|
|
beforeDestroy() {
|
|
clearInterval(this.logInterval);
|
|
},
|
|
methods: {
|
|
refreshLogs() {
|
|
fetch("./api/logs", { credentials: 'include' })
|
|
.then(response => {
|
|
// Retrieve the Content-Type header
|
|
const contentType = response.headers.get("Content-Type") || "";
|
|
// Attempt to extract charset from the header
|
|
const charsetMatch = contentType.match(/charset=([^;]+)/i);
|
|
const charset = charsetMatch ? charsetMatch[1].trim() : "utf-8";
|
|
|
|
// Read response as an ArrayBuffer and decode it with the correct charset
|
|
return response.arrayBuffer().then(buffer => {
|
|
const decoder = new TextDecoder(charset);
|
|
return decoder.decode(buffer);
|
|
});
|
|
})
|
|
.then(text => {
|
|
this.logs = text;
|
|
})
|
|
.catch(error => console.error("Error fetching logs:", error));
|
|
},
|
|
closeApp() {
|
|
this.closeAppPressed = true;
|
|
fetch("./api/apps/close", {
|
|
credentials: 'include',
|
|
method: 'POST'
|
|
})
|
|
.then((r) => r.json())
|
|
.then((r) => {
|
|
this.closeAppPressed = false;
|
|
this.closeAppStatus = r.status;
|
|
setTimeout(() => {
|
|
this.closeAppStatus = null;
|
|
}, 5000);
|
|
});
|
|
},
|
|
copyLogs() {
|
|
navigator.clipboard.writeText(this.actualLogs);
|
|
},
|
|
restart() {
|
|
this.serverRestarting = true;
|
|
setTimeout(() => {
|
|
this.serverRestarting = false;
|
|
}, 5000);
|
|
fetch("./api/restart", {
|
|
credentials: 'include',
|
|
method: 'POST',
|
|
})
|
|
.then((resp) => {
|
|
if (resp.status !== 200) {
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 1000);
|
|
return;
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
this.serverRestarting = false
|
|
console.error(e);
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 1000);
|
|
return;
|
|
});
|
|
},
|
|
quit() {
|
|
if (window.confirm(this.i18n.t('troubleshooting.quit_apollo_confirm'))) {
|
|
this.serverQuitting = true;
|
|
fetch("./api/quit", {
|
|
credentials: 'include',
|
|
method: 'POST',
|
|
})
|
|
.then(() => {
|
|
this.serverQuitting = false;
|
|
this.serverQuit = false;
|
|
alert("Exit failed!");
|
|
})
|
|
.catch(() => {
|
|
this.serverQuitting = false;
|
|
this.serverQuit = true;
|
|
});
|
|
}
|
|
},
|
|
ddResetPersistence() {
|
|
this.ddResetPressed = true;
|
|
fetch("/api/reset-display-device-persistence", {
|
|
credentials: 'include',
|
|
method: 'POST'
|
|
})
|
|
.then((r) => r.json())
|
|
.then((r) => {
|
|
this.ddResetPressed = false;
|
|
this.ddResetStatus = r.status;
|
|
setTimeout(() => {
|
|
this.ddResetStatus = null;
|
|
}, 5000);
|
|
});
|
|
},
|
|
},
|
|
});
|
|
|
|
initApp(app);
|
|
</script>
|
|
|
|
</body>
|