Only propose configured apps during onboarding install step (#22712)
## What - Onboarding "Install your first apps" now proposes only apps that are actually installable: it intersects the onboarding list with `findManyMarketplaceApps`, which the backend already filters to listed + configured apps (all required server variables set). - If none are available, the step auto-skips. If the marketplace query fails, it shows an intentional fallback (heading + Skip) instead of silently skipping or rendering an empty install card. - `findManyMarketplaceApps` now accepts `universalIdentifiers`, so onboarding fetches and configuration-checks only its own apps instead of the entire catalog. ## Why Previously the step rendered all hardcoded apps regardless of configuration, only borrowing logos from the marketplace, so a user could be offered an app the admin never configured. This centralizes onboarding availability on the marketplace's existing logic and keeps the query bounded as the marketplace grows. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22712?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@ export class MarketplacePublicResolver {
|
||||
@Args('isVetted', { type: () => Boolean, defaultValue: true })
|
||||
isVetted: boolean,
|
||||
): Promise<MarketplaceAppDTO[]> {
|
||||
return this.marketplaceQueryService.findManyMarketplaceApps(isVetted);
|
||||
return this.marketplaceQueryService.findManyMarketplaceApps({ isVetted });
|
||||
}
|
||||
|
||||
@Query(() => MarketplaceAppDetailDTO, { name: 'publicMarketplaceAppDetail' })
|
||||
|
||||
+15
-4
@@ -22,16 +22,27 @@ export class MarketplaceQueryService {
|
||||
private readonly coreEntityCacheService: CoreEntityCacheService,
|
||||
) {}
|
||||
|
||||
async findManyMarketplaceApps(
|
||||
isVetted?: boolean,
|
||||
): Promise<MarketplaceAppDTO[]> {
|
||||
async findManyMarketplaceApps({
|
||||
universalIdentifiers,
|
||||
isVetted,
|
||||
}: {
|
||||
universalIdentifiers?: string[];
|
||||
isVetted?: boolean;
|
||||
} = {}): Promise<MarketplaceAppDTO[]> {
|
||||
const appsByUniversalIdentifier =
|
||||
(await this.coreEntityCacheService.get(
|
||||
'marketplaceCatalog',
|
||||
MARKETPLACE_CATALOG_CACHE_ENTITY_ID,
|
||||
)) ?? {};
|
||||
|
||||
const apps = Object.values(appsByUniversalIdentifier);
|
||||
const apps = isNonEmptyArray(universalIdentifiers)
|
||||
? universalIdentifiers
|
||||
.map(
|
||||
(universalIdentifier) =>
|
||||
appsByUniversalIdentifier[universalIdentifier],
|
||||
)
|
||||
.filter(isDefined)
|
||||
: Object.values(appsByUniversalIdentifier);
|
||||
|
||||
if (!isDefined(isVetted)) {
|
||||
return apps;
|
||||
|
||||
+11
-2
@@ -28,8 +28,17 @@ export class MarketplaceResolver {
|
||||
) {}
|
||||
|
||||
@Query(() => [MarketplaceAppDTO])
|
||||
async findManyMarketplaceApps(): Promise<MarketplaceAppDTO[]> {
|
||||
return this.marketplaceQueryService.findManyMarketplaceApps();
|
||||
async findManyMarketplaceApps(
|
||||
@Args({
|
||||
name: 'universalIdentifiers',
|
||||
type: () => [String],
|
||||
nullable: true,
|
||||
})
|
||||
universalIdentifiers?: string[],
|
||||
): Promise<MarketplaceAppDTO[]> {
|
||||
return this.marketplaceQueryService.findManyMarketplaceApps({
|
||||
universalIdentifiers,
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => MarketplaceAppDetailDTO)
|
||||
|
||||
Reference in New Issue
Block a user