agentleFS
LedgerHQLedgerHQ/ledger-live/.agents/skills/dialogs-slice/SKILL.md

dialogs-slice

Skill627 starsChanged 8 days agoMITView on GitHub

Open and close a Ledger Wallet Desktop global dialog through the shared `dialogs` Redux slice (`DIALOG_IDS`, `openDialog`, `selectIsDialogOpen`) and mount it once in `GlobalDialogs`. Use when adding a desktop dialog mounted at the app root and opened from a distant part of the tree, or when editing `apps/ledger-live-desktop/src/renderer/reducers/dialogs.ts`, `src/mvvm/features/GlobalDialogs/` or a feature `*Dialog.ts` helper.

The file

We split this skill into the rules it gives an agent

11 rules. About 0 are common, 2 are distinctive, and 9 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 9

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this pattern for dialogs that are:

    line 12
  2. Very specific:

    Do NOT use this for dialogs that are local to a single component or screen -- prefer a simple useState instead.

    line 17
  3. Very specific:

    Add the new ID to the DIALOG_IDS array in renderer/reducers/dialogs.ts.

    line 30
  4. Very specific:

    Create myFeature/myNewDialog.ts in the feature folder:

    line 39
  5. Very specific:

    Add the dialog component to mvvm/features/GlobalDialogs/index.tsx, lazy-loaded and in its own Suspense like the dialogs already there.

    line 72
  6. Distinctive:

    NEVER create a dedicated Redux slice just for dialog open/close state

    line 99
  7. Very specific:

    NEVER use this pattern for dialogs local to a single component -- use useState instead

    line 100
  8. Very specific:

    ALWAYS add new dialog IDs to the DIALOG_IDS array (the type is derived automatically)

    line 101
  9. Very specific:

    ALWAYS use SCREAMING_SNAKE_CASE for dialog IDs

    line 102
  10. Very specific:

    ALWAYS mount new global dialogs in GlobalDialogs/index.tsx, not directly in Default.tsx

    line 103
  11. Very specific:

    No modification to reducers/index.ts or Default.tsx is needed when adding new dialogs

    line 105

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Global Dialogs Slice Pattern

Centralized Redux state for global dialog open/close, avoiding one slice per dialog.

When to use

Use this pattern for dialogs that are:

  • Mounted at the app root (e.g. in Default.tsx)
  • Triggered from distant parts of the component tree (e.g. a settings button opening a dialog rendered at root level)

Do NOT use this for dialogs that are local to a single component or screen -- prefer a simple useState instead.

Architecture

  • One shared slice: renderer/reducers/dialogs.ts manages all global dialog states via a Record<DialogId, boolean>
  • Single source of truth: DIALOG_IDS runtime array defines all IDs; DialogId type is derived from it via (typeof DIALOG_IDS)[number]
  • Feature wrappers: Each feature creates a thin *Dialog.ts file that re-exports typed helpers bound to its ID
  • Single mount point: mvvm/features/GlobalDialogs/index.tsx renders all global dialog components at the app root

Adding a new global dialog

Step 1: Register the dialog ID

Add the new ID to the DIALOG_IDS array in renderer/reducers/dialogs.ts. The DialogId type updates automatically:

export const DIALOG_IDS = ["RELEASE_NOTES", "MY_NEW_DIALOG"] as const;
// DialogId is now "RELEASE_NOTES" | "MY_NEW_DIALOG"

Step 2: Create the feature dialog file

Create myFeature/myNewDialog.ts in the feature folder:

import {
  openDialog,
  closeDialog,
  selectIsDialogOpen,
  type DialogId,
} from "~/renderer/reducers/dialogs";
import type { State } from "~/renderer/reducers";

const DIALOG_ID: DialogId = "MY_NEW_DIALOG";

export const openMyNewDialog = () => openDialog(DIALOG_ID);
export const closeMyNewDialog = () => closeDialog(DIALOG_ID);
export const selectIsMyNewDialogOpen = (state: State) => selectIsDialogOpen(state, DIALOG_ID);

Step 3: Use in the view model

import { selectIsMyNewDialogOpen, closeMyNewDialog } from "../myNewDialog";

const useMyNewDialogViewModel = () => {
  const isOpen = useSelector(selectIsMyNewDialogOpen);
  const dispatch = useDispatch();
  const onClose = useCallback(() => dispatch(closeMyNewDialog()), [dispatch]);
  return { isOpen, onClose };
};

Step 4: Mount in GlobalDialogs

Add the dialog component to mvvm/features/GlobalDialogs/index.tsx, lazy-loaded and in its own Suspense like the dialogs already there. A sketch of that file:

const MyNewDialog = lazy(() => import("LLD/features/MyFeature"));

const GlobalDialogs = () => (
  <>
    {/* ...existing dialogs */}
    <Suspense fallback={null}>
      <MyNewDialog />
    </Suspense>
  </>
);

Step 5: Trigger from anywhere

import { openMyNewDialog } from "LLD/features/MyFeature/myNewDialog";

dispatch(openMyNewDialog());

Rules

  • NEVER create a dedicated Redux slice just for dialog open/close state
  • NEVER use this pattern for dialogs local to a single component -- use useState instead
  • ALWAYS add new dialog IDs to the DIALOG_IDS array (the type is derived automatically)
  • ALWAYS use SCREAMING_SNAKE_CASE for dialog IDs
  • ALWAYS mount new global dialogs in GlobalDialogs/index.tsx, not directly in Default.tsx
  • Feature dialog files should only contain the ID constant and re-exported typed helpers
  • No modification to reducers/index.ts or Default.tsx is needed when adding new dialogs

Reference

  • Slice: apps/ledger-live-desktop/src/renderer/reducers/dialogs.ts
  • Mount point: apps/ledger-live-desktop/src/mvvm/features/GlobalDialogs/index.tsx
  • Example: apps/ledger-live-desktop/src/mvvm/features/ReleaseNotes/releaseNotesDialog.ts

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.