fix(website): query isVetted so the apps marketplace renders again (#22859)

## What

Production `/apps` renders no apps. The marketplace queries still
request `isFeatured`, but #22674 renamed that flag to `isVetted` across
the server schema (2-20 instance command renames the DB column — same
flag, same data, trust-signal semantics). Production (2.21) rejects the
query:

```
Cannot query field "isFeatured" on type "MarketplaceApp"
```

The transport throws on GraphQL errors, `fetchMarketplaceApps` catches
and falls back to `[]`, so the page renders the empty state.
`/apps/[slug]` detail pages degrade the same way.

## Fix

Rename `isFeatured` -> `isVetted` across the website marketplace module:
both queries, the API response types, the `MarketplaceApp` domain type,
and the vetted-first sort. 4 files, no behavior change beyond restoring
the data (same column, same values).

The catch-all `[]` fallback is intentionally left in place.

## Verification

- Corrected query run against `https://api.twenty.com/metadata`: returns
the 3 live apps (People Data Labs, Last contact, Call Recorder),
`isVetted: true`.
- Rename provenance confirmed: #22674 is a pure rename (paired diff,
symmetric column rename, `previousName: 'isFeatured'` marker on the
entity).
- `nx typecheck twenty-website` + `nx lint twenty-website` green.

Takes effect on the next website deploy (`force-dynamic` route, 300s
revalidate).
This commit is contained in:
Abdullah.
2026-07-13 16:56:35 +05:00
committed by GitHub
parent a6af730353
commit b06f3c7f8f
4 changed files with 8 additions and 10 deletions
@@ -88,9 +88,7 @@ export function AppsMarketplaceClient({ apps }: AppsMarketplaceClientProps) {
? apps
: apps.filter((app) => app.category === activeCategory);
return matching.toSorted(
(a, b) => Number(b.isFeatured) - Number(a.isFeatured),
);
return matching.toSorted((a, b) => Number(b.isVetted) - Number(a.isVetted));
}, [apps, activeCategory]);
return (
@@ -10,7 +10,7 @@ const FIND_MARKETPLACE_APP_DETAIL_QUERY = `
name
sourcePackage
latestAvailableVersion
isFeatured
isVetted
description
author
category
@@ -27,7 +27,7 @@ type ApiMarketplaceAppDetail = {
name: string;
sourcePackage?: string | null;
latestAvailableVersion?: string | null;
isFeatured: boolean;
isVetted: boolean;
description?: string | null;
author?: string | null;
category?: string | null;
@@ -71,7 +71,7 @@ export async function fetchMarketplaceAppDetailBySlug(
category: detail.category ?? app.category,
logoUrl: detail.logo ?? app.logoUrl,
sourcePackage: detail.sourcePackage ?? undefined,
isFeatured: detail.isFeatured,
isVetted: detail.isVetted,
description: detail.aboutDescription ?? detail.description ?? app.tagline,
screenshots: detail.screenshots ?? [],
websiteUrl: detail.websiteUrl ?? undefined,
@@ -12,7 +12,7 @@ const FIND_MANY_MARKETPLACE_APPS_QUERY = `
category
logo
sourcePackage
isFeatured
isVetted
}
}
`;
@@ -25,7 +25,7 @@ type ApiMarketplaceApp = {
category: string;
logo?: string | null;
sourcePackage?: string | null;
isFeatured: boolean;
isVetted: boolean;
};
type FindManyMarketplaceAppsData = {
@@ -41,7 +41,7 @@ const normalizeApp = (apiApp: ApiMarketplaceApp): MarketplaceApp => ({
category: apiApp.category,
logoUrl: apiApp.logo ?? undefined,
sourcePackage: apiApp.sourcePackage ?? undefined,
isFeatured: apiApp.isFeatured,
isVetted: apiApp.isVetted,
});
export async function fetchMarketplaceApps(): Promise<
@@ -7,7 +7,7 @@ export type MarketplaceApp = {
category: string;
logoUrl?: string;
sourcePackage?: string;
isFeatured: boolean;
isVetted: boolean;
};
export type MarketplaceAppDetail = MarketplaceApp & {