mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
Let the radio settings pane open but not be used, rather than disabled
This commit is contained in:
@@ -255,12 +255,6 @@ export function App() {
|
||||
refreshUnreads,
|
||||
} = useUnreadCounts(channels, contacts, activeConversation);
|
||||
|
||||
useEffect(() => {
|
||||
if (showSettings && !config && settingsSection === 'radio') {
|
||||
setSettingsSection('local');
|
||||
}
|
||||
}, [config, settingsSection, setSettingsSection, showSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeConversation?.type !== 'channel') {
|
||||
setChannelUnreadMarker(null);
|
||||
@@ -573,7 +567,6 @@ export function App() {
|
||||
settingsSection={settingsSection}
|
||||
sidebarOpen={sidebarOpen}
|
||||
showCracker={showCracker}
|
||||
disabledSettingsSections={config ? [] : ['radio']}
|
||||
onSettingsSectionChange={setSettingsSection}
|
||||
onSidebarOpenChange={setSidebarOpen}
|
||||
onCrackerRunningChange={setCrackerRunning}
|
||||
|
||||
@@ -155,13 +155,11 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
const renderSectionHeader = (section: SettingsSection): ReactNode => {
|
||||
if (!showSectionButton) return null;
|
||||
const Icon = SETTINGS_SECTION_ICONS[section];
|
||||
const disabled = section === 'radio' && !config;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${sectionButtonClasses} disabled:cursor-not-allowed disabled:opacity-50`}
|
||||
className={sectionButtonClasses}
|
||||
aria-expanded={expandedSections[section]}
|
||||
disabled={disabled}
|
||||
onClick={() => toggleSection(section)}
|
||||
>
|
||||
<span className="inline-flex items-center gap-2 font-medium" role="heading" aria-level={3}>
|
||||
@@ -206,8 +204,8 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
/>
|
||||
) : (
|
||||
<div className={sectionContentClass}>
|
||||
<div className="rounded-md border border-input bg-muted/20 px-4 py-3 text-sm text-muted-foreground">
|
||||
Radio settings are unavailable until a radio connects.
|
||||
<div className="flex items-center justify-center py-12 text-sm text-muted-foreground">
|
||||
Radio is not available.
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -327,19 +327,17 @@ describe('App startup hash resolution', () => {
|
||||
expect(window.location.hash).toBe('');
|
||||
});
|
||||
|
||||
it('opens settings from a settings hash and falls back away from radio when disconnected', async () => {
|
||||
it('stays on radio settings section even when radio is disconnected', async () => {
|
||||
window.location.hash = '#settings/radio';
|
||||
mocks.api.getRadioConfig.mockRejectedValue(new Error('radio offline'));
|
||||
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('settings-modal-section')).toHaveTextContent('local');
|
||||
expect(screen.getByTestId('settings-modal-section')).toHaveTextContent('radio');
|
||||
});
|
||||
|
||||
for (const button of screen.getAllByRole('button', { name: 'Radio' })) {
|
||||
expect(button).toBeDisabled();
|
||||
}
|
||||
expect(window.location.hash).toBe('#settings/local');
|
||||
// Section stays on radio (no redirect to local) and hash is preserved
|
||||
expect(window.location.hash).toBe('#settings/radio');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -206,30 +206,24 @@ describe('SettingsModal', () => {
|
||||
expect(screen.getByText(/Configured radio contact capacity/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps non-radio settings available when radio config is unavailable', () => {
|
||||
it('shows radio-unavailable message when config is null', () => {
|
||||
renderModal({ config: null });
|
||||
|
||||
const radioToggle = screen.getByRole('button', { name: /Radio/i });
|
||||
expect(radioToggle).toBeDisabled();
|
||||
expect(radioToggle).not.toBeDisabled();
|
||||
|
||||
openLocalSection();
|
||||
expect(screen.getByLabelText('Local label text')).toBeInTheDocument();
|
||||
|
||||
openDatabaseSection();
|
||||
expect(screen.getByText('Delete Undecrypted Packets')).toBeInTheDocument();
|
||||
fireEvent.click(radioToggle);
|
||||
expect(screen.getByText('Radio is not available.')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows a radio-unavailable message instead of blocking the whole settings page', () => {
|
||||
it('shows radio-unavailable message in sidebar-nav mode when config is null', () => {
|
||||
renderModal({
|
||||
config: null,
|
||||
externalSidebarNav: true,
|
||||
desktopSection: 'radio',
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText('Radio settings are unavailable until a radio connects.')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Loading configuration...')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Radio is not available.')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows cached radio firmware and capacity info under the connection status', () => {
|
||||
|
||||
Reference in New Issue
Block a user