forked from mirrors/amnezia-wg-easy
		
	Merge branch 'feat-h3' into master
This commit is contained in:
		
						commit
						1a3cff855e
					
				
					 17 changed files with 431 additions and 181 deletions
				
			
		|  | @ -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; | ||||
| } | ||||
|  | @ -832,6 +852,10 @@ video { | |||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| .min-w-20 { | ||||
|   min-width: 5rem; | ||||
| } | ||||
| 
 | ||||
| .max-w-3xl { | ||||
|   max-width: 48rem; | ||||
| } | ||||
|  | @ -844,6 +868,10 @@ video { | |||
|   flex-shrink: 0; | ||||
| } | ||||
| 
 | ||||
| .shrink-0 { | ||||
|   flex-shrink: 0; | ||||
| } | ||||
| 
 | ||||
| .flex-grow { | ||||
|   flex-grow: 1; | ||||
| } | ||||
|  | @ -917,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; | ||||
| } | ||||
|  | @ -931,6 +971,10 @@ video { | |||
|   white-space: nowrap; | ||||
| } | ||||
| 
 | ||||
| .whitespace-nowrap { | ||||
|   white-space: nowrap; | ||||
| } | ||||
| 
 | ||||
| .rounded { | ||||
|   border-radius: 0.25rem; | ||||
| } | ||||
|  | @ -1097,6 +1141,11 @@ video { | |||
|   padding-bottom: 0.75rem; | ||||
| } | ||||
| 
 | ||||
| .py-5 { | ||||
|   padding-top: 1.25rem; | ||||
|   padding-bottom: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .pb-1 { | ||||
|   padding-bottom: 0.25rem; | ||||
| } | ||||
|  | @ -1105,10 +1154,6 @@ video { | |||
|   padding-bottom: 3rem; | ||||
| } | ||||
| 
 | ||||
| .pb-2 { | ||||
|   padding-bottom: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .pb-20 { | ||||
|   padding-bottom: 5rem; | ||||
| } | ||||
|  | @ -1342,6 +1387,11 @@ video { | |||
|   transition-timing-function: cubic-bezier(0, 0, 0.2, 1); | ||||
| } | ||||
| 
 | ||||
| .is-disabled { | ||||
|   opacity: 0.25; | ||||
|   cursor: default; | ||||
| } | ||||
| 
 | ||||
| .last\:border-b-0:last-child { | ||||
|   border-bottom-width: 0px; | ||||
| } | ||||
|  | @ -1413,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; | ||||
|  | @ -1480,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; | ||||
|   } | ||||
|  | @ -1524,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 { | ||||
|  | @ -1536,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) { | ||||
|  |  | |||
|  | @ -18,11 +18,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" | ||||
|  | @ -90,11 +87,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> | ||||
|  | @ -109,52 +109,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" | ||||
|  | @ -163,39 +137,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"> | ||||
|  | @ -215,9 +255,14 @@ | |||
| 
 | ||||
|                     <!-- Show QR--> | ||||
| 
 | ||||
|                     <button | ||||
|                       class="align-middle bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white p-2 rounded transition" | ||||
|                       :title="$t('showQR')" @click="qrcode = `./api/wireguard/client/${client.id}/qrcode.svg`"> | ||||
|                     <button :disabled="!client.downloadableConfig" | ||||
|                       class="align-middle bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition" | ||||
|                       :class="{ | ||||
|                         'hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white': client.downloadableConfig, | ||||
|                         'is-disabled': !client.downloadableConfig | ||||
|                       }" | ||||
|                       :title="!client.downloadableConfig ? $t('noPrivKey') : $t('showQR')" | ||||
|                       @click="qrcode = `./api/wireguard/client/${client.id}/qrcode.svg`"> | ||||
|                       <svg class="w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" | ||||
|                         stroke="currentColor"> | ||||
|                         <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | ||||
|  | @ -226,9 +271,16 @@ | |||
|                     </button> | ||||
| 
 | ||||
|                     <!-- Download Config --> | ||||
|                     <a :href="'./api/wireguard/client/' + client.id + '/configuration'" download | ||||
|                       class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white p-2 rounded transition" | ||||
|                       :title="$t('downloadConfig')"> | ||||
|                     <a :disabled="!client.downloadableConfig" | ||||
|                       :href="'./api/wireguard/client/' + client.id + '/configuration'" | ||||
|                       :download="client.downloadableConfig ? 'configuration' : null" | ||||
|                       class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition" | ||||
|                       :class="{ | ||||
|                         'hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white': client.downloadableConfig, | ||||
|                         'is-disabled': !client.downloadableConfig | ||||
|                       }" | ||||
|                       :title="!client.downloadableConfig ? $t('noPrivKey') : $t('downloadConfig')" | ||||
|                       @click="if(!client.downloadableConfig) { $event.preventDefault(); }"> | ||||
|                       <svg class="w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" | ||||
|                         stroke="currentColor"> | ||||
|                         <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | ||||
|  | @ -510,4 +562,4 @@ | |||
|   <script src="./js/app.js"></script> | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
| </html> | ||||
|  | @ -43,6 +43,13 @@ class API { | |||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   async getuiTrafficStats() { | ||||
|     return this.call({ | ||||
|       method: 'get', | ||||
|       path: '/ui-traffic-stats', | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   async getSession() { | ||||
|     return this.call({ | ||||
|       method: 'get', | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ new Vue({ | |||
|     latestRelease: null, | ||||
| 
 | ||||
|     isDark: null, | ||||
|     uiTrafficStats: false, | ||||
| 
 | ||||
|     chartOptions: { | ||||
|       chart: { | ||||
|  | @ -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)); | ||||
|   }, | ||||
| }); | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ const messages = { // eslint-disable-line no-unused-vars | |||
|     disableClient: 'Disable Client', | ||||
|     enableClient: 'Enable Client', | ||||
|     noClients: 'There are no clients yet.', | ||||
|     noPrivKey: 'This client has no known private key. Cannot create Configuration.', | ||||
|     showQR: 'Show QR Code', | ||||
|     downloadConfig: 'Download Configuration', | ||||
|     madeBy: 'Made by', | ||||
|  | @ -213,6 +214,7 @@ const messages = { // eslint-disable-line no-unused-vars | |||
|     disableClient: 'Client deaktivieren', | ||||
|     enableClient: 'Client aktivieren', | ||||
|     noClients: 'Es wurden noch keine Clients konfiguriert.', | ||||
|     noPrivKey: 'Es ist kein Private Key für diesen Client bekannt. Eine Konfiguration kann nicht erstellt werden.', | ||||
|     showQR: 'Zeige den QR Code', | ||||
|     downloadConfig: 'Konfiguration herunterladen', | ||||
|     madeBy: 'Erstellt von', | ||||
|  | @ -461,4 +463,58 @@ const messages = { // eslint-disable-line no-unused-vars | |||
|     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: 'บริจาค', | ||||
|   }, | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Philip H
						Philip H