Skip to content
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
2 changes: 1 addition & 1 deletion src/web-ui/src/app/components/AboutDialog/AboutDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export const AboutDialog: React.FC<AboutDialogProps> = ({
<div className="bitfun-about-dialog__hero" data-bf-component="about-dialog" data-bf-part="hero">
<h1 className="bitfun-about-dialog__title" data-bf-component="about-dialog" data-bf-part="title">{version.name}</h1>
<div className="bitfun-about-dialog__version-badge" data-bf-component="about-dialog" data-bf-part="version">
{t('about.version', { version: formatVersion(version.version, version.isDev) })}
{t('about.version', { version: displayedVersion })}
</div>
<div className="bitfun-about-dialog__divider" data-bf-component="about-dialog" data-bf-part="decoration" />
<div className="bitfun-about-dialog__dots" data-bf-component="about-dialog" data-bf-part="decoration">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { useCanvasStore } from '@/app/components/panels/content-canvas/stores';
import { useToolbarModeContext } from '@/flow_chat/components/toolbar-mode/ToolbarModeContext';
import { useNotification } from '@/shared/notification-system';
import { useAccountLoginState } from '@/infrastructure/account/useAccountLoginState';
import { remoteConnectAPI } from '@/infrastructure/api/service-api/RemoteConnectAPI';
import NotificationButton from '../../TitleBar/NotificationButton';
import GithubStarButton from './GithubStarButton';
import { usePrivacy } from '../../Privacy/PrivacyContext';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import { open } from '@tauri-apps/plugin-dialog';
import {
Box,
FolderPlus,
Expand Down
4 changes: 2 additions & 2 deletions src/web-ui/src/app/scenes/settings/SettingsScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ const SettingsScene: React.FC = () => {
const setActiveTab = useSettingsStore(s => s.setActiveTab);

const resolvedTab: ConfigTab =
(activeTab as string) === 'session-config' ? 'session-personalization' : activeTab;
(activeTab as string) === 'session-config' ? 'session-permissions' : activeTab;

useEffect(() => {
/** Legacy merged session settings tab removed in favor of two panels. */
if ((activeTab as string) === 'session-config') {
setActiveTab('session-personalization');
setActiveTab('session-permissions');
}
}, [activeTab, setActiveTab]);

Expand Down
1 change: 0 additions & 1 deletion src/web-ui/src/app/scenes/settings/settingsTabI18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export const SETTINGS_TAB_I18N_NAMESPACES: Record<ConfigTab, readonly I18nNamesp
'archived-sessions': ['common'],
worktrees: ['worktrees'],
// Both session panels live in the same module and share its sub-sections.
'session-personalization': ['settings/session-config', 'settings/agentic-tools', 'settings/debug'],
'session-permissions': ['settings/session-config', 'settings/agentic-tools', 'settings/debug'],
'quick-actions': ['settings/quick-actions'],
'voice-input': ['settings/voice-input'],
Expand Down
3 changes: 1 addition & 2 deletions src/web-ui/src/app/scenes/welcome/WelcomeScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { createLogger } from '@/shared/utils/logger';
import type { SceneTabId } from '@/app/components/SceneBar/types';
import type { WorkspaceInfo } from '@/shared/types';
import { getRecentWorkspaceLineParts } from '@/shared/utils/recentWorkspaceDisplay';
import { formatRecentWorkspaceDate } from './recentWorkspaceDate';
import './WelcomeScene.scss';
import {workspaceAPI} from "@/infrastructure";

Expand Down Expand Up @@ -67,7 +66,7 @@ const WelcomeScene: React.FC = () => {
} finally {
setIsSelecting(false);
}
}, [openWorkspace, openScene, t]);
}, [openWorkspace, openScene]);

const handleNewProject = useCallback(() => {
window.dispatchEvent(new Event('nav:new-project'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ export const Modal: React.FC<ModalProps> = ({
]
.filter(Boolean)
.join(' ')}
onClick={closeOnOverlayClick ? onClose : undefined}
onClick={closeOnOverlayClick ? handleOverlayClick : undefined}
onMouseDown={handleOverlayMouseDown}
data-bf-component="modal"
data-bf-part="overlay"
Expand Down
5 changes: 4 additions & 1 deletion src/web-ui/src/flow_chat/components/ModelSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import {
type ReasoningCatalogProjection,
} from '@/infrastructure/api/service-api/AIApi';
import { ACPClientAPI, type AcpSessionOptions } from '@/infrastructure/api/service-api/ACPClientAPI';
import { getProviderDisplayName } from '@/infrastructure/config/services/modelConfigs';
import {
getProviderDisplayName,
getProviderTemplateId,
} from '@/infrastructure/config/services/modelConfigs';
import { globalEventBus } from '@/infrastructure/event-bus';
import type { AIModelConfig, AgentModelDefaultsConfig, DefaultModelsConfig } from '@/infrastructure/config/types';
import { Switch, Tooltip } from '@/component-library';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import React, { useState, useCallback, useRef } from 'react';
import { Image, Loader2 } from 'lucide-react';
import { createRoot } from 'react-dom/client';
import { FlowChatStore } from '../../store/FlowChatStore';
import { notificationService } from '@/shared/notification-system';
Expand All @@ -22,6 +23,7 @@ import { withTimeout } from '@/shared/utils/timing';
import { downloadDir, join } from '@tauri-apps/api/path';
import { writeFile } from '@tauri-apps/plugin-fs';
import { ModelThinkingDisplay } from '../../tool-cards/ModelThinkingDisplay';
import { Tooltip } from '@/component-library';
import './ExportImageButton.scss';

const log = createLogger('ExportImageButton');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import { useAIExperienceSettings } from '@/infrastructure/config/hooks';
import { isTauriRuntime } from '@/infrastructure/runtime';
import { useSceneStore } from '@/app/stores/sceneStore';
import { useSettingsStore } from '@/app/scenes/settings/settingsStore';
import { notificationService } from '@/shared/notification-system';
import { createLogger } from '@/shared/utils/logger';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import type {
SessionHistoryHydrationLocation,
} from './types';
import type { Session } from '../../types/flow-chat';
import { touchSessionActivity, cleanupSaveState, updateSessionMetadata } from './PersistenceModule';
import { cleanupSessionBuffers } from './TextChunkModule';
import { touchSessionActivity } from './PersistenceModule';
import {
createTextSessionTitleDescriptor,
createDefaultSessionTitleDescriptor,
Expand Down
15 changes: 13 additions & 2 deletions src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import type { ToolCardProps } from '../types/flow-chat';
import { Terminal, ExternalLink, Square } from 'lucide-react';
import { createTerminalTab } from '@/shared/utils/tabUtils';
import { BaseToolCard, ToolCardHeader } from './BaseToolCard';
import { CompactToolCard, CompactToolCardHeader } from './CompactToolCard';
import { ToolCardStatusSlot } from './ToolCardStatusSlot';
import { DotMatrixLoader, IconButton } from '../../component-library';
import { LazyTerminalOutputRenderer } from '@/tools/terminal/components/LazyTerminalOutputRenderer';
import { createLogger } from '@/shared/utils/logger';
Expand Down Expand Up @@ -453,11 +455,11 @@ export const TerminalToolCard: React.FC<TerminalToolCardProps> = ({

const handleMouseDown = useCallback(() => {
setShouldExpand(true);
}, [toggleExpanded, shouldExpand, setShouldExpand]);
}, []);

const handleMouseMove = useCallback(() => {
setShouldExpand(false);
}, [toggleExpanded, shouldExpand, setShouldExpand]);
}, []);

const handleCardClick = useCallback((e: React.MouseEvent) => {
const target = e.target as HTMLElement;
Expand Down Expand Up @@ -605,6 +607,15 @@ export const TerminalToolCard: React.FC<TerminalToolCardProps> = ({
/>
);

const renderCompactHeader = () => (
<CompactToolCardHeader
icon={<ToolCardStatusSlot status={status} toolIcon={<Terminal size={16} />} defaultIcon="tool" />}
action={t('toolCards.terminal.executeCommand')}
content={renderCommandContent('compact')}
rightStatusIcon={renderLoadingStatusIcon()}
/>
);

const compactSettledPreview =
isExpanded &&
isLastItem === true &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { configAPI } from '@/infrastructure/api/service-api/ConfigAPI';
import { api } from '@/infrastructure/api/service-api/ApiClient';
import { workspaceAPI } from '@/infrastructure/api/service-api/WorkspaceAPI';
import { createLogger } from '@/shared/utils/logger';
import {
builtinAppearanceCatalog,
DEFAULT_DARK_APPEARANCE_ID,
DEFAULT_LIGHT_APPEARANCE_ID,
getBuiltinAppearance,
getSystemAppearanceId,
} from '../builtins/catalog';
Expand Down Expand Up @@ -31,6 +35,7 @@ import type { AppearanceRuntime } from './AppearanceRuntime';
const log = createLogger('AppearanceService');
const APPEARANCE_SELECTION_CONFIG_PATH = 'appearance.selection';
const MAX_SEEN_SYNC_EVENTS = 256;
const SYSTEM_COLOR_SCHEME_CHANGED_EVENT = 'bitfun:system-color-scheme-changed';

interface AppearanceSource {
pkg: AppearancePackage;
Expand Down Expand Up @@ -129,6 +134,8 @@ export class AppearanceService {
private initializePromise: Promise<void> | null = null;
private mutationQueue: Promise<void> = Promise.resolve();
private systemMedia: MediaQueryList | null = null;
private systemColorSchemeUnsubscribe: (() => void) | null = null;
private ohosSystemAppearanceId: string | null = null;
private syncUnsubscribe: (() => void) | null = null;
private reconciliationQueued = false;
private activeSource: AppearanceSource | null = null;
Expand Down Expand Up @@ -403,6 +410,7 @@ export class AppearanceService {

async dispose(): Promise<void> {
this.detachSystemListener();
this.detachNativeSystemListener();
this.detachReconciliationListeners();
this.syncUnsubscribe?.();
this.syncUnsubscribe = null;
Expand All @@ -421,6 +429,9 @@ export class AppearanceService {
? configuredSelection.trim()
: SYSTEM_APPEARANCE_ID;
this.persistedSelectionId = selected;
if (selected === SYSTEM_APPEARANCE_ID) {
await this.refreshNativeSystemAppearance();
}
try {
await this.applySelectionTransaction(selected, {
persist: false,
Expand Down Expand Up @@ -450,14 +461,28 @@ export class AppearanceService {
});
}
this.attachSystemListener();
this.attachNativeSystemListener();
this.attachReconciliationListeners();
}

private async applySelectionTransaction(
selected: AppearanceSelectionId,
options: ApplySelectionOptions,
): Promise<void> {
const resolvedId = selected === SYSTEM_APPEARANCE_ID ? getSystemAppearanceId() : selected;
if (selected === SYSTEM_APPEARANCE_ID && !this.ohosSystemAppearanceId) {
await this.refreshNativeSystemAppearance();
} else if (selected !== SYSTEM_APPEARANCE_ID) {
this.ohosSystemAppearanceId = null;
const selectedPackage = await this.resolvePackage(selected);
if (selectedPackage?.pkg.mode === 'light' || selectedPackage?.pkg.mode === 'dark') {
void workspaceAPI.setThemeMode(selectedPackage.pkg.mode).catch(error => {
log.debug('Native appearance mode sync is unavailable', { error });
});
}
}
const resolvedId = selected === SYSTEM_APPEARANCE_ID
? (this.ohosSystemAppearanceId ?? getSystemAppearanceId())
: selected;
const unchanged = this.snapshot.initialized
&& this.snapshot.selectedAppearanceId === selected
&& this.snapshot.resolvedAppearanceId === resolvedId
Expand Down Expand Up @@ -587,6 +612,40 @@ export class AppearanceService {
this.systemMedia.addEventListener('change', this.handleSystemAppearanceChange);
}

private attachNativeSystemListener(): void {
if (this.systemColorSchemeUnsubscribe) return;
this.systemColorSchemeUnsubscribe = api.listen<{ scheme?: 'light' | 'dark' }>(
SYSTEM_COLOR_SCHEME_CHANGED_EVENT,
payload => {
if (this.snapshot.selectedAppearanceId !== SYSTEM_APPEARANCE_ID) return;
const scheme = payload?.scheme;
if (scheme !== 'light' && scheme !== 'dark') return;
this.ohosSystemAppearanceId = scheme === 'dark'
? DEFAULT_DARK_APPEARANCE_ID
: DEFAULT_LIGHT_APPEARANCE_ID;
this.handleSystemAppearanceChange();
},
);
}

private detachNativeSystemListener(): void {
this.systemColorSchemeUnsubscribe?.();
this.systemColorSchemeUnsubscribe = null;
}

private async refreshNativeSystemAppearance(): Promise<void> {
try {
const scheme = await workspaceAPI.setThemeMode('system');
if (scheme === 'light' || scheme === 'dark') {
this.ohosSystemAppearanceId = scheme === 'dark'
? DEFAULT_DARK_APPEARANCE_ID
: DEFAULT_LIGHT_APPEARANCE_ID;
}
} catch (error) {
log.debug('Native system appearance discovery is unavailable', { error });
}
}

private detachSystemListener(): void {
this.systemMedia?.removeEventListener('change', this.handleSystemAppearanceChange);
this.systemMedia = null;
Expand Down
Loading