mirror of https://github.com/wg-easy/wg-easy
20 changed files with 333 additions and 208 deletions
@ -1,33 +1,25 @@ |
|||||
<script> |
|
||||
import IconAvatarDefault from './icons/IconAvatarDefault.vue'; |
|
||||
|
|
||||
export default { |
|
||||
props: ['client'], |
|
||||
components: { IconAvatarDefault }, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<template> |
<template> |
||||
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative"> |
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative"> |
||||
<IconAvatarDefault class="w-6 m-2 text-gray-300" /> |
<IconAvatarDefault class="w-6 m-2 text-gray-300" /> |
||||
<img |
<img v-if="props.client.avatar" :src="props.client.avatar" class="w-10 rounded-full absolute top-0 left-0" /> |
||||
v-if="client.avatar" |
|
||||
:src="client.avatar" |
|
||||
class="w-10 rounded-full absolute top-0 left-0" |
|
||||
/> |
|
||||
|
|
||||
<div |
<div |
||||
v-if=" |
v-if="props.client.latestHandshakeAt && new Date() - new Date(props.client.latestHandshakeAt) < 1000 * 60 * 10" |
||||
client.latestHandshakeAt && |
|
||||
new Date() - new Date(client.latestHandshakeAt) < 1000 * 60 * 10 |
|
||||
" |
|
||||
> |
> |
||||
<div |
<div class="animate-ping w-4 h-4 p-1 bg-red-100 dark:bg-red-100 rounded-full absolute -bottom-1 -right-1"></div> |
||||
class="animate-ping w-4 h-4 p-1 bg-red-100 dark:bg-red-100 rounded-full absolute -bottom-1 -right-1" |
<div class="w-2 h-2 bg-red-800 dark:bg-red-600 rounded-full absolute bottom-0 right-0"></div> |
||||
></div> |
|
||||
<div |
|
||||
class="w-2 h-2 bg-red-800 dark:bg-red-600 rounded-full absolute bottom-0 right-0" |
|
||||
></div> |
|
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { defineProps } from 'vue'; |
||||
|
import IconAvatarDefault from './icons/IconAvatarDefault.vue'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
client: { |
||||
|
type: Object, |
||||
|
required: true, |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
|||||
@ -1,67 +1,82 @@ |
|||||
<template> |
<template> |
||||
<div class="flex-grow"> |
<div class="flex flex-col xxs:flex-row w-full gap-2"> |
||||
<!-- Name --> |
<div class="flex flex-col flex-grow gap-1"> |
||||
<ClientName |
<!-- Name --> |
||||
:client="client" |
<ClientName :client="client" /> |
||||
@update-client-name="updateClientName" |
<!-- Info --> |
||||
/> |
<div class="text-gray-400 dark:text-neutral-400 text-xs"> |
||||
|
<!-- Address --> |
||||
<!-- Info --> |
<ClientAddress :client="client" /> |
||||
<div class="text-gray-400 dark:text-neutral-400 text-xs"> |
<!-- Transfer TX --> |
||||
<!-- Address --> |
<ClientTransfer |
||||
<ClientAddress :client="client" @update-address="updateClientAddress" /> |
v-if="!uiTrafficStats && client.transferTx" |
||||
<!-- Transfer TX --> |
:transfer-data="client.transferTx" |
||||
<ClientTransfer |
:transfer-data-current="client.transferTxCurrent" |
||||
:transferData="client.transferTx" |
:title="$t('totalDownload') + bytes(client.transferTx)" |
||||
:transferDataCurrent="client.transferTxCurrent" |
><IconDownArrow |
||||
:title="'Total Download: ' + bytes(client.transferTx)" |
/></ClientTransfer> |
||||
><IconDownArrow |
<!-- Transfer RX --> |
||||
/></ClientTransfer> |
<ClientTransfer |
||||
|
v-if="!uiTrafficStats && client.transferTx" |
||||
<!-- Transfer RX --> |
:transfer-data="client.transferRx" |
||||
<ClientTransfer |
:transfer-data-current="client.transferRxCurrent" |
||||
:transferData="client.transferRx" |
:title="$t('totalUpload') + bytes(client.transferRx)" |
||||
:transferDataCurrent="client.transferRxCurrent" |
> |
||||
:title="'Total Upload: ' + bytes(client.transferRx)" |
<IconUpArrow /> |
||||
> |
</ClientTransfer> |
||||
<IconUpArrow /> |
<!-- Last seen --> |
||||
</ClientTransfer> |
<span v-if="client.latestHandshakeAt" :title="'Last seen on ' + dateTime(new Date(client.latestHandshakeAt))"> |
||||
|
<!-- FIXME: add "timeago" --> |
||||
<!-- Last seen --> |
<!-- · {{ new Date(client.latestHandshakeAt) | timeago }} --> |
||||
<span |
{{ !uiTrafficStats ? ' · ' : '' }}{{ timeago(client.latestHandshakeAt) }} |
||||
v-if="client.latestHandshakeAt" |
</span> |
||||
:title="'Last seen on ' + dateTime(new Date(client.latestHandshakeAt))" |
</div> |
||||
> |
</div> |
||||
<!-- FIXME: add "timeago" --> |
<div |
||||
<!-- · {{ new Date(client.latestHandshakeAt) | timeago }} --> |
v-if="uiTrafficStats && client.transferTx && client.transferRx" |
||||
· {{ timeago(client.latestHandshakeAt) }} |
class="flex gap-2 items-center shrink-0 text-gray-400 dark:text-neutral-400 text-xs mt-px justify-end" |
||||
</span> |
> |
||||
|
<ClientTrafficStat |
||||
|
:transfer-data-current="client.transferTxCurrent" |
||||
|
:transfer-data="client.transferTx" |
||||
|
type="tx" |
||||
|
/> |
||||
|
<ClientTrafficStat |
||||
|
:transfer-data-current="client.transferRxCurrent" |
||||
|
:transfer-data="client.transferRx" |
||||
|
type="rx" |
||||
|
/> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script setup> |
<script setup> |
||||
import { ref } from 'vue'; |
import { storeToRefs } from 'pinia'; |
||||
|
|
||||
|
import API from '@/services/api'; |
||||
|
import { useStore } from '@/store/store'; |
||||
|
|
||||
import ClientName from '@/components/ClientName.vue'; |
import ClientName from '@/components/ClientName.vue'; |
||||
import ClientAddress from '@/components/ClientAddress.vue'; |
import ClientAddress from '@/components/ClientAddress.vue'; |
||||
import IconUpArrow from '@/components/icons/IconUpArrow.vue'; |
import IconUpArrow from '@/components/icons/IconUpArrow.vue'; |
||||
import IconDownArrow from '@/components/icons/IconDownArrow.vue'; |
import IconDownArrow from '@/components/icons/IconDownArrow.vue'; |
||||
import ClientTransfer from '@/components/ClientTransfer.vue'; |
import ClientTransfer from '@/components/ClientTransfer.vue'; |
||||
|
import ClientTrafficStat from '@/components/ClientTrafficStat.vue'; |
||||
|
|
||||
import { useDateTime } from '@/composables/useDateTime'; |
import { useDateTime } from '@/composables/useDateTime'; |
||||
import { useTimeAgo } from '@/composables/useTimeAgo'; |
import { useTimeAgo } from '@/composables/useTimeAgo'; |
||||
import { useBytes } from '@/composables/useBytes'; |
import { useBytes } from '@/composables/useBytes'; |
||||
import API from '@/services/api'; |
|
||||
|
|
||||
defineProps({ |
defineProps({ |
||||
client: {}, |
client: {}, |
||||
}); |
}); |
||||
|
|
||||
|
const store = useStore(); |
||||
|
const { uiTrafficStats } = storeToRefs(store); |
||||
|
|
||||
const { dateTime } = useDateTime(); |
const { dateTime } = useDateTime(); |
||||
const { timeago } = useTimeAgo(); |
const { timeago } = useTimeAgo(); |
||||
const { bytes } = useBytes(); |
const { bytes } = useBytes(); |
||||
|
|
||||
const api = new API(); |
const api = new API(); |
||||
|
|
||||
|
|
||||
</script> |
</script> |
||||
|
|||||
@ -0,0 +1,39 @@ |
|||||
|
<template> |
||||
|
<div class="flex gap-2 items-center shrink-0 text-gray-400 dark:text-neutral-400 text-xs mt-px justify-end"> |
||||
|
<div class="min-w-20 md:min-w-24"> |
||||
|
<span class="flex gap-1" :title="$t('totalDownload') + bytes(transferData)"> |
||||
|
<IconTX v-if="type === 'tx'" /> |
||||
|
<IconRX v-if="type === 'rx'" /> |
||||
|
<div> |
||||
|
<span class="text-gray-700 dark:text-neutral-200">{{ bytes(transferDataCurrent) }}/s</span> |
||||
|
<!-- Total --> |
||||
|
<br /><span class="font-regular" style="font-size: 0.85em">{{ bytes(transferData) }}</span> |
||||
|
</div> |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { useBytes } from '@/composables/useBytes'; |
||||
|
|
||||
|
import IconRX from '@/components/icons/IconRX.vue'; |
||||
|
import IconTX from '@/components/icons/IconTX.vue'; |
||||
|
|
||||
|
const { bytes } = useBytes(); |
||||
|
|
||||
|
defineProps({ |
||||
|
transferData: { |
||||
|
type: Object, |
||||
|
default: null, |
||||
|
}, |
||||
|
transferDataCurrent: { |
||||
|
type: Object, |
||||
|
default: null, |
||||
|
}, |
||||
|
type: { |
||||
|
type: String, |
||||
|
default: '', |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<template> |
||||
|
<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> |
||||
|
</template> |
||||
|
|
||||
|
<script setup></script> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<template> |
||||
|
<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> |
||||
|
</template> |
||||
|
|
||||
|
<script setup></script> |
||||
Loading…
Reference in new issue