Skip to content

feat(pricing): align desktop and marketing comparison tables#3867

Merged
saddlepaddle merged 1 commit into
mainfrom
feat-pricing-table-revamp
Apr 29, 2026
Merged

feat(pricing): align desktop and marketing comparison tables#3867
saddlepaddle merged 1 commit into
mainfrom
feat-pricing-table-revamp

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Apr 29, 2026

Summary

Mirrors the same set of changes on the desktop billing comparison table and the marketing /pricing comparison table:

  • Rename Cloud workspaces → Remote workspaces
  • Replace the inline (Coming Soon) text with proper Badges:
    • Remote workspaces → Beta (primary)
    • Mobile app → Coming soon (secondary)
  • Add an Automations row (Pro + Enterprise)
  • Reorder Features so they read top-to-bottom by surface area: Desktop app → Local workspaces → Remote workspaces → Automations → Mobile app → GitHub → Linear → Slack → Team collaboration
  • Drop the marketing-only "CLI" row (not on desktop, not actually shipping near-term)
  • Marketing renderer: replaces the single-purpose ComingSoonBadge with a RowBadge that picks primary/secondary styling from the row's badge config

The two comparison tables now show the exact same feature list in the exact same order.

Test plan

  • bun run typecheck and bun run lint clean (verified locally)
  • Open desktop Settings → Billing → Plans, confirm new order, Beta + Coming soon badges, Automations row
  • Open marketing site /pricing, scroll to comparison table — desktop and mobile breakpoints both show new order, badges, Automations row
  • Confirm CLI row no longer appears on marketing

Summary by cubic

Aligns the desktop Billing and marketing /pricing comparison tables so they show the same features in the same order, and replaces inline “Coming soon” text with clear badges.

  • New Features
    • Renamed “Cloud workspaces” → “Remote workspaces”.
    • Added “Automations” row (Pro + Enterprise).
    • Swapped inline text for badges: Remote workspaces = Beta (primary); Mobile app = Coming soon (secondary).
    • Reordered features: Desktop app → Local workspaces → Remote workspaces → Automations → Mobile app → GitHub → Linear → Slack → Team collaboration.
    • Removed the marketing-only “CLI” row; marketing table now uses a reusable RowBadge with primary/secondary variants.

Written for commit 7320a0f. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Enhanced pricing comparison table with improved status badges displaying Beta and Coming Soon indicators with better visual distinction
    • Added Automations feature to pricing comparison across all plans
  • Style

    • Improved visual presentation of feature status indicators throughout pricing tables for enhanced clarity

Renames Cloud → Remote workspaces, swaps the (Coming Soon) text for
proper Beta/Coming-soon Badges, adds an Automations row (Pro+),
and reorders Features so they read top-to-bottom by surface
(workspaces → automations → mobile → integrations → collab).
The marketing /pricing page mirrors the desktop billing comparison.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

A boolean comingSoon flag in the billing plan comparison feature is replaced with a more flexible badge object containing a label and variant. The changes span the desktop and marketing applications, updating the data model, constants, and component rendering logic across three files.

Changes

Cohort / File(s) Summary
Desktop Billing Comparison
apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx
Updated feature comparison data to replace comingSoon boolean with labeled badges (Beta, Coming soon). Adjusted table rendering to display a Badge component when row.badge exists instead of a text suffix.
Marketing Pricing Comparison
apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx, apps/marketing/src/app/pricing/constants.ts
Replaced comingSoon boolean in ComparisonRow interface with badge object (label, variant). Updated comparison constants to convert Remote workspaces and Mobile app entries to labeled badges, removed dedicated CLI row, and added Automations row. Updated component renderers to use RowBadge component when badge is present.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A badge so fine, a feature bright,
No more boolean, what a delight!
Beta, coming soon—labels clear,
Our comparison tables brought good cheer! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main objective of the changeset: aligning the desktop and marketing comparison tables to show identical features and styling.
Description check ✅ Passed The description is comprehensive and well-structured, covering the main changes, test plan, and related context, though it lacks explicit Type of Change selection and Related Issues linking as specified in the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-pricing-table-revamp

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR aligns the desktop billing comparison table and the marketing /pricing comparison table by renaming "Cloud workspaces" → "Remote workspaces", replacing inline (Coming Soon) text with structured badge configs, adding an Automations row, reordering features, and dropping the CLI row. All three files apply the same data shape change (comingSoon?: booleanbadge?: { label; variant }).

Confidence Score: 5/5

Safe to merge; all remaining findings are P2 style/copy issues that don't block functionality.

All changes are purely presentational data/UI updates with no logic, state, or API surface affected. The two P2 findings (uppercase badge casing in marketing, stale tier card feature bullets) are cosmetic inconsistencies that do not cause runtime errors or data problems.

No files require special attention.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx Replaces comingSoon boolean with a structured badge config, adds Badge import, reorders/renames features rows to match marketing — looks correct.
apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx Replaces ComingSoonBadge with RowBadge; the uppercase CSS class causes badge labels to render in ALL-CAPS on marketing while the desktop Badge renders normal-cased text, creating a visual inconsistency.
apps/marketing/src/app/pricing/constants.ts Comparison table data aligned with desktop (reorder, rename, new Automations row, badge config); PRICING_TIERS feature bullets still reference the dropped CLI and old "Mobile (coming soon)" label.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["ComparisonRow data\n{ label, values, badge? }"] --> B["Desktop page.tsx\n<Badge variant> from @superset/ui"]
    A --> C["Marketing constants.ts\nCOMPARISON_SECTIONS"]
    C --> D["ComparisonTable.tsx\n<RowBadge> span with CSS"]
    B --> E["Renders: 'Beta' / 'Coming soon'\n(normal case)"]
    D --> F["Renders: 'BETA' / 'COMING SOON'\n(uppercase via CSS class)"]
    E -.->|"Visual mismatch"| F
Loading

Comments Outside Diff (1)

  1. apps/marketing/src/app/pricing/constants.ts, line 35-41 (link)

    P2 Stale CLI and Mobile feature bullets in tier cards

    The comparison table now drops the CLI row and renames "Mobile" to "Mobile app", but PRICING_TIERS still lists "CLI (coming soon)" in the Free tier features and "Mobile (coming soon)" in the Pro tier. If those bullet lists are rendered anywhere on the pricing page, visitors will see the dropped CLI feature and a mismatched name for Mobile. Worth updating to keep the tier card copy consistent with the comparison table.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/marketing/src/app/pricing/constants.ts
    Line: 35-41
    
    Comment:
    **Stale CLI and Mobile feature bullets in tier cards**
    
    The comparison table now drops the CLI row and renames "Mobile" to "Mobile app", but `PRICING_TIERS` still lists `"CLI (coming soon)"` in the Free tier features and `"Mobile (coming soon)"` in the Pro tier. If those bullet lists are rendered anywhere on the pricing page, visitors will see the dropped CLI feature and a mismatched name for Mobile. Worth updating to keep the tier card copy consistent with the comparison table.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx
Line: 176-189

Comment:
**Badge text casing differs from desktop**

`RowBadge` applies `uppercase tracking-wide` in the marketing component, so "Beta" renders as **BETA** and "Coming soon" renders as **COMING SOON**. The desktop `<Badge>` component renders text exactly as-is, giving "Beta" and "Coming soon". Since this PR explicitly aligns the two tables, the uppercase transform creates a visible inconsistency that will be obvious when both surfaces show the same label.

Consider dropping `uppercase` from the class list (or applying it in both), so the rendered text matches what's in the data.

```suggestion
function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
	const isPrimary = badge.variant === "default";
	return (
		<span
			className={cn(
				"rounded-sm px-2 py-0.5 text-[10px] font-medium tracking-wide",
				isPrimary
					? "bg-foreground text-background"
					: "bg-accent/40 text-muted-foreground",
			)}
		>
			{badge.label}
		</span>
	);
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/marketing/src/app/pricing/constants.ts
Line: 35-41

Comment:
**Stale CLI and Mobile feature bullets in tier cards**

The comparison table now drops the CLI row and renames "Mobile" to "Mobile app", but `PRICING_TIERS` still lists `"CLI (coming soon)"` in the Free tier features and `"Mobile (coming soon)"` in the Pro tier. If those bullet lists are rendered anywhere on the pricing page, visitors will see the dropped CLI feature and a mismatched name for Mobile. Worth updating to keep the tier card copy consistent with the comparison table.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(pricing): align desktop and marketi..." | Re-trigger Greptile

Comment on lines +176 to 189
function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
const isPrimary = badge.variant === "default";
return (
<span
className={cn(
"rounded-sm bg-accent/40 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",
"rounded-sm px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide",
isPrimary
? "bg-foreground text-background"
: "bg-accent/40 text-muted-foreground",
)}
>
Coming soon
{badge.label}
</span>
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge text casing differs from desktop

RowBadge applies uppercase tracking-wide in the marketing component, so "Beta" renders as BETA and "Coming soon" renders as COMING SOON. The desktop <Badge> component renders text exactly as-is, giving "Beta" and "Coming soon". Since this PR explicitly aligns the two tables, the uppercase transform creates a visible inconsistency that will be obvious when both surfaces show the same label.

Consider dropping uppercase from the class list (or applying it in both), so the rendered text matches what's in the data.

Suggested change
function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
const isPrimary = badge.variant === "default";
return (
<span
className={cn(
"rounded-sm bg-accent/40 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",
"rounded-sm px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide",
isPrimary
? "bg-foreground text-background"
: "bg-accent/40 text-muted-foreground",
)}
>
Coming soon
{badge.label}
</span>
);
function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
const isPrimary = badge.variant === "default";
return (
<span
className={cn(
"rounded-sm px-2 py-0.5 text-[10px] font-medium tracking-wide",
isPrimary
? "bg-foreground text-background"
: "bg-accent/40 text-muted-foreground",
)}
>
{badge.label}
</span>
);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx
Line: 176-189

Comment:
**Badge text casing differs from desktop**

`RowBadge` applies `uppercase tracking-wide` in the marketing component, so "Beta" renders as **BETA** and "Coming soon" renders as **COMING SOON**. The desktop `<Badge>` component renders text exactly as-is, giving "Beta" and "Coming soon". Since this PR explicitly aligns the two tables, the uppercase transform creates a visible inconsistency that will be obvious when both surfaces show the same label.

Consider dropping `uppercase` from the class list (or applying it in both), so the rendered text matches what's in the data.

```suggestion
function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
	const isPrimary = badge.variant === "default";
	return (
		<span
			className={cn(
				"rounded-sm px-2 py-0.5 text-[10px] font-medium tracking-wide",
				isPrimary
					? "bg-foreground text-background"
					: "bg-accent/40 text-muted-foreground",
			)}
		>
			{badge.label}
		</span>
	);
}
```

How can I resolve this? If you propose a fix, please make it concise.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
apps/marketing/src/app/pricing/constants.ts (1)

105-113: ⚠️ Potential issue | 🟠 Major

Migrate remaining comingSoon usage to badge pattern.

The ComparisonRow migration from comingSoon?: boolean to badge?: { label: string; variant } is incomplete. A stale comingSoon: true, reference remains at apps/desktop/src/renderer/components/Paywall/constants.ts:75 and must be updated to match the new interface.

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

In `@apps/marketing/src/app/pricing/constants.ts` around lines 105 - 113,
ComparisonRow's shape changed from comingSoon?: boolean to badge?: { label:
string; variant: "default" | "secondary" }, so find the object still using
comingSoon: true and replace that property with badge: { label: "Coming soon",
variant: "secondary" } (or "default" if visually intended) so it conforms to the
ComparisonRow interface; update the object literal where comingSoon appears and
remove the comingSoon key, adding the badge key instead.
🧹 Nitpick comments (2)
apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx (1)

176-190: Prefer the shared Badge primitive here.

RowBadge is only restyling a badge chip; reusing @superset/ui/badge would keep the marketing and desktop tables visually aligned and avoid a second variant map.

Suggested change
+import { Badge } from "@superset/ui/badge";
 import { cn } from "@superset/ui/utils";
@@
 function RowBadge({ badge }: { badge: NonNullable<ComparisonRow["badge"]> }) {
-	const isPrimary = badge.variant === "default";
-	return (
-		<span
-			className={cn(
-				"rounded-sm px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide",
-				isPrimary
-					? "bg-foreground text-background"
-					: "bg-accent/40 text-muted-foreground",
-			)}
-		>
-			{badge.label}
-		</span>
-	);
+	return <Badge variant={badge.variant}>{badge.label}</Badge>;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx`
around lines 176 - 190, Replace the custom span in RowBadge with the shared
Badge component from `@superset/ui/badge`: import Badge and render <Badge> instead
of the span inside function RowBadge({ badge }: { badge:
NonNullable<ComparisonRow["badge"]> }), map the local badge.variant ("default"
vs other) to the Badge's variant prop (e.g., "default" -> Badge variant
"primary" or the project equivalent) and pass badge.label as children; remove
the custom className string and any duplicate styling so the component uses the
shared Badge's styling and variants to keep visuals consistent.
apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx (1)

50-54: Keep the comparison-row shape strict.

values: ComparisonValue[] is looser than the fixed 3-column grid, so a fourth value would compile even though the layout can't render it correctly. Reusing the shared tuple shape here would catch that mismatch earlier.

Suggested change
 type ComparisonRow = {
 	label: string;
-	values: ComparisonValue[];
+	values: [ComparisonValue, ComparisonValue, ComparisonValue];
 	badge?: { label: string; variant: "default" | "secondary" };
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx`
around lines 50 - 54, The ComparisonRow type allows any-length arrays via
values: ComparisonValue[] which lets a fourth value compile even though the UI
renders a fixed three-column grid; change the values property to the fixed tuple
type [ComparisonValue, ComparisonValue, ComparisonValue] (or the shared tuple
alias if one exists) so the compiler enforces exactly three columns—update the
ComparisonRow declaration to use that tuple and adjust any places that construct
ComparisonRow to supply exactly three ComparisonValue items (or refactor to
reuse the shared tuple type).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/marketing/src/app/pricing/constants.ts`:
- Around line 105-113: ComparisonRow's shape changed from comingSoon?: boolean
to badge?: { label: string; variant: "default" | "secondary" }, so find the
object still using comingSoon: true and replace that property with badge: {
label: "Coming soon", variant: "secondary" } (or "default" if visually intended)
so it conforms to the ComparisonRow interface; update the object literal where
comingSoon appears and remove the comingSoon key, adding the badge key instead.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx`:
- Around line 50-54: The ComparisonRow type allows any-length arrays via values:
ComparisonValue[] which lets a fourth value compile even though the UI renders a
fixed three-column grid; change the values property to the fixed tuple type
[ComparisonValue, ComparisonValue, ComparisonValue] (or the shared tuple alias
if one exists) so the compiler enforces exactly three columns—update the
ComparisonRow declaration to use that tuple and adjust any places that construct
ComparisonRow to supply exactly three ComparisonValue items (or refactor to
reuse the shared tuple type).

In
`@apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx`:
- Around line 176-190: Replace the custom span in RowBadge with the shared Badge
component from `@superset/ui/badge`: import Badge and render <Badge> instead of
the span inside function RowBadge({ badge }: { badge:
NonNullable<ComparisonRow["badge"]> }), map the local badge.variant ("default"
vs other) to the Badge's variant prop (e.g., "default" -> Badge variant
"primary" or the project equivalent) and pass badge.label as children; remove
the custom className string and any duplicate styling so the component uses the
shared Badge's styling and variants to keep visuals consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 70323c21-67e6-4793-b167-e362bf04efa0

📥 Commits

Reviewing files that changed from the base of the PR and between 55af7a5 and 7320a0f.

📒 Files selected for processing (3)
  • apps/desktop/src/renderer/routes/_authenticated/settings/billing/plans/page.tsx
  • apps/marketing/src/app/pricing/components/ComparisonTable/ComparisonTable.tsx
  • apps/marketing/src/app/pricing/constants.ts

@saddlepaddle saddlepaddle merged commit f723bf2 into main Apr 29, 2026
14 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.

1 participant