diff --git a/src/ui/app/AppRoot.tsx b/src/ui/app/AppRoot.tsx index 881f7de..cd7afe6 100644 --- a/src/ui/app/AppRoot.tsx +++ b/src/ui/app/AppRoot.tsx @@ -164,11 +164,8 @@ export function AppRoot(): VNode { applyTheme('light'); }); - sf.getOnboarding().then(progress => { - if (!progress.dismissedAt && progress.completedSteps.length === 0) { - setShowOnboarding(true); - } - }).catch(() => {}); + // Onboarding modal is no longer auto-shown on first launch. Users can + // open it from the Home "Getting started" surface when they choose. }, []); useEffect(() => { @@ -217,7 +214,7 @@ export function AppRoot(): VNode { () => setRoute('import'), ), shortcutRegistry.register( - { id: 'toggle-undo', defaultKeys: 'ctrl+z', description: 'Toggle undo panel', scope: 'global' }, + { id: 'toggle-undo', defaultKeys: 'ctrl+shift+z', description: 'Toggle undo panel', scope: 'global' }, () => setUndoPanelOpen(v => !v), ), ]; diff --git a/src/ui/components/OnboardingWizard.tsx b/src/ui/components/OnboardingWizard.tsx index 9b61068..a363a11 100644 --- a/src/ui/components/OnboardingWizard.tsx +++ b/src/ui/components/OnboardingWizard.tsx @@ -28,7 +28,7 @@ type OnboardingCategory = OnboardingStep['category']; /** Category display labels in presentation order. */ const ONBOARDING_CATEGORIES: OnboardingCategory[] = [ 'getting-started', - 'data-push', + 'import', 'query', 'advanced', ]; @@ -36,7 +36,7 @@ const ONBOARDING_CATEGORIES: OnboardingCategory[] = [ /** Human-readable labels for each category. */ const CATEGORY_LABELS: Record = { 'getting-started': 'Getting Started', - 'data-push': 'Data Push', + 'import': 'Import', 'query': 'Query', 'advanced': 'Advanced', }; diff --git a/src/ui/screens/HelpScreen.tsx b/src/ui/screens/HelpScreen.tsx index d10ed00..a7a0aef 100644 --- a/src/ui/screens/HelpScreen.tsx +++ b/src/ui/screens/HelpScreen.tsx @@ -31,9 +31,9 @@ const HELP_CATEGORIES: Array<{ filter: (s) => s.category === 'getting-started', }, { - name: 'Data Push', + name: 'Import', description: 'Upload files, map fields, push records, and review push history.', - filter: (s) => s.category === 'data-push', + filter: (s) => s.category === 'import', }, { name: 'Query & Objects', diff --git a/src/ui/utils/onboarding.ts b/src/ui/utils/onboarding.ts index 32c076e..8cde81c 100644 --- a/src/ui/utils/onboarding.ts +++ b/src/ui/utils/onboarding.ts @@ -14,7 +14,7 @@ export interface OnboardingStep { title: string; description: string; targetRoute?: AppRoute; - category: 'getting-started' | 'data-push' | 'query' | 'advanced'; + category: 'getting-started' | 'import' | 'query' | 'advanced'; /** Opens a bounded, non-sensitive example in the relevant workflow. */ example?: 'export' | 'import'; } @@ -59,7 +59,7 @@ export const ONBOARDING_STEPS: OnboardingStep[] = [ title: 'Upload Data from a File', description: 'Upload a CSV or Excel file to prepare data for pushing to Salesforce. WaveLink will parse and preview your records.', targetRoute: APP_ROUTES.import, - category: 'data-push', + category: 'import', example: 'import', }, { @@ -67,14 +67,14 @@ export const ONBOARDING_STEPS: OnboardingStep[] = [ title: 'Push Data to Salesforce', description: 'Map your uploaded fields to Salesforce fields and push records using insert, update, upsert, or delete operations.', targetRoute: APP_ROUTES.import, - category: 'data-push', + category: 'import', }, { id: 'use-templates', title: 'Save and Use Data Templates', description: 'Save your field mappings and sample data as reusable templates for repeated data push operations.', targetRoute: APP_ROUTES.templates, - category: 'data-push', + category: 'import', }, // ── Advanced ── diff --git a/src/ui/utils/shortcuts.ts b/src/ui/utils/shortcuts.ts index 74bc0c5..f9dd7b5 100644 --- a/src/ui/utils/shortcuts.ts +++ b/src/ui/utils/shortcuts.ts @@ -98,6 +98,22 @@ class ShortcutRegistryImpl { } handleKeydown(e: KeyboardEvent): boolean { + // Never hijack native undo/redo/editing inside text inputs unless the + // binding uses a modifier combo that users don't expect to conflict + // (ctrl+shift, ctrl+alt, etc.). Plain ctrl+z / ctrl+y must pass through. + const target = e.target as HTMLElement | null; + if (target) { + const tag = target.tagName.toLowerCase(); + const isEditable = + tag === 'input' || + tag === 'textarea' || + tag === 'select' || + target.isContentEditable; + if (isEditable && !e.shiftKey && !e.altKey) { + return false; + } + } + const normalized = normalizeKeys(e); const id = this.keyIndex.get(normalized); if (!id) return false;