feat(cli): export view notation in screenshots#2950
Conversation
🦋 Changeset detectedLatest commit: 63b62ba The changes in this PR will be included in the next version bump. This PR includes changesets to release 22 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughAdds ChangesNotation Export Feature
Sequence Diagram(s)sequenceDiagram
participant CLI
participant takeScreenshot
participant Playwright
participant ExportPage
CLI->>takeScreenshot: call(viewId,padding,theme,format,notation,description)
takeScreenshot->>takeScreenshot: createExportViewUrl()
takeScreenshot->>Playwright: navigate(export URL)
Playwright->>ExportPage: load (query includes notation/description)
Playwright->>Playwright: locate export-page & measure bbox
Playwright->>Playwright: resize viewport if bbox > viewport
Playwright->>Playwright: exportPage.screenshot()
Playwright-->>takeScreenshot: image buffer
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (5)
packages/likec4-spa/src/pages/ExportPage.tsx (2)
284-374: 💤 Low valueConsider marking component props as readonly.
Similar to
ExportNotationPanel, marking props as readonly provides compile-time safety.🔒 Suggested readonly props
-function ExportNotationItem({ entry }: { entry: NodeNotation }) { +function ExportNotationItem({ entry }: Readonly<{ entry: NodeNotation }>) {Based on learnings: The SonarCloud warning aligns with React best practices for immutability.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/ExportPage.tsx` around lines 284 - 374, The prop object for ExportNotationItem should be made readonly to enforce immutability at compile time; update the component signature (ExportNotationItem) so its parameter type is { readonly entry: NodeNotation } (or define a ReadonlyProps interface and use it) and ensure any references still use entry but do not attempt to mutate it.
240-246: 💤 Low valueConsider marking component props as readonly.
React 19 treats props as immutable at runtime, but TypeScript doesn't enforce this by default. Marking the props interface as
Readonly<{...}>provides compile-time safety against accidental mutations.🔒 Suggested readonly props
function ExportNotationPanel({ entries, layout, -}: { +}: Readonly<{ entries: NodeNotation[] layout: NonNullable<ReturnType<typeof computeExportPageLayout>['notation']> -}) { +}>) {Based on learnings: The SonarCloud warning aligns with React best practices for immutability.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/ExportPage.tsx` around lines 240 - 246, The ExportNotationPanel component props should be marked readonly to prevent accidental mutations: update the props type for ExportNotationPanel (the object containing entries: NodeNotation[] and layout: NonNullable<ReturnType<typeof computeExportPageLayout>['notation']>) to be Readonly<...> (or use a readonly modifier on the entries and layout properties) so TypeScript enforces immutability for entries and layout inside ExportNotationPanel.packages/likec4-spa/src/pages/export-layout.spec.ts (1)
58-70: ⚡ Quick winReview the assertion logic on line 69.
The assertion
expect(layout.notation!.height).toBeGreaterThan(layout.diagram.height - 20 * 2 - EXPORT_NOTATION_INSET)seems to verify that notation is taller than the diagram's available content area. However, this formula doesn't clearly align with the layout calculation incomputeExportPageLayout(line 57), which usesMath.max(diagram.height, notationHeight + padding * 2).Consider simplifying the assertion to directly verify the intended behavior, such as:
expect(layout.height).toBeGreaterThan(layout.diagram.height)This would more clearly express that the export height grew to accommodate the notation panel.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/export-layout.spec.ts` around lines 58 - 70, The assertion comparing layout.notation!.height to layout.diagram.height - 20 * 2 - EXPORT_NOTATION_INSET is brittle and doesn't match the Math.max logic in computeExportPageLayout; update the test in export-layout.spec.ts to assert the exported page height grew because notation dominated by verifying computeExportPageLayout produced a height larger than the original diagram height (e.g., expect(layout.height).toBeGreaterThan(layout.diagram.height)) and/or assert layout.height equals Math.max(layout.diagram.height, exportNotationHeight(5) + padding * 2) using the same helpers (computeExportPageLayout, exportNotationHeight, padding, EXPORT_NOTATION_INSET) so the test directly reflects the function's intended behavior.packages/likec4-spa/src/pages/export-layout.ts (1)
59-69: ⚡ Quick winVerify the width calculation includes correct padding.
On line 60, the total width adds
paddingonce at the end. This suggests padding is only applied to the right side of the notation panel. Ensure this matches the intended layout—typically, you'd want symmetric padding on both sides, or clarify if the diagram already includes left padding.Looking at line 43,
diagram.widthalready includespadding * 2, so the notation side needs only one additionalpaddingon its right edge. This appears correct, but consider adding a comment to clarify the padding distribution.💡 Suggested comment for clarity
return { + // Total width: diagram (with 2x padding) + gap + notation width + right padding width: diagram.width + EXPORT_NOTATION_GAP + EXPORT_NOTATION_WIDTH + padding, height,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/export-layout.ts` around lines 59 - 69, The width calculation currently returns width: diagram.width + EXPORT_NOTATION_GAP + EXPORT_NOTATION_WIDTH + padding and is correct because diagram.width already includes padding * 2; add a short clarifying comment next to this return (or above the calculation) explaining that diagram.width contains both left and right padding and the extra padding added here is only the right-side padding for the notation panel—reference the symbols diagram.width, EXPORT_NOTATION_GAP, EXPORT_NOTATION_WIDTH, padding and notation.left to make the intent clear.packages/likec4/src/cli/export/png/takeScreenshot.ts (1)
33-55: ⚡ Quick winAdd JSDoc for the exported function.
The
createExportViewUrlfunction is exported and used by other modules, but lacks documentation. Consider adding a JSDoc comment describing its purpose and parameters.📝 Suggested JSDoc
+/** + * Constructs the export page URL with query parameters for padding, theme, and optional notation/format. + * `@param` params - Configuration object with viewId, padding, theme, and optional export settings + * `@returns` Formatted URL path with encoded viewId and query string + */ export function createExportViewUrl({As per coding guidelines: Use JSDoc to document public classes and methods.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4/src/cli/export/png/takeScreenshot.ts` around lines 33 - 55, Add a JSDoc block above the exported createExportViewUrl function that briefly describes its purpose (builds an export URL for a view with padding, theme, optional dynamicVariant, format, and notation), documents each parameter (viewId, padding, theme, dynamicVariant, format with default 'png', notation boolean) including accepted values/types, and documents the return value (string URL). Reference the behavior that it encodes viewId and includes query keys padding, theme, dynamic, notation, and format so callers understand what query params are produced.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/likec4-spa/src/pages/export-layout.spec.ts`:
- Around line 58-70: The assertion comparing layout.notation!.height to
layout.diagram.height - 20 * 2 - EXPORT_NOTATION_INSET is brittle and doesn't
match the Math.max logic in computeExportPageLayout; update the test in
export-layout.spec.ts to assert the exported page height grew because notation
dominated by verifying computeExportPageLayout produced a height larger than the
original diagram height (e.g.,
expect(layout.height).toBeGreaterThan(layout.diagram.height)) and/or assert
layout.height equals Math.max(layout.diagram.height, exportNotationHeight(5) +
padding * 2) using the same helpers (computeExportPageLayout,
exportNotationHeight, padding, EXPORT_NOTATION_INSET) so the test directly
reflects the function's intended behavior.
In `@packages/likec4-spa/src/pages/export-layout.ts`:
- Around line 59-69: The width calculation currently returns width:
diagram.width + EXPORT_NOTATION_GAP + EXPORT_NOTATION_WIDTH + padding and is
correct because diagram.width already includes padding * 2; add a short
clarifying comment next to this return (or above the calculation) explaining
that diagram.width contains both left and right padding and the extra padding
added here is only the right-side padding for the notation panel—reference the
symbols diagram.width, EXPORT_NOTATION_GAP, EXPORT_NOTATION_WIDTH, padding and
notation.left to make the intent clear.
In `@packages/likec4-spa/src/pages/ExportPage.tsx`:
- Around line 284-374: The prop object for ExportNotationItem should be made
readonly to enforce immutability at compile time; update the component signature
(ExportNotationItem) so its parameter type is { readonly entry: NodeNotation }
(or define a ReadonlyProps interface and use it) and ensure any references still
use entry but do not attempt to mutate it.
- Around line 240-246: The ExportNotationPanel component props should be marked
readonly to prevent accidental mutations: update the props type for
ExportNotationPanel (the object containing entries: NodeNotation[] and layout:
NonNullable<ReturnType<typeof computeExportPageLayout>['notation']>) to be
Readonly<...> (or use a readonly modifier on the entries and layout properties)
so TypeScript enforces immutability for entries and layout inside
ExportNotationPanel.
In `@packages/likec4/src/cli/export/png/takeScreenshot.ts`:
- Around line 33-55: Add a JSDoc block above the exported createExportViewUrl
function that briefly describes its purpose (builds an export URL for a view
with padding, theme, optional dynamicVariant, format, and notation), documents
each parameter (viewId, padding, theme, dynamicVariant, format with default
'png', notation boolean) including accepted values/types, and documents the
return value (string URL). Reference the behavior that it encodes viewId and
includes query keys padding, theme, dynamic, notation, and format so callers
understand what query params are produced.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 88f66ac6-b921-4645-8e1e-4bff741ea40e
📒 Files selected for processing (11)
.changeset/export-image-notation.mdapps/docs/src/content/docs/tooling/cli.mdxpackages/likec4-spa/src/pages/ExportPage.tsxpackages/likec4-spa/src/pages/export-layout.spec.tspackages/likec4-spa/src/pages/export-layout.tspackages/likec4-spa/src/routes/_single/export.$viewId.tsxpackages/likec4-spa/src/routes/project.$projectId/export.$viewId.tsxpackages/likec4/src/cli/export/jpg/handler.tspackages/likec4/src/cli/export/png/handler.tspackages/likec4/src/cli/export/png/takeScreenshot.spec.tspackages/likec4/src/cli/export/png/takeScreenshot.ts
f053497 to
afeca8c
Compare
|
@coderabbitai review |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
✅ Actions performedReview triggered.
|
afeca8c to
c27bee3
Compare
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/likec4-spa/src/pages/ExportPage.tsx (1)
287-293: ⚡ Quick winRemove the
as CSSPropertiescast and use explicit type instead.The cast on line 292 violates the coding guideline to avoid
ascasts. Replace it with an explicitPaletteCssVarstype that properly documents the expected CSS custom properties:Proposed fix
+type PaletteCssVars = CSSProperties & Record< + '--likec4-palette-fill' | '--likec4-palette-stroke' | '--likec4-palette-hiContrast' | '--likec4-palette-loContrast', + string +> + function ExportNotationItem({ entry }: Readonly<{ entry: NodeNotation }>) { const styles = useLikeC4Styles() const elementColors = styles.colors(entry.color).elements - const colorVars = { + const colorVars: PaletteCssVars = { '--likec4-palette-fill': elementColors.fill, '--likec4-palette-stroke': elementColors.stroke, '--likec4-palette-hiContrast': elementColors.hiContrast, '--likec4-palette-loContrast': elementColors.loContrast, - } as CSSProperties + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/ExportPage.tsx` around lines 287 - 293, Replace the inline "as CSSProperties" cast on colorVars with a proper explicit type: define or import a PaletteCssVars interface/type that maps the CSS custom property names ('--likec4-palette-fill', '--likec4-palette-stroke', '--likec4-palette-hiContrast', '--likec4-palette-loContrast') to string (or string | undefined if needed) and declare colorVars with that type (e.g., const colorVars: PaletteCssVars = { ... }), using elementColors.fill/stroke/hiContrast/loContrast for values so the cast is removed and the expected shape is documented.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/likec4-spa/src/pages/ExportPage.tsx`:
- Around line 287-293: Replace the inline "as CSSProperties" cast on colorVars
with a proper explicit type: define or import a PaletteCssVars interface/type
that maps the CSS custom property names ('--likec4-palette-fill',
'--likec4-palette-stroke', '--likec4-palette-hiContrast',
'--likec4-palette-loContrast') to string (or string | undefined if needed) and
declare colorVars with that type (e.g., const colorVars: PaletteCssVars = { ...
}), using elementColors.fill/stroke/hiContrast/loContrast for values so the cast
is removed and the expected shape is documented.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5b7f0bac-3653-4c39-978d-882e206e1c97
📒 Files selected for processing (11)
.changeset/export-image-notation.mdapps/docs/src/content/docs/tooling/cli.mdxpackages/likec4-spa/src/pages/ExportPage.tsxpackages/likec4-spa/src/pages/export-layout.spec.tspackages/likec4-spa/src/pages/export-layout.tspackages/likec4-spa/src/routes/_single/export.$viewId.tsxpackages/likec4-spa/src/routes/project.$projectId/export.$viewId.tsxpackages/likec4/src/cli/export/jpg/handler.tspackages/likec4/src/cli/export/png/handler.tspackages/likec4/src/cli/export/png/takeScreenshot.spec.tspackages/likec4/src/cli/export/png/takeScreenshot.ts
✅ Files skipped from review due to trivial changes (3)
- .changeset/export-image-notation.md
- packages/likec4/src/cli/export/png/takeScreenshot.spec.ts
- apps/docs/src/content/docs/tooling/cli.mdx
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/likec4-spa/src/pages/export-layout.ts
- packages/likec4-spa/src/pages/export-layout.spec.ts
- packages/likec4/src/cli/export/png/handler.ts
- packages/likec4/src/cli/export/png/takeScreenshot.ts
c27bee3 to
389d304
Compare
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/likec4-spa/src/pages/ExportPage.tsx (1)
247-289: 💤 Low valueConsider simplifying the key prop.
The key
${entry.title}-${index}works but might not be unique if entries share titles. Since this is a static render of a readonly array, using just the index would be simpler and sufficient.- {entries.map((entry, index) => <ExportNotationItem key={`${entry.title}-${index}`} entry={entry} />)} + {entries.map((entry, index) => <ExportNotationItem key={index} entry={entry} />)}This is a minor point; the current implementation is functional.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/likec4-spa/src/pages/ExportPage.tsx` around lines 247 - 289, In ExportNotationPanel, simplify the list key used in entries.map by using the map index as the key instead of the interpolated `${entry.title}-${index}`; update the call that renders ExportNotationItem (the entries.map callback) to pass key={index} since the array is a static readonly render and index is sufficient, which removes reliance on potentially non-unique titles.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/likec4-spa/src/pages/ExportPage.tsx`:
- Around line 247-289: In ExportNotationPanel, simplify the list key used in
entries.map by using the map index as the key instead of the interpolated
`${entry.title}-${index}`; update the call that renders ExportNotationItem (the
entries.map callback) to pass key={index} since the array is a static readonly
render and index is sufficient, which removes reliance on potentially non-unique
titles.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e3bf8610-2ed2-42de-84d6-02a2ebe6e6fc
📒 Files selected for processing (11)
.changeset/export-image-notation.mdapps/docs/src/content/docs/tooling/cli.mdxpackages/likec4-spa/src/pages/ExportPage.tsxpackages/likec4-spa/src/pages/export-layout.spec.tspackages/likec4-spa/src/pages/export-layout.tspackages/likec4-spa/src/routes/_single/export.$viewId.tsxpackages/likec4-spa/src/routes/project.$projectId/export.$viewId.tsxpackages/likec4/src/cli/export/jpg/handler.tspackages/likec4/src/cli/export/png/handler.tspackages/likec4/src/cli/export/png/takeScreenshot.spec.tspackages/likec4/src/cli/export/png/takeScreenshot.ts
|
CodeRabbit nitpick on the notation item key: keeping |
Summary
--notationto PNG/JPEG exports.Example
Checks
likec4...build