Merge branch 'feat-no-privateKey' into feat/clients-without-privatekey

This commit is contained in:
Philip H 2024-03-02 14:12:38 +01:00 committed by GitHub
commit ce1af6d691
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 620 additions and 211 deletions

View file

@ -548,6 +548,18 @@ video {
width: 100%;
}
@media (min-width: 450px) {
.container {
max-width: 450px;
}
}
@media (min-width: 576px) {
.container {
max-width: 576px;
}
}
@media (min-width: 640px) {
.container {
max-width: 640px;
@ -700,8 +712,12 @@ video {
margin-right: 0.5rem;
}
.mr-5 {
margin-right: 1.25rem;
.mt-0 {
margin-top: 0px;
}
.mt-0\.5 {
margin-top: 0.125rem;
}
.mt-10 {
@ -720,6 +736,10 @@ video {
margin-top: 1.25rem;
}
.mt-px {
margin-top: 1px;
}
.block {
display: block;
}
@ -768,10 +788,6 @@ video {
height: 3rem;
}
.h-14 {
height: 3.5rem;
}
.h-2 {
height: 0.5rem;
}
@ -784,10 +800,6 @@ video {
height: 0.75rem;
}
.h-32 {
height: 8rem;
}
.h-4 {
height: 1rem;
}
@ -840,6 +852,10 @@ video {
width: 100%;
}
.min-w-20 {
min-width: 5rem;
}
.max-w-3xl {
max-width: 48rem;
}
@ -852,6 +868,10 @@ video {
flex-shrink: 0;
}
.shrink-0 {
flex-shrink: 0;
}
.flex-grow {
flex-grow: 1;
}
@ -925,6 +945,18 @@ video {
gap: 0.25rem;
}
.gap-2 {
gap: 0.5rem;
}
.gap-3 {
gap: 0.75rem;
}
.self-start {
align-self: flex-start;
}
.overflow-hidden {
overflow: hidden;
}
@ -939,6 +971,10 @@ video {
white-space: nowrap;
}
.whitespace-nowrap {
white-space: nowrap;
}
.rounded {
border-radius: 0.25rem;
}
@ -1105,6 +1141,11 @@ video {
padding-bottom: 0.75rem;
}
.py-5 {
padding-top: 1.25rem;
padding-bottom: 1.25rem;
}
.pb-1 {
padding-bottom: 0.25rem;
}
@ -1113,10 +1154,6 @@ video {
padding-bottom: 3rem;
}
.pb-2 {
padding-bottom: 0.5rem;
}
.pb-20 {
padding-bottom: 5rem;
}
@ -1426,6 +1463,12 @@ video {
opacity: 1;
}
@media (min-width: 450px) {
.xxs\:flex-row {
flex-direction: row;
}
}
@media (min-width: 640px) {
.sm\:mx-0 {
margin-left: 0px;
@ -1493,6 +1536,10 @@ video {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.sm\:flex-row {
flex-direction: row;
}
.sm\:flex-row-reverse {
flex-direction: row-reverse;
}
@ -1537,8 +1584,12 @@ video {
display: inline-block;
}
.md\:flex-row {
flex-direction: row;
.md\:min-w-24 {
min-width: 6rem;
}
.md\:gap-4 {
gap: 1rem;
}
.md\:px-0 {
@ -1549,6 +1600,11 @@ video {
.md\:pb-0 {
padding-bottom: 0px;
}
.md\:text-base {
font-size: 1rem;
line-height: 1.5rem;
}
}
@media (prefers-color-scheme: dark) {

View file

@ -17,11 +17,8 @@
</style>
<body class="bg-gray-50 dark:bg-neutral-800">
<div id="app">
<div v-cloak class="container mx-auto max-w-3xl px-5 md:px-0">
<div v-cloak class="container mx-auto max-w-3xl px-3 md:px-0">
<div v-if="authenticated === true">
<span v-if="requiresPassword"
class="text-sm text-gray-400 dark:text-neutral-400 mb-10 mr-2 mt-3 cursor-pointer hover:underline float-right"
@ -89,11 +86,14 @@
style="transform: scaleY(-1);">
</apexchart>
</div>
<div class="relative p-5 z-10 flex flex-col md:flex-row justify-between">
<div class="flex items-center pb-2 md:pb-0">
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative">
<svg class="w-6 m-2 text-gray-300" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20" fill="currentColor">
<div class="relative py-5 px-3 z-10 flex flex-col sm:flex-row justify-between gap-3">
<div class="flex gap-3 md:gap-4 w-full items-center ">
<!-- Avatar -->
<div class="h-10 w-10 mt-2 self-start rounded-full bg-gray-50 relative">
<svg class="w-6 m-2 text-gray-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
clip-rule="evenodd" />
</svg>
@ -108,52 +108,26 @@
</div>
</div>
<div class="flex-grow">
<!-- Name & Info -->
<div class="flex flex-col xxs:flex-row w-full gap-2">
<!-- Name -->
<div class="text-gray-700 dark:text-neutral-200 group"
:title="$t('createdOn') + dateTime(new Date(client.createdAt))">
<!-- Show -->
<input v-show="clientEditNameId === client.id" v-model="clientEditName"
v-on:keyup.enter="updateClientName(client, clientEditName); clientEditName = null; clientEditNameId = null;"
v-on:keyup.escape="clientEditName = null; clientEditNameId = null;"
:ref="'client-' + client.id + '-name'"
class="rounded px-1 border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 dark:placeholder:text-neutral-500 outline-none w-30" />
<span v-show="clientEditNameId !== client.id"
class="inline-block border-t-2 border-b-2 border-transparent">{{client.name}}</span>
<!-- Edit -->
<span v-show="clientEditNameId !== client.id"
@click="clientEditName = client.name; clientEditNameId = client.id; setTimeout(() => $refs['client-' + client.id + '-name'][0].select(), 1);"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
</span>
</div>
<!-- Info -->
<div class="text-gray-400 dark:text-neutral-400 text-xs">
<!-- Address -->
<span class="group block md:inline-block pb-1 md:pb-0">
<div class="flex flex-col flex-grow gap-1">
<div class="text-gray-700 dark:text-neutral-200 group text-sm md:text-base"
:title="$t('createdOn') + dateTime(new Date(client.createdAt))">
<!-- Show -->
<input v-show="clientEditAddressId === client.id" v-model="clientEditAddress"
v-on:keyup.enter="updateClientAddress(client, clientEditAddress); clientEditAddress = null; clientEditAddressId = null;"
v-on:keyup.escape="clientEditAddress = null; clientEditAddressId = null;"
:ref="'client-' + client.id + '-address'"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500" />
<span v-show="clientEditAddressId !== client.id"
class="inline-block border-t-2 border-b-2 border-transparent">{{client.address}}</span>
<input v-show="clientEditNameId === client.id" v-model="clientEditName"
v-on:keyup.enter="updateClientName(client, clientEditName); clientEditName = null; clientEditNameId = null;"
v-on:keyup.escape="clientEditName = null; clientEditNameId = null;"
:ref="'client-' + client.id + '-name'"
class="rounded px-1 border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 dark:placeholder:text-neutral-500 outline-none w-30" />
<span v-show="clientEditNameId !== client.id"
class="border-t-2 border-b-2 border-transparent">{{client.name}}</span>
<!-- Edit -->
<span v-show="clientEditAddressId !== client.id"
@click="clientEditAddress = client.address; clientEditAddressId = client.id; setTimeout(() => $refs['client-' + client.id + '-address'][0].select(), 1);"
<span v-show="clientEditNameId !== client.id"
@click="clientEditName = client.name; clientEditNameId = client.id; setTimeout(() => $refs['client-' + client.id + '-name'][0].select(), 1);"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100" fill="none"
@ -162,39 +136,105 @@
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
</span>
</span>
</div>
<!-- Address -->
<div class=" block md:inline-block pb-1 md:pb-0 text-gray-500 dark:text-neutral-400 text-xs">
<span class="group">
<!-- Show -->
<input v-show="clientEditAddressId === client.id" v-model="clientEditAddress"
v-on:keyup.enter="updateClientAddress(client, clientEditAddress); clientEditAddress = null; clientEditAddressId = null;"
v-on:keyup.escape="clientEditAddress = null; clientEditAddressId = null;"
:ref="'client-' + client.id + '-address'"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500" />
<span v-show="clientEditAddressId !== client.id"
class="inline-block ">{{client.address}}</span>
<!-- Edit -->
<span v-show="clientEditAddressId !== client.id"
@click="clientEditAddress = client.address; clientEditAddressId = client.id; setTimeout(() => $refs['client-' + client.id + '-address'][0].select(), 1);"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
</span>
</span>
<!-- Inline Transfer TX -->
<span v-if="!uiTrafficStats && client.transferTx" class="whitespace-nowrap" :title="$t('totalDownload') + bytes(client.transferTx)">
·
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
{{client.transferTxCurrent | bytes}}/s
</span>
<!-- Inline Transfer RX -->
<span v-if="!uiTrafficStats && client.transferRx" class="whitespace-nowrap" :title="$t('totalUpload') + bytes(client.transferRx)">
·
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
{{client.transferRxCurrent | bytes}}/s
</span>
<!-- Last seen -->
<span class="text-gray-400 dark:text-neutral-500 whitespace-nowrap" v-if="client.latestHandshakeAt"
:title="$t('lastSeen') + dateTime(new Date(client.latestHandshakeAt))">
{{!uiTrafficStats ? " · " : ""}}{{new Date(client.latestHandshakeAt) | timeago}}
</span>
</div>
</div>
<!-- Info -->
<div v-if="uiTrafficStats"
class="flex gap-2 items-center shrink-0 text-gray-400 dark:text-neutral-400 text-xs mt-px justify-end">
<!-- Transfer TX -->
<span v-if="client.transferTx" :title="$t('totalDownload') + bytes(client.transferTx)">
·
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
{{client.transferTxCurrent | bytes}}/s
</span>
<div class="min-w-20 md:min-w-24" v-if="client.transferTx">
<span class="flex gap-1" :title="$t('totalDownload') + bytes(client.transferTx)">
<svg class="align-middle h-3 inline mt-0.5" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
<div>
<span class="text-gray-700 dark:text-neutral-200">{{client.transferTxCurrent |
bytes}}/s</span>
<!-- Total TX -->
<br><span class="font-regular" style="font-size:0.85em">{{bytes(client.transferTx)}}</span>
</div>
</span>
</div>
<!-- Transfer RX -->
<span v-if="client.transferRx" :title="$t('totalUpload') + bytes(client.transferRx)">
·
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
{{client.transferRxCurrent | bytes}}/s
</span>
<div class="min-w-20 md:min-w-24" v-if="client.transferRx">
<span class="flex gap-1" :title="$t('totalUpload') + bytes(client.transferRx)">
<svg class="align-middle h-3 inline mt-0.5" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
<div>
<span class="text-gray-700 dark:text-neutral-200">{{client.transferRxCurrent |
bytes}}/s</span>
<!-- Total RX -->
<br><span class="font-regular" style="font-size:0.85em">{{bytes(client.transferRx)}}</span>
</div>
</span>
</div>
<!-- Last seen -->
<span v-if="client.latestHandshakeAt"
:title="$t('lastSeen') + dateTime(new Date(client.latestHandshakeAt))">
· {{new Date(client.latestHandshakeAt) | timeago}}
</span>
</div>
</div>
<!-- </div> --> <!-- <div class="flex flex-grow items-center"> -->
</div>
<div class="flex items-center justify-end">
@ -514,11 +554,11 @@
<script src="./js/vendor/vue-i18n.min.js"></script>
<script src="./js/vendor/apexcharts.min.js"></script>
<script src="./js/vendor/vue-apexcharts.min.js"></script>
<script src="./js/vendor/sha512.min.js"></script>
<script src="./js/vendor/sha256.min.js"></script>
<script src="./js/vendor/timeago.full.min.js"></script>
<script src="./js/api.js"></script>
<script src="./js/i18n.js"></script>
<script src="./js/app.js"></script>
</body>
</html>
</html>

View file

@ -43,6 +43,13 @@ class API {
});
}
async getuiTrafficStats() {
return this.call({
method: 'get',
path: '/ui-traffic-stats',
});
}
async getSession() {
return this.call({
method: 'get',

View file

@ -53,6 +53,7 @@ new Vue({
latestRelease: null,
isDark: null,
uiTrafficStats: false,
chartOptions: {
chart: {
@ -138,7 +139,7 @@ new Vue({
const clients = await this.api.getClients();
this.clients = clients.map((client) => {
if (client.name.includes('@') && client.name.includes('.')) {
client.avatar = `https://www.gravatar.com/avatar/${sha512(client.name)}?d=blank`;
client.avatar = `https://gravatar.com/avatar/${sha256(client.name.toLowerCase().trim())}.jpg`;
}
if (!this.clientsPersist[client.id]) {
@ -292,6 +293,15 @@ new Vue({
}).catch(console.error);
}, 1000);
this.api.getuiTrafficStats()
.then((res) => {
this.uiTrafficStats = res;
})
.catch(() => {
console.log('Failed to get ui-traffic-stats');
this.uiTrafficStats = false;
});
Promise.resolve().then(async () => {
const lang = await this.api.getLang();
if (lang !== localStorage.getItem('lang') && i18n.availableLocales.includes(lang)) {
@ -321,6 +331,6 @@ new Vue({
this.currentRelease = currentRelease;
this.latestRelease = latestRelease;
}).catch(console.error);
}).catch((err) => console.error(err));
},
});

View file

@ -29,6 +29,33 @@ const messages = { // eslint-disable-line no-unused-vars
madeBy: 'Made by',
donate: 'Donate',
},
ua: {
name: 'Ім`я',
password: 'Пароль',
signIn: 'Увійти',
logout: 'Вихід',
updateAvailable: 'Доступне оновлення!',
update: 'Оновити',
clients: 'Клієнти',
new: 'Новий',
deleteClient: 'Видалити клієнта',
deleteDialog1: 'Ви впевнені, що бажаєте видалити',
deleteDialog2: 'Цю дію неможливо скасувати.',
cancel: 'Скасувати',
create: 'Створити',
createdOn: 'Створено ',
lastSeen: 'Останнє підключення в ',
totalDownload: 'Всього завантажено: ',
totalUpload: 'Всього відправлено: ',
newClient: 'Новий клієнт',
disableClient: 'Вимкнути клієнта',
enableClient: 'Увімкнути клієнта',
noClients: 'Ще немає клієнтів.',
showQR: 'Показати QR-код',
downloadConfig: 'Завантажити конфігурацію',
madeBy: 'Зроблено',
donate: 'Пожертвувати',
},
ru: {
name: 'Имя',
password: 'Пароль',
@ -301,4 +328,193 @@ const messages = { // eslint-disable-line no-unused-vars
madeBy: 'Được tạo bởi',
donate: 'Ủng hộ',
},
nl: {
name: 'Naam',
password: 'Wachtwoord',
signIn: 'Inloggen',
logout: 'Uitloggen',
updateAvailable: 'Nieuw update beschikbaar!',
update: 'update',
clients: 'clients',
new: 'Nieuw',
deleteClient: 'client verwijderen',
deleteDialog1: 'Weet je zeker dat je wilt verwijderen',
deleteDialog2: 'Deze actie kan niet ongedaan worden gemaakt.',
cancel: 'Annuleren',
create: 'Creëren',
createdOn: 'Gemaakt op ',
lastSeen: 'Laatst gezien op ',
totalDownload: 'Totaal Gedownload: ',
totalUpload: 'Totaal Geupload: ',
newClient: 'Nieuwe client',
disableClient: 'client uitschakelen',
enableClient: 'client inschakelen',
noClients: 'Er zijn nog geen clients.',
showQR: 'QR-code weergeven',
downloadConfig: 'Configuratie downloaden',
madeBy: 'Gemaakt door',
donate: 'Doneren',
},
is: {
name: 'Nafn',
password: 'Lykilorð',
signIn: 'Skrá inn',
logout: 'Útskráning',
updateAvailable: 'Það er uppfærsla í boði!',
update: 'Uppfæra',
clients: 'Viðskiptavinir',
new: 'Nýtt',
deleteClient: 'Eyða viðskiptavin',
deleteDialog1: 'Ertu viss um að þú viljir eyða',
deleteDialog2: 'Þessi aðgerð getur ekki verið afturkallað.',
cancel: 'Hætta við',
create: 'Búa til',
createdOn: 'Búið til á ',
lastSeen: 'Síðast séð á ',
totalDownload: 'Samtals Niðurhlaða: ',
totalUpload: 'Samtals Upphlaða: ',
newClient: 'Nýr Viðskiptavinur',
disableClient: 'Gera viðskiptavin óvirkan',
enableClient: 'Gera viðskiptavin virkan',
noClients: 'Engir viðskiptavinir ennþá.',
showQR: 'Sýna QR-kóða',
downloadConfig: 'Niðurhal Stillingar',
madeBy: 'Gert af',
donate: 'Gefa',
},
pt: {
name: 'Nome',
password: 'Palavra Chave',
signIn: 'Entrar',
logout: 'Sair',
updateAvailable: 'Existe uma atualização disponível!',
update: 'Atualizar',
clients: 'Clientes',
new: 'Novo',
deleteClient: 'Apagar Clientes',
deleteDialog1: 'Tem certeza que pretende apagar',
deleteDialog2: 'Esta ação não pode ser revertida.',
cancel: 'Cancelar',
create: 'Criar',
createdOn: 'Criado em ',
lastSeen: 'Último acesso em ',
totalDownload: 'Total Download: ',
totalUpload: 'Total Upload: ',
newClient: 'Novo Cliente',
disableClient: 'Desativar Cliente',
enableClient: 'Ativar Cliente',
noClients: 'Não existem ainda clientes.',
showQR: 'Apresentar o código QR',
downloadConfig: 'Descarregar Configuração',
madeBy: 'Feito por',
donate: 'Doar',
},
chs: {
name: '名称',
password: '密码',
signIn: '登录',
logout: '退出',
updateAvailable: '有新版本可用!',
update: '更新',
clients: '客户端',
new: '新建',
deleteClient: '删除客户端',
deleteDialog1: '您确定要删除',
deleteDialog2: '此操作无法撤销。',
cancel: '取消',
create: '创建',
createdOn: '创建于 ',
lastSeen: '最后访问于 ',
totalDownload: '总下载: ',
totalUpload: '总上传: ',
newClient: '新建客户端',
disableClient: '禁用客户端',
enableClient: '启用客户端',
noClients: '目前没有客户端。',
showQR: '显示二维码',
downloadConfig: '下载配置',
madeBy: '由',
donate: '捐赠',
},
cht: {
name: '名字',
password: '密碼',
signIn: '登入',
logout: '登出',
updateAvailable: '有新版本可用!',
update: '更新',
clients: '客戶',
new: '新建',
deleteClient: '刪除客戶',
deleteDialog1: '您確定要刪除',
deleteDialog2: '此操作無法撤銷。',
cancel: '取消',
create: '建立',
createdOn: '建立於 ',
lastSeen: '最後訪問於 ',
totalDownload: '總下載: ',
totalUpload: '總上傳: ',
newClient: '新客戶',
disableClient: '禁用客戶',
enableClient: '啟用客戶',
noClients: '目前沒有客戶。',
showQR: '顯示二維碼',
downloadConfig: '下載配置',
madeBy: '由',
donate: '捐贈',
},
it: {
name: 'Nome',
password: 'Password',
signIn: 'Accedi',
logout: 'Esci',
updateAvailable: 'È disponibile un aggiornamento!',
update: 'Aggiorna',
clients: 'Client',
new: 'Nuovo',
deleteClient: 'Elimina Client',
deleteDialog1: 'Sei sicuro di voler eliminare',
deleteDialog2: 'Questa azione non può essere annullata.',
cancel: 'Annulla',
create: 'Crea',
createdOn: 'Creato il ',
lastSeen: 'Visto l\'ultima volta il ',
totalDownload: 'Totale Download: ',
totalUpload: 'Totale Upload: ',
newClient: 'Nuovo Client',
disableClient: 'Disabilita Client',
enableClient: 'Abilita Client',
noClients: 'Non ci sono ancora client.',
showQR: 'Mostra codice QR',
downloadConfig: 'Scarica configurazione',
madeBy: 'Realizzato da',
donate: 'Donazione',
},
th: {
name: 'ชื่อ',
password: 'รหัสผ่าน',
signIn: 'ลงชื่อเข้าใช้',
logout: 'ออกจากระบบ',
updateAvailable: 'มีอัปเดตพร้อมใช้งาน!',
update: 'อัปเดต',
clients: 'Clients',
new: 'ใหม่',
deleteClient: 'ลบ Client',
deleteDialog1: 'คุณแน่ใจหรือไม่ว่าต้องการลบ',
deleteDialog2: 'การกระทำนี้;ไม่สามารถยกเลิกได้',
cancel: 'ยกเลิก',
create: 'สร้าง',
createdOn: 'สร้างเมื่อ ',
lastSeen: 'เห็นครั้งสุดท้ายเมื่อ ',
totalDownload: 'ดาวน์โหลดทั้งหมด: ',
totalUpload: 'อัพโหลดทั้งหมด: ',
newClient: 'Client ใหม่',
disableClient: 'ปิดการใช้งาน Client',
enableClient: 'เปิดการใช้งาน Client',
noClients: 'ยังไม่มี Clients เลย',
showQR: 'แสดงรหัส QR',
downloadConfig: 'ดาวน์โหลดการตั้งค่า',
madeBy: 'สร้างโดย',
donate: 'บริจาค',
},
};

File diff suppressed because one or more lines are too long

9
src/www/js/vendor/sha256.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long