Skip to content

Commit

Permalink
feat(hotspot)
Browse files Browse the repository at this point in the history
- Status content
  • Loading branch information
nicolorevelli committed Oct 12, 2023
1 parent 1eb2236 commit 9ad8437
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 25 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@headlessui/vue": "^1.7.13",
"@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light",
"@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid",
"@nethserver/vue-tailwind-lib": "^0.0.77",
"@nethserver/vue-tailwind-lib": "^0.0.79",
"@types/lodash": "^4.14.195",
"axios": "^1.4.0",
"chart.js": "^4.4.0",
Expand Down
26 changes: 20 additions & 6 deletions public/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@
"cannot_retrieve_wan_traffic": "Cannot retrieve WAN traffic",
"register_unit_error": "Cannot register unit",
"cancel_registration_error": "Cannot cancel registration",
"cannot_load_routes": "Cannot retrive routes",
"cannot_load_routes": "Cannot retrieve routes",
"cannot_create_route": "Cannot create route",
"cannot_edit_route": "Cannot edit route",
"cannot_retrive_interfaces": "Cannot retrieve interfaces",
"cannot_retrive_route_types": "Cannot retrieve route types",
"cannot_retrive_parent_hotspot": "Cannot retrieve parent hotspot",
"cannot_retrive_network_device": "Cannot retrieve network device",
"cannot_retrive_configuration": "Cannot retrieve hotspot configuration",
"cannot_retrive_dhcp_range": "Cannot retrieve default DHCP range",
"cannot_retrieve_parent_hotspot": "Cannot retrieve parent hotspot",
"cannot_retrieve_network_device": "Cannot retrieve network device",
"cannot_retrieve_configuration": "Cannot retrieve hotspot configuration",
"cannot_retrieve_dhcp_range": "Cannot retrieve default DHCP range",
"invalid_metric": "Enter an integer number greater than or equal to 0",
"cannot_update_status_route": "Cannot update route status",
"cannot_delete_port_forward": "Cannot delete port forward",
Expand All @@ -79,7 +79,8 @@
"cannot_retrieve_wan_interfaces": "Cannot retrieve WAN interfaces",
"cannot_login_hotspot": "Cannot login",
"cannot_login_hotspot_description": "Login failed",
"cannot_unregister_hotspot": "Cannot unregister"
"cannot_unregister_hotspot": "Cannot unregister",
"cannot_load_hotspot_configuration": "Cannot load hotspot configuration"
},
"ne_text_input": {
"show_password": "Show password",
Expand Down Expand Up @@ -495,6 +496,19 @@
"status": "Status",
"settings": "Settings"
},
"status": {
"no_hotspot_configuration_found": "No Hotspot configuration found",
"no_hotspot_configuration_found_description": "Authenticate in \"Settings\" to edit hotspot configuration",
"no_hotspot_configuration_found_button": "Go to settings",
"mac_address": "MAC address",
"ip_address": "IP address",
"login_status": "Login status",
"session_key": "Session key",
"session_time": "Session time",
"idle_time": "Idle time",
"downloaded": "Downloaded",
"uploaded": "Uploaded"
},
"settings": {
"login": "Login",
"login_description": "Authenticate to edit hotspot configuration or unregister your hotspot.",
Expand Down
28 changes: 18 additions & 10 deletions src/components/standalone/hotspot/SettingsContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import { useI18n } from 'vue-i18n'
import { validateIp4Cidr, validateIp4Address, validateRequired } from '@/lib/validation'
import { ubusCall } from '@/lib/standalone/ubus'
import { AxiosError } from 'axios'
import { useUciPendingChangesStore } from '@/stores/standalone/uciPendingChanges'
const { t } = useI18n()
const uciPendingChangesStore = useUciPendingChangesStore()
interface Login {
hostname: string
Expand Down Expand Up @@ -112,7 +114,7 @@ async function getFirewallData() {
loading.value = true
errorLoadingData.value = { ...objError }
// Retrive parent hotspot
// Retrieve parent hotspot
try {
let getParentHotspot = await ubusCall('ns.dedalo', 'list-parents', {})
if (
Expand All @@ -129,7 +131,7 @@ async function getFirewallData() {
configurationForm.value.parentHotspot = getParentHotspot.data.parents[0].id
}
} catch (exception: any) {
errorLoadingData.value.notificationTitle = t('error.cannot_retrive_parent_hotspot')
errorLoadingData.value.notificationTitle = t('error.cannot_retrieve_parent_hotspot')
errorLoadingData.value.notificationDescription = t(getAxiosErrorMessage(exception))
} finally {
try {
Expand All @@ -147,7 +149,7 @@ async function getFirewallData() {
configurationForm.value.networkDevice = getNetworkDevice.data.devices[0]
}
} catch (exception: any) {
errorLoadingData.value.notificationTitle = t('error.cannot_retrive_network_device')
errorLoadingData.value.notificationTitle = t('error.cannot_retrieve_network_device')
errorLoadingData.value.notificationDescription = t(getAxiosErrorMessage(exception))
} finally {
loading.value = false
Expand Down Expand Up @@ -177,7 +179,7 @@ async function getConfiguration() {
if (configuration.dhcp_end) configurationForm.value.dhcpRangeEnd = configuration.dhcp_end
} else isLoggedIn.value = false
} catch (exception: any) {
errorLoadingData.value.notificationTitle = t('error.cannot_retrive_configuration')
errorLoadingData.value.notificationTitle = t('error.cannot_retrieve_configuration')
errorLoadingData.value.notificationDescription = t(getAxiosErrorMessage(exception))
}
}
Expand Down Expand Up @@ -236,9 +238,10 @@ function login() {
}
ubusCall('ns.dedalo', 'login', payload)
.then((response) => {
if (response.data && response.data.response && response.data.response === 'success')
if (response.data && response.data.response && response.data.response === 'success') {
isLoggedIn.value = true
else {
getFirewallData()
} else {
error.value.notificationTitle = t('error.cannot_login_hotspot')
error.value.notificationDescription = t('error.cannot_login_hotspot_description')
}
Expand Down Expand Up @@ -355,7 +358,10 @@ function saveConfiguration() {
errorSave.value.notificationTitle = t('error.cannot_save_configuration')
errorSave.value.notificationDescription = t(getAxiosErrorMessage(exception))
})
.finally(() => (saving.value = false))
.finally(() => {
saving.value = false
uciPendingChangesStore.getChanges()
})
}
}
Expand Down Expand Up @@ -403,13 +409,12 @@ function getDhcpRange() {
ubusCall('ns.dedalo', 'get-dhcp-range', payload)
.then((response) => {
if (response.data) {
console.log(response.data)
if (response.data.start) configurationForm.value.dhcpRangeStart = response.data.start
if (response.data.end) configurationForm.value.dhcpRangeEnd = response.data.end
}
})
.catch((exception: AxiosError) => {
errorDhcpRange.value.notificationTitle = t('error.cannot_retrive_dhcp_range')
errorDhcpRange.value.notificationTitle = t('error.cannot_retrieve_dhcp_range')
errorDhcpRange.value.notificationDescription = t(getAxiosErrorMessage(exception))
})
.finally(() => (loadingDhcpRange.value = false))
Expand Down Expand Up @@ -640,7 +645,10 @@ function getDhcpRange() {
</form>
</FormLayout>
<hr class="my-8" />
<FormLayout v-if="!loading && isLoggedIn" :title="t('standalone.hotspot.settings.unregister')">
<FormLayout
v-if="!loading && isLoggedIn && activeConficuration"
:title="t('standalone.hotspot.settings.unregister')"
>
<div>
<NeInlineNotification
v-if="errorUnregister.notificationTitle"
Expand Down
178 changes: 176 additions & 2 deletions src/components/standalone/hotspot/StatusContent.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,179 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import {
NeButton,
NeSkeleton,
NeEmptyState,
NeInlineNotification,
getAxiosErrorMessage
} from '@nethserver/vue-tailwind-lib'
import { faCircleCheck, faCircleXmark } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { ubusCall } from '@/lib/standalone/ubus'
import NeTable from '@/components/standalone/NeTable.vue'
const { t } = useI18n()
const emit = defineEmits(['goToSetting'])
let hotspotSession: any = ref({})
let loading = ref(true)
let error = ref({
notificationTitle: '',
notificationDescription: ''
})
onMounted(async () => {
await loadListSessions()
loading.value = false
})
async function loadListSessions() {
try {
const res = await ubusCall('ns.dedalo', 'list-sessions')
if (res.data && res.data.sessions && res.data.sessions.length)
hotspotSession.value = res.data.sessions
} catch (err: any) {
error.value.notificationTitle = t('error.cannot_load_hotspot_configuration')
error.value.notificationDescription = t(getAxiosErrorMessage(err))
}
}
function secondsToHMS(seconds: number): string {
if (seconds) {
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const remainingSeconds = seconds % 60
const formattedHours = hours.toString().padStart(2, '0')
const formattedMinutes = minutes.toString().padStart(2, '0')
const formattedSeconds = remainingSeconds.toString().padStart(2, '0')
return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`
} else return '-'
}
function autoConvertSize(sizeInBytes: number): string {
if (sizeInBytes) {
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let unitIndex = 0
while (sizeInBytes >= 1024 && unitIndex < units.length - 1) {
sizeInBytes /= 1024
unitIndex++
}
return `${sizeInBytes.toFixed(2)} ${units[unitIndex]}`
} else return '-'
}
</script>

<template>
<div></div>
<div>
<NeSkeleton v-if="loading" :lines="15" />
<NeInlineNotification
v-if="!loading && error.notificationTitle"
class="my-4"
kind="error"
:title="error.notificationTitle"
:description="error.notificationDescription"
/>
<NeEmptyState
v-if="!loading && !error.notificationTitle && !hotspotSession.length"
:title="t('standalone.hotspot.status.no_hotspot_configuration_found')"
:description="t('standalone.hotspot.status.no_hotspot_configuration_found_description')"
:icon="['fa', 'wifi']"
>
<NeButton kind="primary" size="lg" @click="emit('goToSetting')">
<template #prefix>
<FontAwesomeIcon :icon="['fas', 'circle-plus']" aria-hidden="true" />
</template>
{{ t('standalone.hotspot.status.no_hotspot_configuration_found_button') }}
</NeButton>
</NeEmptyState>
<div>
<template v-if="!loading && hotspotSession.length > 0">
<NeTable
:data="hotspotSession"
:headers="[
{
key: 'mac_address',
label: t('standalone.hotspot.status.mac_address')
},
{
key: 'ip_address',
label: t('standalone.hotspot.status.ip_address')
},
{
key: 'login_status',
label: t('standalone.hotspot.status.login_status')
},
{
key: 'session_key',
label: t('standalone.hotspot.status.session_key')
},
{
key: 'session_time',
label: t('standalone.hotspot.status.session_time')
},
{
key: 'idle_time',
label: t('standalone.hotspot.status.idle_time')
},
{
key: 'downloaded',
label: t('standalone.hotspot.status.downloaded')
},
{
key: 'uploaded',
label: t('standalone.hotspot.status.uploaded')
}
]"
>
<template #mac_address="{ item }">
<div class="flex items-center gap-x-4">
{{ item.macAddress }}
</div>
</template>
<template #ip_address="{ item }">
<div class="flex flex-wrap gap-2">
{{ item.ipAddress }}
</div>
</template>
<template #login_status="{ item }">
<div class="flex items-center gap-x-2">
<template v-if="item.status && item.status === 'authenticated'">
<FontAwesomeIcon :icon="faCircleCheck" />
</template>
<template v-else>
<FontAwesomeIcon :icon="faCircleXmark" />
</template>
{{ item.status }}
</div>
</template>
<template #session_key="{ item }">
<div class="flex items-center gap-x-2">
{{ item.sessionKey }}
</div>
</template>
<template #session_time="{ item }">
<div class="flex items-center gap-x-2">
{{ secondsToHMS(item.sessionTimeElapsed) }}
</div>
</template>
<template #idle_time="{ item }">
<div class="flex items-center gap-x-2">
{{ secondsToHMS(item.idleTimeElapsed) }}
</div>
</template>
<template #downloaded="{ item }">
{{ autoConvertSize(item.inputOctetsDownloaded) }}
</template>
<template #uploaded="{ item }">
{{ autoConvertSize(item.outputOctetsUploaded) }}
</template>
</NeTable>
</template>
</div>
</div>
</template>
4 changes: 3 additions & 1 deletion src/lib/fontawesome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
faPowerOff,
faCircleStop,
faHouse as fasHouse,
faUserGear
faUserGear,
faWifi
} from '@fortawesome/free-solid-svg-icons'
import { faHouse as falHouse } from '@nethesis/nethesis-light-svg-icons'
import { faServer as fasServer } from '@fortawesome/free-solid-svg-icons'
Expand Down Expand Up @@ -127,4 +128,5 @@ export async function loadFontAwesome(app: any) {
library.add(faClone)
library.add(faUserGear)
library.add(faCircleStop)
library.add(faWifi)
}
5 changes: 4 additions & 1 deletion src/views/standalone/network/HotspotView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ watch(selectedTab, () => {
class="mb-8"
@selectTab="selectedTab = $event"
/>
<StatusContent v-if="selectedTab == 'tab-status'" />
<StatusContent
v-if="selectedTab == 'tab-status'"
@go-to-setting="selectedTab = 'tab-settings'"
/>
<SettingsContent v-if="selectedTab == 'tab-settings'" />
</div>
</template>

0 comments on commit 9ad8437

Please sign in to comment.