mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
## CHANGES
- Removed tab title tooltips for a cleaner, distraction-free TabBar UX 🧼 - Added demo-mode and dev-mode isolated data directories to avoid conflicts 🗂️ - Defaulted sync storage path to configured userData when unset 🔄 - Ensured userData path is set before Store initialization for correctness 🧭 - Improved TTS IPC reliability with utf8 writes, callbacks, and stdin checks 🗣️ - Added richer TTS debug logging in main process for easier troubleshooting 🔍 - Logged ToastContext TTS triggers and explicit skip reasons for clarity 📣 - Extended toast test coverage to include audioNotification disabled state ✅ - Fixed FilePreview search match index reset to prevent unnecessary jumps 🎯
This commit is contained in:
@@ -1512,7 +1512,8 @@ describe('TabBar', () => {
|
||||
expect(inactiveTab.style.backgroundColor).not.toBe('rgba(255, 255, 255, 0.08)');
|
||||
});
|
||||
|
||||
it('sets tab title attribute', () => {
|
||||
it('does not set title attribute on tabs (removed for cleaner UX)', () => {
|
||||
// Tab title tooltips were intentionally removed to streamline the tab interaction feel
|
||||
const tabs = [createTab({
|
||||
id: 'tab-1',
|
||||
name: 'My Tab',
|
||||
@@ -1531,51 +1532,7 @@ describe('TabBar', () => {
|
||||
);
|
||||
|
||||
const tab = screen.getByText('My Tab').closest('[data-tab-id]')!;
|
||||
expect(tab).toHaveAttribute('title', 'My Tab');
|
||||
});
|
||||
|
||||
it('uses agentSessionId for title when no name', () => {
|
||||
const tabs = [createTab({
|
||||
id: 'tab-1',
|
||||
name: '',
|
||||
agentSessionId: 'session-123-abc'
|
||||
})];
|
||||
|
||||
render(
|
||||
<TabBar
|
||||
tabs={tabs}
|
||||
activeTabId="tab-1"
|
||||
theme={mockTheme}
|
||||
onTabSelect={mockOnTabSelect}
|
||||
onTabClose={mockOnTabClose}
|
||||
onNewTab={mockOnNewTab}
|
||||
/>
|
||||
);
|
||||
|
||||
const tab = screen.getByText('SESSION').closest('[data-tab-id]')!;
|
||||
expect(tab).toHaveAttribute('title', 'session-123-abc');
|
||||
});
|
||||
|
||||
it('uses "New tab" for title when no name or agentSessionId', () => {
|
||||
const tabs = [createTab({
|
||||
id: 'tab-1',
|
||||
name: '',
|
||||
agentSessionId: undefined
|
||||
})];
|
||||
|
||||
render(
|
||||
<TabBar
|
||||
tabs={tabs}
|
||||
activeTabId="tab-1"
|
||||
theme={mockTheme}
|
||||
onTabSelect={mockOnTabSelect}
|
||||
onTabClose={mockOnTabClose}
|
||||
onNewTab={mockOnNewTab}
|
||||
/>
|
||||
);
|
||||
|
||||
const tab = screen.getByText('New Session').closest('[data-tab-id]')!;
|
||||
expect(tab).toHaveAttribute('title', 'New tab');
|
||||
expect(tab).not.toHaveAttribute('title');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ describe('ToastContext', () => {
|
||||
taskDuration: 5000,
|
||||
agentSessionId: 'test-session-id',
|
||||
tabName: 'TestTab',
|
||||
audioNotification: { enabled: false },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -32,6 +32,31 @@ interface BootstrapSettings {
|
||||
iCloudSyncEnabled?: boolean; // Legacy - kept for backwards compatibility during migration
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Data Directory Configuration (MUST happen before any Store initialization)
|
||||
// ============================================================================
|
||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
// Demo mode: use a separate data directory for fresh demos
|
||||
if (DEMO_MODE) {
|
||||
app.setPath('userData', DEMO_DATA_PATH);
|
||||
console.log(`[DEMO MODE] Using data directory: ${DEMO_DATA_PATH}`);
|
||||
}
|
||||
|
||||
// Development mode: use a separate data directory to allow running alongside production
|
||||
// This prevents database lock conflicts (e.g., Service Worker storage)
|
||||
// Set USE_PROD_DATA=1 to use the production data directory instead (requires closing production app)
|
||||
if (isDevelopment && !DEMO_MODE && !process.env.USE_PROD_DATA) {
|
||||
const devDataPath = path.join(app.getPath('userData'), '..', 'maestro-dev');
|
||||
app.setPath('userData', devDataPath);
|
||||
console.log(`[DEV MODE] Using data directory: ${devDataPath}`);
|
||||
} else if (isDevelopment && process.env.USE_PROD_DATA) {
|
||||
console.log(`[DEV MODE] Using production data directory: ${app.getPath('userData')}`);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Store Initialization (after userData path is configured)
|
||||
// ============================================================================
|
||||
const bootstrapStore = new Store<BootstrapSettings>({
|
||||
name: 'maestro-bootstrap',
|
||||
defaults: {},
|
||||
@@ -62,12 +87,11 @@ function getSyncPath(): string | undefined {
|
||||
}
|
||||
|
||||
// Get the sync path once at startup
|
||||
const syncPath = getSyncPath();
|
||||
// If no custom sync path, use the (potentially modified) userData path
|
||||
const syncPath = getSyncPath() || app.getPath('userData');
|
||||
|
||||
// Initialize Sentry for crash reporting (before app.ready)
|
||||
// Initialize Sentry for crash reporting
|
||||
// Only enable in production - skip during development to avoid noise from hot-reload artifacts
|
||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
// Check if crash reporting is enabled (default: true for opt-out behavior)
|
||||
const crashReportingStore = new Store<{ crashReportingEnabled: boolean }>({
|
||||
name: 'maestro-settings',
|
||||
@@ -93,23 +117,6 @@ if (crashReportingEnabled && !isDevelopment) {
|
||||
});
|
||||
}
|
||||
|
||||
// Demo mode: use a separate data directory for fresh demos
|
||||
if (DEMO_MODE) {
|
||||
app.setPath('userData', DEMO_DATA_PATH);
|
||||
console.log(`[DEMO MODE] Using data directory: ${DEMO_DATA_PATH}`);
|
||||
}
|
||||
|
||||
// Development mode: use a separate data directory to allow running alongside production
|
||||
// This prevents database lock conflicts (e.g., Service Worker storage)
|
||||
// Set USE_PROD_DATA=1 to use the production data directory instead (requires closing production app)
|
||||
if (isDevelopment && !DEMO_MODE && !process.env.USE_PROD_DATA) {
|
||||
const devDataPath = path.join(app.getPath('userData'), '..', 'maestro-dev');
|
||||
app.setPath('userData', devDataPath);
|
||||
console.log(`[DEV MODE] Using data directory: ${devDataPath}`);
|
||||
} else if (isDevelopment && process.env.USE_PROD_DATA) {
|
||||
console.log(`[DEV MODE] Using production data directory: ${app.getPath('userData')}`);
|
||||
}
|
||||
|
||||
// Type definitions
|
||||
interface MaestroSettings {
|
||||
activeThemeId: string;
|
||||
@@ -1405,8 +1412,17 @@ function setupIpcHandlers() {
|
||||
logger.error('TTS stdin error', 'TTS', { error: String(err), code: errorCode });
|
||||
}
|
||||
});
|
||||
child.stdin.write(text);
|
||||
child.stdin.end();
|
||||
console.log('[TTS Main] Writing to stdin:', text);
|
||||
child.stdin.write(text, 'utf8', (err) => {
|
||||
if (err) {
|
||||
console.error('[TTS Main] stdin write error:', err);
|
||||
} else {
|
||||
console.log('[TTS Main] stdin write completed, ending stream');
|
||||
}
|
||||
child.stdin!.end();
|
||||
});
|
||||
} else {
|
||||
console.error('[TTS Main] No stdin available on child process');
|
||||
}
|
||||
|
||||
child.on('error', (err) => {
|
||||
|
||||
@@ -756,9 +756,9 @@ export function FilePreview({ file, onClose, theme, markdownEditMode, setMarkdow
|
||||
}
|
||||
}
|
||||
|
||||
// Update match count
|
||||
// Update match count - only reset index if it's truly out of bounds and not already 0
|
||||
setTotalMatches(allRanges.length);
|
||||
if (allRanges.length > 0 && currentMatchIndex >= allRanges.length) {
|
||||
if (allRanges.length > 0 && currentMatchIndex >= allRanges.length && currentMatchIndex !== 0) {
|
||||
setCurrentMatchIndex(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,9 +110,12 @@ export function ToastProvider({ children, defaultDuration: initialDuration = 20
|
||||
|
||||
// Speak toast via TTS if audio feedback is enabled and command is configured
|
||||
if (audioEnabled && audioCommand) {
|
||||
console.log('[ToastContext] Triggering TTS with message:', toast.message, 'command:', audioCommand);
|
||||
window.maestro.notification.speak(toast.message, audioCommand).catch(err => {
|
||||
console.error('[ToastContext] Failed to speak toast:', err);
|
||||
});
|
||||
} else {
|
||||
console.log('[ToastContext] TTS skipped - enabled:', audioEnabled, 'command:', audioCommand);
|
||||
}
|
||||
|
||||
// Show OS notification if enabled
|
||||
|
||||
Reference in New Issue
Block a user