import AddIcon from '@mui/icons-material/Add'; import CancelIcon from '@mui/icons-material/Cancel'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import RefreshIcon from '@mui/icons-material/Refresh'; import WarningIcon from '@mui/icons-material/Warning'; import { Button, Typography, Box } from '@mui/material'; import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table'; import { useTheme } from '@table-library/react-table-library/theme'; // eslint-disable-next-line import/named import { updateState, useRequest } from 'alova'; import { useState, useCallback } from 'react'; import { useBlocker } from 'react-router-dom'; import { toast } from 'react-toastify'; import SettingsCustomEntitiesDialog from './SettingsCustomEntitiesDialog'; import * as EMSESP from './api'; import { DeviceValueTypeNames, DeviceValueUOM_s } from './types'; import { entityItemValidation } from './validators'; import type { EntityItem } from './types'; import type { FC } from 'react'; import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; const SettingsCustomEntities: FC = () => { const { LL } = useI18nContext(); const [numChanges, setNumChanges] = useState(0); const blocker = useBlocker(numChanges !== 0); const [selectedEntityItem, setSelectedEntityItem] = useState(); const [creating, setCreating] = useState(false); const [dialogOpen, setDialogOpen] = useState(false); const { data: entities, send: fetchEntities, error } = useRequest(EMSESP.readCustomEntities, { initialData: [], force: true }); const { send: writeEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false }); function hasEntityChanged(ei: EntityItem) { return ( ei.id !== ei.o_id || ei.ram !== ei.o_ram || (ei?.name || '') !== (ei?.o_name || '') || ei.device_id !== ei.o_device_id || ei.type_id !== ei.o_type_id || ei.offset !== ei.o_offset || ei.uom !== ei.o_uom || ei.factor !== ei.o_factor || ei.value_type !== ei.o_value_type || ei.writeable !== ei.o_writeable || ei.deleted !== ei.o_deleted || (ei.value || '') !== (ei.o_value || '') ); } const entity_theme = useTheme({ Table: ` --data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px 90px; `, BaseRow: ` font-size: 14px; .td { height: 32px; } `, BaseCell: ` &:nth-of-type(1) { padding: 8px; } &:nth-of-type(2) { text-align: center; } &:nth-of-type(3) { text-align: center; } &:nth-of-type(4) { text-align: center; } &:nth-of-type(5) { text-align: center; } &:nth-of-type(6) { text-align: center; } `, HeaderRow: ` text-transform: uppercase; background-color: black; color: #90CAF9; .th { border-bottom: 1px solid #565656; height: 36px; } `, Row: ` background-color: #1e1e1e; position: relative; cursor: pointer; .td { border-top: 1px solid #565656; border-bottom: 1px solid #565656; } &:hover .td { border-top: 1px solid #177ac9; border-bottom: 1px solid #177ac9; } &:nth-of-type(odd) .td { background-color: #303030; } ` }); const saveEntities = async () => { await writeEntities({ entities: entities .filter((ei) => !ei.deleted) .map((condensed_ei) => ({ id: condensed_ei.id, ram: condensed_ei.ram, name: condensed_ei.name, device_id: condensed_ei.device_id, type_id: condensed_ei.type_id, offset: condensed_ei.offset, factor: condensed_ei.factor, uom: condensed_ei.uom, writeable: condensed_ei.writeable, value_type: condensed_ei.value_type, value: condensed_ei.value })) }) .then(() => { toast.success(LL.ENTITIES_UPDATED()); }) .catch((err) => { toast.error(err.message); }) .finally(async () => { await fetchEntities(); setNumChanges(0); }); }; const editEntityItem = useCallback((ei: EntityItem) => { setCreating(false); setSelectedEntityItem(ei); setDialogOpen(true); }, []); const onDialogClose = () => { setDialogOpen(false); }; const onDialogCancel = async () => { await fetchEntities().then(() => { setNumChanges(0); }); }; const onDialogSave = (updatedItem: EntityItem) => { setDialogOpen(false); updateState('entities', (data) => { const new_data = creating ? [...data.filter((ei) => creating || ei.o_id !== updatedItem.o_id), updatedItem] : data.map((ei) => (ei.id === updatedItem.id ? { ...ei, ...updatedItem } : ei)); setNumChanges(new_data.filter((ei) => hasEntityChanged(ei)).length); return new_data; }); }; const addEntityItem = () => { setCreating(true); setSelectedEntityItem({ id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100), name: '', ram: 0, device_id: '0', type_id: '0', offset: 0, factor: 1, uom: 0, value_type: 0, writeable: false, deleted: false, value: '' }); setDialogOpen(true); }; function formatValue(value: any, uom: number) { return value === undefined || uom === undefined ? '' : typeof value === 'number' ? new Intl.NumberFormat().format(value) + (uom === 0 ? '' : ' ' + DeviceValueUOM_s[uom]) : value; } function showHex(value: number, digit: number) { return '0x' + value.toString(16).toUpperCase().padStart(digit, '0'); } const renderEntity = () => { if (!entities) { return ; } return ( !ei.deleted) }} theme={entity_theme} layout={{ custom: true }}> {(tableList: any) => ( <>
{LL.NAME(0)} {LL.ID_OF(LL.DEVICE())} {LL.ID_OF(LL.TYPE(1))} {LL.OFFSET()} {LL.TYPE(1)} {LL.VALUE(1)}
{tableList.map((ei: EntityItem) => ( editEntityItem(ei)}> {ei.name}  {ei.writeable && } {ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)} {ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)} {ei.ram === 1 ? '' : ei.offset} {ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]} {formatValue(ei.value, ei.uom)} ))} )}
); }; return ( {blocker ? : null} {LL.ENTITIES_HELP_1()} {renderEntity()} {selectedEntityItem && ( )} {numChanges > 0 && ( )} ); }; export default SettingsCustomEntities;