Skip to content

fix(storybook): make stories pass strict TypeScript - #392

Merged
draedful merged 3 commits into
v2from
fix/v2-storybook-strict
Oct 17, 2026
Merged

draedful merged 3 commits into
v2from
fix/v2-storybook-strict

Conversation

@draedful

@draedful draedful commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #367 (epic #353).

Summary

The Storybook app (apps/storybook) now type-checks under strict TypeScript, and "strict": true is enabled in apps/storybook/tsconfig.json. Before this change the strict debt was visible only through the strict gate overlay.

  • Before: a temporary strict run (tsc -p tsconfig.json --noEmit --strict) reported 179 diagnostics in 32 files. By code: TS18048 ×89, TS7006 ×18, TS2322 ×17, TS2783 ×15, TS18047 ×14, TS2345 ×7, TS2540 ×4, TS2532 ×4, TS7053 ×4, others ×7.
  • After: 0.

No packages/* files change, so no library types are widened. The diff adds no any, @ts-ignore/@ts-expect-error, non-null ! or as casts.

Approach

  • Nullable refs (TS18047/TS18048/TS2540): graphRef.current?.… in handlers; layer and editor refs are typed useRef<T | null>(null) and also accessed with ?..
  • Story wrapper main/GraphEditor.tsx: the graphRef prop is MutableRefObject<Graph | undefined>, and renderBlock may return null. The wrapper already falls back to BlockStory via ||.
  • TS2783 in main/GraphEditor.stories.tsx: {...args} now comes before config=. Storybook args never contain config, so rendering is unchanged.
  • Generators: they return narrower story-local types (TGeneratedGraphConfig, { blocks; connections }, TGravityActionBlockWithAnchors), so blocks/connections are non-optional.
  • Implicit any: fixed with explicit parameter types (TPoint, LayerProps, monaco editor.ITextModel, …).

Behavior notes

  • Paths that used to throw a TypeError on a missing ref, model, meta or context now return early or use ?..
  • GraphPlayground: the selection-change handler skips ids missing from the store. Before, it sent partial { selected } objects that produced a wrong editor edit. updateGraphSize gets default: return; instead of calling setEntities(undefined).
  • ToolboxLayer: the unknown html.className key, which Layer ignored, became classNames: ["custom-control"], so the class is now actually applied. No CSS targets it, so nothing renders differently.
  • CustomLayerConfig.ts and the layers block of minimap.stories.tsx are untouched; a separate PR changes them.

Verification

All of the following exit 0:

  • pnpm run build, then pnpm --filter @gravity-ui/graph-storybook exec tsc -p tsconfig.json --noEmit → 0 diagnostics
  • pnpm run typecheck
  • pnpm run test:type-configs
  • pnpm test (graph 379 passed, graph-react 167 passed, devtools 11 passed)
  • pnpm run lint
  • node scripts/strict-diagnostics.mjs → apps/storybook/tsconfig.json: 0 existing diagnostics (baseline not edited; stale entries are retired later)
  • pnpm run build-storybook

Independent review rounds, including an architectural one that checked every hunk against the origin/v2 strict baseline, reported no unresolved P2+ findings. A Sourcery-suggested change to the editor id search was dropped from this PR: numeric ids are not reachable, because the editor schema types id as a string.

🤖 Generated with Claude Code

Summary by Sourcery

Enable strict TypeScript checking for Storybook and make its stories type-safe without weakening shared library types.

Bug Fixes:

  • Prevent Storybook interactions from failing when refs, models, metadata, contexts, or source blocks are unavailable.
  • Correct playground selection updates and ignore unsupported graph-size values instead of applying invalid state.
  • Apply the Toolbox layer's custom class through the supported layer configuration.

Enhancements:

  • Enable strict TypeScript checking for the Storybook app and resolve all existing strict-mode diagnostics with precise Storybook, generator, callback, and ref typings.

@draedful
draedful requested a review from Antamansid as a code owner October 16, 2026 14:00
@sourcery-ai

sourcery-ai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR enables strict TypeScript for apps/storybook and brings the entire Storybook codebase to zero strict diagnostics by adding precise local types, narrowing generated data, and guarding nullable refs and runtime values. It also fixes selection-update and layer-class handling edge cases while preserving story behavior, with no changes to library package types.

File-Level Changes

Change Details Files
Enabled strict TypeScript for the Storybook application and eliminated all resulting diagnostics through null-safe ref handling and explicit typing.
  • Set strict to true in the Storybook TypeScript configuration.
  • Guard graph, editor, model, canvas, metadata, and layer accesses against missing values.
  • Add explicit types for callback parameters, refs, Monaco utilities, drawing helpers, constructors, and generated data.
  • Use optional chaining or early returns where missing runtime objects previously could throw.
apps/storybook/tsconfig.json
apps/storybook/src/stories/Playground/ActionBlock/ActionBlockHtml.tsx
apps/storybook/src/stories/Playground/ActionBlock/index.tsx
apps/storybook/src/stories/Playground/Editor/index.tsx
apps/storybook/src/stories/Playground/Editor/utils.ts
apps/storybook/src/stories/Playground/GraphPlayground.tsx
apps/storybook/src/stories/Playground/Settings.tsx
apps/storybook/src/stories/Playground/TextBlock/TextBlockHtml.tsx
apps/storybook/src/stories/Playground/TextBlock/index.tsx
apps/storybook/src/stories/api/updateBlock/updateBlock.stories.tsx
apps/storybook/src/stories/api/updateConnection/updateConnection.stories.tsx
apps/storybook/src/stories/api/updateGraphColors/updateGraphColors.stories.tsx
apps/storybook/src/stories/api/zoomSpeed/zoomSpeed.stories.tsx
apps/storybook/src/stories/api/zoomToBlocks/zoomToBlocks.stories.tsx
apps/storybook/src/stories/api/zoomToRect/zoomToRect.stories.tsx
apps/storybook/src/stories/api/zoomToViewPort/zoomToViewPort.stories.tsx
apps/storybook/src/stories/configurations/verticalGraph.ts
apps/storybook/src/stories/examples/connectionLayer/connectionLayer.stories.tsx
apps/storybook/src/stories/examples/imageByBlocks/imageByBlocks.stories.tsx
apps/storybook/src/stories/examples/imageInsteadBlock/imageInsteadBlock.stories.tsx
apps/storybook/src/stories/examples/newBlockLayer/newBlockLayer.stories.tsx
apps/storybook/src/stories/examples/portConnectionLayer/portConnectionLayer.stories.tsx
apps/storybook/src/stories/examples/themeChange/themeChange.stories.tsx
apps/storybook/src/stories/main/GraphEditor.tsx
apps/storybook/src/stories/main/ToolboxLayer.tsx
apps/storybook/src/stories/plugins/elk/elk.stories.tsx
Strengthened Storybook-only generated configuration and block types so generated collections are known to be present and specialized block invariants are preserved.
  • Introduced non-optional generated graph configuration types.
  • Added an anchored action-block subtype and typed generator return values.
  • Refactored generators to build explicitly typed block and connection arrays.
  • Updated ELK examples to consume the narrower generated configuration types.
apps/storybook/src/stories/Playground/generateLayout.tsx
apps/storybook/src/stories/configurations/generatePretty.ts
apps/storybook/src/stories/plugins/elk/elk.stories.tsx
apps/storybook/src/stories/plugins/elk/generateExampleTree.ts
apps/storybook/src/stories/plugins/elk/getExampleConfig.ts
Resolved strict JSX and Storybook typing issues without changing story rendering semantics.
  • Moved story args spreads before explicit config props to avoid duplicate-property diagnostics.
  • Allowed custom block renderers to return null, preserving fallback to the default block story.
  • Typed the GraphEditor ref as potentially undefined.
apps/storybook/src/stories/main/GraphEditor.stories.tsx
apps/storybook/src/stories/main/GraphEditor.tsx
Corrected two runtime edge cases uncovered while making the stories strict-safe.
  • Skip selection updates for block IDs absent from the store and make unknown graph-size options no-ops.
  • Apply the ToolboxLayer CSS class through the supported classNames property.
apps/storybook/src/stories/Playground/GraphPlayground.tsx
apps/storybook/src/stories/main/ToolboxLayer.tsx

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gravity-ui-bot

Copy link
Copy Markdown
Contributor

Preview is ready.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="apps/storybook/src/stories/examples/imageByBlocks/imageByBlocks.stories.tsx" line_range="62-64" />
<code_context>
       canvas.width = pic.width;
       canvas.height = pic.height;
       const ctx = canvas.getContext("2d");
+      if (!ctx) {
+        console.error("imageByBlocks: 2D canvas context is not available");
+        return;
+      }

</code_context>
<issue_to_address>
**Image story stays blank**

When `canvas.getContext("2d")` returns null, the `pic.onload` callback logs and returns without resolving or rejecting the promise created by `generateByImage`. The caller’s `.then` never sets the config, so `GraphApp` renders nothing and the story stays blank.

Resolve or reject the promise when the 2D canvas context is unavailable.
</issue_to_address>

### Comment 2
<location path="apps/storybook/src/stories/Playground/Editor/utils.ts" line_range="6" />
<code_context>
+
+export function findBlockPositionsMonaco(
+  model: editor.ITextModel,
+  blockId: TBlockId
+): { start: IPosition; end: IPosition } {
   const configString = model.getValue();
</code_context>
<issue_to_address>
**Numeric IDs navigate incorrectly**

When a caller navigates to a block whose ID is numeric, `findBlockPositionsMonaco` searches for a quoted ID, but JSON serializes numeric IDs without quotes, so the search misses and returns positions that send the editor selection to the wrong location.

Build the search text using the ID’s JSON representation and return safely when the ID is not found.

Also at `apps/storybook/src/stories/Playground/Editor/index.tsx:46`.
</issue_to_address>

Sourcery assessment

Approval pending. 2 findings to address first.

Blocking findings: apps/storybook/src/stories/examples/imageByBlocks/imageByBlocks.stories.tsx:64, apps/storybook/src/stories/Playground/Editor/utils.ts:6


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread apps/storybook/src/stories/Playground/Editor/utils.ts
@draedful
draedful force-pushed the fix/v2-storybook-strict branch from a15d82d to bb1d448 Compare October 16, 2026 15:39

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourcery assessment

Approved.

draedful and others added 3 commits October 18, 2026 01:12
Enable "strict": true in apps/storybook/tsconfig.json and fix the
179 strict diagnostics in 32 story files: null-safe ref access with
early returns, explicit parameter types, spread before explicit props,
story-local narrower generator types, and nullable refs instead of
readonly ref assignment. No library types are changed.

Part of #367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- imageByBlocks: reject the generation promise when the 2D canvas
  context is unavailable instead of leaving it pending.
- Playground editor: search block ids as JSON serializes them (numeric
  ids are unquoted), require a value boundary so `1` does not match
  `12`, and skip scroll/update when the id is not found instead of
  selecting from the document start.

Part of #367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Editor: keep findBlockPositionsMonaco typed only; drop the numeric-id
  search change (ids are strings by the editor schema), to be handled
  separately if needed.
- Annotate generated configs instead of extracting local arrays.
- Use optional chaining for graphRef in api and themeChange stories.
- Simplify parseTheme and imageInsteadBlock narrowing.

Part of #367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@draedful
draedful force-pushed the fix/v2-storybook-strict branch from bb1d448 to 561391d Compare October 17, 2026 22:14
@draedful
draedful merged commit 97f5baf into v2 Oct 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants