Name and unpair individual clients (#2042)

This commit is contained in:
Xander Frangos 2024-05-27 16:43:08 -04:00 committed by GitHub
commit 5fcd07ecb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 296 additions and 94 deletions

View file

@ -8,10 +8,11 @@
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form class="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">
<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" autofocus id="pin-input" class="form-control my-4" />
<input type="text" pattern="\d*" :placeholder="`${$t('navbar.pin')}`" autofocus id="pin-input" class="form-control mt-2" required />
<input type="text" :placeholder="`${$t('pin.device_name')}`" id="name-input" class="form-control my-4" required />
<button class="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<div class="alert alert-warning">
@ -24,37 +25,38 @@
<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import {initApp} from "./init";
let app = createApp({
components: {
Navbar
},
inject: ['i18n'],
methods: {
registerDevice(e) {
let pin = document.querySelector("#pin-input").value;
let name = document.querySelector("#name-input").value;
document.querySelector("#status").innerHTML = "";
let b = JSON.stringify({pin: pin, name: name});
fetch("/api/pin", {method: "POST", body: b})
.then((response) => response.json())
.then((response) => {
if (response.status.toString().toLowerCase() === "true") {
document.querySelector(
"#status"
).innerHTML = `<div class="alert alert-success" role="alert">${this.i18n.t('pin.pair_success')}</div>`;
document.querySelector("#pin-input").value = "";
document.querySelector("#name-input").value = "";
} else {
document.querySelector(
"#status"
).innerHTML = `<div class="alert alert-danger" role="alert">${this.i18n.t('pin.pair_failure')}</div>`;
}
});
}
}
});
initApp(app, (app => {
// this must be after mounting the app
document.querySelector("#form").addEventListener("submit", (e) => {
e.preventDefault();
let pin = document.querySelector("#pin-input").value;
document.querySelector("#status").innerHTML = "";
let b = JSON.stringify({ pin: pin });
fetch("/api/pin", { method: "POST", body: b })
.then((response) => response.json())
.then((response) => {
if (response.status.toString().toLowerCase() === "true") {
document.querySelector(
"#status"
).innerHTML = `<div class="alert alert-success" role="alert">${i18n.global.t('pin.pair_success')}</div>`;
document.querySelector("#pin-input").value = "";
} else {
document.querySelector(
"#status"
).innerHTML = `<div class="alert alert-danger" role="alert">${i18n.global.t('pin.pair_failure')}</div>`;
}
});
});
}));
initApp(app);
</script>

View file

@ -7,6 +7,7 @@
"cancel": "Cancel",
"disabled": "Disabled",
"disabled_def": "Disabled (default)",
"dismiss": "Dismiss",
"do_cmd": "Do Command",
"elevated": "Elevated",
"enabled": "Enabled",
@ -353,6 +354,7 @@
"success_msg": "Password has been changed successfully! This page will reload soon, your browser will ask you for the new credentials."
},
"pin": {
"device_name": "Device Name",
"pair_failure": "Pairing Failed: Check if the PIN is typed correctly",
"pair_success": "Success! Please check Moonlight to continue",
"pin_pairing": "PIN Pairing",
@ -382,9 +384,13 @@
"restart_sunshine_success": "Sunshine is restarting",
"troubleshooting": "Troubleshooting",
"unpair_all": "Unpair All",
"unpair_all_desc": "Remove all your paired devices",
"unpair_all_error": "Error while unpairing",
"unpair_all_success": "Unpair Successful!"
"unpair_all_success": "All devices unpaired.",
"unpair_desc": "Remove your paired devices. Individually unpaired devices with an active session will remain connected, but cannot start or resume a session.",
"unpair_single_no_devices": "There are no paired devices.",
"unpair_single_success": "However, the device(s) may still be in an active session. Use the 'Force Close' button above to end any open sessions.",
"unpair_single_unknown": "Unknown Client",
"unpair_title": "Unpair Devices"
},
"welcome": {
"confirm_password": "Confirm password",

View file

@ -75,24 +75,39 @@
</div>
</div>
</div>
<!-- Unpair all Clients -->
<div class="card p-2 my-4">
<!-- Unpair Clients -->
<div class="card my-4">
<div class="card-body">
<h2 id="unpair">{{ $t('troubleshooting.unpair_all') }}</h2>
<br>
<p>{{ $t('troubleshooting.unpair_all_desc') }}</p>
<div class="alert alert-success" v-if="unpairAllStatus === true">
{{ $t('troubleshooting.unpair_all_success') }}
</div>
<div class="alert alert-danger" v-if="unpairAllStatus === false">
{{ $t('troubleshooting.unpair_all_error') }}
</div>
<div>
<button class="btn btn-danger" :disabled="unpairAllPressed" @click="unpairAll">
{{ $t('troubleshooting.unpair_all') }}
</button>
<div class="p-2">
<div class="d-flex justify-content-end align-items-center">
<h2 id="unpair" class="text-center me-auto">{{ $t('troubleshooting.unpair_title') }}</h2>
<button class="btn btn-danger" :disabled="unpairAllPressed" @click="unpairAll">
{{ $t('troubleshooting.unpair_all') }}
</button>
</div>
<br />
<p class="mb-0">{{ $t('troubleshooting.unpair_desc') }}</p>
<div id="apply-alert" class="alert alert-success d-flex align-items-center mt-3" :style="{ 'display': (showApplyMessage ? 'flex !important': 'none !important') }">
<div class="me-2"><b>{{ $t('_common.success') }}</b> {{ $t('troubleshooting.unpair_single_success') }}</div>
<button class="btn btn-success ms-auto apply" @click="clickedApplyBanner">{{ $t('_common.dismiss') }}</button>
</div>
<div class="alert alert-success mt-3" v-if="unpairAllStatus === true">
{{ $t('troubleshooting.unpair_all_success') }}
</div>
<div class="alert alert-danger mt-3" v-if="unpairAllStatus === false">
{{ $t('troubleshooting.unpair_all_error') }}
</div>
</div>
</div>
<ul id="client-list" class="list-group list-group-flush list-group-item-light" v-if="clients && clients.length > 0">
<div v-for="client in clients" class="list-group-item d-flex">
<div class="p-2 flex-grow-1">{{client.name != "" ? client.name : $t('troubleshooting.unpair_single_unknown')}}</div><div class="me-2 ms-auto btn btn-danger" @click="unpairSingle(client.uuid)"><i class="fas fa-trash"></i></div>
</div>
</ul>
<ul v-else class="list-group list-group-flush list-group-item-light">
<div class="list-group-item p-3 text-center"><em>{{ $t('troubleshooting.unpair_single_no_devices') }}</em></div>
</ul>
</div>
<!-- Logs -->
<div class="card p-2 my-4">
@ -123,14 +138,16 @@
},
data() {
return {
clients: [],
closeAppPressed: false,
closeAppStatus: null,
unpairAllPressed: false,
unpairAllStatus: null,
restartPressed: false,
logs: 'Loading...',
logFilter: null,
logInterval: null,
restartPressed: false,
showApplyMessage: false,
unpairAllPressed: false,
unpairAllStatus: null,
};
},
computed: {
@ -146,6 +163,7 @@
this.refreshLogs();
}, 5000);
this.refreshLogs();
this.refreshClients();
},
beforeDestroy() {
clearInterval(this.logInterval);
@ -172,7 +190,7 @@
},
unpairAll() {
this.unpairAllPressed = true;
fetch("/api/clients/unpair", { method: "POST" })
fetch("/api/clients/unpair-all", { method: "POST" })
.then((r) => r.json())
.then((r) => {
this.unpairAllPressed = false;
@ -180,8 +198,32 @@
setTimeout(() => {
this.unpairAllStatus = null;
}, 5000);
this.refreshClients();
});
},
unpairSingle(uuid) {
fetch("/api/clients/unpair", { method: "POST", body: JSON.stringify({ uuid }) }).then(() => {
this.showApplyMessage = true;
this.refreshClients();
});
},
refreshClients() {
fetch("/api/clients/list")
.then((response) => response.json())
.then((response) => {
const clientList = document.querySelector("#client-list");
if (response.status === 'true' && response.named_certs && response.named_certs.length) {
this.clients = response.named_certs.sort((a, b) => {
return (a.name.toLowerCase() > b.name.toLowerCase() || a.name == "" ? 1 : -1)
});
} else {
this.clients = [];
}
});
},
clickedApplyBanner() {
this.showApplyMessage = false;
},
copyLogs() {
navigator.clipboard.writeText(this.actualLogs);
},