Files
Apollo/src_assets/common/assets/web/troubleshooting.html
2025-05-28 14:09:12 +08:00

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>