Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn users when deleting current IP being used or the last interface IP #2427

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 92 additions & 0 deletions core/frontend/src/components/ethernet/AddressDeletionDialog.vue
@@ -0,0 +1,92 @@
<template>
<v-dialog
width="350"
:value="show"
@input="resolve"
>
<v-card>
<v-card-title>{{ title }}</v-card-title>

<v-card-subtitle class="text-center mb-3 mt-3">
{{ message }}
</v-card-subtitle>

<v-card-text class="d-flex flex-row justify-space-around">
<v-btn
color="grey"
class="ma-2 elevation-2"
text
@click="resolve(false)"
>
Abort
</v-btn>
<v-btn
color="primary"
class="ma-2 elevation-2"
text
@click="resolve(true)"
>
Confirm
</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
name: 'AddressDeletionDialog',
model: {
prop: 'show',
event: 'change',
},
props: {
show: {
type: Boolean,
default: false,
},
dialogType: {
type: String,
default: '',
validator: (value: string) => ['', 'last-ip-address', 'ip-being-used'].includes(value),
},
},
data() {
return {
resolveCallback: undefined as ((state: boolean) => void) | undefined,
}
},
computed: {
title() {
if (this.dialogType === 'last-ip-address') {
return 'Last IP address'
}
if (this.dialogType === 'ip-being-used') {
return 'IP address in use'
}

return 'IP Deletion'
},
message() {
if (this.dialogType === 'last-ip-address') {
return 'This is the last IP address on this interface.'
+ ' Deleting it could prevent you from accessing your vehicle. Are you sure you want to proceed?'
}
if (this.dialogType === 'ip-being-used') {
return 'The IP address is currently being used to access BlueOS.'
+ ' Deleting it could prevent you from accessing your vehicle. Are you sure you want to proceed?'
}

return 'Are you sure you want to delete this IP address?'
},
},
methods: {
resolve(state: boolean) {
this.resolveCallback?.(state)
this.$emit('change', false)
},
},
})
</script>
59 changes: 59 additions & 0 deletions core/frontend/src/components/ethernet/InterfaceCard.vue
Expand Up @@ -47,6 +47,11 @@
v-model="show_creation_dialog"
:interface-name="adapter.name"
/>
<address-deletion-dialog
ref="deletionDialog"
v-model="show_deletion_dialog"
:dialog-type="deletion_dialog_type"
/>
<v-btn
small
class="ma-2 px-2 py-5 elevation-1"
Expand Down Expand Up @@ -85,12 +90,14 @@
import Vue, { PropType } from 'vue'

import Notifier from '@/libs/notifier'
import beacon from '@/store/beacon'
import ethernet from '@/store/ethernet'
import { AddressMode, EthernetInterface } from '@/types/ethernet'
import { ethernet_service } from '@/types/frontend_services'
import back_axios from '@/utils/api'

import AddressCreationDialog from './AddressCreationDialog.vue'
import AddressDeletionDialog from './AddressDeletionDialog.vue'
import DHCPServerDialog from './DHCPServerDialog.vue'

const notifier = new Notifier(ethernet_service)
Expand All @@ -99,6 +106,7 @@ export default Vue.extend({
name: 'InterfaceCard',
components: {
AddressCreationDialog,
AddressDeletionDialog,
'dhcp-server-dialog': DHCPServerDialog,
},
props: {
Expand All @@ -111,7 +119,9 @@ export default Vue.extend({
data() {
return {
show_creation_dialog: false,
show_deletion_dialog: false,
show_dhcp_server_dialog: false,
deletion_dialog_type: '',
}
},
computed: {
Expand All @@ -127,8 +137,50 @@ export default Vue.extend({
is_static_ip_present(): boolean {
return this.adapter.addresses.some((address) => address.mode === AddressMode.unmanaged)
},
is_interface_last_ip_address(): boolean {
return this.adapter.addresses.length === 1
},
},
mounted() {
beacon.registerBeaconListener(this)
},
methods: {
async fireConfirmDeletionModal(type: 'last-ip-address' | 'ip-being-used'): Promise<boolean> {
const dialog = this.$refs.deletionDialog as InstanceType<typeof AddressDeletionDialog>

this.deletion_dialog_type = type
this.show_deletion_dialog = true

return new Promise((resolve) => {
dialog.resolveCallback = resolve
})
},
/**
* Opens a dialog and requests the user to confirm the deletion of the IP address.
* @returns {Promise<boolean>} - Resolves to true if no confirmation is needed or
* granted and false otherwise.
*/
async confirm_last_interface_ip(): Promise<boolean> {
if (this.is_interface_last_ip_address) {
return this.fireConfirmDeletionModal('last-ip-address')
}

return true
},
/**
* Opens a dialog and requests the user to confirm the deletion of current used IP address.
* @returns {Promise<boolean>} - Resolves to true if no confirmation is needed or
* granted and false otherwise.
*/
async confirm_ip_being_used(ip: string): Promise<boolean> {
const ip_being_used = ip === beacon.nginx_ip_address

if (ip_being_used) {
return this.fireConfirmDeletionModal('ip-being-used')
}

return true
},
showable_mode_name(mode: AddressMode): string {
switch (mode) {
case AddressMode.client: return 'Dynamic IP'
Expand All @@ -141,6 +193,13 @@ export default Vue.extend({
this.show_creation_dialog = true
},
async deleteAddress(ip: string): Promise<void> {
const confirmed_ip_used = await this.confirm_ip_being_used(ip)
const confirmed_last_ip = confirmed_ip_used && await this.confirm_last_interface_ip()

if (!confirmed_ip_used || !confirmed_last_ip) {
return
}

ethernet.setUpdatingInterfaces(true)

await back_axios({
Expand Down
27 changes: 27 additions & 0 deletions core/frontend/src/components/wifi/DisconnectionDialog.vue
Expand Up @@ -18,6 +18,26 @@
</v-btn>
</v-card-title>

<v-card-title
v-if="holds_ip_being_used"
class="justify-center"
>
<v-icon
color="white"
size="45"
>
mdi-alert-octagon
</v-icon>
</v-card-title>

<v-card-subtitle
v-if="holds_ip_being_used"
class="text-center mt-2 mb-2"
>
This IP address is currently being used to access BlueOS.
Deleting it could prevent you from accessing your vehicle. Are you sure you want to disconnect?
</v-card-subtitle>

<v-expand-transition>
<div v-show="show_more_info">
<v-card-text>
Expand Down Expand Up @@ -58,6 +78,7 @@
import Vue, { PropType } from 'vue'

import Notifier from '@/libs/notifier'
import beacon from '@/store/beacon'
import wifi from '@/store/wifi'
import { wifi_service } from '@/types/frontend_services'
import { Network, WifiStatus } from '@/types/wifi'
Expand Down Expand Up @@ -100,6 +121,12 @@ export default Vue.extend({
}
return { ...this.network, ...this.status }
},
holds_ip_being_used(): boolean {
return this.status?.ip_address === beacon.nginx_ip_address
},
},
mounted() {
beacon.registerBeaconListener(this)
},
methods: {
toggleInfoShow(): void {
Expand Down