tags owned by device are loaded with device page data, adding tag is object agnostic

This commit is contained in:
Carter 2025-01-22 13:44:56 -06:00
parent 4e7c68401b
commit 0076f2d208
8 changed files with 93 additions and 34 deletions

3
package-lock.json generated
View file

@ -4247,8 +4247,7 @@
}, },
"node_modules/protobuf-ts": { "node_modules/protobuf-ts": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#e3d1689e1bf3842b0601cf166be9aff78ef093ff", "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#91931b1936a92bb0bc24700664adf72eb8a912dd",
"integrity": "sha512-hlkiHxih/Z+kBGMoyWI2Y/vn6afNqRElGuZ/LLGPaLZe2BLXRLKAQOHzR3a7SLfz6p2TkZISNdpmeveK7xgKSg==",
"dependencies": { "dependencies": {
"protobufjs": "^6.8.8" "protobufjs": "^6.8.8"
} }

View file

@ -10,7 +10,7 @@ import { User } from '../models/user'
import { Team } from '../models/team' import { Team } from '../models/team'
import { makeStyles } from '@mui/styles' import { makeStyles } from '@mui/styles'
import { Theme } from '@mui/material' import { Theme } from '@mui/material'
import FirmwareLoader from './FirmwareLoader' // import FirmwareLoader from './FirmwareLoader'
const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => { const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => {
return { return {
@ -99,11 +99,11 @@ export default function UserWrapper(props: Props) {
return ( return (
<StateProvider state={global} reducer={reducer}> <StateProvider state={global} reducer={reducer}>
<FirmwareLoader> {/* <FirmwareLoader> */}
<main className={classes.appContent}> <main className={classes.appContent}>
<NavigationContainer toggleTheme={toggleTheme} /> <NavigationContainer toggleTheme={toggleTheme} />
</main> </main>
</FirmwareLoader> {/* </FirmwareLoader> */}
</StateProvider> </StateProvider>
) )
} }

View file

@ -27,8 +27,8 @@ import {
Wifi as WifiIcon Wifi as WifiIcon
} from "@mui/icons-material"; } from "@mui/icons-material";
import { Skeleton } from "@mui/material"; import { Skeleton } from "@mui/material";
import Datadog from "assets/external/datadog.png"; // import Datadog from "assets/external/datadog.png";
import { ImgIcon } from "common/ImgIcon"; // import { ImgIcon } from "common/ImgIcon";
import NotificationButton from "common/NotificationButton"; import NotificationButton from "common/NotificationButton";
// import ComponentOrder from "component/ComponentOrder"; // import ComponentOrder from "component/ComponentOrder";
// import ComponentSettings from "component/ComponentSettings"; // import ComponentSettings from "component/ComponentSettings";
@ -44,7 +44,7 @@ import { cloneDeep } from "lodash";
// import { Component, Device, deviceScope, Interaction } from "models"; // import { Component, Device, deviceScope, Interaction } from "models";
import { Device, deviceScope } from "models"; import { Device, deviceScope } from "models";
// import { MatchParams } from "navigation/Routes"; // import { MatchParams } from "navigation/Routes";
import { isShareableLink } from "pbHelpers/Device"; // import { isShareableLink } from "pbHelpers/Device";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import { useGlobalState } from "providers"; import { useGlobalState } from "providers";
import React, { useState } from "react"; import React, { useState } from "react";
@ -64,7 +64,7 @@ import { useNavigate } from "react-router-dom";
import DeviceSettings from "device/DeviceSettings"; import DeviceSettings from "device/DeviceSettings";
import ObjectTeams from "teams/ObjectTeams"; import ObjectTeams from "teams/ObjectTeams";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((_theme: Theme) => {
// const isMobile = useMobile() // const isMobile = useMobile()
return ({ return ({
greenIcon: { greenIcon: {
@ -373,7 +373,6 @@ export default function DeviceActions(props: Props) {
isJsonDataDialogOpen isJsonDataDialogOpen
} = dialogState; } = dialogState;
console.log(canWrite)
return ( return (
<React.Fragment> <React.Fragment>
<DeviceSettings <DeviceSettings

View file

@ -39,11 +39,12 @@ interface Props {
usage?: Usage; usage?: Usage;
loading?: boolean; loading?: boolean;
disableAddTag?: boolean; disableAddTag?: boolean;
tags: pond.Tag[];
} }
export default function DeviceOverview(props: Props) { export default function DeviceOverview(props: Props) {
const [{ user, firmware }] = useGlobalState(); const [{ user, firmware }] = useGlobalState();
const { device, components, usage, loading, disableAddTag } = props; const { device, components, usage, loading, disableAddTag, tags } = props;
const prevComponents = usePrevious(components); const prevComponents = usePrevious(components);
const { info } = useSnackbar(); const { info } = useSnackbar();
const classes = useStyles(); const classes = useStyles();
@ -224,7 +225,7 @@ export default function DeviceOverview(props: Props) {
<StatusChip status="pending" /> <StatusChip status="pending" />
</Grid> </Grid>
)} )}
{user.allowedTo("provision") && <DeviceTags device={device} disableAdd={disableAddTag} />} {user.allowedTo("provision") && <DeviceTags tags={tags} device={device} disableAdd={disableAddTag} />}
</Grid> </Grid>
); );
}; };

View file

@ -22,6 +22,7 @@ import { filterByTag } from "pbHelpers/Tag";
import { useDeviceAPI, useSnackbar, useTagAPI } from "providers"; import { useDeviceAPI, useSnackbar, useTagAPI } from "providers";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
const useStyles = makeStyles((_theme: Theme) => { const useStyles = makeStyles((_theme: Theme) => {
return ({ return ({
@ -128,6 +129,7 @@ function DeviceTag(props: DeviceTagProps) {
interface DeviceTagsProps { interface DeviceTagsProps {
device: Device; device: Device;
disableAdd?: boolean; disableAdd?: boolean;
tags: pond.Tag[];
} }
export default function DeviceTags(props: DeviceTagsProps) { export default function DeviceTags(props: DeviceTagsProps) {
@ -155,19 +157,45 @@ export default function DeviceTags(props: DeviceTagsProps) {
} }
useEffect(() => { useEffect(() => {
console.log(tags) console.log(props.tags)
}, [tags]) let newTags: string[] = []
props.tags.forEach(tag => {
if (tag.settings) newTags.push(tag.settings?.key)
})
setDeviceTags(newTags)
}, [props.tags])
useEffect(() => { useEffect(() => {
loadTags() loadTags()
}, []) }, [])
useEffect(() => { // useEffect(() => {
if (previousDeviceRef.current !== device) { // // if (previousDeviceRef.current !== device) {
setDeviceTags(device.status.tagKeys); // let keys = getContextKeys()
previousDeviceRef.current = device; // keys.push(device.id().toString())
} // let types = getContextTypes()
}, [device]); // types.push("device")
// setDeviceTags(device.status.tagKeys);
// previousDeviceRef.current = device;
// tagAPI.listTags(
// undefined,
// undefined,
// undefined,
// undefined,
// undefined,
// undefined,
// keys,
// types,
// ).then(resp => {
// // console.log(resp.data)
// let newTagKeys: string[] = []
// resp.data.tags.forEach((tag: any) => {
// newTagKeys.push(tag.settings.key)
// })
// setDeviceTags(newTagKeys)
// })
// // }
// }, [device]);
const addTag = (tag: Tag) => { const addTag = (tag: Tag) => {
if (!deviceTags.some(dt => dt === tag.key())) { if (!deviceTags.some(dt => dt === tag.key())) {
@ -195,12 +223,6 @@ export default function DeviceTags(props: DeviceTagsProps) {
return null; return null;
} }
if (loading) {
return (
<CircularProgress />
)
}
return ( return (
<React.Fragment> <React.Fragment>
{deviceTags.map(key => { {deviceTags.map(key => {

View file

@ -24,6 +24,7 @@ export default function DevicePage() {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [permissions, setPermissions] = useState<pond.Permission[]>([]) const [permissions, setPermissions] = useState<pond.Permission[]>([])
const [preferences, setPreferences] = useState<pond.DevicePreferences>(pond.DevicePreferences.create()) const [preferences, setPreferences] = useState<pond.DevicePreferences>(pond.DevicePreferences.create())
const [tags, setTags] = useState<pond.Tag[]>([]);
const [cellularUsage, _setCellularUsage] = useState<number>(0); const [cellularUsage, _setCellularUsage] = useState<number>(0);
const [cellularStatus, _setCellularStatus] = useState<string>(""); const [cellularStatus, _setCellularStatus] = useState<string>("");
@ -55,6 +56,7 @@ export default function DevicePage() {
setPermissions(newPermissions) setPermissions(newPermissions)
let u = User.any(resp.data.user); let u = User.any(resp.data.user);
setPreferences(u.preferences) setPreferences(u.preferences)
setTags(resp.data.tags)
}).catch(err => { }).catch(err => {
setDevice(Device.create()); setDevice(Device.create());
// setComponents(new Map()); // setComponents(new Map());
@ -79,10 +81,6 @@ export default function DevicePage() {
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }
useEffect(() => {
console.log(permissions)
}, [permissions])
useEffect(() => { useEffect(() => {
loadDevice() loadDevice()
}, [deviceID]) }, [deviceID])
@ -138,6 +136,7 @@ export default function DevicePage() {
components={[]} components={[]}
usage={getUsage()} usage={getUsage()}
loading={loading} loading={loading}
tags={tags}
/> />
</PageContainer> </PageContainer>
); );

View file

@ -164,7 +164,6 @@ export default function Devices() {
const loadDevices = () => { const loadDevices = () => {
setDevicesLoading(true) setDevicesLoading(true)
console.log(getKeys())
deviceAPI.list( deviceAPI.list(
limit, limit,
page*limit, page*limit,

View file

@ -2,13 +2,23 @@ import { useHTTP } from "hooks";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import { createContext, PropsWithChildren, useContext } from "react"; import { createContext, PropsWithChildren, useContext } from "react";
import { pondURL } from "./pond"; import { pondURL } from "./pond";
import { useGlobalState } from "providers/StateContainer";
export interface ITagAPIContext { export interface ITagAPIContext {
addTag: (tag: pond.TagSettings) => Promise<any>; addTag: (tag: pond.TagSettings) => Promise<any>;
updateTag: (tagID: string, tag: pond.TagSettings) => Promise<any>; updateTag: (tagID: string, tag: pond.TagSettings) => Promise<any>;
removeTag: (tagID: string) => Promise<any>; removeTag: (tagID: string) => Promise<any>;
getTag: (tagID: string) => Promise<any>; getTag: (tagID: string) => Promise<any>;
listTags: () => Promise<any>; listTags: (
limit?: number,
offset?: number,
order?: "asc" | "desc",
orderBy?: string,
search?: string,
asRoot?: boolean,
keys?: string[],
types?: string[]
) => Promise<any>;
} }
export const TagAPIContext = createContext<ITagAPIContext>({} as ITagAPIContext); export const TagAPIContext = createContext<ITagAPIContext>({} as ITagAPIContext);
@ -18,6 +28,7 @@ interface Props {}
export default function TagProvider(props: PropsWithChildren<Props>) { export default function TagProvider(props: PropsWithChildren<Props>) {
const { children } = props; const { children } = props;
const { get, del, put, post } = useHTTP(); const { get, del, put, post } = useHTTP();
const [{ as }] = useGlobalState()
const addTag = (tag: pond.TagSettings) => { const addTag = (tag: pond.TagSettings) => {
return post(pondURL("/tags"), tag); return post(pondURL("/tags"), tag);
@ -35,8 +46,37 @@ export default function TagProvider(props: PropsWithChildren<Props>) {
return get(pondURL("/tags/" + tagID)); return get(pondURL("/tags/" + tagID));
}; };
const listTags = () => { // const listTags = () => {
return get(pondURL("/tags"));
// return get(pondURL("/tags"));
// };
const listTags = (
limit?: number,
offset?: number,
order?: "asc" | "desc",
orderBy?: string,
search?: string,
asRoot?: boolean,
keys?: string[],
types?: string[]
) => {
limit = limit ? limit : 100
const url = pondURL(
"/tags" +
"?limit=" +
limit +
"&offset=" +
offset +
("&order=" + (order ? order : "asc")) +
("&by=" + (orderBy ? orderBy : "deviceId")) +
(search ? "&search=" + search : "") +
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
(as && !(types && types.length > 0 && types[0] === "team") ? "&as=" + as : "") +
(keys ? "&keys=" + keys.toString() : "") +
(types ? "&types=" + types.toString() : "")
);
return get<pond.ListDevicesResponse>(url);
}; };
return ( return (