mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 23:14:37 +00:00
feat(settings): present desktop Settings as a full-app modal overlay (#4002)
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useT } from '../../lib/i18n/I18nContext';
|
||||
import type { SubconsciousMode } from '../../utils/tauriCommands/heartbeat';
|
||||
import type { SubconsciousStatus } from '../../utils/tauriCommands/subconscious';
|
||||
import { settingsNavState } from '../settings/modal/settingsOverlay';
|
||||
|
||||
interface ModeOption {
|
||||
id: SubconsciousMode;
|
||||
@@ -67,6 +68,7 @@ export default function IntelligenceSubconsciousTab({
|
||||
}: IntelligenceSubconsciousTabProps) {
|
||||
const { t } = useT();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const providerUnavailable = status?.provider_available === false;
|
||||
const providerUnavailableReason = providerUnavailable
|
||||
? (status?.provider_unavailable_reason ?? t('subconscious.providerUnavailableTitle'))
|
||||
@@ -238,7 +240,7 @@ export default function IntelligenceSubconsciousTab({
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/settings/llm')}
|
||||
onClick={() => navigate('/settings/llm', settingsNavState(location))}
|
||||
className="flex-shrink-0 rounded-md bg-amber-600 px-2.5 py-1.5 text-xs font-medium text-white hover:bg-amber-700 transition-colors">
|
||||
{t('subconscious.providerSettings')}
|
||||
</button>
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
LuSparkles,
|
||||
LuX,
|
||||
} from 'react-icons/lu';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useT } from '../../lib/i18n/I18nContext';
|
||||
import { TaskKanbanBoard } from '../../pages/conversations/components/TaskKanbanBoard';
|
||||
@@ -48,6 +48,7 @@ import {
|
||||
import type { ThreadMessage } from '../../types/thread';
|
||||
import type { TaskBoard, TaskBoardCard, TaskBoardCardStatus } from '../../types/turnState';
|
||||
import { chatThreadPath } from '../../utils/chatRoutes';
|
||||
import { settingsNavState } from '../settings/modal/settingsOverlay';
|
||||
import { UserTaskComposer } from './UserTaskComposer';
|
||||
|
||||
const log = debug('intelligence:tasks');
|
||||
@@ -779,6 +780,7 @@ function TaskSourceTaskList({
|
||||
}) {
|
||||
const { t } = useT();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const sortedCards = useMemo(
|
||||
() => [...board.cards].sort((a, b) => a.order - b.order),
|
||||
[board.cards]
|
||||
@@ -797,7 +799,7 @@ function TaskSourceTaskList({
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/settings/integrations')}
|
||||
onClick={() => navigate('/settings/integrations', settingsNavState(location))}
|
||||
className="text-xs font-medium text-ocean-600 hover:text-ocean-700 dark:text-ocean-300 dark:hover:text-ocean-200">
|
||||
{t('conversations.taskKanban.sources.manage')}
|
||||
</button>
|
||||
|
||||
@@ -9,7 +9,16 @@ import IntelligenceSubconsciousTab from '../IntelligenceSubconsciousTab';
|
||||
|
||||
const mockNavigate = vi.fn();
|
||||
|
||||
vi.mock('react-router-dom', () => ({ useNavigate: () => mockNavigate }));
|
||||
vi.mock('react-router-dom', () => ({
|
||||
useNavigate: () => mockNavigate,
|
||||
useLocation: () => ({
|
||||
pathname: '/intelligence',
|
||||
search: '',
|
||||
hash: '',
|
||||
state: null,
|
||||
key: 'test',
|
||||
}),
|
||||
}));
|
||||
|
||||
function baseProps(): ComponentProps<typeof IntelligenceSubconsciousTab> {
|
||||
return {
|
||||
|
||||
@@ -67,7 +67,17 @@ vi.mock('../../../store/hooks', () => ({
|
||||
|
||||
vi.mock('react-router-dom', async () => {
|
||||
const actual = await vi.importActual<typeof import('react-router-dom')>('react-router-dom');
|
||||
return { ...actual, useNavigate: () => hoisted.navigate };
|
||||
return {
|
||||
...actual,
|
||||
useNavigate: () => hoisted.navigate,
|
||||
useLocation: () => ({
|
||||
pathname: '/intelligence',
|
||||
search: '',
|
||||
hash: '',
|
||||
state: null,
|
||||
key: 'test',
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
// Stub the composer so we can drive its `onCreated` callback without
|
||||
@@ -276,7 +286,7 @@ describe('IntelligenceTasksTab', () => {
|
||||
// "Manage sources" jumps to the merged Integrations settings page
|
||||
// (task-sources was folded into /settings/integrations).
|
||||
fireEvent.click(screen.getByText('Manage sources'));
|
||||
expect(hoisted.navigate).toHaveBeenCalledWith('/settings/integrations');
|
||||
expect(hoisted.navigate).toHaveBeenCalledWith('/settings/integrations', expect.anything());
|
||||
});
|
||||
|
||||
test('refines a source task and approves it into the personal agent board', async () => {
|
||||
|
||||
Reference in New Issue
Block a user