Newer
Older
import {
NetworkelementFlattenedManagedNetworkElement,
NetworkelementManagedNetworkElement,
PndPrincipalNetworkDomain
} from '@api/api'
import { DeviceViewTabValues } from '@component/devices/view/device.view.tabs'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { REHYDRATE } from 'redux-persist'
import { RootState } from 'src/stores'
import '../routines/index'
import { startListening } from '/src/stores/middleware/listener.middleware'
export type Device = NetworkelementFlattenedManagedNetworkElement
interface SelectedObject {
mne: NetworkelementManagedNetworkElement | null
export interface DeviceSliceState {
devices: Device[]
pnds: PndPrincipalNetworkDomain[]
selected: SelectedObject | null
}
const initialState: DeviceSliceState = {
devices: [],
}
interface SetSelectedDeviceType {
device: Device | null,
options?: {
bypassCheck: boolean
}
}
const deviceSlice = createSlice({
name: 'device',
initialState,
reducers: {
setDevices: (state, action: PayloadAction<Device[] | undefined>) => {
state.devices = action.payload || []
setPnds: (state, action: PayloadAction<PndPrincipalNetworkDomain[] | undefined>) => {
state.pnds = action.payload || []
},
setActiveTab: (state, action: PayloadAction<DeviceViewTabValues>) => {
state.activeTab = action.payload
},
reducer: (state, { payload, meta }: PayloadAction<SetSelectedDeviceType, string, { skipListener?: boolean }>) => {
/**
* Do nothing if desired device is already selected
* Bypass the check if the flag is set to true. We
* use this bypass to trigger the listener functions
* accordingly
*/
if (!payload?.options?.bypassCheck && state.selected?.device.id === payload.device?.id) {
meta.skipListener = true
if (!payload.device) {
throw Error('Passed null device as parameter while bypassing the safety check')
}
let selectedObject: SelectedObject | null = null;
if (payload) {
selectedObject = { device: payload.device, mne: null, json: null }
state.selected = selectedObject
},
payload,
meta: { skipListener: false }
},
setSelectedMne: (state, action: PayloadAction<NetworkelementManagedNetworkElement>) => {
if (!state.selected) {
throw new Error('Can not find corresponding device')
}
// safety check to prevent possible race conditions
if (state.selected.device.id !== action.payload.id) {
// TODO proper error handling by retry fetching the device object
throw new Error('Device and mne id does not match')
state.selected.mne = action.payload
},
setSelectedJson: (state, action: PayloadAction<JSON>) => {
throw new Error('Selected Device is null where it shouldn´t be null')
}
state.selected.json = action.payload || null
},
})
export const { setDevices, setActiveTab, setSelectedDevice, setSelectedMne, setSelectedJson, setPnds } =
export default deviceSlice.reducer
export const deviceReducerPath = deviceSlice.reducerPath
// add default selected device if no selected device is set
startListening({
predicate: (action) => setDevices.match(action),
effect: async (action, listenerApi) => {
const { device: state } = listenerApi.getOriginalState() as RootState
// if there are no devices available do set null
const device = action.payload?.[0] || null
listenerApi.dispatch(setSelectedDevice({ device } as SetSelectedDeviceType))
/**
* On startup reset the selected device
*/
startListening({
predicate: ({ type }: any) => type === REHYDRATE,
effect: async (_, listenerApi) => {
const { device: state } = listenerApi.getState() as RootState
const device = state.selected?.device
if (!device) {
return
}
listenerApi.dispatch(setSelectedDevice({ device, options: { bypassCheck: true } } as SetSelectedDeviceType))
},
})