Skip to content
Open
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
42 changes: 34 additions & 8 deletions src/features/DebugConsole/DebugConsole.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { skipToken } from '@reduxjs/toolkit/query';
import { useState } from "react";
import { Alert, Button, Form } from "react-bootstrap";
import ListFiltersHeader from "../../shared/ListFiltersHeader";
import { useState } from 'react';
import { Alert, Button, Form } from 'react-bootstrap';
import ListFiltersHeader from '../../shared/ListFiltersHeader';
import useAppParams from '../../shared/hooks/useAppParams';
import {
useGetDoNotLoadConfigOnNextBootQuery,
useSetDoNotLoadConfigOnNextBootMutation,
useSetLoadConfigMutation,
useSetRestartMutation
} from "../../store/apiSlice";
} from '../../store/apiSlice';
import { selectSearchText } from '../../store/debugConsole/debugConsoleSelectors';
import { debugConsoleActions } from '../../store/debugConsole/debugConsoleSlice';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import type { RootState } from '../../store/store';
import ConsoleWindow from "./ConsoleWindow";
import { DebugFilters } from "./DebugFilters";
import ConsoleWindow from './ConsoleWindow';
import { DebugFilters } from './DebugFilters';
import MinimumLogLevelDropdown from './MinimumLogLevelDropdown';
import RestartConfirmModal from "./RestartConfirmModal";
import { useFilteredMessages } from "./hooks/useFilteredMessages";
import RestartConfirmModal from './RestartConfirmModal';
import { useFilteredMessages } from './hooks/useFilteredMessages';

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

const exportFilteredItems = () => {
const content = filteredItems
.map((item) => `${item.Timestamp} [${item.Level}]${item.Properties?.Key ? ` [${item.Properties.Key}]` : ''} ${item.RenderedMessage}`)
.join('\n');
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `debug-log-${new Date().toISOString().replace(/[:.]/g, '-')}.log`;
document.body.appendChild(a);
a.click();
setTimeout(() => {
Comment on lines +48 to +55
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
};

const clickRestart = () => {
setShowModal(true);
};
Expand Down Expand Up @@ -104,6 +121,15 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => {
>
Clear Console Trace
</Button>
<Button
className="mx-1"
variant="primary"
size="sm"
onClick={exportFilteredItems}
disabled={filteredItems.length === 0}
>
Export Log
</Button>
<Button
className="mx-1"
variant="primary"
Expand Down
2 changes: 1 addition & 1 deletion src/features/DebugConsole/DebugFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const DebugFilters = () => {

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

return [{ id: debugConsts.GLOBAL, label: 'Global' }, ...deviceItems];
}, [devices]);
Expand Down
2 changes: 1 addition & 1 deletion src/features/DebugConsole/DeviceFilterDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => {
<Form.Check
type="checkbox"
id={`device-check-${stringId}`}
label={item.label}
label={`${item.label} (${stringId})`}
checked={isChecked}
Comment on lines 66 to 70
onChange={(e) => handleCheckChange(e, stringId)}
className="flex-grow-1 m-0"
Expand Down
22 changes: 11 additions & 11 deletions src/features/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FormEvent, useState } from "react";
import { Alert, Button, Form, Spinner } from "react-bootstrap";
import { Navigate, useLocation, useNavigate } from "react-router-dom";
import useAppParams from "../shared/hooks/useAppParams";
import { useSetLoginCredentialsMutation } from "../store/apiSlice";
import { FormEvent, useState } from 'react';
import { Alert, Button, Form, Spinner } from 'react-bootstrap';
import { Navigate, useLocation, useNavigate } from 'react-router-dom';
import useAppParams from '../shared/hooks/useAppParams';
import { useSetLoginCredentialsMutation } from '../store/apiSlice';
import {
selectAvailableApps,
selectIsAuthenticated,
} from "../store/auth/authSelectors";
import { authActions } from "../store/auth/authSlice";
import { useAppDispatch, useAppSelector } from "../store/hooks";
} from '../store/auth/authSelectors';
import { authActions } from '../store/auth/authSlice';
import { useAppDispatch, useAppSelector } from '../store/hooks';

const ALL_APP_IDS = [
"app01",
Expand Down Expand Up @@ -53,7 +53,7 @@ const LoginForm = () => {
setError(null);
setIsLoading(true);

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

setIsLoading(false);

if (availableApps.length === 0) {
setIsLoading(false);
setError("Invalid credentials. Please try again.");
return;
}

setIsLoading(false);
dispatch(authActions.loginSuccess(availableApps));

const destination = from ?? `/${availableApps[0] ?? probeAppId}/versions`;
Expand Down
2 changes: 1 addition & 1 deletion src/shared/FilterSearchText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const FilterSearchText = ({
onChangeValue(val);
} else {
// URL params mode (default)
const tokens = val.split(" ");
const tokens = val.split(' ').filter(Boolean);
searchParams.delete(PARAM);
if (val.length) tokens.forEach((t) => searchParams.append(PARAM, t));
setSearchParams(searchParams);
Expand Down