Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ jobs:

- name: 🕵️ Typecheck
run: |
pnpm g:typecheck
pnpm -r --filter '!@teable/v2-*' --workspace-concurrency=8 typecheck

- name: 🔬 Linter
run: |
pnpm g:lint
pnpm g:lint-styles
pnpm -r --filter '!@teable/v2-*' --parallel lint --color
pnpm -r --filter '!@teable/v2-*' lint-styles --color
10 changes: 10 additions & 0 deletions apps/nestjs-backend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,15 @@ module.exports = {
'@typescript-eslint/consistent-type-imports': 'off',
},
},
{
// Relax rules for test files — these are not production code
files: ['test/**', 'src/**/*.spec.ts', 'src/**/*.e2e-spec.ts'],
rules: {
'@typescript-eslint/naming-convention': 'off',
'sonarjs/no-duplicate-string': 'off',
'sonarjs/no-identical-functions': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
},
],
};
2 changes: 1 addition & 1 deletion apps/nestjs-backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { AttachmentsModule } from './features/attachments/attachments.module';
import { AuthModule } from './features/auth/auth.module';
import { BaseModule } from './features/base/base.module';
import { BaseNodeModule } from './features/base-node/base-node.module';
import { BaseShareModule } from './features/base-share/base-share.module';
import { BuiltinAssetsInitModule } from './features/builtin-assets-init';
import { CanaryModule } from './features/canary';
import { ChatModule } from './features/chat/chat.module';
Expand All @@ -40,7 +41,6 @@ import { PluginPanelModule } from './features/plugin-panel/plugin-panel.module';
import { SelectionModule } from './features/selection/selection.module';
import { AdminOpenApiModule } from './features/setting/open-api/admin-open-api.module';
import { SettingOpenApiModule } from './features/setting/open-api/setting-open-api.module';
import { BaseShareModule } from './features/base-share/base-share.module';
import { ShareModule } from './features/share/share.module';
import { SpaceModule } from './features/space/space.module';
import { TemplateOpenApiModule } from './features/template/template-open-api.module';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export class TrashListener {
case Events.APP_DELETE: {
resourceId = payload.appId;
resourceType = ResourceType.App;
const app = await this.prismaService.app.findUnique({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const app = await (this.prismaService as any).app.findUnique({
where: { id: resourceId },
select: { id: true, baseId: true, deletedTime: true },
});
Expand All @@ -86,7 +87,8 @@ export class TrashListener {
case Events.WORKFLOW_DELETE: {
resourceId = payload.workflowId;
resourceType = ResourceType.Workflow;
const workflow = await this.prismaService.workflow.findUnique({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const workflow = await (this.prismaService as any).workflow.findUnique({
where: { id: resourceId },
select: { id: true, baseId: true, deletedTime: true },
});
Expand Down
4 changes: 2 additions & 2 deletions apps/nestjs-backend/src/features/canary/canary.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Injectable } from '@nestjs/common';
import type { ICanaryConfig, V2Feature } from '@teable/openapi';
import { SettingKey } from '@teable/openapi';
import { ClsService } from 'nestjs-cls';
import type { IClsStore, V2Reason } from '../../types/cls';
import type { IClsStore, IV2Reason } from '../../types/cls';
import { SettingService } from '../setting/setting.service';

export interface IV2Decision {
useV2: boolean;
reason: V2Reason;
reason: IV2Reason;
}

@Injectable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
type CallHandler,
Logger,
} from '@nestjs/common';
import * as Sentry from '@sentry/nestjs';
import { trace } from '@opentelemetry/api';
import * as Sentry from '@sentry/nestjs';
import type { Response } from 'express';
import { ClsService } from 'nestjs-cls';
import type { Observable } from 'rxjs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ import { FormulaFieldDto } from '../model/field-dto/formula-field.dto';
import type { LinkFieldDto } from '../model/field-dto/link-field.dto';
import { RollupFieldDto } from '../model/field-dto/rollup-field.dto';

type LinkFieldReference = Pick<IFieldVo, 'name' | 'isMultipleCellValue'> & {
type ILinkFieldReference = Pick<IFieldVo, 'name' | 'isMultipleCellValue'> & {
options: Pick<ILinkFieldOptionsRo, 'relationship' | 'foreignTableId'> &
Partial<Pick<ILinkFieldOptions, 'fkHostTableName' | 'selfKeyName' | 'foreignKeyName'>>;
};
Expand Down Expand Up @@ -526,11 +526,11 @@ export class FieldSupplementService {
const batchLinkField = batchFieldVos?.find(
(candidate) => candidate.id === linkFieldId && candidate.type === FieldType.Link
);
const linkFieldOptions: LinkFieldReference['options'] | undefined =
const linkFieldOptions: ILinkFieldReference['options'] | undefined =
(optionsRaw && (JSON.parse(optionsRaw as string) as ILinkFieldOptions)) ||
(batchLinkField?.options as ILinkFieldOptions | ILinkFieldOptionsRo | undefined);

const linkFieldReference: LinkFieldReference | undefined =
const linkFieldReference: ILinkFieldReference | undefined =
linkFieldRaw && linkFieldOptions
? {
name: linkFieldRaw.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class CreatedTimeFieldDto extends CreatedTimeFieldCore implements FieldBa
return input.toISOString();
}
if (typeof input === 'string') {
const hasTimezone = /[zZ]|[+-]\d{2}:\d{2}$/.test(input);
const hasTimezone = /z|[+-]\d{2}:\d{2}$/i.test(input);
const parsed = new Date(hasTimezone ? input : `${input}Z`);
if (!Number.isNaN(parsed.getTime())) {
return parsed.toISOString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class LastModifiedTimeFieldDto extends LastModifiedTimeFieldCore implemen
return input.toISOString();
}
if (typeof input === 'string') {
const hasTimezone = /[zZ]|[+-]\d{2}:\d{2}$/.test(input);
const hasTimezone = /z|[+-]\d{2}:\d{2}$/i.test(input);
const parsed = new Date(hasTimezone ? input : `${input}Z`);
if (!Number.isNaN(parsed.getTime())) {
return parsed.toISOString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { ViewOpenApiModule } from '../../view/open-api/view-open-api.module';
import { ViewModule } from '../../view/view.module';
import { FieldCalculateModule } from '../field-calculate/field-calculate.module';
import { FieldModule } from '../field.module';
import { FieldOpenApiController } from './field-open-api.controller';
import { FieldOpenApiV2Service } from './field-open-api-v2.service';
import { FieldOpenApiController } from './field-open-api.controller';
import { FieldOpenApiService } from './field-open-api.service';

@Module({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { FieldModule } from '../field/field.module';
import { TableDomainQueryModule } from '../table-domain';
import { V2Module } from '../v2/v2.module';
import { ForeignKeyIntegrityService } from './foreign-key.service';
import { IntegrityController } from './integrity.controller';
import { IntegrityV2Controller } from './integrity-v2.controller';
import { IntegrityV2Service } from './integrity-v2.service';
import { IntegrityController } from './integrity.controller';
import { LinkFieldIntegrityService } from './link-field.service';
import { LinkIntegrityService } from './link-integrity.service';
import { UniqueIndexService } from './unique-index.service';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { ModuleRef } from '@nestjs/core';
import { OnEvent } from '@nestjs/event-emitter';
import { IUserInfoVo } from '@teable/openapi';
import { EventEmitterService } from '../../event-emitter/event-emitter.service';
import { Events } from '../../event-emitter/events';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { Injectable, Logger } from '@nestjs/common';
import type { IRedoVo, IUndoVo } from '@teable/openapi';
import { RedoCommand, RedoResult, UndoCommand, UndoResult, v2CoreTokens } from '@teable/v2-core';
import type { ICommandBus } from '@teable/v2-core';
import { RedoCommand, UndoCommand, v2CoreTokens } from '@teable/v2-core';
import type { ICommandBus, RedoResult, UndoResult } from '@teable/v2-core';
import { ClsService } from 'nestjs-cls';
import { CacheService } from '../../../cache/cache.service';
import type { ICacheStore } from '../../../cache/types';
Expand All @@ -15,11 +15,11 @@ import { buildUndoRedoEnginePreferenceKey } from './undo-redo-engine-preference'

export const X_TEABLE_UNDO_REDO_ENGINE_HEADER = 'x-teable-undo-redo-engine';

export type UndoRedoEngine = 'v1' | 'v2';
export type IUndoRedoEngine = 'v1' | 'v2';

type UndoRedoResponse<T extends IUndoVo | IRedoVo> = {
type IUndoRedoResponse<T extends IUndoVo | IRedoVo> = {
body: T;
engine: UndoRedoEngine;
engine: IUndoRedoEngine;
};

@Injectable()
Expand All @@ -34,7 +34,7 @@ export class UndoRedoService {
private readonly undoRedoOperationService: UndoRedoOperationService
) {}

async undo(tableId: string, windowId: string): Promise<UndoRedoResponse<IUndoVo>> {
async undo(tableId: string, windowId: string): Promise<IUndoRedoResponse<IUndoVo>> {
const preferredEngine = await this.getPreferredEngine(tableId, windowId);
if (preferredEngine === 'v1') {
const v1Result = await this.executeV1Undo(tableId, windowId);
Expand All @@ -58,7 +58,7 @@ export class UndoRedoService {
return this.executeV1Undo(tableId, windowId);
}

async redo(tableId: string, windowId: string): Promise<UndoRedoResponse<IRedoVo>> {
async redo(tableId: string, windowId: string): Promise<IUndoRedoResponse<IRedoVo>> {
const preferredEngine = await this.getPreferredEngine(tableId, windowId);
if (preferredEngine === 'v1') {
const v1Result = await this.executeV1Redo(tableId, windowId);
Expand Down Expand Up @@ -96,7 +96,7 @@ export class UndoRedoService {
private async getPreferredEngine(
tableId: string,
windowId: string
): Promise<UndoRedoEngine | undefined> {
): Promise<IUndoRedoEngine | undefined> {
const key = this.getPreferenceKey(tableId, windowId);
if (!key) {
return undefined;
Expand All @@ -107,7 +107,7 @@ export class UndoRedoService {
private async executeV1Undo(
tableId: string,
windowId: string
): Promise<UndoRedoResponse<IUndoVo>> {
): Promise<IUndoRedoResponse<IUndoVo>> {
const { operation, push } = await this.undoRedoStackService.popUndo(tableId, windowId);

if (!operation) {
Expand Down Expand Up @@ -154,7 +154,7 @@ export class UndoRedoService {
private async executeV1Redo(
tableId: string,
windowId: string
): Promise<UndoRedoResponse<IRedoVo>> {
): Promise<IUndoRedoResponse<IRedoVo>> {
const { operation, push } = await this.undoRedoStackService.popRedo(tableId, windowId);
if (!operation) {
return {
Expand Down Expand Up @@ -201,7 +201,7 @@ export class UndoRedoService {
tableId: string,
windowId: string,
mode: 'undo' | 'redo'
): Promise<UndoRedoResponse<IUndoVo | IRedoVo> | undefined> {
): Promise<IUndoRedoResponse<IUndoVo | IRedoVo> | undefined> {
try {
const container = await this.v2ContainerService.getContainer();
const commandBus = container.resolve<ICommandBus>(v2CoreTokens.commandBus);
Expand Down
6 changes: 3 additions & 3 deletions apps/nestjs-backend/src/features/v2/v2-container.service.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import type { OnModuleDestroy } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { KeyvUndoRedoStore } from '@teable/v2-adapter-undo-redo-keyv';
import { v2PostgresDbTokens } from '@teable/v2-adapter-db-postgres-pg';
import {
ShareDbPubSubPublisher,
registerV2ShareDbRealtime,
} from '@teable/v2-adapter-realtime-sharedb';
import { v2CoreTokens } from '@teable/v2-core';
import { KeyvUndoRedoStore } from '@teable/v2-adapter-undo-redo-keyv';
import { createV2NodePgContainer } from '@teable/v2-container-node';
import { v2CoreTokens } from '@teable/v2-core';
import type { DependencyContainer } from '@teable/v2-di';
import { registerV2ImportServices } from '@teable/v2-import';
import { PinoLogger } from 'nestjs-pino';
import { ShareDbService } from '../../share-db/share-db.service';
import { CacheService } from '../../cache/cache.service';
import { IThresholdConfig, ThresholdConfig } from '../../configs/threshold.config';
import { ShareDbService } from '../../share-db/share-db.service';
import { V2ActionTriggerService } from './v2-action-trigger.service';
import { CommandBusTracingMiddleware } from './v2-command-bus-tracing.middleware';
import { PinoLoggerAdapter } from './v2-logger.adapter';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { FieldDeleted, ProjectionHandler, ok } from '@teable/v2-core';
import type { DomainError, IEventHandler, IExecutionContext, Result } from '@teable/v2-core';
import type { DependencyContainer } from '@teable/v2-di';
import { ViewService } from '../view/view.service';
import { V2ContainerService } from './v2-container.service';
import { V2_FIELD_DELETE_COMPAT_CONTEXT_KEY } from './v2-field-delete-compat.constants';
import type { IV2FieldDeleteCompatContext } from './v2-field-delete-compat.constants';
import { V2ContainerService } from './v2-container.service';
import type { IV2ProjectionRegistrar } from './v2-projection-registrar';

const getFieldDeleteCompatContext = (
Expand Down
2 changes: 1 addition & 1 deletion apps/nestjs-backend/src/features/v2/v2.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { ViewModule } from '../view/view.module';
import { V2ActionTriggerService } from './v2-action-trigger.service';
import { V2BaseNodeCompatService } from './v2-base-node-compat.service';
import { V2ContainerService } from './v2-container.service';
import { V2Controller } from './v2.controller';
import { V2ExecutionContextFactory } from './v2-execution-context.factory';
import { V2FieldDeleteCompatService } from './v2-field-delete-compat.service';
import { V2OpenApiController } from './v2-openapi.controller';
import { V2RecordHistoryService } from './v2-record-history.service';
import { V2UserRenamePropagationService } from './v2-user-rename-propagation.service';
import { V2Controller } from './v2.controller';

const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === 'object' && value !== null;
Expand Down
4 changes: 2 additions & 2 deletions apps/nestjs-backend/src/types/cls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { IPerformanceCacheStore } from '../performance-cache';
import type { IRawOpMap } from '../share-db/interface';
import type { IDataLoaderCache } from './data-loader';

export type V2Reason =
export type IV2Reason =
| 'env_force_v2_all'
| 'config_force_v2_all'
| 'header_override'
Expand Down Expand Up @@ -74,7 +74,7 @@ export interface IClsStore extends ClsStore {
clearCacheKeys?: (keyof IPerformanceCacheStore)[];
canaryHeader?: string; // x-canary header value for canary release override
useV2?: boolean; // Flag to indicate if V2 implementation should be used (set by V2FeatureGuard)
v2Reason?: V2Reason; // Reason why V2 was enabled or disabled
v2Reason?: IV2Reason; // Reason why V2 was enabled or disabled
v2Feature?: V2Feature; // The feature name that triggered V2 check
windowId?: string; // Window ID from x-window-id header for undo/redo tracking
skipFieldComputation?: boolean; // Skip computed field evaluation during bulk structure creation (import/duplicate)
Expand Down
5 changes: 5 additions & 0 deletions apps/nestjs-backend/src/vendor.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module '@teamwork/websocket-json-stream' {
// eslint-disable-next-line @typescript-eslint/naming-convention
const WebSocketJSONStream: any;
export default WebSocketJSONStream;
}
15 changes: 3 additions & 12 deletions apps/nestjs-backend/test/comment-count-collapsed-group.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import type { INestApplication } from '@nestjs/common';
import type { IFieldVo, IFilter, IGroup } from '@teable/core';
import { Colors, FieldKeyType, FieldType, SortFunc } from '@teable/core';
import {
CommentNodeType,
GroupPointType,
createComment,
getCommentCount,
} from '@teable/openapi';
import { CommentNodeType, GroupPointType, createComment, getCommentCount } from '@teable/openapi';
import type { IGroupHeaderPoint, ITableFullVo } from '@teable/openapi';
import {
createField,
Expand Down Expand Up @@ -58,15 +53,11 @@ describe('OpenAPI Comment count with collapsed groups (e2e)', () => {
records: [{ fields: { LookupKey: 'K-1' } }, { fields: { LookupKey: 'K-2' } }],
});

const sourceKeyField = sourceTable.fields.find(
({ name }) => name === 'LookupKey'
) as IFieldVo;
const sourceKeyField = sourceTable.fields.find(({ name }) => name === 'LookupKey') as IFieldVo;
const sourceCategoryField = sourceTable.fields.find(
({ name }) => name === 'Category'
) as IFieldVo;
const hostKeyField = hostTable.fields.find(
({ name }) => name === 'LookupKey'
) as IFieldVo;
const hostKeyField = hostTable.fields.find(({ name }) => name === 'LookupKey') as IFieldVo;

const matchByKeyFilter: IFilter = {
conjunction: 'and',
Expand Down
2 changes: 1 addition & 1 deletion apps/nestjs-backend/test/record-unary-filter.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { INestApplication } from '@nestjs/common';
import type { IGetRecordsRo, ITableFullVo } from '@teable/openapi';
import { Colors, FieldKeyType, FieldType } from '@teable/core';
import type { IGetRecordsRo, ITableFullVo } from '@teable/openapi';
import { createTable, getRecords, initApp, permanentDeleteTable } from './utils/init-app';

describe('Record unary filter operators (e2e)', () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/nestjs-backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
},
"types": ["vitest/globals", "node"]
},
"exclude": ["**/node_modules", "**/.*/", "dist"]
"exclude": ["**/node_modules", "**/.*/", "dist", "src/**/*.spec.ts", "test/**"]
}
4 changes: 4 additions & 0 deletions apps/nestjs-backend/tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/node_modules", "**/.*/", "dist"]
}
2 changes: 1 addition & 1 deletion apps/nestjs-backend/vitest-e2e.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default defineConfig({
target: 'es2022',
},
}),
tsconfigPaths(),
tsconfigPaths({ projects: ['./tsconfig.test.json'] }),
],
cacheDir: '../../.cache/vitest/nestjs-backend/e2e',
test: {
Expand Down
2 changes: 1 addition & 1 deletion apps/nestjs-backend/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default defineConfig({
target: 'es2022',
},
}),
tsconfigPaths(),
tsconfigPaths({ projects: ['./tsconfig.test.json'] }),
],
cacheDir: '../../.cache/vitest/nestjs-backend/unit',
test: {
Expand Down
2 changes: 1 addition & 1 deletion apps/nextjs-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
],
"types": ["vitest/globals", "node"]
},
"exclude": ["**/node_modules", "**/.*/"],
"exclude": ["**/node_modules", "**/.*/", "**/*.spec.ts", "**/*.spec.tsx"],
"include": [
"next-env.d.ts",
"**/*.ts",
Expand Down
4 changes: 4 additions & 0 deletions apps/nextjs-app/tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/node_modules", "**/.*/"]
}
Loading
Loading