Skip to content

Commit 18afbe2

Browse files
authored
Merge pull request #32 from PepperDash/various-fixes
Various fixes
2 parents 804d099 + 21e6ead commit 18afbe2

5 files changed

Lines changed: 48 additions & 22 deletions

File tree

src/features/DebugConsole/DebugConsole.tsx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
import { skipToken } from '@reduxjs/toolkit/query';
2-
import { useState } from "react";
3-
import { Alert, Button, Form } from "react-bootstrap";
4-
import ListFiltersHeader from "../../shared/ListFiltersHeader";
2+
import { useState } from 'react';
3+
import { Alert, Button, Form } from 'react-bootstrap';
4+
import ListFiltersHeader from '../../shared/ListFiltersHeader';
55
import useAppParams from '../../shared/hooks/useAppParams';
66
import {
77
useGetDoNotLoadConfigOnNextBootQuery,
88
useSetDoNotLoadConfigOnNextBootMutation,
99
useSetLoadConfigMutation,
1010
useSetRestartMutation
11-
} from "../../store/apiSlice";
11+
} from '../../store/apiSlice';
1212
import { selectSearchText } from '../../store/debugConsole/debugConsoleSelectors';
1313
import { debugConsoleActions } from '../../store/debugConsole/debugConsoleSlice';
1414
import { useAppDispatch, useAppSelector } from '../../store/hooks';
1515
import type { RootState } from '../../store/store';
16-
import ConsoleWindow from "./ConsoleWindow";
17-
import { DebugFilters } from "./DebugFilters";
16+
import ConsoleWindow from './ConsoleWindow';
17+
import { DebugFilters } from './DebugFilters';
1818
import MinimumLogLevelDropdown from './MinimumLogLevelDropdown';
19-
import RestartConfirmModal from "./RestartConfirmModal";
20-
import { useFilteredMessages } from "./hooks/useFilteredMessages";
19+
import RestartConfirmModal from './RestartConfirmModal';
20+
import { useFilteredMessages } from './hooks/useFilteredMessages';
2121

2222
const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => {
2323
//* HOOKS ***********************************************************/
@@ -41,6 +41,23 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => {
4141
//* EFFECTS *********************************************************/
4242
const filteredItems = useFilteredMessages(messages);
4343

44+
const exportFilteredItems = () => {
45+
const content = filteredItems
46+
.map((item) => `${item.Timestamp} [${item.Level}]${item.Properties?.Key ? ` [${item.Properties.Key}]` : ''} ${item.RenderedMessage}`)
47+
.join('\n');
48+
const blob = new Blob([content], { type: 'text/plain' });
49+
const url = URL.createObjectURL(blob);
50+
const a = document.createElement('a');
51+
a.href = url;
52+
a.download = `debug-log-${new Date().toISOString().replace(/[:.]/g, '-')}.log`;
53+
document.body.appendChild(a);
54+
a.click();
55+
setTimeout(() => {
56+
document.body.removeChild(a);
57+
URL.revokeObjectURL(url);
58+
}, 0);
59+
};
60+
4461
const clickRestart = () => {
4562
setShowModal(true);
4663
};
@@ -104,6 +121,15 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => {
104121
>
105122
Clear Console Trace
106123
</Button>
124+
<Button
125+
className="mx-1"
126+
variant="primary"
127+
size="sm"
128+
onClick={exportFilteredItems}
129+
disabled={filteredItems.length === 0}
130+
>
131+
Export Log
132+
</Button>
107133
<Button
108134
className="mx-1"
109135
variant="primary"

src/features/DebugConsole/DebugFilters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const DebugFilters = () => {
2121

2222
const deviceItems: IdLabel[] = devices
2323
.map((d) => ({ id: d.Key, label: d.Name || d.Key }))
24-
.sort((a, b) => a.label.localeCompare(b.label));
24+
.sort((a, b) => a.id.localeCompare(b.id));
2525

2626
return [{ id: debugConsts.GLOBAL, label: 'Global' }, ...deviceItems];
2727
}, [devices]);

src/features/DebugConsole/DeviceFilterDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => {
6666
<Form.Check
6767
type="checkbox"
6868
id={`device-check-${stringId}`}
69-
label={item.label}
69+
label={`${item.label} (${stringId})`}
7070
checked={isChecked}
7171
onChange={(e) => handleCheckChange(e, stringId)}
7272
className="flex-grow-1 m-0"

src/features/LoginForm.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { FormEvent, useState } from "react";
2-
import { Alert, Button, Form, Spinner } from "react-bootstrap";
3-
import { Navigate, useLocation, useNavigate } from "react-router-dom";
4-
import useAppParams from "../shared/hooks/useAppParams";
5-
import { useSetLoginCredentialsMutation } from "../store/apiSlice";
1+
import { FormEvent, useState } from 'react';
2+
import { Alert, Button, Form, Spinner } from 'react-bootstrap';
3+
import { Navigate, useLocation, useNavigate } from 'react-router-dom';
4+
import useAppParams from '../shared/hooks/useAppParams';
5+
import { useSetLoginCredentialsMutation } from '../store/apiSlice';
66
import {
77
selectAvailableApps,
88
selectIsAuthenticated,
9-
} from "../store/auth/authSelectors";
10-
import { authActions } from "../store/auth/authSlice";
11-
import { useAppDispatch, useAppSelector } from "../store/hooks";
9+
} from '../store/auth/authSelectors';
10+
import { authActions } from '../store/auth/authSlice';
11+
import { useAppDispatch, useAppSelector } from '../store/hooks';
1212

1313
const ALL_APP_IDS = [
1414
"app01",
@@ -53,7 +53,7 @@ const LoginForm = () => {
5353
setError(null);
5454
setIsLoading(true);
5555

56-
// Probe all slots in parallel — credentials are valid if at least one succeeds
56+
// Send login to all program slots in parallel
5757
const results = await Promise.allSettled(
5858
ALL_APP_IDS.map((id) =>
5959
setLoginCredentials({ appId: id, username, password }).unwrap(),
@@ -64,13 +64,13 @@ const LoginForm = () => {
6464
(_, i) => results[i].status === "fulfilled",
6565
);
6666

67+
setIsLoading(false);
68+
6769
if (availableApps.length === 0) {
68-
setIsLoading(false);
6970
setError("Invalid credentials. Please try again.");
7071
return;
7172
}
7273

73-
setIsLoading(false);
7474
dispatch(authActions.loginSuccess(availableApps));
7575

7676
const destination = from ?? `/${availableApps[0] ?? probeAppId}/versions`;

src/shared/FilterSearchText.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const FilterSearchText = ({
2929
onChangeValue(val);
3030
} else {
3131
// URL params mode (default)
32-
const tokens = val.split(" ");
32+
const tokens = val.split(' ').filter(Boolean);
3333
searchParams.delete(PARAM);
3434
if (val.length) tokens.forEach((t) => searchParams.append(PARAM, t));
3535
setSearchParams(searchParams);

0 commit comments

Comments
 (0)