Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/homesec #82

Merged
merged 18 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
node-version: [20.x]
steps:
- name: Check out the repo 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
uses: docker/metadata-action@v5
with:
images: mdworld/homeremote

Expand All @@ -40,7 +40,7 @@ jobs:

- name: Build and push Docker image
# if: ${{ github.ref == 'main' }}
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
uses: docker/build-push-action@v5
with:
context: .
push: true
Expand Down
21 changes: 15 additions & 6 deletions .github/workflows/validateAndBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@ jobs:

strategy:
matrix:
node-version: [16.x]
node-version: [20.x]

steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install and Build components 🔧
- name: Install dependencies ⚙️
run: |
npm i --legacy-peer-deps
# Workaround for missing binary
npm i @swc/core-linux-x64-gnu --legacy-peer-deps
npm run build --if-present
- name: writeGitInfo ✍️
run: npm run writeGitInfo --if-present
- name: Typecheck 🤙
run: npm run typecheck --if-present
- name: Lint 👌
run: npm run lint --if-present
- name: Test 🧪
run: npm run test:ci --if-present
env:
CI: false # true -> fails on warning
- name: Build docker image
- name: Build components 🔧
run: npm run build --ignore-scripts --if-present
- name: Build docker image 💿
if: ${{ github.ref == 'main' }}
run: |
docker build . -t mdworld/homeremote:latest
10 changes: 7 additions & 3 deletions apps/client/src/Components/Molecules/DockerInfo/DockerInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DockerContainerInfo } from "@homeremote/types";
import {
Alert,
Button,
Expand All @@ -10,15 +11,14 @@ import {
} from "@mui/material";
import { FC, useState } from "react";
import {
DockerContainerInfo,
useStartDockerMutation,
useStopDockerMutation,
} from "../../../Services/dockerListApi";

const DockerInfo: FC<{ info: DockerContainerInfo }> = ({ info }) => {
const [startDocker] = useStartDockerMutation();
const [stopDocker] = useStopDockerMutation();
const { Names, Status, Id, State } = info;
const { Names, Status, Id, State, Labels } = info;
const isUp = Status.indexOf("Up") === 0;

const toggleContainer = () => {
Expand Down Expand Up @@ -50,7 +50,11 @@ const DockerInfo: FC<{ info: DockerContainerInfo }> = ({ info }) => {
cursor: "pointer",
}}
>
{name} | {Status}
{name}{" "}
{Labels["com.docker.compose.project"]
? `(${Labels["com.docker.compose.project"]})`
: ""}{" "}
| {Status}
</Alert>
<Dialog
open={open}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DockerContainerInfo } from "@homeremote/types";
import { Box } from "@mui/material";
import { FC } from "react";
import { DockerContainerInfo } from "../../../Services/dockerListApi";

const ContainerDot: FC<{ info: DockerContainerInfo }> = ({ info }) => (
<Box
Expand Down
23 changes: 10 additions & 13 deletions apps/client/src/Components/Molecules/DockerList/DockerList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Alert, Box, Grid } from "@mui/material";
import { DockerContainerInfo } from "@homeremote/types";
import { Box, Grid } from "@mui/material";
import { Stack } from "@mui/system";
import { FC, useEffect, useState } from "react";
import {
DockerContainerInfo,
useGetDockerListQuery,
} from "../../../Services/dockerListApi";
import { useGetDockerListQuery } from "../../../Services/dockerListApi";
import { getErrorMessage } from "../../../Utils/getErrorMessage";
import CardExpandBar from "../CardExpandBar/CardExpandBar";
import DockerInfo from "../DockerInfo/DockerInfo";
import ErrorRetry from "../ErrorRetry/ErrorRetry";
import LoadingDot from "../LoadingDot/LoadingDot";
import ContainerDot from "./ContainerDot";

Expand All @@ -22,14 +21,12 @@ interface DockerListProps {
const DockerList: FC<DockerListProps> = ({ onError }) => {
const [isOpen, setIsOpen] = useState(false);
const [isSkippingBecauseError, setIsSkippingBecauseError] = useState(false);
const { data, isLoading, isFetching, error } = useGetDockerListQuery(
undefined,
{
const { data, isLoading, isFetching, error, refetch } =
useGetDockerListQuery(undefined, {
pollingInterval: isSkippingBecauseError
? undefined
: UPDATE_INTERVAL_MS,
}
);
});

useEffect(() => {
if (error) {
Expand All @@ -40,9 +37,9 @@ const DockerList: FC<DockerListProps> = ({ onError }) => {

if (error) {
return (
<Box mx={-2}>
<Alert severity="error">{getErrorMessage(error)}</Alert>
</Box>
<ErrorRetry retry={() => refetch()}>
DockerList could not load
</ErrorRetry>
);
}

Expand Down
28 changes: 15 additions & 13 deletions apps/client/src/Components/Molecules/DownloadList/DownloadList.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { List, Paper } from "@mui/material";
import { FC, useEffect, useState } from "react";
import { Alert, List, Paper } from "@mui/material";
import { useAppDispatch } from "../../../store";
import DownloadListItem from "./DownloadListItem";
import { logError } from "../LogCard/logSlice";
import { useGetDownloadListQuery } from "../../../Services/downloadListApi";
import { getErrorMessage } from "../../../Utils/getErrorMessage";
import { useAppDispatch } from "../../../store";
import CardExpandBar from "../CardExpandBar/CardExpandBar";
import ErrorRetry from "../ErrorRetry/ErrorRetry";
import LoadingDot from "../LoadingDot/LoadingDot";
import { logError } from "../LogCard/logSlice";
import DownloadListItem from "./DownloadListItem";

const UPDATE_INTERVAL_MS = 30000;

Expand All @@ -14,20 +16,20 @@ const DownloadList: FC = () => {
const [isSkippingBecauseError, setIsSkippingBecauseError] = useState(false);
const dispatch = useAppDispatch();

const { data, error, isLoading, isFetching } = useGetDownloadListQuery(
undefined,
{
const { data, error, isLoading, isFetching, refetch } =
useGetDownloadListQuery(undefined, {
pollingInterval: isSkippingBecauseError
? undefined
: UPDATE_INTERVAL_MS,
}
);
});
const [listItems, setListItems] = useState<JSX.Element[]>([]);

useEffect(() => {
if (error) {
setIsSkippingBecauseError(true);
dispatch(logError("GetDownloadList failed"));
dispatch(
logError(`GetDownloadList failed: ${getErrorMessage(error)}`)
);
}
}, [dispatch, error]);

Expand All @@ -50,9 +52,9 @@ const DownloadList: FC = () => {
<List component={Paper}>
<LoadingDot isLoading={isLoading || isFetching} />
{error && (
<Alert severity="error">
There is an error, data may be stale
</Alert>
<ErrorRetry marginate retry={() => refetch()}>
DL could not load
</ErrorRetry>
)}
{listItems}
<CardExpandBar
Expand Down
52 changes: 52 additions & 0 deletions apps/client/src/Components/Molecules/ErrorRetry/ErrorRetry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import RestartAltIcon from "@mui/icons-material/RestartAlt";
import { Alert, Box, IconButton, Tooltip } from "@mui/material";
import { FC, PropsWithChildren } from "react";

interface Props extends PropsWithChildren {
marginate?: boolean;
retry: () => void;
}

export const ErrorRetry: FC<Props> = ({
marginate = false,
children,
retry,
}) => {
return (
<Box
mx={marginate ? undefined : -2}
component={Alert}
severity="error"
square
sx={{
".MuiAlert-message": {
width: "100%",
},
}}
>
<Box
display="flex"
flex={1}
flexDirection="row"
justifyContent="space-between"
>
<div>{children}</div>
<Tooltip title="Retry">
<IconButton
size="small"
onClick={retry}
sx={{
".MuiSvgIcon-root": {
marginTop: "-0.5rem",
},
}}
>
<RestartAltIcon />
</IconButton>
</Tooltip>
</Box>
</Box>
);
};

export default ErrorRetry;
38 changes: 38 additions & 0 deletions apps/client/src/Components/Molecules/HomeSec/HomeSec.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { HomesecStatusResponse } from "@homeremote/types";
import { render, screen } from "@testing-library/react";
import fetchMock, { enableFetchMocks } from "jest-fetch-mock";
import { FC, ReactNode } from "react";
import { homesecApi } from "../../../Services/homesecApi";
import { MockStoreProvider } from "../../../testHelpers";
import HomeSec from "./HomeSec";

enableFetchMocks();

const Wrapper: FC<{ children: ReactNode }> = ({ children }) => {
return (
<MockStoreProvider apis={[homesecApi]}>{children}</MockStoreProvider>
);
};

describe("HomeSec", () => {
it("shows status and list of devices", async () => {
const mockStatusResponse: HomesecStatusResponse = {
status: "Disarm",
devices: [
{
id: "1",
name: "Front door",
status: "Door Close",
rssi: "Strong, 9",
type_f: "Door Contact",
cond_ok: "1",
},
],
};
fetchMock.mockResponse(JSON.stringify(mockStatusResponse));
render(<HomeSec />, { wrapper: Wrapper });

await screen.findByText("sensor_door");
expect(screen.getByText("Front door")).toBeVisible();
});
});
Loading