Adds a standalone Keyboard Shortcuts settings section with an easier-to-use capture input and support for more shortcut actions. - Introduce a new KeyboardShortcutsSection with a dedicated ShortcutCaptureInput component for recording key combos - Split keyboard-shortcut settings out of the general settings section into their own settings tab - Extend the shortcut schema/types and useDashboardKeyboardShortcuts hook to support additional actions - Update settings save-split, section-keys, and defaults/parity tests to cover the new section - Update dashboard docs and add a changeset for the new settings section Files changed: .changeset/fn-7553-keyboard-shortcuts-section.md | 7 + docs/dashboard-guide.md | 22 ++- packages/core/src/__tests__/global-settings.test.ts | 9 +- packages/core/src/__tests__/settings-defaults.test.ts | 4 + packages/core/src/__tests__/settings-parity.test.ts | 2 +- packages/core/src/settings-schema.ts | 6 +- packages/core/src/types.ts | 12 ++ packages/dashboard/app/App.tsx | 26 +++- packages/dashboard/app/__tests__/App.keyboard-shortcuts.test.tsx | 47 ++++++- packages/dashboard/app/components/SettingsModal.css | 56 ++++++-- packages/dashboard/app/components/SettingsModal.tsx | 30 +++- packages/dashboard/app/components/__tests__/SettingsModal.general.test.tsx | 63 --------- packages/dashboard/app/components/__tests__/SettingsModal.keyboardShortcuts.test.tsx | 156 +++++++++++++++++++++ packages/dashboard/app/components/settings/__tests__/section-keys.test.ts | 1 + packages/dashboard/app/components/settings/save-split.ts | 6 +- packages/dashboard/app/components/settings/sections/GlobalGeneralSection.tsx | 38 ----- packages/dashboard/app/components/settings/sections/KeyboardShortcutsSection.tsx | 78 +++++++++++ packages/dashboard/app/components/settings/sections/ShortcutCaptureInput.tsx | 118 ++++++++++++++++ packages/dashboard/app/components/settings/sections/__tests__/KeyboardShortcutsSection.test.tsx | 113 +++++++++++++++ packages/dashboard/app/hooks/__tests__/useDashboardKeyboardShortcuts.test.tsx | 73 +++++++++- packages/dashboard/app/hooks/useDashboardKeyboardShortcuts.ts | 38 ++++- packages/dashboard/app/utils/__tests__/keyboardShortcuts.test.ts | 37 ++++- packages/dashboard/app/utils/keyboardShortcuts.ts | 54 ++++++- 23 files changed, 854 insertions(+), 142 deletions(-) Fusion-Task-Id: FN-7553 Fusion-Task-Lineage: 51c1ad69-fbd3-45ce-8d2d-45d9962d7b76 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
79 lines
3.8 KiB
TypeScript
79 lines
3.8 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { SectionBaseProps } from "./context";
|
|
import { ShortcutCaptureInput } from "./ShortcutCaptureInput";
|
|
import {
|
|
DEFAULT_DASHBOARD_KEYBOARD_SHORTCUTS,
|
|
SHORTCUT_CATEGORIES,
|
|
describeShortcutValidation,
|
|
getShortcutActionLabel,
|
|
normalizeKeyboardShortcut,
|
|
resolveDashboardKeyboardShortcuts,
|
|
type DashboardShortcutAction,
|
|
} from "../../../utils/keyboardShortcuts";
|
|
|
|
export interface KeyboardShortcutsSectionProps extends SectionBaseProps {
|
|
scopeBanner: ReactNode;
|
|
}
|
|
|
|
/*
|
|
FNXC:DashboardShortcuts 2026-07-04-00:00:
|
|
FN-7553 promotes keyboard shortcuts from two bare inputs buried in Global General to their own dedicated settings section, grouped by category (Communication/Workspace/Navigation/Tasks from SHORTCUT_CATEGORIES) with a press-to-record capture control per row. `dashboardKeyboardShortcuts` ownership moved here from `global-general` (save-split.ts GLOBAL_SECTION_KEYS + section-keys.ts) so exactly one section owns the key for save/reset.
|
|
*/
|
|
export function KeyboardShortcutsSection({ scopeBanner, form, setForm }: KeyboardShortcutsSectionProps) {
|
|
const { t } = useTranslation("app");
|
|
const shortcutValues = resolveDashboardKeyboardShortcuts(form.dashboardKeyboardShortcuts);
|
|
const shortcutValidationMessage = describeShortcutValidation(shortcutValues);
|
|
|
|
const updateShortcut = (action: DashboardShortcutAction, value: string) => setForm((f) => ({
|
|
...f,
|
|
dashboardKeyboardShortcuts: {
|
|
...resolveDashboardKeyboardShortcuts(f.dashboardKeyboardShortcuts),
|
|
[action]: value,
|
|
},
|
|
}));
|
|
|
|
return (
|
|
<>
|
|
{scopeBanner}
|
|
<h4 className="settings-section-heading">{t("settings.keyboardShortcuts.title", "Keyboard Shortcuts")}</h4>
|
|
<p className="settings-description">{t("settings.keyboardShortcuts.hint", "Configure global dashboard shortcuts. Click Record and press a combination, or type one manually. Shortcuts are ignored while typing in inputs, editors, chat composers, and terminal fields. Leave blank to disable an action.")}</p>
|
|
<div className="form-group settings-keyboard-shortcuts" data-testid="keyboard-shortcuts-settings">
|
|
{SHORTCUT_CATEGORIES.map((category) => (
|
|
<div className="shortcut-category" key={category.id}>
|
|
<h5 className="settings-section-heading">{t(`settings.keyboardShortcuts.category.${category.id}`, category.label)}</h5>
|
|
{category.actions.map((action) => {
|
|
const parsed = normalizeKeyboardShortcut(shortcutValues[action]);
|
|
const inputId = `dashboardShortcut-${action}`;
|
|
const hintId = `${inputId}Hint`;
|
|
return (
|
|
<div className="shortcut-row" key={action}>
|
|
<label htmlFor={inputId}>{t(`settings.keyboardShortcuts.action.${action}`, getShortcutActionLabel(action))}</label>
|
|
<ShortcutCaptureInput
|
|
id={inputId}
|
|
value={shortcutValues[action]}
|
|
defaultValue={DEFAULT_DASHBOARD_KEYBOARD_SHORTCUTS[action]}
|
|
invalid={!parsed.valid}
|
|
describedById={hintId}
|
|
onChange={(value) => updateShortcut(action, value)}
|
|
/>
|
|
<small id={hintId}>
|
|
{parsed.valid
|
|
? t("settings.keyboardShortcuts.rowHint", "Default: {{default}}. Leave blank to disable.", { default: DEFAULT_DASHBOARD_KEYBOARD_SHORTCUTS[action] })
|
|
: parsed.error}
|
|
</small>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
))}
|
|
{shortcutValidationMessage && (
|
|
<small className="settings-description shortcut-conflict-banner" role="alert">{shortcutValidationMessage}</small>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default KeyboardShortcutsSection;
|