<!--
  - CoolerControl - monitor and control your cooling and other devices
  - Copyright (c) 2021-2025  Guy Boldon and contributors
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU General Public License as published by
  - the Free Software Foundation, either version 3 of the License, or
  - (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  - GNU General Public License for more details.
  -
  - You should have received a copy of the GNU General Public License
  - along with this program.  If not, see <https://www.gnu.org/licenses/>.
  -->

<script setup lang="ts">
// @ts-ignore
import SvgIcon from '@jamescoyle/vue-icon/lib/svg-icon.vue'
import {
    mdiBellCircleOutline,
    mdiBellOutline,
    mdiBellRingOutline,
    mdiBookmarkCheckOutline,
    mdiBookmarkMultipleOutline,
    mdiBookmarkOffOutline,
    mdiBookmarkOutline,
    mdiChartBoxMultipleOutline,
    mdiChartBoxOutline,
    mdiChartLine,
    mdiChartMultiple,
    mdiDotsVertical,
    mdiFan,
    mdiFlaskRoundBottom,
    mdiFunction,
    mdiHomeAnalytics,
    mdiLedOn,
    mdiLightningBoltCircle,
    mdiMemory,
    mdiPinOutline,
    mdiSineWave,
    mdiSpeedometer,
    mdiTelevisionShimmer,
    mdiThermometer,
} from '@mdi/js'
import { inject, onMounted, onUnmounted, ref, Ref, toRaw, watch } from 'vue'
import { ElCollapse, ElCollapseItem } from 'element-plus'
import 'element-plus/es/components/collapse/style/css'
import Popover from 'primevue/popover'
import { ChannelValues, useDeviceStore } from '@/stores/DeviceStore'
import { useSettingsStore } from '@/stores/SettingsStore.ts'
import { Emitter, EventType } from 'mitt'
import { Color, DeviceType, UID } from '@/models/Device.ts'
import MenuRename from '@/components/menu/MenuRename.vue'
import MenuColorPicker from '@/components/menu/MenuColorPicker.vue'
import MenuDeviceInfo from '@/components/menu/MenuDeviceInfo.vue'
import MenuDashboardAdd from '@/components/menu/MenuDashboardAdd.vue'
import MenuDashboardRename from '@/components/menu/MenuDashboardRename.vue'
import SubMenuDashboardDelete from '@/components/menu/SubMenuDashboardDelete.vue'
import SubMenuCustomSensorDelete from '@/components/menu/SubMenuCustomSensorDelete.vue'
import MenuCustomSensorAdd from '@/components/menu/MenuCustomSensorAdd.vue'
import { useRoute, useRouter } from 'vue-router'
import MenuFunctionRename from '@/components/menu/MenuFunctionRename.vue'
import SubMenuFunctionDelete from '@/components/menu/SubMenuFunctionDelete.vue'
import MenuFunctionAdd from '@/components/menu/MenuFunctionAdd.vue'
import SubMenuFunctionDuplicate from '@/components/menu/SubMenuFunctionDuplicate.vue'
import SubMenuDashboardDuplicate from '@/components/menu/SubMenuDashboardDuplicate.vue'
import SubMenuProfileDelete from '@/components/menu/SubMenuProfileDelete.vue'
import MenuProfileRename from '@/components/menu/MenuProfileRename.vue'
import SubMenuProfileDuplicate from '@/components/menu/SubMenuProfileDuplicate.vue'
import MenuProfileAdd from '@/components/menu/MenuProfileAdd.vue'
import MenuModeAdd from '@/components/menu/MenuModeAdd.vue'
import MenuModeRename from '@/components/menu/MenuModeRename.vue'
import SubMenuModeDelete from '@/components/menu/SubMenuModeDelete.vue'
import SubMenuModeDuplicate from '@/components/menu/SubMenuModeDuplicate.vue'
import SubMenuModeUpdate from '@/components/menu/SubMenuModeUpdate.vue'
import MenuModeInfo from '@/components/menu/MenuModeInfo.vue'
import MenuProfileInfo from '@/components/menu/MenuProfileInfo.vue'
import MenuDashboardInfo from '@/components/menu/MenuDashboardInfo.vue'
import MenuFunctionInfo from '@/components/menu/MenuFunctionInfo.vue'
import MenuCustomSensorInfo from '@/components/menu/MenuCustomSensorInfo.vue'
import { AlertState } from '@/models/Alert.ts'
import MenuAlertInfo from '@/components/menu/MenuAlertInfo.vue'
import MenuAlertRename from '@/components/menu/MenuAlertRename.vue'
import MenuAlertAdd from '@/components/menu/MenuAlertAdd.vue'
import SubMenuAlertDelete from '@/components/menu/SubMenuAlertDelete.vue'
import MenuDashboardHome from '@/components/menu/MenuDashboardHome.vue'
import MenuControlView from '@/components/menu/MenuControlView.vue'
import MenuModeView from '@/components/menu/MenuModeView.vue'
import { VueDraggable } from 'vue-draggable-plus'
import { useI18n } from 'vue-i18n'
import SubMenuMoveTop from '@/components/menu/SubMenuMoveTop.vue'
import SubMenuMoveBottom from '@/components/menu/SubMenuMoveBottom.vue'
import SubMenuDisable from '@/components/menu/SubMenuDisable.vue'
import { useDaemonState } from '@/stores/DaemonState.ts'
import SubMenuPin from '@/components/menu/SubMenuPin.vue'
import MenuModeActivate from '@/components/menu/MenuModeActivate.vue'
import MenuProfileApply from '@/components/menu/MenuProfileApply.vue'
import MenuFunctionApply from '@/components/menu/MenuFunctionApply.vue'
import SubMenuTagAssign from '@/components/menu/SubMenuTagAssign.vue'
import SubMenuAlertDuplicate from '@/components/menu/SubMenuAlertDuplicate.vue'
import SubMenuAlertAddFail from '@/components/menu/SubMenuAlertAddFail.vue'
import SubMenuAlertAddTemp from '@/components/menu/SubMenuAlertAddTemp.vue'
import SubMenuDeviceColorPicker from '@/components/menu/SubMenuDeviceColorPicker.vue'
import SubMenuEntityColorPicker from '@/components/menu/SubMenuEntityColorPicker.vue'
import { useThemeColorsStore } from '@/stores/ThemeColorsStore.ts'
import SubMenuDeviceExtensionSettings from '@/components/menu/SubMenuDeviceExtensionSettings.vue'

interface Tree {
    [key: string]: any
}

const deviceStore = useDeviceStore()
const settingsStore = useSettingsStore()
const colorStore = useThemeColorsStore()
const router = useRouter()
const route = useRoute()
const daemonState = useDaemonState()
const emitter: Emitter<Record<EventType, any>> = inject('emitter')!
const { t } = useI18n()

// Reactive key to force re-computation of colors when theme changes
const themeColorKey = ref(0)
const onThemeChanged = () => {
    colorStore.reLoadThemeColors()
    themeColorKey.value++
}

const deviceChannelValues = (deviceUID: UID, channelName: string): ChannelValues | undefined =>
    deviceStore.currentDeviceStatus.get(deviceUID)?.get(channelName)
const deviceChannelColor = (deviceUID: UID | undefined, channelName: string): Ref<Color> => {
    // blank color will use the theme's css
    const color = ref('')
    if (
        deviceUID == null ||
        deviceUID.startsWith('Dashboards') ||
        deviceUID.startsWith('Modes') ||
        deviceUID.startsWith('Profiles') ||
        deviceUID.startsWith('Functions')
    ) {
        color.value = ''
    } else {
        color.value =
            settingsStore.allUIDeviceSettings.get(deviceUID)?.sensorsAndChannels.get(channelName)
                ?.color ?? ''
    }
    return color
}
const deviceColor = (deviceUID: UID | undefined): Ref<Color> => {
    // Access themeColorKey to trigger reactivity on theme change
    void themeColorKey.value
    // blank color will use the theme's css
    const color = ref('')
    if (deviceUID != null) {
        if (settingsStore.allUIDeviceSettings.get(deviceUID) == null) {
            return color
        }
        // default device color should be the theme's text color:
        color.value =
            settingsStore.allUIDeviceSettings.get(deviceUID)?.userColor ??
            colorStore.themeColors.text_color
    }
    return color
}

const entityColor = (entityID: string): Ref<Color> => {
    const color = ref('')
    const foundColorEntry = settingsStore.entityColors.find(
        (entityColor) => entityColor[0] === entityID,
    )
    if (entityID === 'dashboards') {
        color.value = foundColorEntry != null ? foundColorEntry[1] : '#FF7F00'
    } else if (entityID === 'modes') {
        color.value = foundColorEntry != null ? foundColorEntry[1] : '#7F00FF'
    } else if (entityID === 'profiles') {
        color.value = foundColorEntry != null ? foundColorEntry[1] : '#007FFF'
    } else if (entityID === 'functions') {
        color.value = foundColorEntry != null ? foundColorEntry[1] : '#7FFF00'
    } else if (entityID === 'alerts') {
        color.value = foundColorEntry != null ? foundColorEntry[1] : '#FF007F'
    }
    return color
}
const getIconColor = (item: any): Color => {
    // Access themeColorKey to trigger reactivity on theme change
    void themeColorKey.value
    if (item.color != null) {
        return item.color
    }
    if (item.name == null) {
        if (item.deviceUID == null) {
            return entityColor(item.id).value
        } else {
            return deviceColor(item.deviceUID).value
        }
    }
    return deviceChannelColor(item.deviceUID, item.name).value
}

const getLabelColor = (item: any): Color => {
    // this is only used for devices currently
    if (item.name == null && item.deviceUID != null) {
        return deviceColor(item.deviceUID).value
    }
    return ''
}

const getSideBorderColor = (item: any): Color => {
    if (item.name == null && item.deviceUID != null) {
        // Device
        const color = ref('')
        if (settingsStore.allUIDeviceSettings.get(item.deviceUID) == null) {
            return color.value
        }
        // default device color should be the default css:
        const deviceColor = settingsStore.allUIDeviceSettings.get(item.deviceUID)?.userColor
        color.value = deviceColor != null ? deviceColor + '8C' : ''
        return color.value
    }
    // Entity colors
    return entityColor(item.id).value + '8C'
}

const deviceChannelIconSize = (deviceUID: UID | undefined, name: string | undefined): number => {
    if (deviceUID == null) {
        // Group root like Dashboards, Modes, etc
        return 1.75
    } else if (
        // group items
        deviceUID.startsWith('Dashboards') ||
        deviceUID.startsWith('Modes') ||
        deviceUID.startsWith('Profiles') ||
        deviceUID.startsWith('Functions')
    ) {
        return 1.25
    } else if (deviceUID && !name) {
        // Device roots
        return 1.75
    } else {
        // channels, etc.
        return 1.5
    }
}

const data: Ref<Array<Tree>> = ref([])
const pinnedItems: Ref<Array<Tree>> = ref([])

const pinItem = (item: any) => {
    pinnedItems.value.push(item)
    changedPinnedItems()
}
const isPinned = (item: any): boolean => {
    return pinnedItems.value.some((pinnedItem) => pinnedItem.id === item.id)
}
const unPinItem = (item: any) => {
    pinnedItems.value = pinnedItems.value.filter((pinnedItem) => pinnedItem.id !== item.id)
    changedPinnedItems()
}
const changedPinnedItems = () => {
    settingsStore.pinnedIds = pinnedItems.value.map((item: any) => item.id)
}

enum Menu {
    COLOR,
    RENAME,
    DEVICE_INFO,
    CUSTOM_SENSOR_INFO,
    CUSTOM_SENSOR_ADD,
    DASHBOARD_INFO,
    DASHBOARD_ADD,
    DASHBOARD_HOME,
    DASHBOARD_RENAME,
    MODE_INFO,
    MODE_ADD,
    MODE_ACTIVATE,
    MODE_RENAME,
    PROFILE_INFO,
    PROFILE_ADD,
    PROFILE_APPLY,
    PROFILE_RENAME,
    FUNCTION_INFO,
    FUNCTION_ADD,
    FUNCTION_APPLY,
    FUNCTION_RENAME,
    ALERT_INFO,
    ALERT_ADD,
    ALERT_RENAME,
    IS_CONTROLLABLE,
}
enum SubMenu {
    MOVE_TOP,
    PIN,
    COLOR,
    DEVICE_EXTENSIONS,
    DISABLE,
    CUSTOM_SENSOR_DELETE,
    DASHBOARD_DUPLICATE,
    DASHBOARD_DELETE,
    MODE_UPDATE,
    MODE_DUPLICATE,
    MODE_DELETE,
    PROFILE_DUPLICATE,
    PROFILE_DELETE,
    FUNCTION_DUPLICATE,
    FUNCTION_DELETE,
    ALERT_DUPLICATE,
    ALERT_DELETE,
    ALERT_ADD_FAIL,
    ALERT_ADD_TEMP,
    TAG,
    MOVE_BOTTOM,
}

const createTreeMenu = (): void => {
    data.value.length = 0
    const result: Tree[] = []
    result.push(...devicesTreeArray())
    result.push(customSensorsTree())
    result.push(dashboardsTree())
    result.push(modesTree())
    result.push(profilesTree())
    result.push(functionsTree())
    result.push(alertsTree())
    if (settingsStore.menuOrder.length > 0) {
        // Sort main menu items (new items get sorted to top)
        const getRootIndex = (item: any) => {
            const index = settingsStore.menuOrder.findIndex((menuItem) => menuItem.id === item.id)
            return index >= 0 ? index : Number.MIN_SAFE_INTEGER
        }
        result.sort((a, b) => getRootIndex(a) - getRootIndex(b))

        // Sort children of each menu item
        result.forEach((menuItem) => {
            const menuOrderItem = settingsStore.menuOrder.find((item) => item.id === menuItem.id)
            if (menuOrderItem?.children?.length) {
                const getIndex = (item: any) => {
                    const index = menuOrderItem.children.indexOf(item.id)
                    return index >= 0 ? index : Number.MAX_SAFE_INTEGER
                }
                menuItem.children.sort((a: any, b: any) => getIndex(a) - getIndex(b))
            }
        })
        sortStoreProfiles()
        sortStoreFunctions()
        deviceStore.reSortDevicesByMenuOrder(true)
    }
    data.value.push(...result)
}

const saveMenuOrderChanges = () => {
    settingsStore.menuOrder = data.value.map((item: any) => {
        return { id: item.id, children: item.children.map((child: any) => child.id) }
    })
    sortStoreProfiles()
    sortStoreFunctions()
    deviceStore.reSortDevicesByMenuOrder()
}

const sortStoreProfiles = () => {
    const profilesOrderItem = settingsStore.menuOrder.find((item) => item.id === 'profiles')
    if (profilesOrderItem?.children?.length) {
        const getIndex = (item: any) => {
            const index = profilesOrderItem.children.indexOf(item.uid)
            return index >= 0 ? index : Number.MAX_SAFE_INTEGER
        }
        settingsStore.profiles.sort((a: any, b: any) => getIndex(a) - getIndex(b))
    }
}
const sortStoreFunctions = () => {
    const functionsOrderItem = settingsStore.menuOrder.find((item) => item.id === 'functions')
    if (functionsOrderItem?.children?.length) {
        const getIndex = (item: any) => {
            const index = functionsOrderItem.children.indexOf(item.uid)
            return index >= 0 ? index : Number.MAX_SAFE_INTEGER
        }
        settingsStore.functions.sort((a: any, b: any) => getIndex(a) - getIndex(b))
    }
}

const createPinnedMenu = (): void => {
    pinnedItems.value.length = 0
    if (settingsStore.pinnedIds.length > 0) {
        settingsStore.pinnedIds.forEach((id: string) => {
            data.value.forEach((item: any) => {
                item.children.forEach((child: any) => {
                    if (child.id === id) {
                        pinnedItems.value.push(child)
                    }
                })
            })
        })
    }
}

const dashboardsTree = (): any => {
    return {
        id: 'dashboards',
        label: t('layout.menu.dashboards'),
        icon: mdiChartBoxMultipleOutline,
        name: null, // devices should not have names
        menus: [Menu.DASHBOARD_INFO, Menu.DASHBOARD_ADD],
        subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
        children: settingsStore.dashboards.map((dashboard) => {
            return {
                id: dashboard.uid,
                label: dashboard.name,
                icon:
                    dashboard.uid === settingsStore.homeDashboard
                        ? mdiHomeAnalytics
                        : mdiChartBoxOutline,
                deviceUID: 'Dashboards',
                dashboardUID: dashboard.uid,
                name: dashboard.uid,
                to: { name: 'dashboards', params: { dashboardUID: dashboard.uid } },
                menus: [Menu.DASHBOARD_HOME, Menu.DASHBOARD_RENAME],
                subMenus: [
                    SubMenu.MOVE_TOP,
                    SubMenu.PIN,
                    SubMenu.DASHBOARD_DUPLICATE,
                    SubMenu.DASHBOARD_DELETE,
                    SubMenu.MOVE_BOTTOM,
                ],
            }
        }),
    }
}
const modesTree = (): any => {
    return {
        id: 'modes',
        label: t('layout.menu.modes'),
        icon: mdiBookmarkMultipleOutline,
        name: null, // devices should not have names
        menus: [Menu.MODE_INFO, Menu.MODE_ADD],
        subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
        children: settingsStore.modes.map((mode) => {
            const isActive: boolean = settingsStore.modeActiveCurrent === mode.uid
            const isRecentlyActive: boolean = settingsStore.modeActivePrevious === mode.uid
            return {
                id: mode.uid,
                label: mode.name,
                icon: isActive
                    ? mdiBookmarkCheckOutline
                    : isRecentlyActive
                      ? mdiBookmarkOffOutline
                      : mdiBookmarkOutline,
                deviceUID: 'Modes',
                uid: mode.uid,
                isActive: isActive,
                isRecentlyActive: isRecentlyActive,
                to: { name: 'modes', params: { modeUID: mode.uid } },
                menus: [Menu.MODE_ACTIVATE, Menu.MODE_RENAME],
                subMenus: [
                    SubMenu.MOVE_TOP,
                    SubMenu.PIN,
                    SubMenu.MODE_UPDATE,
                    SubMenu.MODE_DUPLICATE,
                    SubMenu.MODE_DELETE,
                    SubMenu.MOVE_BOTTOM,
                ],
            }
        }),
    }
}

const profilesTree = (): any => {
    return {
        id: 'profiles',
        label: t('layout.menu.profiles'),
        name: null, // devices should not have names
        icon: mdiChartMultiple,
        menus: [Menu.PROFILE_INFO, Menu.PROFILE_ADD],
        subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
        children: settingsStore.profiles
            .filter((profile) => profile.uid !== '0') // Default Profile
            .map((profile) => {
                return {
                    id: profile.uid,
                    label: profile.name,
                    icon: mdiChartLine,
                    deviceUID: 'Profiles',
                    uid: profile.uid,
                    to: { name: 'profiles', params: { profileUID: profile.uid } },
                    menus: [Menu.PROFILE_APPLY, Menu.PROFILE_RENAME],
                    subMenus: [
                        SubMenu.MOVE_TOP,
                        SubMenu.PIN,
                        SubMenu.PROFILE_DUPLICATE,
                        SubMenu.PROFILE_DELETE,
                        SubMenu.MOVE_BOTTOM,
                    ],
                }
            }),
    }
}

const functionsTree = (): any => {
    return {
        id: 'functions',
        label: t('layout.menu.functions'),
        icon: mdiFunction,
        name: null, // devices should not have names
        menus: [Menu.FUNCTION_INFO, Menu.FUNCTION_ADD],
        subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
        children: settingsStore.functions
            .filter((fun) => fun.uid !== '0') // Default Function
            .map((fun) => {
                return {
                    id: fun.uid,
                    label: fun.name,
                    icon: mdiFunction,
                    deviceUID: 'Functions',
                    uid: fun.uid,
                    to: { name: 'functions', params: { functionUID: fun.uid } },
                    menus: [Menu.FUNCTION_APPLY, Menu.FUNCTION_RENAME],
                    subMenus: [
                        SubMenu.MOVE_TOP,
                        SubMenu.PIN,
                        SubMenu.FUNCTION_DUPLICATE,
                        SubMenu.FUNCTION_DELETE,
                        SubMenu.MOVE_BOTTOM,
                    ],
                }
            }),
    }
}

const alertsTree = (): any => {
    return {
        id: 'alerts',
        label: t('layout.menu.alerts'),
        name: null, // devices should not have names
        icon: mdiBellCircleOutline,
        menus: [Menu.ALERT_INFO, Menu.ALERT_ADD],
        subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
        children: settingsStore.alerts.map((alert) => {
            const isActive: boolean = settingsStore.alertsActive.includes(alert.uid)
            return {
                id: alert.uid,
                label: alert.name,
                icon: isActive ? mdiBellRingOutline : mdiBellOutline,
                deviceUID: 'Alerts',
                uid: alert.uid,
                alertIsActive: isActive,
                to: { name: 'alerts', params: { alertUID: alert.uid } },
                menus: [Menu.ALERT_RENAME],
                subMenus: [
                    SubMenu.MOVE_TOP,
                    SubMenu.PIN,
                    SubMenu.ALERT_DUPLICATE,
                    SubMenu.ALERT_DELETE,
                    SubMenu.MOVE_BOTTOM,
                ],
            }
        }),
    }
}
const customSensorsTree = (): any => {
    const sensorsChildren = []
    let deviceUID = ''
    for (const device of deviceStore.allDevices()) {
        if (device.type !== DeviceType.CUSTOM_SENSORS) {
            continue
        }
        deviceUID = device.uid
        const deviceSettings = settingsStore.allUIDeviceSettings.get(device.uid)!
        for (const temp of device.status.temps) {
            sensorsChildren.push({
                // This prefix is needed, as names are not unique across devices
                id: `${device.uid}_${temp.name}`,
                label: deviceSettings.sensorsAndChannels.get(temp.name)!.name,
                name: temp.name,
                icon: mdiFlaskRoundBottom,
                to: { name: 'custom-sensors', params: { customSensorID: temp.name } },
                deviceUID: device.uid,
                temp: temp.temp.toFixed(1),
                menus: [Menu.COLOR, Menu.RENAME],
                subMenus: [
                    SubMenu.MOVE_TOP,
                    SubMenu.PIN,
                    SubMenu.ALERT_ADD_TEMP,
                    SubMenu.CUSTOM_SENSOR_DELETE,
                    SubMenu.MOVE_BOTTOM,
                ],
            })
        }
        return {
            // deviceUID is used to sort the menu items and custom-sensors has a deviceUID
            id: deviceUID,
            tourAnchor: 'custom-sensors',
            label: t('layout.menu.customSensors'),
            icon: mdiFlaskRoundBottom,
            name: null, // devices should not have names
            deviceUID: deviceUID,
            menus: [Menu.CUSTOM_SENSOR_INFO, Menu.CUSTOM_SENSOR_ADD],
            subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.MOVE_BOTTOM],
            children: sensorsChildren,
        }
    }
}

const hoverMenusAreClosed: Ref<boolean> = ref(true)
const setHoverMenuStatus = (isOpen: boolean): void => {
    hoverMenusAreClosed.value = !isOpen
    const elements = document.querySelectorAll('.el-collapse-item__header')
    for (const element of elements) {
        if (isOpen) {
            // This overrides the hover:bg-bg-two style set in the CSS style
            // The reason for this is to avoid a flicker effect that happens when we add or remove
            // css classes, which is due to the EL component also changing the classes (is-active).
            element.setAttribute(
                'style',
                'background-color: rgb(var(--colors-bg-one)); cursor: default;',
            )
        } else {
            element.removeAttribute('style')
        }
    }
}

const devicesTreeArray = (): any[] => {
    const allDevices = []
    for (const device of deviceStore.allDevices()) {
        if (device.type === DeviceType.CUSTOM_SENSORS) {
            continue // has its own dedicated menu above
        }
        const deviceSettings = settingsStore.allUIDeviceSettings.get(device.uid)!
        const hasApplicableDeviceExtensions = device.type !== DeviceType.CPU
        const deviceItem = {
            id: device.uid,
            label: deviceSettings.name,
            name: null, // devices should not have names
            icon: mdiMemory,
            deviceUID: device.uid,
            children: [],
            menus: [Menu.DEVICE_INFO, Menu.RENAME],
            subMenus: [SubMenu.MOVE_TOP, SubMenu.COLOR, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
        }
        if (hasApplicableDeviceExtensions) {
            deviceItem.subMenus.splice(2, 0, SubMenu.DEVICE_EXTENSIONS)
        }
        for (const temp of device.status.temps) {
            // @ts-ignore
            deviceItem.children.push({
                id: `${device.uid}_${temp.name}`,
                label: deviceSettings.sensorsAndChannels.get(temp.name)!.name,
                name: temp.name,
                icon: mdiThermometer,
                to: {
                    name: 'single-dashboard',
                    params: { deviceUID: device.uid, channelName: temp.name },
                },
                deviceUID: device.uid,
                temp: temp.temp.toFixed(1),
                menus: [Menu.COLOR, Menu.RENAME],
                subMenus: [
                    SubMenu.MOVE_TOP,
                    SubMenu.PIN,
                    SubMenu.ALERT_ADD_TEMP,
                    SubMenu.DISABLE,
                    SubMenu.MOVE_BOTTOM,
                ],
            })
        }
        for (const channel of device.status.channels) {
            if (channel.name.toLowerCase().includes('freq')) {
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channel.name}`,
                    label: deviceSettings.sensorsAndChannels.get(channel.name)!.name,
                    name: channel.name,
                    icon: mdiSineWave,
                    to: {
                        name: 'single-dashboard',
                        params: { deviceUID: device.uid, channelName: channel.name },
                    },
                    deviceUID: device.uid,
                    freq: channel.freq,
                    menus: [Menu.COLOR, Menu.RENAME],
                    subMenus: [SubMenu.MOVE_TOP, SubMenu.PIN, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
                })
            }
        }
        for (const channel of device.status.channels) {
            if (channel.name.toLowerCase().includes('power')) {
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channel.name}`,
                    label: deviceSettings.sensorsAndChannels.get(channel.name)!.name,
                    name: channel.name,
                    icon: mdiLightningBoltCircle,
                    to: {
                        name: 'single-dashboard',
                        params: { deviceUID: device.uid, channelName: channel.name },
                    },
                    deviceUID: device.uid,
                    watts: channel.watts,
                    menus: [Menu.COLOR, Menu.RENAME],
                    subMenus: [SubMenu.MOVE_TOP, SubMenu.PIN, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
                })
            }
        }
        for (const channel of device.status.channels) {
            if (channel.name.toLowerCase().includes('load')) {
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channel.name}`,
                    label: deviceSettings.sensorsAndChannels.get(channel.name)!.name,
                    name: channel.name,
                    icon: mdiSpeedometer,
                    to: {
                        name: 'single-dashboard',
                        params: { deviceUID: device.uid, channelName: channel.name },
                    },
                    deviceUID: device.uid,
                    duty: channel.duty,
                    rpm: channel.rpm,
                    menus: [Menu.COLOR, Menu.RENAME],
                    subMenus: [SubMenu.MOVE_TOP, SubMenu.PIN, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
                })
            }
        }
        if (device.info != null) {
            for (const [channelName, channelInfo] of device.info.channels.entries()) {
                if (channelInfo.speed_options === null) {
                    continue
                }
                // need to get the status data to properly setup the menu item
                let duty: number | undefined = undefined
                let rpm: number | undefined = undefined
                for (const channel of device.status.channels) {
                    if (channel.name === channelName) {
                        duty = channel.duty
                        rpm = channel.rpm
                        break
                    }
                }
                const isControllable: boolean = channelInfo.speed_options?.fixed_enabled ?? false
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channelName}`,
                    label: deviceSettings.sensorsAndChannels.get(channelName)!.name,
                    name: channelName,
                    icon: mdiFan,
                    to: {
                        name: 'device-speed',
                        params: { deviceUID: device.uid, channelName: channelName },
                    },
                    deviceUID: device.uid,
                    duty: duty,
                    rpm: rpm,
                    isSpeedChannel: true,
                    isControllable: isControllable,
                    menus: [Menu.COLOR, Menu.RENAME, Menu.IS_CONTROLLABLE],
                    subMenus:
                        rpm != null
                            ? [
                                  SubMenu.MOVE_TOP,
                                  SubMenu.PIN,
                                  SubMenu.TAG,
                                  SubMenu.ALERT_ADD_FAIL,
                                  SubMenu.DISABLE,
                                  SubMenu.MOVE_BOTTOM,
                              ]
                            : [
                                  SubMenu.MOVE_TOP,
                                  SubMenu.PIN,
                                  SubMenu.TAG,
                                  SubMenu.DISABLE,
                                  SubMenu.MOVE_BOTTOM,
                              ],
                })
            }
            for (const [channelName, channelInfo] of device.info.channels.entries()) {
                if (channelInfo.lighting_modes.length === 0) {
                    continue
                }
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channelName}`,
                    label: deviceSettings.sensorsAndChannels.get(channelName)!.name,
                    name: channelName,
                    icon: mdiLedOn,
                    color: deviceChannelColor(device.uid, channelName),
                    to: {
                        name: 'device-lighting',
                        params: { deviceId: device.uid, channelName: channelName },
                    },
                    deviceUID: device.uid,
                    hasMode: true,
                    menus: [Menu.RENAME],
                    subMenus: [SubMenu.MOVE_TOP, SubMenu.PIN, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
                })
            }
            for (const [channelName, channelInfo] of device.info.channels.entries()) {
                if (channelInfo.lcd_modes.length === 0) {
                    continue
                }
                // @ts-ignore
                deviceItem.children.push({
                    id: `${device.uid}_${channelName}`,
                    label: deviceSettings.sensorsAndChannels.get(channelName)!.name,
                    name: channelName,
                    icon: mdiTelevisionShimmer,
                    color: deviceChannelColor(device.uid, channelName),
                    to: {
                        name: 'device-lcd',
                        params: { deviceId: device.uid, channelName: channelName },
                    },
                    deviceUID: device.uid,
                    hasMode: true,
                    menus: [Menu.RENAME],
                    subMenus: [SubMenu.MOVE_TOP, SubMenu.PIN, SubMenu.DISABLE, SubMenu.MOVE_BOTTOM],
                })
            }
        }
        allDevices.push(deviceItem)
    }
    return allDevices
}

createTreeMenu()
const expandMenusByDefault = (): void => {
    if (settingsStore.expandedMenuIds == null || settingsStore.expandedMenuIds.length == 0) {
        // First run/no settings, so expand all menus
        settingsStore.expandedMenuIds = data.value.map((node: any) => node.id)
        return
    }
    // Check if there are any newly added devices, and if so, add them to the expanded menu ids
    const newDevices: Array<string> = data.value
        .filter(
            (node: any) =>
                settingsStore.menuOrder.findIndex((menuOrder) => menuOrder.id === node.id) < 0,
        )
        .map((node: any) => node.id)
    settingsStore.expandedMenuIds.push(...newDevices)
}
expandMenusByDefault()
createPinnedMenu()

const formatFrequency = (value: string): string =>
    settingsStore.frequencyPrecision === 1
        ? value
        : (Number(value) / settingsStore.frequencyPrecision).toFixed(2)
////////////////////////////////////////////////////////////////////////////////////////////////////
const addDashbaord = (dashboardUID: UID) => {
    const newDashboard = settingsStore.dashboards.find(
        (dashboard) => dashboard.uid === dashboardUID,
    )!
    const dashboardParent = data.value.find((item: any) => item.id === 'dashboards')
    dashboardParent!.children.push({
        id: dashboardUID,
        label: newDashboard.name,
        icon: mdiChartBoxOutline,
        deviceUID: 'Dashboards',
        dashboardUID: dashboardUID,
        name: dashboardUID,
        to: { name: 'dashboards', params: { dashboardUID: dashboardUID } },
        menus: [Menu.DASHBOARD_HOME, Menu.DASHBOARD_RENAME],
        subMenus: [
            SubMenu.MOVE_TOP,
            SubMenu.PIN,
            SubMenu.DASHBOARD_DUPLICATE,
            SubMenu.DASHBOARD_DELETE,
            SubMenu.MOVE_BOTTOM,
        ],
    })
}

interface DashboardUIDObj {
    dashboardUID: UID
}

const addDashboardMenu = (dashboardUIDObj: DashboardUIDObj): void =>
    addDashbaord(dashboardUIDObj.dashboardUID)
emitter.on('dashboard-add-menu', addDashboardMenu)

const deleteDashboard = async (dashboardUID: UID): Promise<void> => {
    if (route.params != null && route.params.dashboardUID === dashboardUID) {
        await router.push({ name: 'startup-page' })
    }
    const dashboardParent = data.value.find((item: any) => item.id === 'dashboards')
    dashboardParent!.children = dashboardParent!.children.filter(
        (item: any) => item.id !== dashboardUID,
    )
    unPinItem({ id: dashboardUID })
}
const homeDashboardSet = async (): Promise<void> => {
    const dashboardParent = data.value.find((item: any) => item.id === 'dashboards')
    dashboardParent!.children.forEach((item: any) => {
        item.icon =
            item.dashboardUID === settingsStore.homeDashboard
                ? mdiHomeAnalytics
                : mdiChartBoxOutline
    })
    await router.push({ name: 'startup-page' })
}
const updateDashboardName = (dashboardUID: UID, name: string): void => {
    const dashboardParent = data.value.find((item: any) => item.id === 'dashboards')
    const dashboardItem = dashboardParent!.children.find(
        (item: any) => item.dashboardUID === dashboardUID,
    )
    if (dashboardItem) {
        dashboardItem.label = name
    }
}
emitter.on('dashboard-name-update', ({ dashboardUID, name }: { dashboardUID: UID; name: string }) =>
    updateDashboardName(dashboardUID, name),
)

////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Updates the mode tree nodes to reflect the current active modes.
 *
 * This is called whenever the active modes change, and also on any settings change.
 * Note that this also performs a router push to the system overview page under certain conditions.
 *
 * @param {string} _ - the UID of the mode that was just activated/deactivated
 */
const activeModesChange = async (_: UID): Promise<void> => {
    const modesParent = data.value.find((item: any) => item.id === 'modes')
    modesParent?.children.forEach((item: any) => {
        const isActive: boolean = settingsStore.modeActiveCurrent === item.uid
        const isRecentlyActive: boolean = settingsStore.modeActivePrevious === item.uid
        item.icon = isActive
            ? mdiBookmarkCheckOutline
            : isRecentlyActive
              ? mdiBookmarkOffOutline
              : mdiBookmarkOutline
        item.isActive = isActive
        item.isRecentlyActive = isRecentlyActive
    })
    if (route.params != null && route.params.modeUID != null) {
        // if on any Modes View page, redirect so that the view doesn't contain outdated info,
        // otherwise we don't need to redirect.
        await router.push({ name: 'startup-page' })
    }
}
emitter.on('active-modes-change-menu', activeModesChange)
const addMode = (modeUID: UID): void => {
    const newMode = settingsStore.modes.find((mode) => mode.uid === modeUID)!
    const isActive: boolean = settingsStore.modeActiveCurrent === newMode.uid
    const isRecentlyActive: boolean = settingsStore.modeActivePrevious === newMode.uid
    const modesParent = data.value.find((item: any) => item.id === 'modes')
    modesParent!.children.push({
        id: newMode.uid,
        label: newMode.name,
        icon: isActive
            ? mdiBookmarkCheckOutline
            : isRecentlyActive
              ? mdiBookmarkOffOutline
              : mdiBookmarkOutline,
        deviceUID: 'Modes',
        uid: newMode.uid,
        isActive: isActive,
        isRecentlyActive: isRecentlyActive,
        to: { name: 'modes', params: { modeUID: newMode.uid } },
        menus: [Menu.MODE_ACTIVATE, Menu.MODE_RENAME],
        subMenus: [
            SubMenu.MOVE_TOP,
            SubMenu.PIN,
            SubMenu.MODE_UPDATE,
            SubMenu.MODE_DUPLICATE,
            SubMenu.MODE_DELETE,
            SubMenu.MOVE_BOTTOM,
        ],
    })
}

interface ModeUIDObj {
    modeUID: UID
}

const addModeMenu = (modeUIDObj: ModeUIDObj): void => addMode(modeUIDObj.modeUID)
emitter.on('mode-add-menu', addModeMenu)

const deleteMode = async (modeUID: UID): Promise<void> => {
    if (route.params != null && route.params.modeUID === modeUID) {
        await router.push({ name: 'startup-page' })
    }
    const modesParent = data.value.find((item: any) => item.id === 'modes')!
    modesParent.children = modesParent.children.filter((item: any) => item.id !== modeUID)
    unPinItem({ id: modeUID })
}
const updateModeName = (modeUID: UID, name: string): void => {
    const modesParent = data.value.find((item: any) => item.id === 'modes')
    const modeItem = modesParent!.children.find((item: any) => item.uid === modeUID)
    if (modeItem) {
        modeItem.label = name
    }
}
emitter.on('mode-name-update', ({ modeUID, name }: { modeUID: UID; name: string }) =>
    updateModeName(modeUID, name),
)

////////////////////////////////////////////////////////////////////////////////////////////////////
const addProfile = (profileUID: UID): void => {
    const newProfile = settingsStore.profiles.find((profile) => profile.uid === profileUID)!
    const profilesParent = data.value.find((item: any) => item.id === 'profiles')
    profilesParent?.children.push({
        id: newProfile.uid,
        label: newProfile.name,
        icon: mdiChartLine,
        deviceUID: 'Profiles',
        uid: newProfile.uid,
        to: { name: 'profiles', params: { profileUID: newProfile.uid } },
        menus: [Menu.PROFILE_APPLY, Menu.PROFILE_RENAME],
        subMenus: [
            SubMenu.MOVE_TOP,
            SubMenu.PIN,
            SubMenu.PROFILE_DUPLICATE,
            SubMenu.PROFILE_DELETE,
            SubMenu.MOVE_BOTTOM,
        ],
    })
}

interface ProfileUIDObj {
    profileUID: UID
}

const addProfileMenu = (profileUIDObj: ProfileUIDObj): void => addProfile(profileUIDObj.profileUID)
emitter.on('profile-add-menu', addProfileMenu)

const deleteProfile = async (profileUID: UID): Promise<void> => {
    if (route.params != null && route.params.profileUID === profileUID) {
        await router.push({ name: 'startup-page' })
    }
    const profilesParent = data.value.find((item: any) => item.id === 'profiles')!
    profilesParent.children = profilesParent.children.filter((item: any) => item.id !== profileUID)
    unPinItem({ id: profileUID })
}
const updateProfileName = (profileUID: UID, name: string): void => {
    const profilesParent = data.value.find((item: any) => item.id === 'profiles')
    const profileItem = profilesParent!.children.find((item: any) => item.uid === profileUID)
    if (profileItem) {
        profileItem.label = name
    }
}
emitter.on('profile-name-update', ({ profileUID, name }: { profileUID: UID; name: string }) =>
    updateProfileName(profileUID, name),
)

////////////////////////////////////////////////////////////////////////////////////////////////////
const addFunction = (functionUID: UID): void => {
    const newFunction = settingsStore.functions.find((fun) => fun.uid === functionUID)!
    const functionsParent = data.value.find((item: any) => item.id === 'functions')
    functionsParent?.children.push({
        id: newFunction.uid,
        label: newFunction.name,
        icon: mdiFunction,
        deviceUID: 'Functions',
        uid: newFunction.uid,
        to: { name: 'functions', params: { functionUID: newFunction.uid } },
        menus: [Menu.FUNCTION_APPLY, Menu.FUNCTION_RENAME],
        subMenus: [
            SubMenu.MOVE_TOP,
            SubMenu.PIN,
            SubMenu.FUNCTION_DUPLICATE,
            SubMenu.FUNCTION_DELETE,
            SubMenu.MOVE_BOTTOM,
        ],
    })
}

interface FunctionUIDObj {
    functionUID: UID
}

const addFunctionMenu = (functionUIDObj: FunctionUIDObj): void =>
    addFunction(functionUIDObj.functionUID)
emitter.on('function-add-menu', addFunctionMenu)

const deleteFunction = async (functionUID: UID): Promise<void> => {
    if (route.params != null && route.params.functionUID === functionUID) {
        await router.push({ name: 'startup-page' })
    }
    const functionsParent = data.value.find((item: any) => item.id === 'functions')!
    functionsParent.children = functionsParent.children.filter(
        (item: any) => item.id !== functionUID,
    )
    unPinItem({ id: functionUID })
}
const updateFunctionName = (functionUID: UID, name: string): void => {
    const functionsParent = data.value.find((item: any) => item.id === 'functions')
    const functionItem = functionsParent!.children.find((item: any) => item.uid === functionUID)
    if (functionItem) {
        functionItem.label = name
    }
}
emitter.on('function-name-update', ({ functionUID, name }: { functionUID: UID; name: string }) =>
    updateFunctionName(functionUID, name),
)

////////////////////////////////////////////////////////////////////////////////////////////////////
const addAlert = (alertUID: UID): void => {
    const newAlert = settingsStore.alerts.find((alert) => alert.uid === alertUID)
    if (newAlert == null) {
        console.error('Alert with UID: ' + alertUID + ' not found')
        return
    }
    const isActive = newAlert.state === AlertState.Active
    const alertsParent = data.value.find((item: any) => item.id === 'alerts')
    alertsParent?.children.push({
        id: newAlert.uid,
        label: newAlert.name,
        icon: isActive ? mdiBellRingOutline : mdiBellOutline,
        deviceUID: 'Alerts',
        uid: newAlert.uid,
        alertIsActive: isActive,
        to: { name: 'alerts', params: { alertUID: newAlert.uid } },
        menus: [Menu.ALERT_RENAME],
        subMenus: [
            SubMenu.MOVE_TOP,
            SubMenu.PIN,
            SubMenu.ALERT_DUPLICATE,
            SubMenu.ALERT_DELETE,
            SubMenu.MOVE_BOTTOM,
        ],
    })
}
interface AlertUIDObj {
    alertUID: UID
}
const addAlertMenu = (alertUIDObj: AlertUIDObj) => addAlert(alertUIDObj.alertUID)
emitter.on('alert-add-menu', addAlertMenu)

const deleteAlert = async (alertUID: UID): Promise<void> => {
    if (route.params != null && route.params.alertUID === alertUID) {
        await router.push({ name: 'startup-page' })
    }
    const alertsParent = data.value.find((item: any) => item.id === 'alerts')!
    alertsParent.children = alertsParent.children.filter((item: any) => item.id !== alertUID)
    unPinItem({ id: alertUID })
}

const alertStateChange = (): void => {
    const alertsParent = data.value.find((item: any) => item.id === 'alerts')!
    alertsParent.children.forEach((item: any) => {
        const isActive = settingsStore.alertsActive.includes(item.uid)
        item.alertIsActive = isActive
        item.icon = isActive ? mdiBellRingOutline : mdiBellOutline
    })
}
emitter.on('alert-state-change', alertStateChange)
const updateAlertName = (alertUID: UID, name: string): void => {
    const alertsParent = data.value.find((item: any) => item.id === 'alerts')
    const alertItem = alertsParent!.children.find((item: any) => item.uid === alertUID)
    if (alertItem) {
        alertItem.label = name
    }
}
emitter.on('alert-name-update', ({ alertUID, name }: { alertUID: UID; name: string }) =>
    updateAlertName(alertUID, name),
)

watch(settingsStore.alertsActive, alertStateChange)

////////////////////////////////////////////////////////////////////////////////////////////////////

const updateDeviceSensorName = (deviceUID: UID, sensorId: string, name: string): void => {
    const deviceParent = data.value.find((item: any) => item.deviceUID === deviceUID)
    const sensorItem = deviceParent!.children.find((item: any) => item.name === sensorId)
    if (sensorItem) {
        sensorItem.label = name
    }
}
emitter.on(
    'device-sensor-name-update',
    ({ deviceUID, sensorId, name }: { deviceUID: UID; sensorId: string; name: string }) =>
        updateDeviceSensorName(deviceUID, sensorId, name),
)

////////////////////////////////////////////////////////////////////////////////////////////////////

// add group class to all collapse header items (used to show options menus on hover)
const addGroup = (): void => {
    setTimeout(() => {
        const elements = document.querySelectorAll('.el-collapse-item__header')
        for (const element of elements) {
            element.classList.add('group')
        }
    })
}
const moveToTop = (item: any, data: any): void => {
    item.subMenuRef.hide()
    data.splice(data.indexOf(item), 1)
    data.unshift(item)
    saveMenuOrderChanges()
}

const moveToBottom = (item: any, data: any): void => {
    item.subMenuRef.hide()
    data.splice(data.indexOf(item), 1)
    data.push(item)
    saveMenuOrderChanges()
}

onMounted(async () => {
    // Listen for language change events, refresh menu
    window.addEventListener('language-changed', () => {
        createTreeMenu()
        createPinnedMenu()
    })

    // Listen for theme change events to update colors
    window.addEventListener('theme-changed', onThemeChanged)

    addGroup()
})

// Remove event listeners when component is unmounted
onUnmounted(() => {
    window.removeEventListener('language-changed', () => {
        createTreeMenu()
        createPinnedMenu()
    })
    window.removeEventListener('theme-changed', onThemeChanged)
})
</script>

<template>
    <div id="system-menu" class="flex text-text-color mx-0 pb-1 tree-text">
        <span class="ml-1 text-2xl mb-2 items-center tree-text">
            {{ daemonState.systemName }}
        </span>
    </div>
    <!--Pined Items-->
    <el-collapse
        v-if="pinnedItems.length > 0"
        expand-icon-position="left"
        :model-value="'pinned'"
        @change="(_activeNames) => addGroup()"
        :before-collapse="() => hoverMenusAreClosed"
    >
        <el-collapse-item name="pinned" :key="'pinned'">
            <template #title>
                <div class="flex group h-full w-full items-center justify-between outline-none">
                    <div class="flex flex-row items-center min-w-0">
                        <svg-icon
                            class="mr-1.5 min-w-7 w-7"
                            type="mdi"
                            :path="mdiPinOutline"
                            :style="{
                                color: deviceChannelColor(undefined, '').value,
                            }"
                            :size="
                                deviceStore.getREMSize(deviceChannelIconSize(undefined, undefined))
                            "
                        />
                        <div class="flex flex-col overflow-hidden">
                            <div class="tree-text leading-tight">
                                {{ t('layout.menu.pinned') }}
                            </div>
                            <div></div>
                        </div>
                    </div>
                </div>
            </template>
            <VueDraggable
                v-model="pinnedItems"
                :scroll="true"
                :force-auto-scroll-fallback="true"
                :fallback-on-body="true"
                :animation="300"
                :direction="'vertical'"
                :scroll-sensitivity="deviceStore.getREMSize(5)"
                :scroll-speed="deviceStore.getREMSize(1.25)"
                :bubble-scroll="true"
                :revert-on-spill="true"
                :force-fallback="true"
                :fallback-tolerance="15"
                :clone="toRaw"
                @start="setHoverMenuStatus(true)"
                @end="
                    () => {
                        setHoverMenuStatus(false)
                        changedPinnedItems()
                    }
                "
            >
                <div v-for="childItem in pinnedItems" :key="childItem.id">
                    <!--Pinned Elements Start-->
                    <!--This is a complete copy from the childItems standard menu below-->
                    <!--With the exception that Pinned Items shoudl not have a Move to Top/Bottom button-->
                    <!-- AND that the subMenuRef needs to be named different for pinned item submenus-->
                    <router-link
                        class="flex h-10 group items-center justify-between outline-none rounded-lg"
                        :class="{
                            'h-12': childItem.isControllable || childItem.hasMode,
                            'hover:bg-bg-two': hoverMenusAreClosed,
                            'pointer-events-none': !hoverMenusAreClosed,
                            'text-accent':
                                route.fullPath === '/' &&
                                childItem.dashboardUID != null &&
                                childItem.dashboardUID === settingsStore.homeDashboard,
                        }"
                        tabindex="0"
                        exact
                        :exact-active-class="childItem.to != null ? 'text-accent font-medium' : ''"
                        :to="!childItem.to ? '' : childItem.to"
                        v-slot="{ isActive }"
                    >
                        <!-- Child Item Icons and Labels -->
                        <div class="flex flex-row items-center min-w-0">
                            <div class="w-2 min-w-2 whitespace-pre" />
                            <div
                                class="w-3 min-w-3 h-10 border-l border-border-one/80 whitespace-pre"
                                :class="{ 'h-12': childItem.isControllable || childItem.hasMode }"
                            />
                            <svg-icon
                                v-if="childItem.icon"
                                class="mr-1.5 min-w-6"
                                :class="{
                                    'text-accent': childItem.isActive,
                                    'text-error': childItem.alertIsActive,
                                    'animate-spin-slow':
                                        settingsStore.eyeCandy &&
                                        childItem.icon === mdiFan &&
                                        (childItem.rpm != null
                                            ? Number(
                                                  deviceChannelValues(
                                                      childItem.deviceUID,
                                                      childItem.name,
                                                  )?.rpm ?? 0,
                                              ) > 0
                                            : Number(
                                                  deviceChannelValues(
                                                      childItem.deviceUID,
                                                      childItem.name,
                                                  )?.duty ?? 0,
                                              ) > 0),
                                }"
                                type="mdi"
                                :path="childItem.icon ?? ''"
                                :style="{
                                    color: deviceChannelColor(childItem.deviceUID, childItem.name)
                                        .value,
                                }"
                                :size="
                                    deviceStore.getREMSize(
                                        deviceChannelIconSize(childItem.deviceUID, childItem.name),
                                    )
                                "
                            />
                            <div class="flex flex-col overflow-hidden">
                                <div
                                    class="tree-text leading-tight"
                                    :class="{ 'mr-2': childItem.deviceUID && !childItem.name }"
                                >
                                    {{ childItem.label }}
                                </div>
                                <div
                                    v-if="
                                        childItem.isSpeedChannel ||
                                        childItem.hasMode ||
                                        settingsStore.getChannelTags(
                                            childItem.deviceUID,
                                            childItem.name,
                                        ).length > 0
                                    "
                                    class="mt-0.5 flex items-center gap-x-1"
                                >
                                    <menu-control-view
                                        v-if="childItem.isSpeedChannel"
                                        :device-u-i-d="childItem.deviceUID"
                                        :channel-name="childItem.name"
                                        :is-controllable="childItem.isControllable"
                                        :is-active="isActive"
                                        :class="{ 'text-text-color-secondary': !isActive }"
                                    />
                                    <menu-mode-view
                                        v-if="childItem.hasMode"
                                        :device-u-i-d="childItem.deviceUID"
                                        :channel-name="childItem.name"
                                        :class="{ 'text-text-color-secondary': !isActive }"
                                    />
                                    <span
                                        v-for="tag in settingsStore.getChannelTags(
                                            childItem.deviceUID,
                                            childItem.name,
                                        )"
                                        :key="tag"
                                        class="text-xs px-1 rounded leading-none py-0.5 border max-h-4 text-nowrap"
                                        :style="{
                                            color: settingsStore.tags.get(tag)?.color ?? '',
                                            borderColor: settingsStore.tags.get(tag)?.color ?? '',
                                        }"
                                    >
                                        {{ tag }}
                                    </span>
                                </div>
                            </div>
                        </div>
                        <!-- Sensor Metrics -->
                        <div
                            class="flex ml-2 mr-1 justify-end select-none"
                            :class="{ 'group-hover:hidden': hoverMenusAreClosed }"
                        >
                            <div v-if="childItem.temp != null" class="items-end tree-data">
                                {{ deviceChannelValues(childItem.deviceUID, childItem.name)!.temp }}
                                <span style="font-size: 0.8rem" class="align-text-top"
                                    >°C&nbsp;</span
                                >
                            </div>
                            <div v-else-if="childItem.freq != null" class="items-end tree-data">
                                {{
                                    formatFrequency(
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .freq!,
                                    )
                                }}
                                <span style="font-size: 0.55rem">
                                    {{ settingsStore.frequencyPrecision === 1 ? 'MHz' : 'GHz' }}
                                </span>
                            </div>
                            <div v-else-if="childItem.watts != null" class="items-end tree-data">
                                {{
                                    deviceChannelValues(childItem.deviceUID, childItem.name)!.watts
                                }}
                                <span style="font-size: 0.62rem">W&nbsp;&nbsp;&nbsp;</span>
                            </div>
                            <div
                                v-else-if="childItem.duty != null && childItem.rpm == null"
                                class="content-end tree-data"
                            >
                                {{ deviceChannelValues(childItem.deviceUID, childItem.name)!.duty }}
                                <span style="font-size: 0.65rem">%&nbsp;&nbsp;&nbsp;</span>
                            </div>
                            <div
                                v-else-if="childItem.rpm != null && childItem.duty == null"
                                class="items-end tree-data"
                            >
                                {{ deviceChannelValues(childItem.deviceUID, childItem.name)!.rpm }}
                                <span style="font-size: 0.65rem">rpm</span>
                            </div>
                            <div
                                v-else-if="childItem.duty != null && childItem.rpm != null"
                                class="items-end flex flex-col leading-none tree-data"
                            >
                                <span :class="{ 'mb-0.5': childItem.isControllable }">
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .duty
                                    }}
                                    <span style="font-size: 0.65rem">%&nbsp;&nbsp;&nbsp;</span>
                                </span>
                                <span :class="{ 'mt-0.5': childItem.isControllable }">
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .rpm
                                    }}
                                    <span style="font-size: 0.65rem">rpm</span>
                                </span>
                            </div>
                        </div>
                        <!-- Hover Menu -->
                        <div
                            class="hidden mr-1 justify-end whitespace-normal"
                            :class="{ 'group-hover:flex': hoverMenusAreClosed }"
                        >
                            <div v-for="menu in childItem.menus">
                                <menu-color-picker
                                    v-if="menu === Menu.COLOR"
                                    :device-u-i-d="childItem.deviceUID"
                                    :channel-name="childItem.name"
                                    :color="
                                        deviceChannelColor(childItem.deviceUID, childItem.name)
                                            .value
                                    "
                                    @open="setHoverMenuStatus"
                                />
                                <menu-rename
                                    v-else-if="menu === Menu.RENAME"
                                    :device-u-i-d="childItem.deviceUID"
                                    :channel-name="childItem.name"
                                    @click.stop
                                    @name-change="(value: string) => (childItem.label = value)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-dashboard-home
                                    v-else-if="menu === Menu.DASHBOARD_HOME"
                                    :dashboard-u-i-d="childItem.dashboardUID"
                                    @home-set="homeDashboardSet"
                                />
                                <menu-dashboard-rename
                                    v-else-if="menu === Menu.DASHBOARD_RENAME"
                                    :dashboard-u-i-d="childItem.dashboardUID"
                                    @name-change="(name: string) => (childItem.label = name)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-mode-activate
                                    v-else-if="menu === Menu.MODE_ACTIVATE"
                                    :mode-u-i-d="childItem.uid"
                                />
                                <menu-mode-rename
                                    v-else-if="menu === Menu.MODE_RENAME"
                                    :mode-u-i-d="childItem.uid"
                                    @name-change="(name: string) => (childItem.label = name)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-profile-apply
                                    v-else-if="menu === Menu.PROFILE_APPLY"
                                    :profile-u-i-d="childItem.uid"
                                />
                                <menu-profile-rename
                                    v-else-if="menu === Menu.PROFILE_RENAME"
                                    :profile-u-i-d="childItem.uid"
                                    @name-change="(name: string) => (childItem.label = name)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-function-apply
                                    v-else-if="menu === Menu.FUNCTION_APPLY"
                                    :function-u-i-d="childItem.uid"
                                />
                                <menu-function-rename
                                    v-else-if="menu === Menu.FUNCTION_RENAME"
                                    :function-u-i-d="childItem.uid"
                                    @name-change="(name: string) => (childItem.label = name)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-alert-rename
                                    v-else-if="menu === Menu.ALERT_RENAME"
                                    :alert-u-i-d="childItem.uid"
                                    @name-change="(name: string) => (childItem.label = name)"
                                    @open="setHoverMenuStatus"
                                />
                            </div>
                            <!-- More Options Menu -->
                            <div
                                v-if="childItem.subMenus"
                                v-tooltip.top="{ value: t('layout.menu.tooltips.options') }"
                            >
                                <div
                                    class="rounded-lg w-8 h-8 border-none p-0 text-text-color-secondary outline-0 text-center justify-center items-center flex hover:text-text-color hover:bg-surface-hover"
                                    @click.stop.prevent="
                                        (event) => childItem.subMenuRefPin.toggle(event)
                                    "
                                >
                                    <svg-icon
                                        class="outline-0"
                                        type="mdi"
                                        :path="mdiDotsVertical"
                                        :size="deviceStore.getREMSize(1.5)"
                                    />
                                </div>
                                <Popover
                                    :ref="(el) => (childItem.subMenuRefPin = el)"
                                    @show="() => setHoverMenuStatus(true)"
                                    @hide="() => setHoverMenuStatus(false)"
                                >
                                    <div
                                        class="mt-2.5 bg-bg-two border border-border-one p-1 rounded-lg text-text-color"
                                    >
                                        <ul>
                                            <li v-for="subMenu in childItem.subMenus">
                                                <!--NOT for pinned Items-->
                                                <!--<sub-menu-move-top
                                                    v-if="subMenu === SubMenu.MOVE_TOP"
                                                    @moveTop="moveToTop(childItem, pinnedItems)"
                                                /> -->
                                                <sub-menu-pin
                                                    v-if="subMenu === SubMenu.PIN"
                                                    :is-pinned="isPinned(childItem)"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                    @pin="pinItem(childItem)"
                                                    @unpin="
                                                        () => {
                                                            setHoverMenuStatus(false)
                                                            unPinItem(childItem)
                                                        }
                                                    "
                                                />
                                                <sub-menu-custom-sensor-delete
                                                    v-else-if="
                                                        subMenu === SubMenu.CUSTOM_SENSOR_DELETE
                                                    "
                                                    :device-u-i-d="childItem.deviceUID"
                                                    :custom-sensor-i-d="childItem.name"
                                                />
                                                <sub-menu-disable
                                                    v-else-if="subMenu === SubMenu.DISABLE"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-dashboard-duplicate
                                                    v-else-if="
                                                        subMenu === SubMenu.DASHBOARD_DUPLICATE
                                                    "
                                                    :dashboard-u-i-d="childItem.dashboardUID"
                                                    @added="addDashbaord"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-dashboard-delete
                                                    v-else-if="subMenu === SubMenu.DASHBOARD_DELETE"
                                                    :dashboard-u-i-d="childItem.dashboardUID"
                                                    @deleted="
                                                        (dashboardUID: UID) => {
                                                            deleteDashboard(dashboardUID)
                                                            setHoverMenuStatus(false)
                                                        }
                                                    "
                                                />
                                                <sub-menu-mode-update
                                                    v-else-if="subMenu === SubMenu.MODE_UPDATE"
                                                    :mode-u-i-d="childItem.uid"
                                                    @updated="activeModesChange"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-mode-duplicate
                                                    v-else-if="subMenu === SubMenu.MODE_DUPLICATE"
                                                    :mode-u-i-d="childItem.uid"
                                                    @added="addMode"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-mode-delete
                                                    v-else-if="subMenu === SubMenu.MODE_DELETE"
                                                    :mode-u-i-d="childItem.uid"
                                                    @deleted="deleteMode"
                                                    @close="
                                                        () => {
                                                            setHoverMenuStatus(false)
                                                            childItem.subMenuRefPin.hide()
                                                        }
                                                    "
                                                />
                                                <sub-menu-profile-duplicate
                                                    v-else-if="
                                                        subMenu === SubMenu.PROFILE_DUPLICATE
                                                    "
                                                    :profile-u-i-d="childItem.uid"
                                                    @added="addProfile"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-profile-delete
                                                    v-else-if="subMenu === SubMenu.PROFILE_DELETE"
                                                    :profile-u-i-d="childItem.uid"
                                                    @deleted="deleteProfile"
                                                    @close="
                                                        () => {
                                                            setHoverMenuStatus(false)
                                                            childItem.subMenuRefPin.hide()
                                                        }
                                                    "
                                                />
                                                <sub-menu-function-duplicate
                                                    v-else-if="
                                                        subMenu === SubMenu.FUNCTION_DUPLICATE
                                                    "
                                                    :function-u-i-d="childItem.uid"
                                                    @added="addFunction"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-function-delete
                                                    v-else-if="subMenu === SubMenu.FUNCTION_DELETE"
                                                    :function-u-i-d="childItem.uid"
                                                    @deleted="deleteFunction"
                                                    @close="
                                                        () => {
                                                            setHoverMenuStatus(false)
                                                            childItem.subMenuRefPin.hide()
                                                        }
                                                    "
                                                />
                                                <sub-menu-alert-duplicate
                                                    v-else-if="subMenu === SubMenu.ALERT_DUPLICATE"
                                                    :alert-u-i-d="childItem.uid"
                                                    @added="addAlert"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-alert-delete
                                                    v-else-if="subMenu === SubMenu.ALERT_DELETE"
                                                    :alert-u-i-d="childItem.uid"
                                                    @deleted="deleteAlert"
                                                    @close="
                                                        () => {
                                                            setHoverMenuStatus(false)
                                                            childItem.subMenuRefPin.hide()
                                                        }
                                                    "
                                                />
                                                <!--NOT for pinned Items-->
                                                <!--<sub-menu-move-bottom
                                                    v-else-if="subMenu === SubMenu.MOVE_BOTTOM"
                                                    @moveBottom="
                                                        moveToBottom(childItem, pinnedItems)
                                                    "
                                                />-->
                                                <sub-menu-alert-add-fail
                                                    v-else-if="subMenu === SubMenu.ALERT_ADD_FAIL"
                                                    :device-u-i-d="childItem.deviceUID"
                                                    :channel-name="childItem.name"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-alert-add-temp
                                                    v-else-if="subMenu === SubMenu.ALERT_ADD_TEMP"
                                                    :device-u-i-d="childItem.deviceUID"
                                                    :channel-name="childItem.name"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                                <sub-menu-tag-assign
                                                    v-else-if="subMenu === SubMenu.TAG"
                                                    :device-u-i-d="childItem.deviceUID"
                                                    :channel-name="childItem.name"
                                                    @open="setHoverMenuStatus"
                                                    @close="childItem.subMenuRefPin.hide()"
                                                />
                                            </li>
                                        </ul>
                                    </div>
                                </Popover>
                            </div>
                        </div>
                    </router-link>
                    <!--Pinned Elements End-->
                </div>
            </VueDraggable>
        </el-collapse-item>
    </el-collapse>
    <!--Main Menu-->
    <VueDraggable
        v-model="data"
        target=".cc-root-items"
        :scroll="true"
        :force-auto-scroll-fallback="true"
        :fallback-on-body="true"
        :animation="300"
        :direction="'vertical'"
        :scroll-sensitivity="deviceStore.getREMSize(5)"
        :scroll-speed="deviceStore.getREMSize(1.25)"
        :bubble-scroll="true"
        :revert-on-spill="true"
        :force-fallback="true"
        :fallback-tolerance="15"
        :clone="toRaw"
        @start="setHoverMenuStatus(true)"
        @end="
            () => {
                setHoverMenuStatus(false)
                saveMenuOrderChanges()
            }
        "
    >
        <el-collapse
            class="cc-root-items"
            expand-icon-position="left"
            v-model="settingsStore.expandedMenuIds"
            @change="addGroup"
            :before-collapse="() => hoverMenusAreClosed"
        >
            <el-collapse-item v-for="item in data" :name="item.id" :key="item.id">
                <template #title>
                    <!--Root Elements-->
                    <div
                        :id="item.id"
                        :data-tour-anchor="item.tourAnchor"
                        class="flex group h-full w-full items-center justify-between outline-none"
                    >
                        <div class="flex flex-row items-center min-w-0">
                            <svg-icon
                                v-if="item.icon"
                                class="mr-1.5 min-w-7 w-7"
                                type="mdi"
                                :path="item.icon"
                                :style="{ color: getIconColor(item) }"
                                :size="
                                    deviceStore.getREMSize(
                                        deviceChannelIconSize(item.deviceUID, item.name),
                                    )
                                "
                            />
                            <div class="flex flex-col overflow-hidden">
                                <div
                                    class="tree-text leading-tight"
                                    :style="{ color: getLabelColor(item) }"
                                >
                                    {{ item.label }}
                                </div>
                                <div></div>
                            </div>
                        </div>
                        <div
                            class="hidden mr-1 justify-end whitespace-normal"
                            :class="{ 'group-hover:flex': hoverMenusAreClosed }"
                        >
                            <div v-for="menu in item.menus">
                                <menu-device-info
                                    v-if="menu === Menu.DEVICE_INFO"
                                    :device-u-i-d="item.deviceUID"
                                    @click.stop
                                    @open="setHoverMenuStatus"
                                />
                                <menu-rename
                                    v-else-if="menu === Menu.RENAME"
                                    :device-u-i-d="item.deviceUID"
                                    :channel-name="item.name"
                                    @click.stop
                                    @name-change="(value: string) => (item.label = value)"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-custom-sensor-info
                                    v-else-if="menu === Menu.CUSTOM_SENSOR_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-custom-sensor-add
                                    v-else-if="menu === Menu.CUSTOM_SENSOR_ADD"
                                />
                                <menu-dashboard-info
                                    v-else-if="menu === Menu.DASHBOARD_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-dashboard-add
                                    v-else-if="menu === Menu.DASHBOARD_ADD"
                                    @added="addDashbaord"
                                />
                                <menu-mode-info
                                    v-else-if="menu === Menu.MODE_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-mode-add
                                    v-else-if="menu === Menu.MODE_ADD"
                                    @added="addMode"
                                />
                                <menu-profile-info
                                    v-else-if="menu === Menu.PROFILE_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-profile-add
                                    v-else-if="menu === Menu.PROFILE_ADD"
                                    @added="addProfile"
                                />
                                <menu-function-info
                                    v-else-if="menu === Menu.FUNCTION_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-function-add
                                    v-else-if="menu === Menu.FUNCTION_ADD"
                                    @added="addFunction"
                                />
                                <menu-alert-info
                                    v-else-if="menu === Menu.ALERT_INFO"
                                    @open="setHoverMenuStatus"
                                />
                                <menu-alert-add v-else-if="menu === Menu.ALERT_ADD" />
                            </div>
                            <div
                                v-if="item.subMenus"
                                v-tooltip.top="{ value: t('layout.menu.tooltips.options') }"
                            >
                                <div
                                    class="rounded-lg w-8 h-8 border-none p-0 text-text-color-secondary outline-0 text-center justify-center items-center flex hover:text-text-color hover:bg-surface-hover"
                                    @click.stop.prevent="(event) => item.subMenuRef.toggle(event)"
                                >
                                    <svg-icon
                                        class="outline-0"
                                        type="mdi"
                                        :path="mdiDotsVertical"
                                        :size="deviceStore.getREMSize(1.5)"
                                    />
                                </div>
                                <Popover
                                    :ref="(el) => (item.subMenuRef = el)"
                                    @show="() => setHoverMenuStatus(true)"
                                    @hide="() => setHoverMenuStatus(false)"
                                >
                                    <div
                                        class="mt-2.5 bg-bg-two border border-border-one p-1 rounded-lg text-text-color"
                                    >
                                        <ul>
                                            <li v-for="subMenu in item.subMenus">
                                                <sub-menu-move-top
                                                    v-if="subMenu === SubMenu.MOVE_TOP"
                                                    @moveTop="moveToTop(item, data)"
                                                />
                                                <sub-menu-device-color-picker
                                                    v-else-if="
                                                        subMenu === SubMenu.COLOR &&
                                                        item.deviceUID != null
                                                    "
                                                    :device-u-i-d="item.deviceUID"
                                                    :color="deviceColor(item.deviceUID).value"
                                                    @open="setHoverMenuStatus"
                                                    @close="item.subMenuRef.hide()"
                                                />
                                                <sub-menu-device-extension-settings
                                                    v-else-if="
                                                        subMenu === SubMenu.DEVICE_EXTENSIONS &&
                                                        item.deviceUID != null
                                                    "
                                                    :device-u-i-d="item.deviceUID"
                                                    @open="setHoverMenuStatus"
                                                    @close="item.subMenuRef.hide()"
                                                />
                                                <sub-menu-entity-color-picker
                                                    v-else-if="
                                                        subMenu === SubMenu.COLOR &&
                                                        item.deviceUID == null
                                                    "
                                                    :entity-i-d="item.id"
                                                    :color="entityColor(item.id).value"
                                                    @open="setHoverMenuStatus"
                                                    @close="item.subMenuRef.hide()"
                                                />
                                                <sub-menu-disable
                                                    v-else-if="subMenu === SubMenu.DISABLE"
                                                    @close="item.subMenuRef.hide()"
                                                />
                                                <sub-menu-move-bottom
                                                    v-else-if="subMenu === SubMenu.MOVE_BOTTOM"
                                                    @moveBottom="moveToBottom(item, data)"
                                                />
                                            </li>
                                        </ul>
                                    </div>
                                </Popover>
                            </div>
                        </div>
                    </div>
                </template>
                <template v-if="item.children == null || item.children.length === 0" #icon>
                    <div class="w-4" />
                </template>
                <VueDraggable
                    v-model="item.children"
                    :scroll="true"
                    :force-auto-scroll-fallback="true"
                    :fallback-on-body="true"
                    :animation="300"
                    :direction="'vertical'"
                    :scroll-sensitivity="deviceStore.getREMSize(5)"
                    :scroll-speed="deviceStore.getREMSize(1.25)"
                    :bubble-scroll="true"
                    :revert-on-spill="true"
                    :force-fallback="true"
                    :fallback-tolerance="15"
                    :clone="toRaw"
                    @start="setHoverMenuStatus(true)"
                    @end="
                        () => {
                            setHoverMenuStatus(false)
                            saveMenuOrderChanges()
                        }
                    "
                >
                    <div v-for="childItem in item.children" :key="childItem.id">
                        <!--Child Elements-->
                        <router-link
                            class="flex h-10 group items-center justify-between outline-none rounded-lg"
                            :class="{
                                'h-12': childItem.isControllable || childItem.hasMode,
                                'hover:bg-bg-two': hoverMenusAreClosed,
                                'pointer-events-none': !hoverMenusAreClosed,
                                'text-accent':
                                    route.fullPath === '/' &&
                                    childItem.dashboardUID != null &&
                                    childItem.dashboardUID === settingsStore.homeDashboard,
                            }"
                            tabindex="0"
                            exact
                            :exact-active-class="
                                childItem.to != null ? 'text-accent font-medium' : ''
                            "
                            :to="!childItem.to ? '' : childItem.to"
                            v-slot="{ isActive }"
                        >
                            <!-- Child Item Icons and Labels -->
                            <div class="flex flex-row items-center min-w-0">
                                <div class="w-2 min-w-2 whitespace-pre" />
                                <div
                                    class="w-3 min-w-3 h-10 border-l border-border-one/80 whitespace-pre"
                                    :class="{
                                        'h-12': childItem.isControllable || childItem.hasMode,
                                    }"
                                    :style="{ 'border-color': getSideBorderColor(item) }"
                                />
                                <svg-icon
                                    v-if="childItem.icon"
                                    class="mr-1.5 min-w-6"
                                    :class="{
                                        'text-accent': childItem.isActive,
                                        'text-error': childItem.alertIsActive,
                                        'animate-spin-slow':
                                            settingsStore.eyeCandy &&
                                            childItem.icon === mdiFan &&
                                            (childItem.rpm != null
                                                ? Number(
                                                      deviceChannelValues(
                                                          childItem.deviceUID,
                                                          childItem.name,
                                                      )?.rpm ?? 0,
                                                  ) > 0
                                                : Number(
                                                      deviceChannelValues(
                                                          childItem.deviceUID,
                                                          childItem.name,
                                                      )?.duty ?? 0,
                                                  ) > 0),
                                    }"
                                    type="mdi"
                                    :path="childItem.icon ?? ''"
                                    :style="{
                                        color: deviceChannelColor(
                                            childItem.deviceUID,
                                            childItem.name,
                                        ).value,
                                    }"
                                    :size="
                                        deviceStore.getREMSize(
                                            deviceChannelIconSize(
                                                childItem.deviceUID,
                                                childItem.name,
                                            ),
                                        )
                                    "
                                />
                                <div class="flex flex-col overflow-hidden">
                                    <div
                                        class="tree-text leading-tight"
                                        :class="{ 'mr-2': childItem.deviceUID && !childItem.name }"
                                    >
                                        {{ childItem.label }}
                                    </div>
                                    <div
                                        v-if="
                                            childItem.isSpeedChannel ||
                                            childItem.hasMode ||
                                            settingsStore.getChannelTags(
                                                childItem.deviceUID,
                                                childItem.name,
                                            ).length > 0
                                        "
                                        class="mt-0.5 flex items-center gap-x-1"
                                    >
                                        <menu-control-view
                                            v-if="childItem.isSpeedChannel"
                                            :device-u-i-d="childItem.deviceUID"
                                            :channel-name="childItem.name"
                                            :is-controllable="childItem.isControllable"
                                            :is-active="isActive"
                                            :class="{ 'text-text-color-secondary': !isActive }"
                                        />
                                        <menu-mode-view
                                            v-if="childItem.hasMode"
                                            :device-u-i-d="childItem.deviceUID"
                                            :channel-name="childItem.name"
                                            :class="{ 'text-text-color-secondary': !isActive }"
                                        />
                                        <span
                                            v-for="tag in settingsStore.getChannelTags(
                                                childItem.deviceUID,
                                                childItem.name,
                                            )"
                                            :key="tag"
                                            class="text-xs px-1 rounded leading-none py-0.5 border max-h-4 text-nowrap"
                                            :style="{
                                                color: settingsStore.tags.get(tag)?.color ?? '',
                                                borderColor:
                                                    settingsStore.tags.get(tag)?.color ?? '',
                                            }"
                                        >
                                            {{ tag }}
                                        </span>
                                    </div>
                                </div>
                            </div>
                            <!-- Sensor Metrics -->
                            <div
                                class="flex ml-2 mr-1 justify-end select-none"
                                :class="{ 'group-hover:hidden': hoverMenusAreClosed }"
                            >
                                <div v-if="childItem.temp != null" class="items-end tree-data">
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .temp
                                    }}
                                    <span style="font-size: 0.8rem" class="align-text-top"
                                        >°C&nbsp;</span
                                    >
                                </div>
                                <div v-else-if="childItem.freq != null" class="items-end tree-data">
                                    {{
                                        formatFrequency(
                                            deviceChannelValues(
                                                childItem.deviceUID,
                                                childItem.name,
                                            )!.freq!,
                                        )
                                    }}
                                    <span style="font-size: 0.55rem">
                                        {{ settingsStore.frequencyPrecision === 1 ? 'MHz' : 'GHz' }}
                                    </span>
                                </div>
                                <div
                                    v-else-if="childItem.watts != null"
                                    class="items-end tree-data"
                                >
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .watts
                                    }}
                                    <span style="font-size: 0.62rem">W&nbsp;&nbsp;&nbsp;</span>
                                </div>
                                <div
                                    v-else-if="childItem.duty != null && childItem.rpm == null"
                                    class="content-end tree-data"
                                >
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .duty
                                    }}
                                    <span style="font-size: 0.65rem">%&nbsp;&nbsp;&nbsp;</span>
                                </div>
                                <div
                                    v-else-if="childItem.rpm != null && childItem.duty == null"
                                    class="items-end tree-data"
                                >
                                    {{
                                        deviceChannelValues(childItem.deviceUID, childItem.name)!
                                            .rpm
                                    }}
                                    <span style="font-size: 0.65rem">rpm</span>
                                </div>
                                <div
                                    v-else-if="childItem.duty != null && childItem.rpm != null"
                                    class="items-end flex flex-col leading-none tree-data"
                                >
                                    <span :class="{ 'mb-0.5': childItem.isControllable }">
                                        {{
                                            deviceChannelValues(
                                                childItem.deviceUID,
                                                childItem.name,
                                            )!.duty
                                        }}
                                        <span style="font-size: 0.65rem">%&nbsp;&nbsp;&nbsp;</span>
                                    </span>
                                    <span :class="{ 'mt-0.5': childItem.isControllable }">
                                        {{
                                            deviceChannelValues(
                                                childItem.deviceUID,
                                                childItem.name,
                                            )!.rpm
                                        }}
                                        <span style="font-size: 0.65rem">rpm</span>
                                    </span>
                                </div>
                            </div>
                            <!-- Hover Menu -->
                            <div
                                class="hidden mr-1 justify-end whitespace-normal"
                                :class="{ 'group-hover:flex': hoverMenusAreClosed }"
                            >
                                <div v-for="menu in childItem.menus">
                                    <menu-color-picker
                                        v-if="menu === Menu.COLOR"
                                        :device-u-i-d="childItem.deviceUID"
                                        :channel-name="childItem.name"
                                        :color="
                                            deviceChannelColor(childItem.deviceUID, childItem.name)
                                                .value
                                        "
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-rename
                                        v-else-if="menu === Menu.RENAME"
                                        :device-u-i-d="childItem.deviceUID"
                                        :channel-name="childItem.name"
                                        @click.stop
                                        @name-change="(value: string) => (childItem.label = value)"
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-dashboard-home
                                        v-else-if="menu === Menu.DASHBOARD_HOME"
                                        :dashboard-u-i-d="childItem.dashboardUID"
                                        @home-set="homeDashboardSet"
                                    />
                                    <menu-dashboard-rename
                                        v-else-if="menu === Menu.DASHBOARD_RENAME"
                                        :dashboard-u-i-d="childItem.dashboardUID"
                                        @name-change="(name: string) => (childItem.label = name)"
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-mode-activate
                                        v-else-if="menu === Menu.MODE_ACTIVATE"
                                        :mode-u-i-d="childItem.uid"
                                    />
                                    <menu-mode-rename
                                        v-else-if="menu === Menu.MODE_RENAME"
                                        :mode-u-i-d="childItem.uid"
                                        @name-change="(name: string) => (childItem.label = name)"
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-profile-apply
                                        v-else-if="menu === Menu.PROFILE_APPLY"
                                        :profile-u-i-d="childItem.uid"
                                    />
                                    <menu-profile-rename
                                        v-else-if="menu === Menu.PROFILE_RENAME"
                                        :profile-u-i-d="childItem.uid"
                                        @name-change="(name: string) => (childItem.label = name)"
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-function-apply
                                        v-else-if="menu === Menu.FUNCTION_APPLY"
                                        :function-u-i-d="childItem.uid"
                                    />
                                    <menu-function-rename
                                        v-else-if="menu === Menu.FUNCTION_RENAME"
                                        :function-u-i-d="childItem.uid"
                                        @name-change="(name: string) => (childItem.label = name)"
                                        @open="setHoverMenuStatus"
                                    />
                                    <menu-alert-rename
                                        v-else-if="menu === Menu.ALERT_RENAME"
                                        :alert-u-i-d="childItem.uid"
                                        @name-change="(name: string) => (childItem.label = name)"
                                        @open="setHoverMenuStatus"
                                    />
                                </div>
                                <!-- More Options Menu -->
                                <div
                                    v-if="childItem.subMenus"
                                    v-tooltip.top="{ value: t('layout.menu.tooltips.options') }"
                                >
                                    <div
                                        class="rounded-lg w-8 h-8 border-none p-0 text-text-color-secondary outline-0 text-center justify-center items-center flex hover:text-text-color hover:bg-surface-hover"
                                        @click.stop.prevent="
                                            (event) => childItem.subMenuRef.toggle(event)
                                        "
                                    >
                                        <svg-icon
                                            class="outline-0"
                                            type="mdi"
                                            :path="mdiDotsVertical"
                                            :size="deviceStore.getREMSize(1.5)"
                                        />
                                    </div>
                                    <Popover
                                        :ref="(el) => (childItem.subMenuRef = el)"
                                        @show="() => setHoverMenuStatus(true)"
                                        @hide="() => setHoverMenuStatus(false)"
                                    >
                                        <div
                                            class="mt-2.5 bg-bg-two border border-border-one p-1 rounded-lg text-text-color"
                                        >
                                            <ul>
                                                <li v-for="subMenu in childItem.subMenus">
                                                    <sub-menu-move-top
                                                        v-if="subMenu === SubMenu.MOVE_TOP"
                                                        @moveTop="
                                                            moveToTop(childItem, item.children)
                                                        "
                                                    />
                                                    <sub-menu-pin
                                                        v-else-if="subMenu === SubMenu.PIN"
                                                        :is-pinned="isPinned(childItem)"
                                                        @close="childItem.subMenuRef.hide()"
                                                        @pin="pinItem(childItem)"
                                                        @unpin="
                                                            () => {
                                                                setHoverMenuStatus(false)
                                                                unPinItem(childItem)
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-custom-sensor-delete
                                                        v-else-if="
                                                            subMenu === SubMenu.CUSTOM_SENSOR_DELETE
                                                        "
                                                        :device-u-i-d="childItem.deviceUID"
                                                        :custom-sensor-i-d="childItem.name"
                                                    />
                                                    <sub-menu-disable
                                                        v-else-if="subMenu === SubMenu.DISABLE"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-dashboard-duplicate
                                                        v-else-if="
                                                            subMenu === SubMenu.DASHBOARD_DUPLICATE
                                                        "
                                                        :dashboard-u-i-d="childItem.dashboardUID"
                                                        @added="addDashbaord"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-dashboard-delete
                                                        v-else-if="
                                                            subMenu === SubMenu.DASHBOARD_DELETE
                                                        "
                                                        :dashboard-u-i-d="childItem.dashboardUID"
                                                        @deleted="
                                                            (dashboardUID: UID) => {
                                                                deleteDashboard(dashboardUID)
                                                                setHoverMenuStatus(false)
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-mode-update
                                                        v-else-if="subMenu === SubMenu.MODE_UPDATE"
                                                        :mode-u-i-d="childItem.uid"
                                                        @updated="activeModesChange"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-mode-duplicate
                                                        v-else-if="
                                                            subMenu === SubMenu.MODE_DUPLICATE
                                                        "
                                                        :mode-u-i-d="childItem.uid"
                                                        @added="addMode"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-mode-delete
                                                        v-else-if="subMenu === SubMenu.MODE_DELETE"
                                                        :mode-u-i-d="childItem.uid"
                                                        @deleted="deleteMode"
                                                        @close="
                                                            () => {
                                                                setHoverMenuStatus(false)
                                                                childItem.subMenuRef.hide()
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-profile-duplicate
                                                        v-else-if="
                                                            subMenu === SubMenu.PROFILE_DUPLICATE
                                                        "
                                                        :profile-u-i-d="childItem.uid"
                                                        @added="addProfile"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-profile-delete
                                                        v-else-if="
                                                            subMenu === SubMenu.PROFILE_DELETE
                                                        "
                                                        :profile-u-i-d="childItem.uid"
                                                        @deleted="deleteProfile"
                                                        @close="
                                                            () => {
                                                                setHoverMenuStatus(false)
                                                                childItem.subMenuRef.hide()
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-function-duplicate
                                                        v-else-if="
                                                            subMenu === SubMenu.FUNCTION_DUPLICATE
                                                        "
                                                        :function-u-i-d="childItem.uid"
                                                        @added="addFunction"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-function-delete
                                                        v-else-if="
                                                            subMenu === SubMenu.FUNCTION_DELETE
                                                        "
                                                        :function-u-i-d="childItem.uid"
                                                        @deleted="deleteFunction"
                                                        @close="
                                                            () => {
                                                                setHoverMenuStatus(false)
                                                                childItem.subMenuRef.hide()
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-alert-duplicate
                                                        v-else-if="
                                                            subMenu === SubMenu.ALERT_DUPLICATE
                                                        "
                                                        :alert-u-i-d="childItem.uid"
                                                        @added="addAlert"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-alert-delete
                                                        v-else-if="subMenu === SubMenu.ALERT_DELETE"
                                                        :alert-u-i-d="childItem.uid"
                                                        @deleted="deleteAlert"
                                                        @close="
                                                            () => {
                                                                setHoverMenuStatus(false)
                                                                childItem.subMenuRef.hide()
                                                            }
                                                        "
                                                    />
                                                    <sub-menu-move-bottom
                                                        v-else-if="subMenu === SubMenu.MOVE_BOTTOM"
                                                        @moveBottom="
                                                            moveToBottom(childItem, item.children)
                                                        "
                                                    />
                                                    <sub-menu-alert-add-fail
                                                        v-else-if="
                                                            subMenu === SubMenu.ALERT_ADD_FAIL
                                                        "
                                                        :device-u-i-d="childItem.deviceUID"
                                                        :channel-name="childItem.name"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-alert-add-temp
                                                        v-else-if="
                                                            subMenu === SubMenu.ALERT_ADD_TEMP
                                                        "
                                                        :device-u-i-d="childItem.deviceUID"
                                                        :channel-name="childItem.name"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                    <sub-menu-tag-assign
                                                        v-else-if="subMenu === SubMenu.TAG"
                                                        :device-u-i-d="childItem.deviceUID"
                                                        :channel-name="childItem.name"
                                                        @open="setHoverMenuStatus"
                                                        @close="childItem.subMenuRef.hide()"
                                                    />
                                                </li>
                                            </ul>
                                        </div>
                                    </Popover>
                                </div>
                            </div>
                        </router-link>
                    </div>
                </VueDraggable>
            </el-collapse-item>
        </el-collapse>
    </VueDraggable>
</template>

<style scoped lang="scss">
.el-collapse {
    --el-fill-color-blank: rgb(var(--colors-bg-one));
    --el-collapse-header-text-color: rgb(var(--colors-text-color));
    --el-collapse-header-font-size: 1rem;
    --el-collapse-content-font-size: 1rem;
    --el-collapse-content-text-color: rgb(var(--colors-text-color));
    border-top: 0;
    border-bottom: 0;
    --el-collapse-border-color: rgb(var(--colors-bg-one));
    --el-collapse-header-height: 2.5rem;
}

.tree-text {
    // This is THE WAY to handle elements overflowing with white-space: nowrap
    // same as tw line-clamp-1
    overflow: hidden;
    display: -webkit-box;
    line-clamp: 1;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    // improves UX when dragging, as otherwise text is sometimes selected
    user-select: none;
}

.tree-data {
    white-space: nowrap;
    align-items: end;
    align-content: end;
    //display: inline-block;
    //min-width: 5rem;
}

.sortable-fallback {
    color: rgb(var(--colors-text-color));
    background-color: rgba(var(--colors-bg-two) / 0.625);
    border-radius: 0.5rem;
}
</style>
<style lang="scss">
/******************************************************************************************
* Unscoped Style needed to deeply affect the element components
*/
.el-collapse-icon-position-left .el-collapse-item__header {
    gap: 0.125rem;
}

.el-collapse-item__header {
    border-bottom: 0;
    //display: block;
    border-radius: 0.5rem;
}

.el-collapse-item__header:hover {
    background-color: rgb(var(--colors-bg-two));
}

.el-collapse-item__header.focusing:focus:not(:hover) {
    // strange issue with fast clicking then triggers this (likely upstream bug)
    color: rgb(var(--colors-text-color));
}

.el-collapse-item__title {
    width: 100%;
}

.el-collapse-item__wrap {
    border-bottom: 0;
    // creates a bit of separation between expanded items
    margin-bottom: 0.5rem;
}

.el-collapse-item__content {
    line-height: normal;
    padding-bottom: 0;
}

.el-collapse-item__arrow {
    font-size: 1rem;
    //font-weight: 800;
    padding-left: 1px !important;
}
</style>
