Skip to content

Refactor: extract shared frontend components to remove duplication#142

Merged
hackerwins merged 8 commits into
mainfrom
refactor/frontend-dedup
Apr 19, 2026
Merged

Refactor: extract shared frontend components to remove duplication#142
hackerwins merged 8 commits into
mainfrom
refactor/frontend-dedup

Conversation

@hackerwins

@hackerwins hackerwins commented Apr 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Extract ColorPickerGrid component — identical color grid + reset button pattern was duplicated 6 times across formatting-toolbar.tsx and docs-formatting-toolbar.tsx
  • Extract DataSourceFormFields component — create and edit datasource dialogs had identical 7-input form layouts
  • Extract AlignmentDropdown in docs toolbar — same 4-item alignment menu (Left/Center/Right/Justify with shortcuts) was duplicated in header/footer and body sections
  • Extract getLegendProps helper — same legend position calculation was duplicated across all 5 chart renderers

Net result: -103 lines (252 added, 355 removed) across 12 files.

Test plan

  • pnpm verify:fast passes (lint + all unit tests)
  • pnpm verify:self passes (includes builds)
  • Manual browser test: verify color pickers work in sheets and docs toolbars
  • Manual browser test: verify datasource create/edit dialogs work
  • Manual browser test: verify alignment dropdown in docs toolbar
  • Manual browser test: verify chart legend rendering for all chart types

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added color picker component with grid-based color selection interface.
    • Added text alignment dropdown for improved formatting options.
  • Refactor

    • Consolidated datasource form fields into reusable component.
    • Extracted and centralized chart legend positioning logic.
    • Improved error handling for document and image operations.
    • Unified image ID validation patterns across the application.

hackerwins and others added 4 commits April 19, 2026 16:29
The same Reset button + color grid pattern was duplicated 6 times
across formatting-toolbar.tsx (2x) and docs-formatting-toolbar.tsx
(4x). Extract into a shared ColorPickerGrid component.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The create and edit datasource dialogs had identical form field
layouts (7 inputs + SSL switch). Extract into a shared component
parameterized by idPrefix and passwordPlaceholder.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The same 4-item alignment dropdown (Left/Center/Right/Justify with
keyboard shortcuts) was duplicated in the header/footer and body
sections. Extract into a local AlignmentDropdown component.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The same verticalAlign/align calculation from legendPosition was
duplicated across all 5 chart renderers (line, bar, area, pie,
scatter). Extract into a getLegendProps helper in chart-registry.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hackerwins has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 47 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 45 minutes and 47 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 69000090-31d8-47ec-a19c-f19c78ace552

📥 Commits

Reviewing files that changed from the base of the PR and between a82bb07 and 0c5e322.

📒 Files selected for processing (8)
  • packages/docs/src/view/selection.ts
  • packages/frontend/src/app/spreadsheet/charts/area-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/bar-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/line-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/pie-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/scatter-chart-renderer.tsx
  • packages/frontend/src/components/color-picker-grid.tsx
  • packages/frontend/src/components/datasource-form-fields.tsx
📝 Walkthrough

Walkthrough

This PR consolidates common patterns across multiple packages into reusable utilities and components. Backend document handling shifts error handling from controllers to the service layer via a new getDocumentOrThrow method. Image ID validation is extracted to a constants file. Frontend introduces three reusable components (ColorPickerGrid, DataSourceFormFields, AlignmentDropdown) and a legend positioning helper. Docs view refactoring adds a pagination helper to reduce code duplication in table-cell lookups. Sheets coordinate utilities remove local range normalization implementations in favor of a centralized toRange function.

Changes

Cohort / File(s) Summary
Backend Document Service Refactoring
packages/backend/src/document/document.service.ts, packages/backend/src/api/v1/cells.controller.ts, packages/backend/src/api/v1/documents.controller.ts, packages/backend/src/api/v1/tabs.controller.ts
Introduced getDocumentOrThrow() method to centralize document-not-found error handling from controllers; controllers now delegate to service layer instead of manual null-checks and explicit NotFoundException throws.
Backend Image Validation
packages/backend/src/image/image.constants.ts, packages/backend/src/api/v1/images.controller.ts, packages/backend/src/image/image.controller.ts
Extracted image ID validation pattern from controllers into a shared VALID_IMAGE_ID_PATTERN constant; controllers updated to import and use the centralized pattern.
Frontend Form Components
packages/frontend/src/components/datasource-form-fields.tsx, packages/frontend/src/app/datasources/datasource-edit-dialog.tsx, packages/frontend/src/components/datasource-dialog.tsx
Created reusable DataSourceFormFields component; replaced duplicated form field implementations in two datasource dialogs with single component using controlled inputs and callback handlers.
Frontend Color Picker
packages/frontend/src/components/color-picker-grid.tsx, packages/frontend/src/app/docs/docs-formatting-toolbar.tsx, packages/frontend/src/components/formatting-toolbar.tsx
Introduced ColorPickerGrid component encapsulating color reset button and swatch grid; replaced inline color selection UI in two toolbar implementations.
Frontend Chart Legend
packages/frontend/src/app/spreadsheet/charts/chart-registry.ts, packages/frontend/src/app/spreadsheet/charts/area-chart-renderer.tsx, packages/frontend/src/app/spreadsheet/charts/bar-chart-renderer.tsx, packages/frontend/src/app/spreadsheet/charts/line-chart-renderer.tsx, packages/frontend/src/app/spreadsheet/charts/pie-chart-renderer.tsx, packages/frontend/src/app/spreadsheet/charts/scatter-chart-renderer.tsx
Added getLegendProps() helper to derive legend positioning logic; five chart renderers updated to use helper instead of inline conditional mapping of legendPosition to layout props.
Frontend Formatting Toolbar
packages/frontend/src/app/docs/docs-formatting-toolbar.tsx
Introduced reusable AlignmentDropdown component; replaced duplicated alignment dropdown markup in header/footer and desktop render paths.
Docs Pagination Utilities
packages/docs/src/view/pagination.ts, packages/docs/src/view/peer-cursor.ts, packages/docs/src/view/selection.ts
Added findPageLine() helper to locate page/line data by block and line indices; refactored peer-cursor.ts and selection.ts to use helper instead of manual iteration over paginated layout.
Sheets Range Normalization
packages/sheets/src/model/worksheet/conditional-format.ts, packages/sheets/src/model/worksheet/range-styles.ts
Removed local normalizeRange() implementations and delegated to centralized toRange() function imported from core/coordinates; updated all callers to use toRange() directly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Components nested, patterns refined,
Helpers shared, code realigned,
From forms to charts, in every place,
Reuse brings harmony and grace! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the primary objective: extracting shared components to eliminate frontend duplication across multiple files.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/frontend-dedup

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 114.5s

Lane Status Duration
sheets:build ✅ pass 12.4s
docs:build ✅ pass 7.8s
verify:fast ✅ pass 57.1s
frontend:build ✅ pass 15.4s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.6s
cli:build ✅ pass 1.7s
verify:entropy ✅ pass 15.1s

Verification: verify:integration

Result: ✅ PASS

hackerwins and others added 3 commits April 19, 2026 16:55
Add DocumentService.getDocumentOrThrow() to replace the repeated
document-not-found check across controllers (documents, tabs, cells).

Move VALID_ID_PATTERN to image.constants.ts so both image controllers
share the same regex instead of defining it independently.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The same nested loop scanning paginatedLayout.pages for a matching
blockIndex + lineIndex was duplicated 4 times across selection.ts
and peer-cursor.ts. Extract into findPageLine() in pagination.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
conditional-format.ts had a local cloneRange identical to the one
already exported from coordinates.ts — replaced with the import.
Both conditional-format.ts and range-styles.ts had local
normalizeRange functions that duplicate toRange() — removed them
and use toRange() directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/docs/src/view/selection.ts (1)

560-568: ⚠️ Potential issue | 🟡 Minor

Return early when the nested outer row cannot be resolved.

If findPageLine misses, baseY stays 0, and the subsequent nested rowYMap can render selection highlights at the wrong canvas position.

🐛 Proposed fix
   let baseY = 0;
   if (outerRowIndex >= 0) {
     const found = findPageLine(paginatedLayout, blockIndex, outerRowIndex);
-    if (found) {
-      baseY = found.pageY + found.pageLine.y + nestedYOffset;
-    }
+    if (!found) return [];
+    baseY = found.pageY + found.pageLine.y + nestedYOffset;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/docs/src/view/selection.ts` around lines 560 - 568, If outerRowIndex
>= 0 and findPageLine(paginatedLayout, blockIndex, outerRowIndex) returns
null/undefined, return early instead of leaving baseY at 0; locate the block
using findPageLine and the variables outerRowIndex, paginatedLayout, blockIndex
and nestedYOffset, and if not found bail out (e.g., return) before computing or
using the nested rowYMap so selection highlights are not rendered at the wrong Y
position.
🧹 Nitpick comments (6)
packages/frontend/src/app/spreadsheet/charts/chart-registry.ts (1)

138-152: LGTM — clean centralization of legend prop mapping.

The helper correctly narrows legendPosition to verticalAlign for top/bottom and align for left/right, leaving others undefined. The "none" case is defensively handled even though all current call sites guard with legendPosition !== "none".

Optional: since each renderer's Props.legendPosition duplicates the same string union, consider having them import and reuse the newly exported LegendPosition type to keep the union in a single place.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/spreadsheet/charts/chart-registry.ts` around lines
138 - 152, The code centralizes the legend-position union into the exported
LegendPosition type but renderers still duplicate the string union; update each
renderer Props that currently declares its own legendPosition union to import
and use the shared LegendPosition type (reference: LegendPosition and
getLegendProps, and chart renderer Prop declarations such as
Props.legendPosition or ChartRendererProps) so the union is maintained in one
place—replace local literal unions with the imported LegendPosition and run
type-checks to ensure no ABI changes.
packages/backend/src/api/v1/documents.controller.ts (1)

54-80: Potential optimization: fold the existence check into the write itself.

update and remove now issue two DB round-trips — a findUnique via getDocumentOrThrow purely to enforce workspace scoping, followed by updateDocument/deleteDocument keyed only by id. Because the subsequent write ignores workspaceId, the pre-check is load‑bearing for authorization, not just ergonomics, so it can't simply be dropped. You can collapse both concerns into a single query with updateMany/deleteMany using a compound where, treating a zero count as NotFoundException:

♻️ Sketch
// service
async updateDocumentScoped(where: Prisma.DocumentWhereInput, data: Prisma.DocumentUpdateInput) {
  const { count } = await this.prisma.document.updateMany({ where, data });
  if (!count) throw new NotFoundException('Document not found');
  // optionally re-fetch to return the updated row
  return this.prisma.document.findFirst({ where });
}

Non-blocking; only worth doing if these endpoints are hot. Otherwise the current shape is clear and consistent with the other controllers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/backend/src/api/v1/documents.controller.ts` around lines 54 - 80,
Both update and remove perform two DB round-trips: getDocumentOrThrow
(findUnique) then updateDocument/deleteDocument keyed only by id; fold existence
+ workspace scoping into a single write by adding service methods that use
Prisma's updateMany/deleteMany with a compound where (id + workspaceId), e.g.
implement documentService.updateDocumentScoped and
documentService.deleteDocumentScoped that call updateMany/deleteMany, throw
NotFoundException when count === 0, and optionally re-fetch with findFirst if
the controller needs the updated row; then have the controller's update and
remove call these new scoped methods instead of getDocumentOrThrow followed by
updateDocument/deleteDocument.
packages/frontend/src/components/datasource-form-fields.tsx (3)

92-101: Missing autoComplete on the password input.

Without autoComplete="new-password" (or "current-password" depending on context), browsers may offer to autofill stored credentials into this connection-password field, or prompt to save the DB password as a site login. Since this component is shared by both create and edit flows, autoComplete="new-password" is the safer default and can be overridden per-call later if needed.

🛡️ Suggested change
           <Input
             id={`${idPrefix}-password`}
             type="password"
+            autoComplete="new-password"
             placeholder={passwordPlaceholder}
             value={password}
             onChange={(e) => onPasswordChange(e.target.value)}
           />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/components/datasource-form-fields.tsx` around lines 92
- 101, The password Input in the datasource form (the Input element with id
built from idPrefix, props value={password}, onChange calling onPasswordChange,
and placeholder passwordPlaceholder) is missing an autoComplete attribute; add
autoComplete="new-password" to that Input component so browsers treat it as a
new/connection password by default (this is safe for both create/edit flows and
can be overridden by callers if needed).

63-71: Port input accepts any numeric string — consider min/max and non-integer guard.

type="number" allows negatives, decimals, and exponent notation (e.g. 1e5), all of which Number(port) will happily convert before sending to the backend. Since TCP ports are integers in [1, 65535], adding min={1} max={65535} step={1} (and optionally inputMode="numeric") would prevent obviously-invalid values reaching createWorkspaceDataSource / updateDataSource.

♻️ Suggested change
           <Input
             id={`${idPrefix}-port`}
             type="number"
+            min={1}
+            max={65535}
+            step={1}
+            inputMode="numeric"
             value={port}
             onChange={(e) => onPortChange(e.target.value)}
           />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/components/datasource-form-fields.tsx` around lines 63
- 71, The Port input currently allows negatives, decimals and exponent notation;
update the Input element in datasource-form-fields (the Input with id
`${idPrefix}-port`) to include min={1} max={65535} step={1} and
inputMode="numeric" to constrain UI input, and add a non-integer/invalid-value
guard in the onPortChange handler (or the function that receives it) to
coerce/validate to an integer in range before passing to
createWorkspaceDataSource/updateDataSource (reject or clamp values outside
[1,65535] and strip decimals so only integers are sent).

5-22: Optional: collapse the 7 on*Change props into a single onChange(field, value) or a values/onValuesChange pair.

The props interface is already 17 fields wide and will grow linearly with every new datasource field. A single discriminated onChange callback (or values: {...} + onValuesChange: (patch) => void) would reduce the prop surface at both call sites and remove the parallel-array-style maintenance burden when adding fields. Not blocking — current shape is fine and explicit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/components/datasource-form-fields.tsx` around lines 5 -
22, The props interface DataSourceFormFieldsProps is verbose due to seven
parallel on*Change callbacks; replace them with a single unified change API by
either adding onChange(field: string, value: string | boolean) and removing
onNameChange/onHostChange/onPortChange/onDatabaseChange/onUsernameChange/onPasswordChange/onSslEnabledChange,
or by switching to values: { name, host, port, database, username, password,
sslEnabled } plus onValuesChange(patch: Partial<typeof values>), then update the
component (where it currently calls the individual handlers) to call the new
onChange or onValuesChange and update all call sites to pass the consolidated
callback/values shape; keep idPrefix, passwordPlaceholder and other unrelated
props unchanged.
packages/frontend/src/components/datasource-dialog.tsx (1)

144-160: Consider passing an explicit passwordPlaceholder for the create dialog.

On the edit dialog the placeholder communicates "Leave blank to keep current", but here no placeholder is passed, so the password field renders with no hint at all. Previously the inline JSX may have had a placeholder; worth confirming the create form still gives users a cue (e.g. passwordPlaceholder="Password").

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/components/datasource-dialog.tsx` around lines 144 -
160, The DataSourceFormFields in the create dialog is missing an explicit
passwordPlaceholder prop so the password input shows no hint; update the
DataSourceFormFields usage in the create dialog to include passwordPlaceholder
(e.g., passwordPlaceholder="Password" or another appropriate cue) so the
password field renders a helpful placeholder; reference the DataSourceFormFields
component and its passwordPlaceholder prop when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/frontend/src/components/color-picker-grid.tsx`:
- Around line 12-26: The color swatch buttons lack accessible names and a button
type; update the button rendered inside colors.map in color-picker-grid.tsx to
include type="button" and an accessible label (e.g., aria-label or
aria-labelledby) that identifies the color (use the color string or a derived
human-readable name) so screen readers can announce the swatch, and keep the
existing onSelect handler intact; also add type="button" to the Reset button for
consistency with onReset.

---

Outside diff comments:
In `@packages/docs/src/view/selection.ts`:
- Around line 560-568: If outerRowIndex >= 0 and findPageLine(paginatedLayout,
blockIndex, outerRowIndex) returns null/undefined, return early instead of
leaving baseY at 0; locate the block using findPageLine and the variables
outerRowIndex, paginatedLayout, blockIndex and nestedYOffset, and if not found
bail out (e.g., return) before computing or using the nested rowYMap so
selection highlights are not rendered at the wrong Y position.

---

Nitpick comments:
In `@packages/backend/src/api/v1/documents.controller.ts`:
- Around line 54-80: Both update and remove perform two DB round-trips:
getDocumentOrThrow (findUnique) then updateDocument/deleteDocument keyed only by
id; fold existence + workspace scoping into a single write by adding service
methods that use Prisma's updateMany/deleteMany with a compound where (id +
workspaceId), e.g. implement documentService.updateDocumentScoped and
documentService.deleteDocumentScoped that call updateMany/deleteMany, throw
NotFoundException when count === 0, and optionally re-fetch with findFirst if
the controller needs the updated row; then have the controller's update and
remove call these new scoped methods instead of getDocumentOrThrow followed by
updateDocument/deleteDocument.

In `@packages/frontend/src/app/spreadsheet/charts/chart-registry.ts`:
- Around line 138-152: The code centralizes the legend-position union into the
exported LegendPosition type but renderers still duplicate the string union;
update each renderer Props that currently declares its own legendPosition union
to import and use the shared LegendPosition type (reference: LegendPosition and
getLegendProps, and chart renderer Prop declarations such as
Props.legendPosition or ChartRendererProps) so the union is maintained in one
place—replace local literal unions with the imported LegendPosition and run
type-checks to ensure no ABI changes.

In `@packages/frontend/src/components/datasource-dialog.tsx`:
- Around line 144-160: The DataSourceFormFields in the create dialog is missing
an explicit passwordPlaceholder prop so the password input shows no hint; update
the DataSourceFormFields usage in the create dialog to include
passwordPlaceholder (e.g., passwordPlaceholder="Password" or another appropriate
cue) so the password field renders a helpful placeholder; reference the
DataSourceFormFields component and its passwordPlaceholder prop when making the
change.

In `@packages/frontend/src/components/datasource-form-fields.tsx`:
- Around line 92-101: The password Input in the datasource form (the Input
element with id built from idPrefix, props value={password}, onChange calling
onPasswordChange, and placeholder passwordPlaceholder) is missing an
autoComplete attribute; add autoComplete="new-password" to that Input component
so browsers treat it as a new/connection password by default (this is safe for
both create/edit flows and can be overridden by callers if needed).
- Around line 63-71: The Port input currently allows negatives, decimals and
exponent notation; update the Input element in datasource-form-fields (the Input
with id `${idPrefix}-port`) to include min={1} max={65535} step={1} and
inputMode="numeric" to constrain UI input, and add a non-integer/invalid-value
guard in the onPortChange handler (or the function that receives it) to
coerce/validate to an integer in range before passing to
createWorkspaceDataSource/updateDataSource (reject or clamp values outside
[1,65535] and strip decimals so only integers are sent).
- Around line 5-22: The props interface DataSourceFormFieldsProps is verbose due
to seven parallel on*Change callbacks; replace them with a single unified change
API by either adding onChange(field: string, value: string | boolean) and
removing
onNameChange/onHostChange/onPortChange/onDatabaseChange/onUsernameChange/onPasswordChange/onSslEnabledChange,
or by switching to values: { name, host, port, database, username, password,
sslEnabled } plus onValuesChange(patch: Partial<typeof values>), then update the
component (where it currently calls the individual handlers) to call the new
onChange or onValuesChange and update all call sites to pass the consolidated
callback/values shape; keep idPrefix, passwordPlaceholder and other unrelated
props unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d08a71c-a34b-4509-ad43-5805bb26e671

📥 Commits

Reviewing files that changed from the base of the PR and between 0db208c and a82bb07.

📒 Files selected for processing (24)
  • packages/backend/src/api/v1/cells.controller.ts
  • packages/backend/src/api/v1/documents.controller.ts
  • packages/backend/src/api/v1/images.controller.ts
  • packages/backend/src/api/v1/tabs.controller.ts
  • packages/backend/src/document/document.service.ts
  • packages/backend/src/image/image.constants.ts
  • packages/backend/src/image/image.controller.ts
  • packages/docs/src/view/pagination.ts
  • packages/docs/src/view/peer-cursor.ts
  • packages/docs/src/view/selection.ts
  • packages/frontend/src/app/datasources/datasource-edit-dialog.tsx
  • packages/frontend/src/app/docs/docs-formatting-toolbar.tsx
  • packages/frontend/src/app/spreadsheet/charts/area-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/bar-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/chart-registry.ts
  • packages/frontend/src/app/spreadsheet/charts/line-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/pie-chart-renderer.tsx
  • packages/frontend/src/app/spreadsheet/charts/scatter-chart-renderer.tsx
  • packages/frontend/src/components/color-picker-grid.tsx
  • packages/frontend/src/components/datasource-dialog.tsx
  • packages/frontend/src/components/datasource-form-fields.tsx
  • packages/frontend/src/components/formatting-toolbar.tsx
  • packages/sheets/src/model/worksheet/conditional-format.ts
  • packages/sheets/src/model/worksheet/range-styles.ts

Comment thread packages/frontend/src/components/color-picker-grid.tsx
- Add type="button" and aria-label to ColorPickerGrid buttons
- Return early in buildCellRangeRects when nested page line is not
  found, preventing baseY from staying 0
- Add autoComplete="new-password" to datasource password input
- Reuse LegendPosition type in all chart renderers instead of
  duplicating the string union

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@hackerwins
hackerwins merged commit b2737b0 into main Apr 19, 2026
4 checks passed
@hackerwins
hackerwins deleted the refactor/frontend-dedup branch April 19, 2026 11:20
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.

1 participant