diff --git a/react-ui/src/components/devices/reducer/plugin.reducer.ts b/react-ui/src/components/devices/reducer/plugin.reducer.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a09876fe65dce2f919dc58a46c60a37c14f03b4 --- /dev/null +++ b/react-ui/src/components/devices/reducer/plugin.reducer.ts @@ -0,0 +1,99 @@ +import { + NetworkelementFlattenedManagedNetworkElement, + NetworkelementManagedNetworkElement, + PndPrincipalNetworkDomain +} from '@api/api' +import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { refreshUpdateTimer } from '@shared/reducer/routine.reducer' +import { Category, CategoryType } from '@shared/types/category.type' +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 { + device: Device + mne: NetworkelementManagedNetworkElement | null + json: JSON | null +} + +export interface DeviceSliceState { + devices: Device[] + pnds: PndPrincipalNetworkDomain[] + + selected: SelectedObject | null +} + +const initialState: DeviceSliceState = { + plugins: [], +} + +interface SetSelectedDeviceType { + device: Device | null, + options?: { + bypassCheck: boolean + } +} + +const deviceSlice = createSlice({ + name: 'plugins', + initialState, + reducers: { + setPlugins: (state, action: PayloadAction<Plugin[] | undefined>) => { + state.devices = action.payload || [] + }, + }, +}) + +export const { setDevices, setSelectedDevice, setSelectedMne, setSelectedJson, setPnds } = + deviceSlice.actions + +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 (state.selected) { + return + } + + // if there are no devices available do set null + const device = action.payload?.[0] || null + listenerApi.dispatch(setSelectedDevice({ device } as SetSelectedDeviceType)) + }, +}) + +startListening({ + predicate: (action) => setSelectedMne.match(action), + effect: async (action, listenerApi) => { + listenerApi.dispatch(refreshUpdateTimer(Category.TAB as CategoryType)) + }, +}) + +startListening({ + predicate: (action) => setDevices.match(action), + effect: async (action, listenerApi) => { + listenerApi.dispatch(refreshUpdateTimer(Category.DEVICE as CategoryType)) + }, +}) + +/** + * 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)) + }, +}) \ No newline at end of file diff --git a/react-ui/src/components/devices/view/subcomponent/modal.view.tsx b/react-ui/src/components/devices/view/subcomponent/modal.view.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d798e7adecd5190a5f7a9f413de0c41a4831e5eb --- /dev/null +++ b/react-ui/src/components/devices/view/subcomponent/modal.view.tsx @@ -0,0 +1,141 @@ +import { NetworkelementAddListRequest, useNetworkElementServiceAddListMutation } from '@api/api'; +import React, { useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; + +interface AddDeviceModalProps { + show: boolean; + onHide: () => void; +} + +interface FormData { + address: '', + mneName: '', + transportOption: undefined, + gnmiSubscribePaths: [], +} + +const AddDeviceModal: React.FC<AddDeviceModalProps> = ({ show, onHide }) => { + const [addNetworkElement] = useNetworkElementServiceAddListMutation(); + const [formData, setFormData] = useState<FormData>({ + address: '', + mneName: '', + transportOption: undefined, + gnmiSubscribePaths: [], + }); + + const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + const request: NetworkelementAddListRequest = { + timestamp: Date.now().toString(), // Convert to nanoseconds if needed + mne: [formData], + pid: formData.pid + }; + + try { + await addNetworkElement({ networkelementAddListRequest: request }); + handleReset(); + // You might want to add a success notification here + } catch (error) { + console.error('Failed to add device:', error); + // You might want to add an error notification here + } + }; + + const handleReset = () => { + setFormData({ + address: '', + pid: '', + pluginId: '', + mneName: '', + transportOption: undefined, + gnmiSubscribePaths: [], + mneId: '' + }); + onHide(); + }; + + return ( + <Modal show={show} onHide={handleReset} centered> + <Modal.Header closeButton> + <Modal.Title>Add New Device</Modal.Title> + </Modal.Header> + <Form onSubmit={handleSubmit}> + <Modal.Body> + <Form.Group className="mb-3"> + <Form.Label>Address</Form.Label> + <Form.Control + type="text" + name="address" + value={formData.address} + onChange={handleInputChange} + placeholder="Enter device address" + /> + </Form.Group> + + <Form.Group className="mb-3"> + <Form.Label>PID</Form.Label> + <Form.Control + type="text" + name="pid" + value={formData.pid} + onChange={handleInputChange} + placeholder="Enter PID" + /> + </Form.Group> + + <Form.Group className="mb-3"> + <Form.Label>Plugin ID</Form.Label> + <Form.Control + type="text" + name="pluginId" + value={formData.pluginId} + onChange={handleInputChange} + placeholder="Enter plugin ID" + /> + </Form.Group> + + <Form.Group className="mb-3"> + <Form.Label>MNE Name</Form.Label> + <Form.Control + type="text" + name="mneName" + value={formData.mneName} + onChange={handleInputChange} + placeholder="Enter MNE name" + /> + </Form.Group> + + <Form.Group className="mb-3"> + <Form.Label>MNE ID</Form.Label> + <Form.Control + type="text" + name="mneId" + value={formData.mneId} + onChange={handleInputChange} + placeholder="Enter MNE ID" + /> + </Form.Group> + </Modal.Body> + <Modal.Footer> + <Button variant="secondary" onClick={handleReset}> + Cancel + </Button> + <Button variant="primary" type="submit"> + Add Device + </Button> + </Modal.Footer> + </Form> + </Modal> + ); +}; + +export default AddDeviceModal; \ No newline at end of file diff --git a/react-ui/src/components/devices/view_model/modal.viewmodel.ts b/react-ui/src/components/devices/view_model/modal.viewmodel.ts new file mode 100644 index 0000000000000000000000000000000000000000..de9bbf68ecba77b9173afd144ac4e36775e22a8e --- /dev/null +++ b/react-ui/src/components/devices/view_model/modal.viewmodel.ts @@ -0,0 +1,10 @@ +import { useEffect } from "react" + + +export const useModalViewModel = () => { + + + useEffect(() => { + + }, []) +} \ No newline at end of file