* Remove unused code in InstalledAppsLayout * Add new app categories "crm", "conferencing" and "messaging" * Sort getAppCategories entries alphabetically * Fix 404s on new category pages (and remove hardcoded category lists) * Fix admin apps list not showing "no available apps" for new categories * Recategorise apps * Sync seed-app-store categories with config files * Replace unnecessary seed-app-store.config.json with appStoreMetadata * Copy video.svg to conferencing.svg * Add messaging.svg * Remove web3 from getAppCategories (used by installed apps, admin apps) * Fix app-store-cli categories - Add conferencing - Add CRM - Remove video - Remove web3 * Remove outdated web3 comment in seed-app-store * Update apps/web/public/static/locales/en/common.json * Add cron script to keep db apps in sync with app metadata * Add redirect for app category "video" to "conferencing" * Fix up "video" category overrides to apply to conferencing * Fix conferencing apps not showing as a location for non-team users * Restore "installed_app" string for conferencing apps * Make linter happier * Remove my "installed_app_conferencing_description" as this was fixed upstream * Quick tidy up * Add dry-run to syncAppMeta via CRON_ENABLE_APP_SYNC env * Replace console.log with logger in syncAppMeta --------- Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: alannnc <alannnc@gmail.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: Omar López <zomars@me.com>
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import type { Prisma, PrismaClient } from "@prisma/client";
|
|
|
|
import { appKeysSchemas } from "@calcom/app-store/apps.keys-schemas.generated";
|
|
import { getLocalAppMetadata } from "@calcom/app-store/utils";
|
|
import { AppCategories } from "@calcom/prisma/enums";
|
|
|
|
import type { TrpcSessionUser } from "../../../trpc";
|
|
import type { TListLocalInputSchema } from "./listLocal.schema";
|
|
|
|
type ListLocalOptions = {
|
|
ctx: {
|
|
user: NonNullable<TrpcSessionUser>;
|
|
prisma: PrismaClient;
|
|
};
|
|
input: TListLocalInputSchema;
|
|
};
|
|
|
|
export const listLocalHandler = async ({ ctx, input }: ListLocalOptions) => {
|
|
const { prisma } = ctx;
|
|
const category = input.category;
|
|
const localApps = getLocalAppMetadata();
|
|
|
|
const dbApps = await prisma.app.findMany({
|
|
where: {
|
|
categories: {
|
|
has: AppCategories[category as keyof typeof AppCategories],
|
|
},
|
|
},
|
|
select: {
|
|
slug: true,
|
|
keys: true,
|
|
enabled: true,
|
|
dirName: true,
|
|
},
|
|
});
|
|
|
|
return localApps.flatMap((app) => {
|
|
// Filter applications that does not belong to the current requested category.
|
|
if (!(app.category === category || app.categories?.some((appCategory) => appCategory === category))) {
|
|
return [];
|
|
}
|
|
|
|
// Find app metadata
|
|
const dbData = dbApps.find((dbApp) => dbApp.slug === app.slug);
|
|
|
|
// If the app already contains keys then return
|
|
if (dbData?.keys) {
|
|
return {
|
|
name: app.name,
|
|
slug: app.slug,
|
|
logo: app.logo,
|
|
title: app.title,
|
|
type: app.type,
|
|
description: app.description,
|
|
// We know that keys are going to be an object or null. Prisma can not type check against JSON fields
|
|
keys: dbData.keys as Prisma.JsonObject | null,
|
|
dirName: app.dirName || app.slug,
|
|
enabled: dbData?.enabled || false,
|
|
isTemplate: app.isTemplate,
|
|
};
|
|
}
|
|
|
|
const keysSchema = appKeysSchemas[app.dirName as keyof typeof appKeysSchemas];
|
|
|
|
const keys: Record<string, string> = {};
|
|
|
|
// `typeof val === 'undefined'` is always slower than !== undefined comparison
|
|
// it is important to avoid string to string comparisons as much as we can
|
|
if (keysSchema !== undefined) {
|
|
// TODO: Why don't we parse with schema here? Not doing it makes default() not work in schema.
|
|
Object.values(keysSchema.keyof()._def.values).reduce((keysObject, key) => {
|
|
keys[key as string] = "";
|
|
return keysObject;
|
|
}, {} as Record<string, string>);
|
|
}
|
|
|
|
return {
|
|
name: app.name,
|
|
slug: app.slug,
|
|
logo: app.logo,
|
|
type: app.type,
|
|
title: app.title,
|
|
description: app.description,
|
|
enabled: dbData?.enabled ?? false,
|
|
dirName: app.dirName ?? app.slug,
|
|
keys: Object.keys(keys).length === 0 ? null : keys,
|
|
};
|
|
});
|
|
};
|