[Apps] Apps marketplace (first draft) (#17562)
https://github.com/user-attachments/assets/c4e63edb-6e98-44bc-841f-ee110ae712d4 How it works - `manifest.json` files are now committed when apps are published to our repo - to display available apps, from the server, we read into our github repo, using a pod-scoped cache - feature flagged - app installation will be behind permission gate MARKETPLACE_APPS Limitations and what is yet to develop - content and settings tabs - installed apps tab - app installation - test and potentially fix reading from .manifest.json once [Reshape manifest structure](https://github.com/twentyhq/core-team-issues/issues/2183) is done. additional work is expected on assets notably. (couldnt properly do it here as manifest.json will only be committed after this pr) - we only read in community/ folder for now - we may want tochange that - the cache is rather artisanal for now and scoped by pod - we may want to change that
This commit is contained in:
+6
-4
@@ -1,22 +1,23 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { ApplicationResolver } from 'src/engine/core-modules/application/application.resolver';
|
||||
import { ApplicationResolver } from 'src/engine/core-modules/application/resolvers/application.resolver';
|
||||
import { MarketplaceResolver } from 'src/engine/core-modules/application/resolvers/marketplace.resolver';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/services/application-sync.service';
|
||||
import { ApplicationVariableEntityModule } from 'src/engine/core-modules/applicationVariable/application-variable.module';
|
||||
import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
||||
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
|
||||
import { PermissionFlagModule } from 'src/engine/metadata-modules/permission-flag/permission-flag.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
||||
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
||||
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module';
|
||||
@@ -46,6 +47,7 @@ import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-commo
|
||||
],
|
||||
providers: [
|
||||
ApplicationResolver,
|
||||
MarketplaceResolver,
|
||||
ApplicationSyncService,
|
||||
WorkspaceMigrationGraphqlApiExceptionInterceptor,
|
||||
],
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { MarketplaceService } from 'src/engine/core-modules/application/services/marketplace.service';
|
||||
import { WorkspaceFlatApplicationMapCacheService } from 'src/engine/core-modules/application/services/workspace-flat-application-map-cache.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
@@ -15,7 +16,15 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
WorkspaceCacheModule,
|
||||
],
|
||||
exports: [ApplicationService, WorkspaceFlatApplicationMapCacheService],
|
||||
providers: [ApplicationService, WorkspaceFlatApplicationMapCacheService],
|
||||
exports: [
|
||||
ApplicationService,
|
||||
WorkspaceFlatApplicationMapCacheService,
|
||||
MarketplaceService,
|
||||
],
|
||||
providers: [
|
||||
ApplicationService,
|
||||
WorkspaceFlatApplicationMapCacheService,
|
||||
MarketplaceService,
|
||||
],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsArray,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
|
||||
@ObjectType('MarketplaceApp')
|
||||
export class MarketplaceAppDTO {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
id: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
@MaxLength(160)
|
||||
description: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
icon: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
version: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
author: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
category: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
logo?: string;
|
||||
|
||||
@IsArray()
|
||||
@Field(() => [String])
|
||||
screenshots: string[];
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
aboutDescription: string;
|
||||
|
||||
@IsArray()
|
||||
@Field(() => [String])
|
||||
providers: string[];
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
websiteUrl?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
termsUrl?: string;
|
||||
}
|
||||
+2
-2
@@ -16,17 +16,17 @@ import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
|
||||
import {
|
||||
ApplicationException,
|
||||
ApplicationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application.exception';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/application.dto';
|
||||
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
|
||||
import { InstallApplicationInput } from 'src/engine/core-modules/application/dtos/install-application.input';
|
||||
import { UninstallApplicationInput } from 'src/engine/core-modules/application/dtos/uninstallApplicationInput';
|
||||
import { UploadApplicationFileInput } from 'src/engine/core-modules/application/dtos/uploadApplicationFileInput';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/services/application-sync.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { FileDTO } from 'src/engine/core-modules/file/dtos/file.dto';
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
import { MarketplaceAppDTO } from 'src/engine/core-modules/application/dtos/marketplace-app.dto';
|
||||
import { MarketplaceService } from 'src/engine/core-modules/application/services/marketplace.service';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
|
||||
@Resolver()
|
||||
@UseGuards(UserAuthGuard, WorkspaceAuthGuard, NoPermissionGuard)
|
||||
export class MarketplaceResolver {
|
||||
constructor(private readonly marketplaceService: MarketplaceService) {}
|
||||
|
||||
@Query(() => [MarketplaceAppDTO])
|
||||
async findManyMarketplaceApps(): Promise<MarketplaceAppDTO[]> {
|
||||
return this.marketplaceService.findAllMarketplaceApps();
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.MARKETPLACE_APPS))
|
||||
async installMarketplaceApp(): Promise<boolean> {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -5,10 +5,10 @@ import { parse } from 'path';
|
||||
import {
|
||||
Manifest,
|
||||
FieldManifest,
|
||||
ObjectManifest,
|
||||
RoleManifest,
|
||||
LogicFunctionManifest,
|
||||
LogicFunctionTriggerManifest,
|
||||
ObjectManifest,
|
||||
RoleManifest,
|
||||
ObjectFieldManifest,
|
||||
RelationFieldManifest,
|
||||
} from 'twenty-shared/application';
|
||||
@@ -20,8 +20,8 @@ import {
|
||||
ApplicationException,
|
||||
ApplicationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application.exception';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
@@ -35,15 +35,15 @@ import { ObjectPermissionService } from 'src/engine/metadata-modules/object-perm
|
||||
import { PermissionFlagService } from 'src/engine/metadata-modules/permission-flag/permission-flag.service';
|
||||
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||
import { LogicFunctionLayerService } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.service';
|
||||
import { LogicFunctionV2Service } from 'src/engine/metadata-modules/logic-function/services/logic-function-v2.service';
|
||||
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { computeMetadataNameFromLabelOrThrow } from 'src/engine/metadata-modules/utils/compute-metadata-name-from-label-or-throw.util';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { LogicFunctionV2Service } from 'src/engine/metadata-modules/logic-function/services/logic-function-v2.service';
|
||||
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { computeMetadataNameFromLabelOrThrow } from 'src/engine/metadata-modules/utils/compute-metadata-name-from-label-or-throw.util';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationSyncService {
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { lowerCase, upperFirst } from 'lodash';
|
||||
import { type Manifest } from 'twenty-shared/application';
|
||||
|
||||
import { MarketplaceAppDTO } from 'src/engine/core-modules/application/dtos/marketplace-app.dto';
|
||||
|
||||
type GitHubContent = {
|
||||
name: string;
|
||||
path: string;
|
||||
type: 'file' | 'dir';
|
||||
download_url?: string;
|
||||
};
|
||||
|
||||
const GITHUB_RAW_BASE_URL =
|
||||
'https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-apps';
|
||||
const GITHUB_API_BASE_URL =
|
||||
'https://api.github.com/repos/twentyhq/twenty/contents/packages/twenty-apps';
|
||||
|
||||
const CACHE_TTL_MS = 60 * 60 * 1000;
|
||||
|
||||
@Injectable()
|
||||
export class MarketplaceService {
|
||||
private readonly logger = new Logger(MarketplaceService.name);
|
||||
|
||||
private cachedApps: MarketplaceAppDTO[] | null = null;
|
||||
private cacheTimestamp: number | null = null;
|
||||
|
||||
async findAllMarketplaceApps(): Promise<MarketplaceAppDTO[]> {
|
||||
if (this.isCacheValid()) {
|
||||
return this.cachedApps as MarketplaceAppDTO[];
|
||||
}
|
||||
|
||||
const apps = await this.fetchAllMarketplaceApps();
|
||||
|
||||
this.cachedApps = apps;
|
||||
this.cacheTimestamp = Date.now();
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
private isCacheValid(): boolean {
|
||||
if (this.cachedApps === null || this.cacheTimestamp === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Date.now() - this.cacheTimestamp < CACHE_TTL_MS;
|
||||
}
|
||||
|
||||
private async fetchAllMarketplaceApps(): Promise<MarketplaceAppDTO[]> {
|
||||
const apps: MarketplaceAppDTO[] = [];
|
||||
|
||||
apps.push(this.loadMockApp());
|
||||
|
||||
try {
|
||||
const appDirs = await this.getAppDirectoriesFromGitHub();
|
||||
|
||||
for (const appDir of appDirs) {
|
||||
try {
|
||||
const manifest = await this.loadAppManifestFromGithub(appDir);
|
||||
|
||||
if (manifest) {
|
||||
apps.push(manifest);
|
||||
} else {
|
||||
// to remove after manifest are committed to the repo
|
||||
const appName = appDir.replace(/^community\//, '');
|
||||
const appLabel = upperFirst(lowerCase(appName));
|
||||
|
||||
apps.push({
|
||||
id: appName,
|
||||
name: appLabel,
|
||||
description: '',
|
||||
icon: '',
|
||||
version: '',
|
||||
author: 'Anonymous',
|
||||
category: '',
|
||||
logo: undefined,
|
||||
screenshots: [],
|
||||
aboutDescription: '',
|
||||
providers: [],
|
||||
websiteUrl: '',
|
||||
termsUrl: '',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.warn(
|
||||
`Failed to load manifest from ${appDir}: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to fetch marketplace apps from GitHub: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
private loadMockApp(): MarketplaceAppDTO {
|
||||
// SVG logo as data URL
|
||||
const logoSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="#1a2744"><ellipse cx="38" cy="20" rx="28" ry="10"/><rect x="10" y="20" width="56" height="50"/><ellipse cx="38" cy="70" rx="28" ry="10"/><ellipse cx="38" cy="35" rx="28" ry="10" fill="none" stroke="#fff" stroke-width="3"/><ellipse cx="38" cy="52" rx="28" ry="10" fill="none" stroke="#fff" stroke-width="3"/><circle cx="72" cy="62" r="22" fill="#1a2744"/><circle cx="72" cy="62" r="18" fill="#fff"/><path d="M72 50 L72 74 M62 58 L72 48 L82 58" stroke="#1a2744" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>`;
|
||||
const logoDataUrl = `data:image/svg+xml,${encodeURIComponent(logoSvg)}`;
|
||||
|
||||
return {
|
||||
id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||||
name: 'Data Enrichment',
|
||||
description: 'Enrich your data easily. Choose your provider.',
|
||||
icon: 'IconSparkles',
|
||||
version: '1.0.0',
|
||||
author: 'Cosmos Labs',
|
||||
category: 'Data',
|
||||
logo: logoDataUrl,
|
||||
screenshots: [
|
||||
'https://placehold.co/800x400/f5f5f5/666?text=Screenshot+1',
|
||||
'https://placehold.co/800x400/f5f5f5/666?text=Screenshot+2',
|
||||
'https://placehold.co/800x400/f5f5f5/666?text=Screenshot+3',
|
||||
],
|
||||
aboutDescription:
|
||||
'Enhance your workspace with automated data intelligence. This app monitors your new records and automatically populates missing details such as job titles, company size, social profiles, and industry insights.',
|
||||
providers: ['Clearbit', 'Apollo', 'Hunter.io'],
|
||||
websiteUrl: 'https://google.com',
|
||||
termsUrl: 'https://google.com',
|
||||
};
|
||||
}
|
||||
|
||||
private async getAppDirectoriesFromGitHub(): Promise<string[]> {
|
||||
const directories: string[] = [];
|
||||
|
||||
const rootContents = await this.fetchGitHubDirectory('');
|
||||
|
||||
for (const entry of rootContents) {
|
||||
// if (entry.type !== 'dir') continue;
|
||||
// if (entry.name.startsWith('.')) continue;
|
||||
// if (entry.name === 'node_modules') continue;
|
||||
// if (entry.name === 'internal') continue;
|
||||
|
||||
if (entry.name === 'community') {
|
||||
const communityContents = await this.fetchGitHubDirectory('community');
|
||||
|
||||
for (const communityEntry of communityContents) {
|
||||
if (communityEntry.type !== 'dir') continue;
|
||||
if (communityEntry.name.startsWith('.')) continue;
|
||||
|
||||
directories.push(`community/${communityEntry.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return directories;
|
||||
}
|
||||
|
||||
private async fetchGitHubDirectory(path: string): Promise<GitHubContent[]> {
|
||||
const url = path ? `${GITHUB_API_BASE_URL}/${path}` : GITHUB_API_BASE_URL;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'Twenty-Marketplace',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`GitHub API error: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
private async fetchGitHubFile(path: string): Promise<string | null> {
|
||||
const url = `${GITHUB_RAW_BASE_URL}/${path}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'User-Agent': 'Twenty-Marketplace',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw new Error(`GitHub raw file error: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.text();
|
||||
}
|
||||
|
||||
private async loadAppManifestFromGithub(
|
||||
appPath: string,
|
||||
): Promise<MarketplaceAppDTO | null> {
|
||||
const manifestContent = await this.fetchGitHubFile(
|
||||
`${appPath}/.twenty/output/manifest.json`,
|
||||
);
|
||||
|
||||
if (!manifestContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const manifest = JSON.parse(manifestContent) as Manifest;
|
||||
|
||||
const { application, packageJson } = manifest;
|
||||
const marketplaceData = application.marketplaceData;
|
||||
|
||||
if (!marketplaceData?.author || !marketplaceData?.category) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: application.universalIdentifier,
|
||||
name: application.displayName ?? packageJson.name,
|
||||
description: application.description ?? '',
|
||||
icon: application.icon ?? 'IconApps',
|
||||
version: packageJson.version,
|
||||
author: marketplaceData.author,
|
||||
category: marketplaceData.category,
|
||||
logo: this.resolveAssetUrl(appPath, marketplaceData.logo),
|
||||
screenshots: this.resolveAssetUrls(appPath, marketplaceData.screenshots),
|
||||
aboutDescription: marketplaceData.aboutDescription ?? '',
|
||||
providers: marketplaceData.providers ?? [],
|
||||
websiteUrl: marketplaceData.websiteUrl,
|
||||
termsUrl: marketplaceData.termsUrl,
|
||||
};
|
||||
}
|
||||
|
||||
private resolveAssetUrl(
|
||||
appPath: string,
|
||||
relativePath: string | undefined,
|
||||
): string | undefined {
|
||||
if (!relativePath) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return `${GITHUB_RAW_BASE_URL}/${appPath}/${relativePath}`;
|
||||
}
|
||||
|
||||
private resolveAssetUrls(
|
||||
appPath: string,
|
||||
relativePaths: string[] | undefined,
|
||||
): string[] {
|
||||
if (!relativePaths) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return relativePaths
|
||||
.map((path) => this.resolveAssetUrl(appPath, path))
|
||||
.filter((url): url is string => url !== undefined);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { USER_SIGNUP_EVENT_NAME } from 'src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants';
|
||||
import { type AppTokenEntity } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ export enum FeatureFlagKey {
|
||||
IS_AI_ENABLED = 'IS_AI_ENABLED',
|
||||
IS_APPLICATION_ENABLED = 'IS_APPLICATION_ENABLED',
|
||||
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED = 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED',
|
||||
IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="#1a2744">
|
||||
<!-- Database cylinder -->
|
||||
<ellipse cx="38" cy="20" rx="28" ry="10"/>
|
||||
<rect x="10" y="20" width="56" height="50"/>
|
||||
<ellipse cx="38" cy="70" rx="28" ry="10"/>
|
||||
<!-- Database stripes -->
|
||||
<ellipse cx="38" cy="35" rx="28" ry="10" fill="none" stroke="#fff" stroke-width="3"/>
|
||||
<ellipse cx="38" cy="52" rx="28" ry="10" fill="none" stroke="#fff" stroke-width="3"/>
|
||||
<!-- Upload circle -->
|
||||
<circle cx="72" cy="62" r="22" fill="#1a2744"/>
|
||||
<circle cx="72" cy="62" r="18" fill="#fff"/>
|
||||
<!-- Upload arrow -->
|
||||
<path d="M72 50 L72 74 M62 58 L72 48 L82 58" stroke="#1a2744" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 743 B |
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"application": {
|
||||
"universalIdentifier": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"functionRoleUniversalIdentifier": "00000000-0000-0000-0000-000000000000",
|
||||
"displayName": "Data Enrichment",
|
||||
"description": "Enrich your data easily. Choose your provider.",
|
||||
"icon": "IconSparkles",
|
||||
"marketplaceData": {
|
||||
"author": "Cosmos Labs",
|
||||
"category": "Data",
|
||||
"logo": "assets/logo.png",
|
||||
"screenshots": [
|
||||
"assets/screenshot-1.png",
|
||||
"assets/screenshot-2.png",
|
||||
"assets/screenshot-3.png"
|
||||
],
|
||||
"aboutDescription": "Enhance your workspace with automated data intelligence. This app monitors your new records and automatically populates missing details such as job titles, company size, social profiles, and industry insights.",
|
||||
"providers": ["Clearbit", "Apollo", "Hunter.io"],
|
||||
"websiteUrl": "https://google.com",
|
||||
"termsUrl": "https://google.com"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"objects": [],
|
||||
"fields": [],
|
||||
"logicFunctions": [],
|
||||
"frontComponents": [],
|
||||
"roles": []
|
||||
},
|
||||
"publicAssets": [],
|
||||
"sources": {},
|
||||
"packageJson": {
|
||||
"name": "@twenty-apps/data-enrichment",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"yarnLock": ""
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { type Repository, type UpdateResult } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { AuthException } from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
|
||||
import { EmailVerificationService } from 'src/engine/core-modules/email-verification/services/email-verification.service';
|
||||
|
||||
@@ -24,7 +24,7 @@ import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/application.dto';
|
||||
import { fromFlatApplicationToApplicationDto } from 'src/engine/core-modules/application/utils/from-flat-application-to-application-dto.util';
|
||||
import { BillingEntitlementDTO } from 'src/engine/core-modules/billing/dtos/billing-entitlement.dto';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { ILike, IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type CreateAgentInput } from 'src/engine/metadata-modules/ai/ai-agent/dtos/create-agent.input';
|
||||
import { type UpdateAgentInput } from 'src/engine/metadata-modules/ai/ai-agent/dtos/update-agent.input';
|
||||
import { fromCreateAgentInputToFlatAgent } from 'src/engine/metadata-modules/ai/ai-agent/utils/from-create-agent-input-to-flat-agent.util';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import {
|
||||
CommandMenuItemException,
|
||||
CommandMenuItemExceptionCode,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type FindOneOptions, type Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { type DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import { Repository } from 'typeorm';
|
||||
import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
|
||||
import { type LogicFunctionExecuteResult } from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { AuditService } from 'src/engine/core-modules/audit/services/audit.service';
|
||||
import { LOGIC_FUNCTION_EXECUTED_EVENT } from 'src/engine/core-modules/audit/utils/events/workspace-event/logic-function/logic-function-executed';
|
||||
import { ApplicationTokenService } from 'src/engine/core-modules/auth/token/services/application-token.service';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard';
|
||||
import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard';
|
||||
import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard';
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { PageLayoutTabLayoutMode } from 'twenty-shared/types';
|
||||
import { computeDiffBetweenObjects, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout-tab/constants/flat-page-layout-tab-editable-properties.constant';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
|
||||
+2
-1
@@ -7,7 +7,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { TOOL_PERMISSION_FLAGS } from 'src/engine/metadata-modules/permissions/constants/tool-permission-flags';
|
||||
import {
|
||||
PermissionsException,
|
||||
@@ -119,6 +119,7 @@ export class PermissionsService {
|
||||
[PermissionFlagType.IMPERSONATE]: false,
|
||||
[PermissionFlagType.SSO_BYPASS]: false,
|
||||
[PermissionFlagType.PROFILE_INFORMATION]: false,
|
||||
[PermissionFlagType.MARKETPLACE_APPS]: false,
|
||||
},
|
||||
objectsPermissions: {},
|
||||
}) as const satisfies UserWorkspacePermissions;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { FlatRoleTarget } from 'src/engine/metadata-modules/flat-role-target/types/flat-role-target.type';
|
||||
|
||||
@@ -18,7 +18,7 @@ import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { ConfigService } from '@nestjs/config';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
|
||||
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { type Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterGroupLogicalOperator } from 'src/engine/metadata-modules/view-filter-group/enums/view-filter-group-logical-operator';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, type Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { fromCreateViewFilterGroupInputToFlatViewFilterGroupToCreate } from 'src/engine/metadata-modules/flat-view-filter-group/utils/from-create-view-filter-group-input-to-flat-view-filter-group-to-create.util';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { fromCreateViewFilterInputToFlatViewFilterToCreate } from 'src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { type Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
|
||||
import {
|
||||
ViewSortException,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { fromCreateWebhookInputToFlatWebhookToCreate } from 'src/engine/metadata-modules/flat-webhook/utils/from-create-webhook-input-to-flat-webhook-to-create.util';
|
||||
|
||||
+1
@@ -242,6 +242,7 @@ describe('WorkspaceEntityManager', () => {
|
||||
IS_NAVIGATION_MENU_ITEM_ENABLED: false,
|
||||
IS_FILES_FIELD_ENABLED: false,
|
||||
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED: false,
|
||||
IS_MARKETPLACE_ENABLED: false,
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false,
|
||||
},
|
||||
userWorkspaceRoleMap: {},
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { type DataSource } from 'typeorm';
|
||||
|
||||
import { type ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { seedBillingCustomers } from 'src/engine/workspace-manager/dev-seeder/core/billing/utils/seed-billing-customers.util';
|
||||
import { seedBillingSubscriptions } from 'src/engine/workspace-manager/dev-seeder/core/billing/utils/seed-billing-subscriptions.util';
|
||||
import {
|
||||
|
||||
+5
@@ -91,6 +91,11 @@ export const seedFeatureFlags = async ({
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_MARKETPLACE_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
Reference in New Issue
Block a user