Skip to content

Commit

Permalink
Merge branch 'main' of github.com:max-at-groundlight/generic_groundli…
Browse files Browse the repository at this point in the history
…ght_server into maxm/32/ecr

pull main into branch
  • Loading branch information
Max McKelvey authored and Max McKelvey committed Sep 12, 2023
2 parents 817214a + 3b4e96f commit ad4b16e
Show file tree
Hide file tree
Showing 17 changed files with 266 additions and 264 deletions.
252 changes: 51 additions & 201 deletions app/detectors/page.tsx

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client"

import { BASE_SERVER_URL } from "@/utils/config";
import Link from "next/link";
import { useEffect, useState } from "react";

Expand All @@ -12,7 +11,7 @@ export default function Home() {

useEffect(() => {
// fetch detector configs
fetch(BASE_SERVER_URL + "/api/config").then((res) => res.json()).then((data) => {
fetch("/api/config").then((res) => res.json()).then((data) => {
setIsDet(!!data.detectors && data.detectors.length > 0);
setIsApiKey(!!data.api_key && data.api_key != "");
setIsImgSrc(!!data.image_sources && data.image_sources.length > 0);
Expand Down Expand Up @@ -47,7 +46,7 @@ export default function Home() {
<input className="rounded-md w-8 ml-auto" type="checkbox" checked={isDet} readOnly />
</Link>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold px-6 py-3 m-1 w-40 rounded-xl" onClick={() => {
fetch(BASE_SERVER_URL + "/api/finished_intro").then(() => setIntroCompleted(true));
fetch("/api/finished_intro").then(() => setIntroCompleted(true));
}}>
{(isApiKey && isImgSrc && isDet) ? "Continue!" : "Skip"}
</button>
Expand Down
11 changes: 5 additions & 6 deletions app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client"

import { BASE_SERVER_URL } from "@/utils/config";
import { useEffect, useState } from "react";

export default function Page() {
Expand All @@ -11,15 +10,15 @@ export default function Page() {

const updateState = () => {
// update json data url
fetch(BASE_SERVER_URL + "/api/config-json-pretty").then((res) => res.json()).then((data) => {
fetch("/api/config-json-pretty").then((res) => res.json()).then((data) => {
setJsonDataUrl(`data:application/json,${encodeURIComponent(data)}`);
});
// update yaml data url
fetch(BASE_SERVER_URL + "/api/config-yaml-pretty").then((res) => res.json()).then((data) => {
fetch("/api/config-yaml-pretty").then((res) => res.json()).then((data) => {
setYamlDataUrl(`data:application/yaml,${encodeURIComponent(data)}`);
});
// fetch detector configs
fetch(BASE_SERVER_URL + "/api/config").then((res) => res.json()).then((data) => {
fetch("/api/config").then((res) => res.json()).then((data) => {
setApiKeyTemp(data.api_key && data.api_key != "" ? (data.api_key as string).substring(0, 15) + "..." : "");
});
}
Expand All @@ -30,7 +29,7 @@ export default function Page() {

const saveApiKey = (apiKey: string) => {
// save api key
fetch(BASE_SERVER_URL + "/api/config/api_key", {
fetch("/api/config/api_key", {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand All @@ -45,7 +44,7 @@ export default function Page() {

const uploadConfig = (config: string) => {
// upload config
fetch(BASE_SERVER_URL + "/api/set_config", {
fetch("/api/set_config", {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand Down
52 changes: 7 additions & 45 deletions app/sources/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,17 @@

import { NewCameraOverlay } from "@/components/NewCameraOverlay";
import { Spinner } from "@/components/Spinner";
import { BASE_SERVER_URL } from "@/utils/config";
import { useImageSources } from "@/utils/useImageSources";
import { ArrowPathIcon, PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
import { useEffect, useState } from "react";
import { useState } from "react";

export default function VideoPage() {
const [cameras, setCameras] = useState<CameraType[] | undefined>(undefined);
const [camerasWaiting, setCamerasWaiting] = useState<boolean[]>([]);
const { imageSources: cameras, imageSourcesLoaded, refreshImageSource, refetchImageSources: fetchCameras } = useImageSources();
const camerasWaiting = imageSourcesLoaded.map(val => !val);
const [addCameraOverlayOpen, setAddCameraOverlayOpen] = useState<boolean>(false);

const fetchCameras = () => {
fetch(BASE_SERVER_URL + "/api/cameras").then((res) => res.json()).then((data) => {
setCameras(data as CameraType[] ? data as CameraType[] : []);
if (data as CameraType[]) setCamerasWaiting(new Array((data as CameraType[]).length).fill(false));
});
}

useEffect(() => {
fetchCameras();
}, []);

const refreshCamera = (idx: number, camera_config: CameraConfigType) => {
// set camera waiting
const cameras_waiting_copy = camerasWaiting.slice();
cameras_waiting_copy[idx] = true;
setCamerasWaiting(cameras_waiting_copy);

// fetch cameras
fetch(BASE_SERVER_URL + "/api/refresh-camera", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(camera_config)
}).then((res) => res.json()).then((data) => {
if (!cameras) return;
const cameras_copy = cameras.slice();
if (!(cameras[idx].config === camera_config)) return;
cameras_copy[idx].image = data.image;
setCameras(cameras_copy);

// set camera waiting false
const cameras_waiting_copy = camerasWaiting.slice();
cameras_waiting_copy[idx] = false;
setCamerasWaiting(cameras_waiting_copy);
});
}

const autodetect = () => {
fetch(BASE_SERVER_URL + "/api/cameras/autodetect", {
fetch("/api/cameras/autodetect", {
method: "POST",
headers: {
"Content-Type": "application/json"
Expand All @@ -59,7 +21,7 @@ export default function VideoPage() {
}

const deleteCamera = (idx: number) => {
fetch(BASE_SERVER_URL + "/api/cameras/delete", {
fetch("/api/cameras/delete", {
method: "POST",
headers: {
"Content-Type": "application/json"
Expand All @@ -79,7 +41,7 @@ export default function VideoPage() {
camera.image ?
<div className="relative m-1">
<img src={`data:image/jpeg;base64,${camera.image}`} width={640} height={480} key={index} alt={camera.config.name} className="rounded" />
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded absolute -right-1 -bottom-1" onClick={() => refreshCamera(index, camera.config)}>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded absolute -right-1 -bottom-1" onClick={() => refreshImageSource(index)}>
<ArrowPathIcon className={`h-4 w-4 ${camerasWaiting[index] && "animate-spin"}`} />
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/EditDetectorOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from "react";
import { Dropdown } from "./Dropdown";
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
import useEscape from "@/hooks/useEscape";
import useEscape from "@/utils/useEscape";

export const EditDetectorOverlay = ({ detector, detectors, index, startWithNew, onSave, onDelete, onBack }:
{ detector: DetType, detectors: DetBaseType[], index: number, startWithNew?: boolean, onSave: (e: { detector: DetType, isNewDetector: boolean, index: number }) => void, onDelete: (e: any) => void, onBack: () => void }
Expand Down
2 changes: 1 addition & 1 deletion components/EditNotificationsOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from "react";
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/24/outline";
import ReactSwitch from "react-switch";
import { PushStacklightConfigButton } from "./PushStacklightConfigButton";
import useEscape from "@/hooks/useEscape";
import useEscape from "@/utils/useEscape";
import { Dropdown } from "./Dropdown";
import Link from "next/link";

Expand Down
3 changes: 1 addition & 2 deletions components/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client"

import { BASE_SERVER_URL } from "@/utils/config";
import { Cog6ToothIcon } from "@heroicons/react/24/outline";
import Link from "next/link";
import { useEffect, useState } from "react";
Expand All @@ -12,7 +11,7 @@ export const Nav = () => {

useEffect(() => {
// fetch intro completed
fetch(BASE_SERVER_URL + "/api/config").then((res) => res.json()).then((data) => {
fetch("/api/config").then((res) => res.json()).then((data) => {
setIntroCompleted(!!data.intro_sequence_finished && data.intro_sequence_finished);
});
}, []);
Expand Down
3 changes: 1 addition & 2 deletions components/NewCameraOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState } from "react";
import { Dropdown } from "./Dropdown";
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
import { BASE_SERVER_URL } from "@/utils/config";

const CameraTypes = ["RTSP Feed"];

Expand All @@ -12,7 +11,7 @@ export const NewCameraOverlay = ({ onBack }: { onBack: () => void }) => {

const makeNewImageSource = async () => {
if (srcType == "RTSP Feed") {
await fetch(BASE_SERVER_URL + "/api/cameras/new", {
await fetch("/api/cameras/new", {
method: "POST",
headers: {
"Content-Type": "application/json"
Expand Down
1 change: 0 additions & 1 deletion public/next.svg

This file was deleted.

1 change: 0 additions & 1 deletion public/vercel.svg

This file was deleted.

1 change: 0 additions & 1 deletion utils/config.ts

This file was deleted.

5 changes: 5 additions & 0 deletions utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ type DetType = {
config: DetConfType;
};

type DetExpType = DetType & {
delete: () => void;
edit: (det: DetType) => void;
};

type DetBaseType = {
name: string;
id: string;
Expand Down
30 changes: 30 additions & 0 deletions utils/useAvailableDetectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useEffect, useState } from "react";

export const useAvailableDetectors = () => {
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [detectors, setDetectors] = useState<DetBaseType[]>([]);

const fetchDetectors = async () => {
setIsLoading(true);
setIsError(false);
try {
const res = await fetch("/api/detectors");
const data = await res.json();
setDetectors(data);
} catch (err) {
setIsError(true);
}
setIsLoading(false);
};

useEffect(() => {
fetchDetectors();
}, []);

const refetchDetectors = () => {
fetchDetectors();
}

return { isLoading, isError, detectors: detectors, refetchDetectors: refetchDetectors };
}
97 changes: 97 additions & 0 deletions utils/useDetectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"use client"

import { useEffect, useState } from "react";

export const useDetectors = () => {
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [detectors, setDetectors] = useState<DetType[]>([]);
const [detectorsByGroup, setDetectorsByGroup] = useState<DetExpType[][]>([]);

console.log("useDetectors")
console.log(detectors)

const saveDetectors = async (detectors_to_save: DetType[]) => {
// save detector configs
await fetch("/api/config/detectors", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
detectors: detectors_to_save,
}),
})
};

const saveAndFetch = async (detectors_to_save: DetType[]) => {
await saveDetectors(detectors_to_save);
await fetchConfig();
}

const deleteDetector = async (index: number) => {
setDetectors((prev) => {
const new_detectors = prev.filter((_, i) => i !== index);
saveAndFetch(new_detectors);
return new_detectors;
});
}

const editDetector = async (index: number, det: DetType) => {
setDetectors((prev) => {
const new_detectors = prev.map((d, i) => i === index ? det : d);
saveAndFetch(new_detectors);
return new_detectors;
});
}

const fetchConfig = async () => {
setIsLoading(true);
try {
await fetch("/api/config").then((res) => res.json()).then((data) => {
console.log("fetchConfig", data.detectors)
setDetectors(data.detectors as DetType[] ? data.detectors as DetType[] : []);
if (data?.detectors) {
const detByGroup = (data.detectors as DetType[]).reduce((acc: DetExpType[][], cur: DetType, old_idx: number) => {
const idx = acc.reduce((pre: number, group: DetType[], idx) => group[0].name === cur.name ? idx : pre, -1);
const new_exp_det = {
...cur,
delete: () => deleteDetector(old_idx),
edit: (det: DetType) => editDetector(old_idx, det),
};
if (idx !== -1) acc[idx].push(new_exp_det);
else acc.push([new_exp_det]);
return acc;
}, []);
setDetectorsByGroup(detByGroup);
}
return data;
});
} catch {
setIsError(true);
}
setIsLoading(false);
}

useEffect(() => {
fetchConfig();
}, []);

const refetchDetectors = async () => {
fetchConfig();
}

const newDetector = async (det: DetType) => {
let detectors_copy = [...detectors];
detectors_copy.push(det);
await saveDetectors(detectors_copy);
await fetchConfig();
return {
...det,
delete: () => deleteDetector(detectors_copy.length - 1),
edit: (det: DetType) => editDetector(detectors_copy.length - 1, det),
}
}

return { isLoading, isError, detectors, detectorsByGroup, refetchDetectors, newDetector };
}
File renamed without changes.
Loading

0 comments on commit ad4b16e

Please sign in to comment.