|
|
|
@ -32,7 +32,7 @@ |
|
|
|
<button |
|
|
|
class="bg-red-800 hover:bg-red-700 text-white border-2 border-none py-2 px-4 rounded inline-flex items-center transition" |
|
|
|
@click=" |
|
|
|
clientCreate = true; |
|
|
|
clientCreateShowModal = true; |
|
|
|
clientCreateName = ''; |
|
|
|
" |
|
|
|
> |
|
|
|
@ -63,34 +63,15 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- Create Dialog --> |
|
|
|
<div v-if="clientCreate" class="fixed z-10 inset-0 overflow-y-auto"> |
|
|
|
<div v-if="clientCreateShowModal" class="fixed z-10 inset-0 overflow-y-auto"> |
|
|
|
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
|
|
|
<!-- |
|
|
|
Background overlay, show/hide based on modal state. |
|
|
|
|
|
|
|
Entering: "ease-out duration-300" |
|
|
|
From: "opacity-0" |
|
|
|
To: "opacity-100" |
|
|
|
Leaving: "ease-in duration-200" |
|
|
|
From: "opacity-100" |
|
|
|
To: "opacity-0" |
|
|
|
--> |
|
|
|
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> |
|
|
|
<div class="absolute inset-0 bg-gray-500 dark:bg-black opacity-75 dark:opacity-50"></div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- This element is to trick the browser into centering the modal contents. --> |
|
|
|
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
|
|
|
<!-- |
|
|
|
Modal panel, show/hide based on modal state. |
|
|
|
|
|
|
|
Entering: "ease-out duration-300" |
|
|
|
From: "opacity-0 tranneutral-y-4 sm:tranneutral-y-0 sm:scale-95" |
|
|
|
To: "opacity-100 tranneutral-y-0 sm:scale-100" |
|
|
|
Leaving: "ease-in duration-200" |
|
|
|
From: "opacity-100 tranneutral-y-0 sm:scale-100" |
|
|
|
To: "opacity-0 tranneutral-y-4 sm:tranneutral-y-0 sm:scale-95" |
|
|
|
--> |
|
|
|
<div |
|
|
|
class="inline-block align-bottom bg-white dark:bg-neutral-700 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg w-full" |
|
|
|
role="dialog" |
|
|
|
@ -126,10 +107,7 @@ |
|
|
|
v-if="clientCreateName.length" |
|
|
|
type="button" |
|
|
|
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-800 text-base font-medium text-white hover:bg-red-700 focus:outline-none sm:ml-3 sm:w-auto sm:text-sm" |
|
|
|
@click=" |
|
|
|
createClient(); |
|
|
|
clientCreate = null; |
|
|
|
" |
|
|
|
@click="createClient()" |
|
|
|
> |
|
|
|
Create |
|
|
|
</button> |
|
|
|
@ -143,7 +121,7 @@ |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-neutral-500 shadow-sm px-4 py-2 bg-white dark:bg-neutral-500 text-base font-medium text-gray-700 dark:text-neutral-50 hover:bg-gray-50 dark:hover:bg-neutral-600 dark:hover:border-neutral-600 focus:outline-none sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |
|
|
|
@click="clientCreate = null" |
|
|
|
@click="clientCreateShowModal = null" |
|
|
|
> |
|
|
|
Cancel |
|
|
|
</button> |
|
|
|
@ -153,7 +131,7 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- Delete Dialog --> |
|
|
|
<div v-if="clientDelete" class="fixed z-10 inset-0 overflow-y-auto"> |
|
|
|
<div v-if="clientToDelete" class="fixed z-10 inset-0 overflow-y-auto"> |
|
|
|
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
|
|
|
<!-- |
|
|
|
Background overlay, show/hide based on modal state. |
|
|
|
@ -202,7 +180,7 @@ |
|
|
|
</h3> |
|
|
|
<div class="mt-2"> |
|
|
|
<p class="text-sm text-gray-500 dark:text-neutral-300"> |
|
|
|
Are you sure you want to delete <strong>{{ clientDelete.name }}</strong |
|
|
|
Are you sure you want to delete <strong>{{ clientToDelete.name }}</strong |
|
|
|
>? This action cannot be undone. |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
@ -213,17 +191,14 @@ |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 dark:bg-red-600 text-base font-medium text-white dark:text-white hover:bg-red-700 dark:hover:bg-red-700 focus:outline-none sm:ml-3 sm:w-auto sm:text-sm" |
|
|
|
@click=" |
|
|
|
deleteClient(clientDelete); |
|
|
|
clientDelete = null; |
|
|
|
" |
|
|
|
@click="deleteClient(clientToDelete)" |
|
|
|
> |
|
|
|
Delete |
|
|
|
</button> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-neutral-500 shadow-sm px-4 py-2 bg-white dark:bg-neutral-500 text-base font-medium text-gray-700 dark:text-neutral-50 hover:bg-gray-50 dark:hover:bg-neutral-600 dark:hover:border-neutral-600 focus:outline-none sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |
|
|
|
@click="clientDelete = null" |
|
|
|
@click="clientToDelete = null" |
|
|
|
> |
|
|
|
Cancel |
|
|
|
</button> |
|
|
|
@ -247,7 +222,7 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup> |
|
|
|
import { ref, reactive } from 'vue'; |
|
|
|
import { ref, onMounted, onBeforeUnmount } from 'vue'; |
|
|
|
import sha256 from 'crypto-js/sha256'; |
|
|
|
|
|
|
|
import Auth from '@/components/Auth.vue'; |
|
|
|
@ -267,58 +242,44 @@ import { useStore } from './store/store'; |
|
|
|
import { storeToRefs } from 'pinia'; |
|
|
|
|
|
|
|
const store = useStore(); |
|
|
|
const { authenticated } = storeToRefs(store); |
|
|
|
const { authenticated, requiresPassword } = storeToRefs(store); |
|
|
|
|
|
|
|
// const authenticated = ref(null); |
|
|
|
// const authenticating = ref(false); |
|
|
|
// const password = ref(null); |
|
|
|
const requiresPassword = ref(null); |
|
|
|
const { clients, clientsPersist, clientCreateShowModal, clientToDelete, clientCreateName, qrcode } = storeToRefs(store); |
|
|
|
|
|
|
|
const clients = ref(null); |
|
|
|
const clientsPersist = reactive({}); |
|
|
|
const clientDelete = ref(null); |
|
|
|
const clientCreate = ref(null); |
|
|
|
const clientCreateName = ref(''); |
|
|
|
const qrcode = ref(null); |
|
|
|
const logout = store.logout; |
|
|
|
const createClient = store.createClient; |
|
|
|
const deleteClient = store.deleteClient; |
|
|
|
|
|
|
|
const currentRelease = ref(null); |
|
|
|
const latestRelease = ref(null); |
|
|
|
|
|
|
|
const isDark = ref(null); |
|
|
|
const refreshInterval = ref(null); |
|
|
|
|
|
|
|
const api = new API(); |
|
|
|
|
|
|
|
isDark.value = false; |
|
|
|
if (localStorage.theme === 'dark') { |
|
|
|
isDark.value = true; |
|
|
|
} |
|
|
|
onMounted(() => { |
|
|
|
api |
|
|
|
.getSession() |
|
|
|
.then((session) => { |
|
|
|
authenticated.value = session.authenticated; |
|
|
|
// authenticated.value = false; //debug |
|
|
|
requiresPassword.value = session.requiresPassword; |
|
|
|
|
|
|
|
api |
|
|
|
.getSession() |
|
|
|
.then((session) => { |
|
|
|
authenticated.value = session.authenticated; |
|
|
|
// authenticated.value = false; //debug |
|
|
|
requiresPassword.value = session.requiresPassword; |
|
|
|
refresh({ |
|
|
|
updateCharts: true, |
|
|
|
}).catch((err) => { |
|
|
|
refreshInterval.value = setInterval(refresh, 1000); |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
console.log(err.message || err.toString()); |
|
|
|
}); |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
console.log(err.message || err.toString()); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
setInterval(() => { |
|
|
|
refresh({ |
|
|
|
updateCharts: true, |
|
|
|
}).catch(console.error); |
|
|
|
}, 1000); |
|
|
|
onBeforeUnmount(() => { |
|
|
|
clearInterval(refreshInterval.value); |
|
|
|
}); |
|
|
|
|
|
|
|
getRelease(); |
|
|
|
|
|
|
|
function handleNewClient() { |
|
|
|
clientCreate.value = true; |
|
|
|
clientCreateShowModal.value = true; |
|
|
|
clientCreateName.value = ''; |
|
|
|
} |
|
|
|
|
|
|
|
@ -354,118 +315,54 @@ async function getRelease() { |
|
|
|
async function refresh({ updateCharts = false } = {}) { |
|
|
|
if (!authenticated.value) return; |
|
|
|
|
|
|
|
const clientsData = await api.getClients(); |
|
|
|
clients.value = clientsData.map((client) => { |
|
|
|
if (client.name.includes('@') && client.name.includes('.')) { |
|
|
|
client.avatar = `https://www.gravatar.com/avatar/${sha256(client.name)}?d=blank`; |
|
|
|
} |
|
|
|
|
|
|
|
if (!clientsPersist[client.id]) { |
|
|
|
clientsPersist[client.id] = {}; |
|
|
|
clientsPersist[client.id].transferRxHistory = Array(50).fill(0); |
|
|
|
clientsPersist[client.id].transferRxPrevious = client.transferRx; |
|
|
|
clientsPersist[client.id].transferTxHistory = Array(50).fill(0); |
|
|
|
clientsPersist[client.id].transferTxPrevious = client.transferTx; |
|
|
|
} |
|
|
|
|
|
|
|
// Debug |
|
|
|
client.transferRx = clientsPersist[client.id].transferRxPrevious + Math.random() * 1000; |
|
|
|
client.transferTx = clientsPersist[client.id].transferTxPrevious + Math.random() * 1000; |
|
|
|
client.latestHandshakeAt = new Date('2024-03-20'); |
|
|
|
// updateCharts = false; |
|
|
|
|
|
|
|
if (updateCharts) { |
|
|
|
clientsPersist[client.id].transferRxCurrent = client.transferRx - clientsPersist[client.id].transferRxPrevious; |
|
|
|
clientsPersist[client.id].transferRxPrevious = client.transferRx; |
|
|
|
clientsPersist[client.id].transferTxCurrent = client.transferTx - clientsPersist[client.id].transferTxPrevious; |
|
|
|
clientsPersist[client.id].transferTxPrevious = client.transferTx; |
|
|
|
|
|
|
|
clientsPersist[client.id].transferRxHistory.push(clientsPersist[client.id].transferRxCurrent); |
|
|
|
clientsPersist[client.id].transferRxHistory.shift(); |
|
|
|
|
|
|
|
clientsPersist[client.id].transferTxHistory.push(clientsPersist[client.id].transferTxCurrent); |
|
|
|
clientsPersist[client.id].transferTxHistory.shift(); |
|
|
|
} |
|
|
|
|
|
|
|
client.transferTxCurrent = clientsPersist[client.id].transferTxCurrent; |
|
|
|
client.transferRxCurrent = clientsPersist[client.id].transferRxCurrent; |
|
|
|
|
|
|
|
client.transferTxHistory = clientsPersist[client.id].transferTxHistory; |
|
|
|
client.transferRxHistory = clientsPersist[client.id].transferRxHistory; |
|
|
|
client.transferMax = Math.max(...client.transferTxHistory, ...client.transferRxHistory); |
|
|
|
|
|
|
|
client.hoverTx = clientsPersist[client.id].hoverTx; |
|
|
|
client.hoverRx = clientsPersist[client.id].hoverRx; |
|
|
|
|
|
|
|
return client; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// function login(e) { |
|
|
|
// e.preventDefault(); |
|
|
|
|
|
|
|
// if (!password.value) return; |
|
|
|
// if (authenticating.value) return; |
|
|
|
|
|
|
|
// authenticating.value = true; |
|
|
|
// api |
|
|
|
// .createSession({ |
|
|
|
// password: password, |
|
|
|
// }) |
|
|
|
// .then(async () => { |
|
|
|
// const session = await api.getSession(); |
|
|
|
// authenticated.value = session.authenticated; |
|
|
|
// requiresPassword.value = session.requiresPassword; |
|
|
|
// return this.refresh(); |
|
|
|
// }) |
|
|
|
// .catch((err) => { |
|
|
|
// alert(err.message || err.toString()); |
|
|
|
// }) |
|
|
|
// .finally(() => { |
|
|
|
// this.authenticating = false; |
|
|
|
// this.password = null; |
|
|
|
// }); |
|
|
|
// } |
|
|
|
|
|
|
|
function logout(e) { |
|
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
api |
|
|
|
.deleteSession() |
|
|
|
.then(() => { |
|
|
|
authenticated.value = false; |
|
|
|
clients.value = null; |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
alert(err.message || err.toString()); |
|
|
|
try { |
|
|
|
const clientsData = await api.getClients(); |
|
|
|
clients.value = clientsData.map((client) => { |
|
|
|
if (client.name.includes('@') && client.name.includes('.')) { |
|
|
|
client.avatar = `https://www.gravatar.com/avatar/${sha256(client.name)}?d=blank`; |
|
|
|
} |
|
|
|
|
|
|
|
if (!clientsPersist[client.id]) { |
|
|
|
clientsPersist[client.id] = {}; |
|
|
|
clientsPersist[client.id].transferRxHistory = Array(50).fill(0); |
|
|
|
clientsPersist[client.id].transferRxPrevious = client.transferRx; |
|
|
|
clientsPersist[client.id].transferTxHistory = Array(50).fill(0); |
|
|
|
clientsPersist[client.id].transferTxPrevious = client.transferTx; |
|
|
|
} |
|
|
|
|
|
|
|
// Debug |
|
|
|
client.transferRx = clientsPersist[client.id].transferRxPrevious + Math.random() * 1000; |
|
|
|
client.transferTx = clientsPersist[client.id].transferTxPrevious + Math.random() * 1000; |
|
|
|
client.latestHandshakeAt = new Date('2024-03-20'); |
|
|
|
updateCharts = true; // DEV TODO: Update. Get from settings |
|
|
|
|
|
|
|
if (updateCharts) { |
|
|
|
clientsPersist[client.id].transferRxCurrent = client.transferRx - clientsPersist[client.id].transferRxPrevious; |
|
|
|
clientsPersist[client.id].transferRxPrevious = client.transferRx; |
|
|
|
clientsPersist[client.id].transferTxCurrent = client.transferTx - clientsPersist[client.id].transferTxPrevious; |
|
|
|
clientsPersist[client.id].transferTxPrevious = client.transferTx; |
|
|
|
|
|
|
|
clientsPersist[client.id].transferRxHistory.push(clientsPersist[client.id].transferRxCurrent); |
|
|
|
clientsPersist[client.id].transferRxHistory.shift(); |
|
|
|
|
|
|
|
clientsPersist[client.id].transferTxHistory.push(clientsPersist[client.id].transferTxCurrent); |
|
|
|
clientsPersist[client.id].transferTxHistory.shift(); |
|
|
|
} |
|
|
|
|
|
|
|
client.transferTxCurrent = clientsPersist[client.id].transferTxCurrent; |
|
|
|
client.transferRxCurrent = clientsPersist[client.id].transferRxCurrent; |
|
|
|
|
|
|
|
client.transferTxHistory = clientsPersist[client.id].transferTxHistory; |
|
|
|
client.transferRxHistory = clientsPersist[client.id].transferRxHistory; |
|
|
|
client.transferMax = Math.max(...client.transferTxHistory, ...client.transferRxHistory); |
|
|
|
|
|
|
|
client.hoverTx = clientsPersist[client.id].hoverTx; |
|
|
|
client.hoverRx = clientsPersist[client.id].hoverRx; |
|
|
|
|
|
|
|
return client; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function createClient() { |
|
|
|
const name = clientCreateName; |
|
|
|
if (!name.value) return; |
|
|
|
|
|
|
|
api |
|
|
|
.createClient({ name }) |
|
|
|
.catch((err) => alert(err.message || err.toString())) |
|
|
|
.finally(() => refresh().catch(console.error)); |
|
|
|
} |
|
|
|
|
|
|
|
function deleteClient(client) { |
|
|
|
api |
|
|
|
.deleteClient({ clientId: client.id }) |
|
|
|
.catch((err) => alert(err.message || err.toString())) |
|
|
|
.finally(() => refresh().catch(console.error)); |
|
|
|
} |
|
|
|
|
|
|
|
function toggleTheme() { |
|
|
|
if (isDark.value) { |
|
|
|
localStorage.theme = 'light'; |
|
|
|
document.documentElement.classList.remove('dark'); |
|
|
|
} else { |
|
|
|
localStorage.theme = 'dark'; |
|
|
|
document.documentElement.classList.add('dark'); |
|
|
|
} catch (error) { |
|
|
|
console.log('Something went wrong', error); |
|
|
|
} |
|
|
|
isDark.value = !isDark.value; |
|
|
|
} |
|
|
|
</script> |
|
|
|
|