From b94e459e0aaac51f9515e5948ff4d7de2dad6b53 Mon Sep 17 00:00:00 2001 From: Tsu-ba-me Date: Wed, 1 Mar 2023 22:43:07 -0500 Subject: [PATCH] fix(striker-ui): connect add and edit forms with ManageUpsPanel --- .../components/ManageUps/ManageUpsPanel.tsx | 218 ++++++++++++++++-- striker-ui/types/APIUps.d.ts | 9 + 2 files changed, 213 insertions(+), 14 deletions(-) diff --git a/striker-ui/components/ManageUps/ManageUpsPanel.tsx b/striker-ui/components/ManageUps/ManageUpsPanel.tsx index 99b2799a..7c4d3f04 100644 --- a/striker-ui/components/ManageUps/ManageUpsPanel.tsx +++ b/striker-ui/components/ManageUps/ManageUpsPanel.tsx @@ -1,25 +1,108 @@ -import { FC, useMemo, useRef, useState } from 'react'; +import { + FC, + FormEventHandler, + useCallback, + useMemo, + useRef, + useState, +} from 'react'; -import AddUpsInputGroup from './AddUpsInputGroup'; +import API_BASE_URL from '../../lib/consts/API_BASE_URL'; + +import AddUpsInputGroup, { INPUT_ID_UPS_TYPE_ID } from './AddUpsInputGroup'; import api from '../../lib/api'; +import { INPUT_ID_UPS_IP, INPUT_ID_UPS_NAME } from './CommonUpsInputGroup'; import ConfirmDialog from '../ConfirmDialog'; +import EditUpsInputGroup, { INPUT_ID_UPS_UUID } from './EditUpsInputGroup'; +import FlexBox from '../FlexBox'; import FormDialog from '../FormDialog'; import handleAPIError from '../../lib/handleAPIError'; import List from '../List'; import { Panel, PanelHeader } from '../Panels'; +import periodicFetch from '../../lib/fetchers/periodicFetch'; import Spinner from '../Spinner'; -import { HeaderText } from '../Text'; +import { BodyText, HeaderText, InlineMonoText, MonoText } from '../Text'; import useConfirmDialogProps from '../../hooks/useConfirmDialogProps'; import useIsFirstRender from '../../hooks/useIsFirstRender'; import useProtectedState from '../../hooks/useProtectedState'; +type UpsFormData = { + upsAgent: string; + upsBrand: string; + upsIPAddress: string; + upsName: string; + upsTypeId: string; + upsUUID: string; +}; + +const getUpsFormData = ( + upsTemplate: APIUpsTemplate, + ...[{ target }]: Parameters> +): UpsFormData => { + const { elements } = target as HTMLFormElement; + + const { value: upsName } = elements.namedItem( + INPUT_ID_UPS_NAME, + ) as HTMLInputElement; + const { value: upsIPAddress } = elements.namedItem( + INPUT_ID_UPS_IP, + ) as HTMLInputElement; + + const inputUpsTypeId = elements.namedItem(INPUT_ID_UPS_TYPE_ID); + + let upsAgent = ''; + let upsBrand = ''; + let upsTypeId = ''; + + if (inputUpsTypeId) { + ({ value: upsTypeId } = inputUpsTypeId as HTMLInputElement); + ({ agent: upsAgent, brand: upsBrand } = upsTemplate[upsTypeId]); + } + + const inputUpsUUID = elements.namedItem(INPUT_ID_UPS_UUID); + + let upsUUID = ''; + + if (inputUpsUUID) { + ({ value: upsUUID } = inputUpsUUID as HTMLInputElement); + } + + return { upsAgent, upsBrand, upsIPAddress, upsName, upsTypeId, upsUUID }; +}; + +const buildConfirmUpsFormData = ({ + upsBrand, + upsIPAddress, + upsName, + upsUUID, +}: UpsFormData) => { + const listItems: Record = { + 'ups-brand': { label: 'Brand', value: upsBrand }, + 'ups-name': { label: 'Host name', value: upsName }, + 'ups-ip-address': { label: 'IP address', value: upsIPAddress }, + }; + + return ( + ( + + {label} + {value} + + )} + /> + ); +}; + const ManageUpsPanel: FC = () => { const isFirstRender = useIsFirstRender(); const confirmDialogRef = useRef({}); const formDialogRef = useRef({}); - const [confirmDialogProps] = useConfirmDialogProps(); + const [confirmDialogProps, setConfirmDialogProps] = useConfirmDialogProps(); const [formDialogProps, setFormDialogProps] = useConfirmDialogProps(); const [isEditUpses, setIsEditUpses] = useState(false); const [isLoadingUpsTemplate, setIsLoadingUpsTemplate] = @@ -28,6 +111,99 @@ const ManageUpsPanel: FC = () => { APIUpsTemplate | undefined >(undefined); + const { data: upsOverviews, isLoading: isUpsOverviewLoading } = + periodicFetch(`${API_BASE_URL}/ups`, { + refreshInterval: 60000, + }); + + const buildEditUpsFormDialogProps = useCallback< + (args: APIUpsOverview[string]) => ConfirmDialogProps + >( + ({ upsAgent, upsIPAddress, upsName, upsUUID }) => { + // Determine the type of existing UPS based on its scan agent. + // TODO: should identity an existing UPS's type in the DB. + const upsTypeId: string = + Object.entries(upsTemplate ?? {}).find( + ([, { agent }]) => upsAgent === agent, + )?.[0] ?? ''; + + return { + actionProceedText: 'Update', + content: ( + + ), + onSubmitAppend: (event) => { + if (!upsTemplate) { + return; + } + + const editData = getUpsFormData(upsTemplate, event); + const { upsName: newUpsName } = editData; + + setConfirmDialogProps({ + actionProceedText: 'Update', + content: buildConfirmUpsFormData(editData), + titleText: ( + + Update{' '} + {newUpsName}{' '} + with the following data? + + ), + }); + + confirmDialogRef.current.setOpen?.call(null, true); + }, + titleText: ( + + Update UPS{' '} + {upsName} + + ), + }; + }, + [setConfirmDialogProps, upsTemplate], + ); + + const addUpsFormDialogProps = useMemo( + () => ({ + actionProceedText: 'Add', + content: , + onSubmitAppend: (event) => { + if (!upsTemplate) { + return; + } + + const addData = getUpsFormData(upsTemplate, event); + const { upsBrand } = addData; + + setConfirmDialogProps({ + actionProceedText: 'Add', + content: buildConfirmUpsFormData(addData), + titleText: ( + + Add a{' '} + {upsBrand} UPS + with the following data? + + ), + }); + + confirmDialogRef.current.setOpen?.call(null, true); + }, + titleText: 'Add a UPS', + }), + [setConfirmDialogProps, upsTemplate], + ); + const listElement = useMemo( () => ( { edit={isEditUpses} header listEmpty="No Ups(es) registered." + listItems={upsOverviews} onAdd={() => { - setFormDialogProps({ - actionProceedText: 'Add', - content: , - titleText: 'Add a UPS', - }); - + setFormDialogProps(addUpsFormDialogProps); formDialogRef.current.setOpen?.call(null, true); }} onEdit={() => { setIsEditUpses((previous) => !previous); }} + onItemClick={(value) => { + setFormDialogProps(buildEditUpsFormDialogProps(value)); + formDialogRef.current.setOpen?.call(null, true); + }} + renderListItem={(upsUUID, { upsAgent, upsIPAddress, upsName }) => ( + + {upsName} + agent="{upsAgent}" + ip="{upsIPAddress}" + + )} /> ), - [isEditUpses, setFormDialogProps, upsTemplate], + [ + addUpsFormDialogProps, + buildEditUpsFormDialogProps, + isEditUpses, + setFormDialogProps, + upsOverviews, + ], ); const panelContent = useMemo( - () => (isLoadingUpsTemplate ? : listElement), - [isLoadingUpsTemplate, listElement], + () => + isLoadingUpsTemplate || isUpsOverviewLoading ? : listElement, + [isLoadingUpsTemplate, isUpsOverviewLoading, listElement], ); if (isFirstRender) { @@ -75,7 +265,7 @@ const ManageUpsPanel: FC = () => { <> - Manage Upses + Manage UPSes {panelContent} diff --git a/striker-ui/types/APIUps.d.ts b/striker-ui/types/APIUps.d.ts index c73d68d4..d0194de5 100644 --- a/striker-ui/types/APIUps.d.ts +++ b/striker-ui/types/APIUps.d.ts @@ -5,3 +5,12 @@ type APIUpsTemplate = { description: string; }; }; + +type APIUpsOverview = { + [upsUUID: string]: { + upsAgent: string; + upsIPAddress: string; + upsName: string; + upsUUID: string; + }; +};