pending changes indication for device and component changes
This commit is contained in:
parent
10f0aa46cc
commit
71fb67bba4
13 changed files with 259 additions and 135 deletions
|
|
@ -4,7 +4,7 @@ import { NextMeasurementChip } from "common/NextMeasurementChip";
|
|||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
// import { getTableIcons } from "common/ResponsiveTable";
|
||||
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
||||
import StatusChip from "common/StatusChip";
|
||||
import PendingChangesChip from "common/PendingChangesChip";
|
||||
import { GetDefaultDateRange } from "common/time/DateRange";
|
||||
import ComponentActions from "component/ComponentActions";
|
||||
import ComponentChart from "component/ComponentChart";
|
||||
|
|
@ -16,11 +16,14 @@ import {
|
|||
useComponentAPI,
|
||||
useDeviceAPI,
|
||||
useGroupAPI,
|
||||
useHTTP,
|
||||
useInteractionsAPI,
|
||||
usePendingChanges,
|
||||
usePrevious,
|
||||
useSnackbar,
|
||||
useUserAPI
|
||||
} from "hooks";
|
||||
import { useWebSocket } from "hooks/useWebSocket";
|
||||
import InteractionChip from "interactions/InteractionChip";
|
||||
import InteractionSettings from "interactions/InteractionSettings";
|
||||
import { cloneDeep } from "lodash";
|
||||
|
|
@ -40,9 +43,10 @@ import { getDefaultInteraction } from "pbHelpers/Interaction";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState } from "providers";
|
||||
import { useTeamAPI } from "providers/pond/teamAPI";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
// import { useRouteMatch } from "react-router";
|
||||
import { isStaleStatusUpdate } from "utils/syncStatus";
|
||||
import { or } from "utils/types";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
|
|
@ -142,6 +146,55 @@ export default function DeviceComponent() {
|
|||
const [deviceComponentPrefs, setDeviceComponentPrefs] = useState<
|
||||
pond.DeviceComponentPreferences
|
||||
>();
|
||||
const { token } = useHTTP();
|
||||
const componentPending = usePendingChanges(
|
||||
component.status.synced,
|
||||
!loadingInitial && component.key() !== ""
|
||||
);
|
||||
|
||||
const liveContextKeys = useMemo(() => getContextKeys(), []);
|
||||
const liveContextTypes = useMemo(() => getContextTypes(), []);
|
||||
/** Matches the REST calls: omit ?as= when first context type is "team". */
|
||||
const liveAs =
|
||||
as && !(liveContextTypes.length > 0 && liveContextTypes[0] === "team")
|
||||
? as
|
||||
: undefined;
|
||||
|
||||
// --- Real-time component updates ---
|
||||
// Streams component changes for this device, including status changes
|
||||
// when the device accepts pending component updates.
|
||||
useWebSocket<{ key: string; component: Component } | null>({
|
||||
path: `/v1/live/devices/${deviceID}/components`,
|
||||
parse: (e) => {
|
||||
try {
|
||||
const raw = JSON.parse(e.data);
|
||||
const comp = Component.any(raw);
|
||||
if (!comp?.settings) {
|
||||
console.warn("[ws] received component without settings:", raw);
|
||||
return null;
|
||||
}
|
||||
return { key: comp.key(), component: comp };
|
||||
} catch (err) {
|
||||
console.warn("[ws] failed to parse component:", err);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onMessage: (data) => {
|
||||
if (!data || data.key !== componentID) return;
|
||||
setComponent((prev) => {
|
||||
if (prev.key() !== data.key) return prev;
|
||||
if (isStaleStatusUpdate(prev.status, data.component.status)) {
|
||||
return prev;
|
||||
}
|
||||
return data.component;
|
||||
});
|
||||
},
|
||||
keys: liveContextKeys,
|
||||
types: liveContextTypes,
|
||||
as: liveAs,
|
||||
token,
|
||||
enabled: !!deviceID && componentID !== "",
|
||||
});
|
||||
|
||||
const setDefaultState = () => {
|
||||
setDevice(Device.create());
|
||||
|
|
@ -389,9 +442,12 @@ export default function DeviceComponent() {
|
|||
alignItems="center"
|
||||
wrap="nowrap"
|
||||
className={classes.overviewContainer}>
|
||||
{!component.status.synced && (
|
||||
{(componentPending.pending || componentPending.accepted) && (
|
||||
<Grid >
|
||||
<StatusChip key="status" status="pending" />
|
||||
<PendingChangesChip
|
||||
pending={componentPending.pending}
|
||||
accepted={componentPending.accepted}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid >
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue