Add server translation (#9847)
First proof of concept for server-side translation. The goal was to translate one metadata item: <img width="939" alt="Screenshot 2025-01-26 at 08 18 41" src="https://github.com/user-attachments/assets/e42a3f7f-f5e3-4ee7-9be5-272a2adccb23" />
This commit is contained in:
@ -240,7 +240,7 @@
|
||||
"@stylistic/eslint-plugin": "^1.5.0",
|
||||
"@swc-node/register": "1.8.0",
|
||||
"@swc/cli": "^0.3.12",
|
||||
"@swc/core": "~1.3.100",
|
||||
"@swc/core": "1.7.42",
|
||||
"@swc/helpers": "~0.5.2",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "14.0.0",
|
||||
|
||||
@ -25,8 +25,12 @@ export default defineConfig({
|
||||
],
|
||||
catalogsMergePath: '<rootDir>/src/locales/generated/{locale}',
|
||||
compileNamespace: 'ts',
|
||||
service: {
|
||||
name: 'TranslationIO',
|
||||
apiKey: process.env.TRANSLATION_IO_API_KEY ?? '',
|
||||
},
|
||||
...(process.env.TRANSLATION_IO_API_KEY
|
||||
? {
|
||||
service: {
|
||||
name: 'TranslationIO',
|
||||
apiKey: process.env.TRANSLATION_IO_API_KEY,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
@ -29,6 +29,7 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
||||
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
|
||||
currentWorkspaceState,
|
||||
);
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||
currentWorkspaceMemberState,
|
||||
@ -61,6 +62,7 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
||||
connectToDevTools: isDebugMode,
|
||||
// We don't want to re-create the client on token change or it will cause infinite loop
|
||||
initialTokenPair: tokenPair,
|
||||
currentWorkspaceMember: currentWorkspaceMember,
|
||||
onTokenPairChange: (tokenPair) => {
|
||||
setTokenPair(tokenPair);
|
||||
},
|
||||
@ -105,5 +107,11 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
||||
}
|
||||
}, [tokenPair]);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (isDefined(apolloRef.current)) {
|
||||
apolloRef.current.updateWorkspaceMember(currentWorkspaceMember);
|
||||
}
|
||||
}, [currentWorkspaceMember]);
|
||||
|
||||
return apolloClient;
|
||||
};
|
||||
|
||||
@ -21,12 +21,22 @@ jest.mock('@/auth/services/AuthService', () => {
|
||||
const mockOnError = jest.fn();
|
||||
const mockOnNetworkError = jest.fn();
|
||||
|
||||
const mockWorkspaceMember = {
|
||||
id: 'workspace-member-id',
|
||||
locale: 'en',
|
||||
name: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
};
|
||||
|
||||
const createMockOptions = (): Options<any> => ({
|
||||
uri: 'http://localhost:3000',
|
||||
initialTokenPair: {
|
||||
accessToken: { token: 'mockAccessToken', expiresAt: '' },
|
||||
refreshToken: { token: 'mockRefreshToken', expiresAt: '' },
|
||||
},
|
||||
currentWorkspaceMember: mockWorkspaceMember,
|
||||
cache: new InMemoryCache(),
|
||||
isDebugMode: true,
|
||||
onError: mockOnError,
|
||||
@ -50,13 +60,21 @@ const makeRequest = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
describe('xApolloFactory', () => {
|
||||
describe('ApolloFactory', () => {
|
||||
it('should create an instance of ApolloFactory', () => {
|
||||
const options = createMockOptions();
|
||||
const apolloFactory = new ApolloFactory(options);
|
||||
expect(apolloFactory).toBeInstanceOf(ApolloFactory);
|
||||
});
|
||||
|
||||
it('should initialize with the correct workspace member', () => {
|
||||
const options = createMockOptions();
|
||||
const apolloFactory = new ApolloFactory(options);
|
||||
expect(apolloFactory['currentWorkspaceMember']).toEqual(
|
||||
mockWorkspaceMember,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call onError when encountering "Unauthorized" error', async () => {
|
||||
const errors = [{ message: 'Unauthorized' }];
|
||||
fetchMock.mockResponse(() =>
|
||||
@ -138,4 +156,21 @@ describe('xApolloFactory', () => {
|
||||
expect(mockOnNetworkError).toHaveBeenCalledWith(mockError);
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
it('should update workspace member when calling updateWorkspaceMember', () => {
|
||||
const options = createMockOptions();
|
||||
const apolloFactory = new ApolloFactory(options);
|
||||
|
||||
const newWorkspaceMember = {
|
||||
id: 'new-workspace-member-id',
|
||||
locale: 'fr',
|
||||
name: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
};
|
||||
|
||||
apolloFactory.updateWorkspaceMember(newWorkspaceMember);
|
||||
expect(apolloFactory['currentWorkspaceMember']).toEqual(newWorkspaceMember);
|
||||
});
|
||||
});
|
||||
|
||||
@ -12,6 +12,7 @@ import { RetryLink } from '@apollo/client/link/retry';
|
||||
import { createUploadLink } from 'apollo-upload-client';
|
||||
|
||||
import { renewToken } from '@/auth/services/AuthService';
|
||||
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { AuthTokenPair } from '~/generated/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { logDebug } from '~/utils/logDebug';
|
||||
@ -28,6 +29,7 @@ export interface Options<TCacheShape> extends ApolloClientOptions<TCacheShape> {
|
||||
onTokenPairChange?: (tokenPair: AuthTokenPair) => void;
|
||||
onUnauthenticatedError?: () => void;
|
||||
initialTokenPair: AuthTokenPair | null;
|
||||
currentWorkspaceMember: CurrentWorkspaceMember | null;
|
||||
extraLinks?: ApolloLink[];
|
||||
isDebugMode?: boolean;
|
||||
}
|
||||
@ -35,6 +37,7 @@ export interface Options<TCacheShape> extends ApolloClientOptions<TCacheShape> {
|
||||
export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
private client: ApolloClient<TCacheShape>;
|
||||
private tokenPair: AuthTokenPair | null = null;
|
||||
private currentWorkspaceMember: CurrentWorkspaceMember | null = null;
|
||||
|
||||
constructor(opts: Options<TCacheShape>) {
|
||||
const {
|
||||
@ -44,12 +47,14 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
onTokenPairChange,
|
||||
onUnauthenticatedError,
|
||||
initialTokenPair,
|
||||
currentWorkspaceMember,
|
||||
extraLinks,
|
||||
isDebugMode,
|
||||
...options
|
||||
} = opts;
|
||||
|
||||
this.tokenPair = initialTokenPair;
|
||||
this.currentWorkspaceMember = currentWorkspaceMember;
|
||||
|
||||
const buildApolloLink = (): ApolloLink => {
|
||||
const httpLink = createUploadLink({
|
||||
@ -64,6 +69,9 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
authorization: this.tokenPair?.accessToken.token
|
||||
? `Bearer ${this.tokenPair?.accessToken.token}`
|
||||
: '',
|
||||
...(this.currentWorkspaceMember?.locale
|
||||
? { 'x-locale': this.currentWorkspaceMember.locale }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -157,6 +165,10 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
this.tokenPair = tokenPair;
|
||||
}
|
||||
|
||||
updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null) {
|
||||
this.currentWorkspaceMember = workspaceMember;
|
||||
}
|
||||
|
||||
getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { ApolloClient } from '@apollo/client';
|
||||
|
||||
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { AuthTokenPair } from '~/generated/graphql';
|
||||
|
||||
export interface ApolloManager<TCacheShape> {
|
||||
getClient(): ApolloClient<TCacheShape>;
|
||||
updateTokenPair(tokenPair: AuthTokenPair | null): void;
|
||||
updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null): void;
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"sourceMaps": true,
|
||||
@ -8,7 +7,12 @@
|
||||
"decorators": true,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"baseUrl": "./../../"
|
||||
"baseUrl": "./../../",
|
||||
"experimental": {
|
||||
"plugins": [
|
||||
["@lingui/swc-plugin", {}]
|
||||
]
|
||||
}
|
||||
},
|
||||
"minify": false
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const jestConfig: JestConfigWithTsJest = {
|
||||
const jestConfig = {
|
||||
// to enable logs, comment out the following line
|
||||
silent: true,
|
||||
clearMocks: true,
|
||||
@ -10,7 +8,24 @@ const jestConfig: JestConfigWithTsJest = {
|
||||
transformIgnorePatterns: ['/node_modules/'],
|
||||
testRegex: '.*\\.spec\\.ts$',
|
||||
transform: {
|
||||
'^.+\\.(t|j)s$': 'ts-jest',
|
||||
'^.+\\.(t|j)s$': [
|
||||
'@swc/jest',
|
||||
{
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
tsx: false,
|
||||
decorators: true,
|
||||
},
|
||||
transform: {
|
||||
decoratorMetadata: true,
|
||||
},
|
||||
experimental: {
|
||||
plugins: [['@lingui/swc-plugin', {}]],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^src/(.*)': '<rootDir>/src/$1',
|
||||
|
||||
25
packages/twenty-server/lingui.config.js
Normal file
25
packages/twenty-server/lingui.config.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { defineConfig } from '@lingui/cli';
|
||||
|
||||
export default defineConfig({
|
||||
sourceLocale: 'en',
|
||||
locales: ['en', 'fr'],
|
||||
extractorParserOptions: {
|
||||
tsExperimentalDecorators: true,
|
||||
},
|
||||
catalogs: [
|
||||
{
|
||||
path: '<rootDir>/src/engine/core-modules/i18n/locales/{locale}',
|
||||
include: ['src'],
|
||||
},
|
||||
],
|
||||
catalogsMergePath:
|
||||
'<rootDir>/src/engine/core-modules/i18n/locales/generated/{locale}',
|
||||
...(process.env.TRANSLATION_IO_API_KEY_BACKEND
|
||||
? {
|
||||
service: {
|
||||
name: 'TranslationIO',
|
||||
apiKey: process.env.TRANSLATION_IO_API_KEY_BACKEND,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
@ -209,6 +209,20 @@
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "seed"
|
||||
},
|
||||
"lingui:extract": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "{projectRoot}",
|
||||
"command": "lingui extract --overwrite"
|
||||
}
|
||||
},
|
||||
"lingui:compile": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "{projectRoot}",
|
||||
"command": "lingui compile --typescript"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/
|
||||
import { ModulesModule } from 'src/modules/modules.module';
|
||||
|
||||
import { CoreEngineModule } from './engine/core-modules/core-engine.module';
|
||||
import { I18nModule } from './engine/core-modules/i18n/i18n.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -51,6 +52,8 @@ import { CoreEngineModule } from './engine/core-modules/core-engine.module';
|
||||
CoreGraphQLApiModule,
|
||||
MetadataGraphQLApiModule,
|
||||
RestApiModule,
|
||||
// I18n module for translations
|
||||
I18nModule,
|
||||
// Conditional modules
|
||||
...AppModule.getConditionalModules(),
|
||||
],
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { isDefined } from 'class-validator';
|
||||
import { Plugin } from 'graphql-yoga';
|
||||
|
||||
export type CacheMetadataPluginConfig = {
|
||||
@ -12,8 +13,12 @@ export function useCachedMetadata(config: CacheMetadataPluginConfig): Plugin {
|
||||
const workspaceMetadataVersion =
|
||||
serverContext.req.workspaceMetadataVersion ?? '0';
|
||||
const operationName = getOperationName(serverContext);
|
||||
const locale = serverContext.req.headers['x-locale'] ?? '';
|
||||
const localeCacheKey = isDefined(serverContext.req.headers['x-locale'])
|
||||
? `:${locale}`
|
||||
: '';
|
||||
|
||||
return `graphql:operations:${operationName}:${workspaceId}:${workspaceMetadataVersion}`;
|
||||
return `graphql:operations:${operationName}:${workspaceId}:${workspaceMetadataVersion}${localeCacheKey}`;
|
||||
};
|
||||
|
||||
const getOperationName = (serverContext: any) =>
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { expect, jest } from '@jest/globals';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { AdminPanelService } from 'src/engine/core-modules/admin-panel/admin-panel.service';
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
const UserFindOneMock = jest.fn();
|
||||
const WorkspaceFindOneMock = jest.fn();
|
||||
|
||||
@ -16,6 +16,7 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
|
||||
import { BeforeCreateOneAppToken } from 'src/engine/core-modules/app-token/hooks/before-create-one-app-token.hook';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
export enum AppTokenType {
|
||||
RefreshToken = 'REFRESH_TOKEN',
|
||||
CodeChallenge = 'CODE_CHALLENGE',
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { expect, jest } from '@jest/globals';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [I18nService],
|
||||
exports: [I18nService],
|
||||
})
|
||||
export class I18nModule {}
|
||||
@ -0,0 +1,16 @@
|
||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
|
||||
import { i18n } from '@lingui/core';
|
||||
|
||||
import { messages as enMessages } from 'src/engine/core-modules/i18n/locales/generated/en.js';
|
||||
import { messages as frMessages } from 'src/engine/core-modules/i18n/locales/generated/fr.js';
|
||||
|
||||
@Injectable()
|
||||
export class I18nService implements OnModuleInit {
|
||||
async onModuleInit() {
|
||||
i18n.load('fr', frMessages);
|
||||
i18n.load('en', enMessages);
|
||||
|
||||
i18n.activate('en');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2025-01-25 21:24+0100\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: en\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:56
|
||||
#~ msgid "Company"
|
||||
#~ msgstr "Company"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:57
|
||||
#~ msgid "Companies"
|
||||
#~ msgstr "Companies"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:58
|
||||
#~ msgid "A company"
|
||||
#~ msgstr "A company"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:58
|
||||
msgid "A company"
|
||||
msgstr "A company"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:57
|
||||
msgid "Companies"
|
||||
msgstr "Companies"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:56
|
||||
msgid "Company"
|
||||
msgstr "Company"
|
||||
@ -0,0 +1,20 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2025-01-26 21:19+0100\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: fr\n"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:58
|
||||
msgid "A company"
|
||||
msgstr "Une entreprise"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:57
|
||||
msgid "Companies"
|
||||
msgstr "Entreprises"
|
||||
|
||||
#: src/modules/company/standard-objects/company.workspace-entity.ts:56
|
||||
msgid "Company"
|
||||
msgstr "Entreprise"
|
||||
@ -0,0 +1 @@
|
||||
/*eslint-disable*/module.exports={messages:JSON.parse("{\"Company\":[\"Company\"],\"Companies\":[\"Companies\"],\"A company\":[\"A company\"],\"kZR6+h\":[\"A company\"],\"s2QZS6\":[\"Companies\"],\"7i8j3G\":[\"Company\"]}")};
|
||||
@ -0,0 +1 @@
|
||||
/*eslint-disable*/module.exports={messages:JSON.parse("{\"Company\":[\"Entreprise\"],\"Companies\":[\"Entreprises\"],\"A company\":[\"Une entreprise\"],\"kZR6+h\":[\"Une entreprise\"],\"s2QZS6\":[\"Entreprises\"],\"7i8j3G\":[\"Entreprise\"]}")};
|
||||
@ -1,8 +1,6 @@
|
||||
import { ExecutionContext } from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { expect, jest } from '@jest/globals';
|
||||
|
||||
import { ImpersonateGuard } from 'src/engine/guards/impersonate-guard';
|
||||
|
||||
describe('ImpersonateGuard', () => {
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
import {
|
||||
Args,
|
||||
Context,
|
||||
Mutation,
|
||||
Parent,
|
||||
ResolveField,
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
@ -22,6 +29,30 @@ export class ObjectMetadataResolver {
|
||||
private readonly beforeUpdateOneObject: BeforeUpdateOneObject<UpdateObjectPayload>,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => String, { nullable: true })
|
||||
async labelPlural(
|
||||
@Parent() objectMetadata: ObjectMetadataDTO,
|
||||
@Context() context,
|
||||
): Promise<string> {
|
||||
return this.objectMetadataService.resolveTranslatableString(
|
||||
objectMetadata,
|
||||
'labelPlural',
|
||||
context.req.headers['x-locale'],
|
||||
);
|
||||
}
|
||||
|
||||
@ResolveField(() => String, { nullable: true })
|
||||
async labelSingular(
|
||||
@Parent() objectMetadata: ObjectMetadataDTO,
|
||||
@Context() context,
|
||||
): Promise<string> {
|
||||
return this.objectMetadataService.resolveTranslatableString(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
context.req.headers['x-locale'],
|
||||
);
|
||||
}
|
||||
|
||||
@Mutation(() => ObjectMetadataDTO)
|
||||
async deleteOneObject(
|
||||
@Args('input') input: DeleteOneObjectInput,
|
||||
|
||||
@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import console from 'console';
|
||||
|
||||
import { i18n } from '@lingui/core';
|
||||
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { isDefined } from 'class-validator';
|
||||
@ -14,6 +15,7 @@ import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataService } from 'src/engine/metadata-modules/index-metadata/index-metadata.service';
|
||||
import { DeleteOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/delete-object.input';
|
||||
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
import { UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
@ -533,4 +535,18 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
async resolveTranslatableString(
|
||||
objectMetadata: ObjectMetadataDTO,
|
||||
labelKey: 'labelPlural' | 'labelSingular',
|
||||
locale: string,
|
||||
): Promise<string> {
|
||||
if (objectMetadata.isCustom) {
|
||||
return objectMetadata[labelKey];
|
||||
}
|
||||
|
||||
i18n.activate(locale);
|
||||
|
||||
return i18n._(objectMetadata[labelKey]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,6 @@ export class GraphQLHydrateRequestFromTokenMiddleware
|
||||
|
||||
const excludedOperations = [
|
||||
'GetClientConfig',
|
||||
'GetCurrentUser',
|
||||
'GetWorkspaceFromInviteHash',
|
||||
'Track',
|
||||
'CheckUserExists',
|
||||
|
||||
@ -150,5 +150,5 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { MessageDescriptor } from '@lingui/core';
|
||||
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { BASE_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
|
||||
@ -6,9 +8,9 @@ import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
interface WorkspaceEntityOptions {
|
||||
standardId: string;
|
||||
namePlural: string;
|
||||
labelSingular: string;
|
||||
labelPlural: string;
|
||||
description?: string;
|
||||
labelSingular: MessageDescriptor | string; // Todo: remove string when translations are added
|
||||
labelPlural: MessageDescriptor | string; // Todo: remove string when translations are added
|
||||
description?: MessageDescriptor | string; // Todo: remove string when translations are added
|
||||
icon?: string;
|
||||
shortcut?: string;
|
||||
labelIdentifierStandardId?: string;
|
||||
@ -38,9 +40,18 @@ export function WorkspaceEntity(
|
||||
standardId: options.standardId,
|
||||
nameSingular: objectName,
|
||||
namePlural: options.namePlural,
|
||||
labelSingular: options.labelSingular,
|
||||
labelPlural: options.labelPlural,
|
||||
description: options.description,
|
||||
labelSingular:
|
||||
typeof options.labelSingular === 'string'
|
||||
? options.labelSingular
|
||||
: (options.labelSingular?.message ?? ''),
|
||||
labelPlural:
|
||||
typeof options.labelPlural === 'string'
|
||||
? options.labelPlural
|
||||
: (options.labelPlural?.message ?? ''),
|
||||
description:
|
||||
typeof options.description === 'string'
|
||||
? options.description
|
||||
: (options.description?.message ?? ''),
|
||||
labelIdentifierStandardId:
|
||||
options.labelIdentifierStandardId ?? BASE_OBJECT_STANDARD_FIELD_IDS.id,
|
||||
imageIdentifierStandardId: options.imageIdentifierStandardId ?? null,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
|
||||
@ -52,9 +53,9 @@ export const SEARCH_FIELDS_FOR_COMPANY: FieldTypeAndNameMetadata[] = [
|
||||
@WorkspaceEntity({
|
||||
standardId: STANDARD_OBJECT_IDS.company,
|
||||
namePlural: 'companies',
|
||||
labelSingular: 'Company',
|
||||
labelPlural: 'Companies',
|
||||
description: 'A company',
|
||||
labelSingular: msg`Company`,
|
||||
labelPlural: msg`Companies`,
|
||||
description: msg`A company`,
|
||||
icon: STANDARD_OBJECT_ICONS.company,
|
||||
shortcut: 'C',
|
||||
labelIdentifierStandardId: COMPANY_STANDARD_FIELD_IDS.name,
|
||||
@ -67,7 +68,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'The company name',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
})
|
||||
[NAME_FIELD_NAME]: string;
|
||||
name: string;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: COMPANY_STANDARD_FIELD_IDS.domainName,
|
||||
@ -78,7 +79,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconLink',
|
||||
})
|
||||
@WorkspaceIsUnique()
|
||||
[DOMAIN_NAME_FIELD_NAME]?: LinksMetadata;
|
||||
domainName: LinksMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: COMPANY_STANDARD_FIELD_IDS.employees,
|
||||
@ -294,5 +295,5 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -2,8 +2,10 @@ import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export class MessageImportDriverException extends CustomException {
|
||||
code: MessageImportDriverExceptionCode;
|
||||
|
||||
constructor(message: string, code: MessageImportDriverExceptionCode) {
|
||||
super(message, code);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Note title',
|
||||
icon: 'IconNotes',
|
||||
})
|
||||
[TITLE_FIELD_NAME]: string;
|
||||
title: string;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: NOTE_STANDARD_FIELD_IDS.body,
|
||||
@ -78,7 +78,7 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconFilePencil',
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
[BODY_FIELD_NAME]: string | null;
|
||||
body: string | null;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: NOTE_STANDARD_FIELD_IDS.createdBy,
|
||||
@ -155,5 +155,5 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -248,5 +248,5 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconUser',
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
[NAME_FIELD_NAME]: FullNameMetadata | null;
|
||||
name: FullNameMetadata | null;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: PERSON_STANDARD_FIELD_IDS.emails,
|
||||
@ -83,7 +83,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconMail',
|
||||
})
|
||||
@WorkspaceIsUnique()
|
||||
[EMAILS_FIELD_NAME]: EmailsMetadata;
|
||||
emails: EmailsMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: PERSON_STANDARD_FIELD_IDS.linkedinLink,
|
||||
@ -112,7 +112,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Contact’s job title',
|
||||
icon: 'IconBriefcase',
|
||||
})
|
||||
[JOB_TITLE_FIELD_NAME]: string;
|
||||
jobTitle: string;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: PERSON_STANDARD_FIELD_IDS.phone,
|
||||
@ -304,5 +304,5 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Task title',
|
||||
icon: 'IconNotes',
|
||||
})
|
||||
[TITLE_FIELD_NAME]: string;
|
||||
title: string;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: TASK_STANDARD_FIELD_IDS.body,
|
||||
@ -80,7 +80,7 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconFilePencil',
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
[BODY_FIELD_NAME]: string | null;
|
||||
body: string | null;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: TASK_STANDARD_FIELD_IDS.dueAt,
|
||||
@ -207,5 +207,5 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Workspace member name',
|
||||
icon: 'IconCircleUser',
|
||||
})
|
||||
[NAME_FIELD_NAME]: FullNameMetadata;
|
||||
name: FullNameMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.colorScheme,
|
||||
@ -126,7 +126,7 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Related user email address',
|
||||
icon: 'IconMail',
|
||||
})
|
||||
[USER_EMAIL_FIELD_NAME]: string;
|
||||
userEmail: string;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userId,
|
||||
@ -351,5 +351,5 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
[SEARCH_VECTOR_FIELD.name]: any;
|
||||
searchVector: any;
|
||||
}
|
||||
|
||||
167
yarn.lock
167
yarn.lock
@ -15192,9 +15192,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.107"
|
||||
"@swc/core-darwin-arm64@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.7.42"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15206,9 +15206,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.107"
|
||||
"@swc/core-darwin-x64@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-darwin-x64@npm:1.7.42"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15220,9 +15220,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.107"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.42"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15234,9 +15234,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.107"
|
||||
"@swc/core-linux-arm64-gnu@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.7.42"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15248,9 +15248,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.107"
|
||||
"@swc/core-linux-arm64-musl@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.7.42"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15262,9 +15262,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.107"
|
||||
"@swc/core-linux-x64-gnu@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.7.42"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15276,9 +15276,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.107"
|
||||
"@swc/core-linux-x64-musl@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.7.42"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15290,9 +15290,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.7.42"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15304,9 +15304,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.7.42"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15318,9 +15318,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-x64-msvc@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.7.42"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -15332,6 +15332,52 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:1.7.42":
|
||||
version: 1.7.42
|
||||
resolution: "@swc/core@npm:1.7.42"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": "npm:1.7.42"
|
||||
"@swc/core-darwin-x64": "npm:1.7.42"
|
||||
"@swc/core-linux-arm-gnueabihf": "npm:1.7.42"
|
||||
"@swc/core-linux-arm64-gnu": "npm:1.7.42"
|
||||
"@swc/core-linux-arm64-musl": "npm:1.7.42"
|
||||
"@swc/core-linux-x64-gnu": "npm:1.7.42"
|
||||
"@swc/core-linux-x64-musl": "npm:1.7.42"
|
||||
"@swc/core-win32-arm64-msvc": "npm:1.7.42"
|
||||
"@swc/core-win32-ia32-msvc": "npm:1.7.42"
|
||||
"@swc/core-win32-x64-msvc": "npm:1.7.42"
|
||||
"@swc/counter": "npm:^0.1.3"
|
||||
"@swc/types": "npm:^0.1.13"
|
||||
peerDependencies:
|
||||
"@swc/helpers": "*"
|
||||
dependenciesMeta:
|
||||
"@swc/core-darwin-arm64":
|
||||
optional: true
|
||||
"@swc/core-darwin-x64":
|
||||
optional: true
|
||||
"@swc/core-linux-arm-gnueabihf":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-musl":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-musl":
|
||||
optional: true
|
||||
"@swc/core-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-ia32-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-x64-msvc":
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 10c0/bf5e242ad4098b5f02c084460fdaac486b420fb3b2ee8e96271e471c100ac6f446cc27c3840eed106130be149e20c8165df23ba5fe1a89364650c07aaa507177
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.18, @swc/core@npm:^1.5.7":
|
||||
version: 1.7.6
|
||||
resolution: "@swc/core@npm:1.7.6"
|
||||
@ -15378,53 +15424,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:~1.3.100":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core@npm:1.3.107"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": "npm:1.3.107"
|
||||
"@swc/core-darwin-x64": "npm:1.3.107"
|
||||
"@swc/core-linux-arm-gnueabihf": "npm:1.3.107"
|
||||
"@swc/core-linux-arm64-gnu": "npm:1.3.107"
|
||||
"@swc/core-linux-arm64-musl": "npm:1.3.107"
|
||||
"@swc/core-linux-x64-gnu": "npm:1.3.107"
|
||||
"@swc/core-linux-x64-musl": "npm:1.3.107"
|
||||
"@swc/core-win32-arm64-msvc": "npm:1.3.107"
|
||||
"@swc/core-win32-ia32-msvc": "npm:1.3.107"
|
||||
"@swc/core-win32-x64-msvc": "npm:1.3.107"
|
||||
"@swc/counter": "npm:^0.1.1"
|
||||
"@swc/types": "npm:^0.1.5"
|
||||
peerDependencies:
|
||||
"@swc/helpers": ^0.5.0
|
||||
dependenciesMeta:
|
||||
"@swc/core-darwin-arm64":
|
||||
optional: true
|
||||
"@swc/core-darwin-x64":
|
||||
optional: true
|
||||
"@swc/core-linux-arm-gnueabihf":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-musl":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-musl":
|
||||
optional: true
|
||||
"@swc/core-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-ia32-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-x64-msvc":
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 10c0/1f5c3b42443f7437e8b46621db6078babf292cc0855d83b2c45f43fd57a7af098243d9f5e2cdebc5fd5219ec8d9c0429cc17601497d7e301336d104618f775b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/counter@npm:^0.1.1, @swc/counter@npm:^0.1.3":
|
||||
"@swc/counter@npm:^0.1.3":
|
||||
version: 0.1.3
|
||||
resolution: "@swc/counter@npm:0.1.3"
|
||||
checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356
|
||||
@ -15481,7 +15481,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/types@npm:^0.1.12, @swc/types@npm:^0.1.5":
|
||||
"@swc/types@npm:^0.1.12":
|
||||
version: 0.1.12
|
||||
resolution: "@swc/types@npm:0.1.12"
|
||||
dependencies:
|
||||
@ -15490,6 +15490,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/types@npm:^0.1.13":
|
||||
version: 0.1.17
|
||||
resolution: "@swc/types@npm:0.1.17"
|
||||
dependencies:
|
||||
"@swc/counter": "npm:^0.1.3"
|
||||
checksum: 10c0/29f5c8933a16042956f1adb7383e836ed7646cbf679826e78b53fdd0c08e8572cb42152e527b6b530a9bd1052d33d0972f90f589761ccd252c12652c9b7a72fc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@szmarczak/http-timer@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@szmarczak/http-timer@npm:1.1.2"
|
||||
@ -45891,7 +45900,7 @@ __metadata:
|
||||
"@stylistic/eslint-plugin": "npm:^1.5.0"
|
||||
"@swc-node/register": "npm:1.8.0"
|
||||
"@swc/cli": "npm:^0.3.12"
|
||||
"@swc/core": "npm:~1.3.100"
|
||||
"@swc/core": "npm:1.7.42"
|
||||
"@swc/helpers": "npm:~0.5.2"
|
||||
"@swc/jest": "npm:^0.2.29"
|
||||
"@tabler/icons-react": "npm:^2.44.0"
|
||||
|
||||
Reference in New Issue
Block a user