Skip to content

Commit ea7b2d2

Browse files
authored
fix: record history rendering issues (#1064)
* fix: record history rendering crash * fix: select editor rendering * fix: duplicate record API return value
1 parent 4bd5d03 commit ea7b2d2

11 files changed

Lines changed: 102 additions & 31 deletions

File tree

apps/nestjs-backend/src/event-emitter/events/table/record.event.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import type { IRecord } from '@teable/core';
1+
import type { IFieldVo, IRecord } from '@teable/core';
22
import { match } from 'ts-pattern';
3-
import type { IFieldInstance } from '../../../features/field/model/factory';
43
import { RawOpType } from '../../../share-db/interface';
54
import type { IEventContext } from '../core-event';
65
import { Events } from '../event.enum';
@@ -16,7 +15,7 @@ type IRecordDeletePayload = { tableId: string; recordId: string | string[] };
1615
type IRecordUpdatePayload = {
1716
tableId: string;
1817
record: IChangeRecord | IChangeRecord[];
19-
oldField: IFieldInstance | undefined;
18+
oldField: IFieldVo | undefined;
2019
};
2120

2221
export class RecordCreateEvent extends OpEvent<IRecordCreatePayload> {
@@ -44,7 +43,7 @@ export class RecordUpdateEvent extends OpEvent<IRecordUpdatePayload> {
4443
constructor(
4544
tableId: string,
4645
record: IChangeRecord | IChangeRecord[],
47-
oldField: IFieldInstance | undefined,
46+
oldField: IFieldVo | undefined,
4847
context: IEventContext
4948
) {
5049
super({ tableId, record, oldField }, context, Array.isArray(record));

apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ export class FieldOpenApiService {
441441
// stage analysis and collect field changes
442442
const { newField, oldField, modifiedOps, supplementChange, references } =
443443
await this.fieldConvertingService.stageAnalysis(tableId, fieldId, updateFieldRo);
444-
this.cls.set('oldField', oldField);
445444

446445
await this.performConvertField({
447446
tableId,
@@ -454,6 +453,8 @@ export class FieldOpenApiService {
454453
const oldFieldVo = instanceToPlain(oldField, { excludePrefixes: ['_'] }) as IFieldVo;
455454
const newFieldVo = instanceToPlain(newField, { excludePrefixes: ['_'] }) as IFieldVo;
456455

456+
this.cls.set('oldField', oldFieldVo);
457+
457458
if (windowId) {
458459
this.eventEmitterService.emitAsync(Events.OPERATION_FIELD_CONVERT, {
459460
windowId,

apps/nestjs-backend/src/features/record/open-api/record-open-api.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,6 @@ export class RecordOpenApiService {
585585
const createdRecords = await this.prismaService.$tx(async () =>
586586
this.createRecords(tableId, createRecordsRo)
587587
);
588-
return { ids: createdRecords.records.map((record) => record.id) };
588+
return { id: createdRecords.records[0]?.id };
589589
}
590590
}

apps/nestjs-backend/src/types/cls.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import type { Action } from '@teable/core';
1+
import type { Action, IFieldVo } from '@teable/core';
22
import type { Prisma } from '@teable/db-main-prisma';
33
import type { ClsStore } from 'nestjs-cls';
4-
import type { IFieldInstance } from '../features/field/model/factory';
54
import type { IRawOpMap } from '../share-db/interface';
65

76
export interface IClsStore extends ClsStore {
@@ -26,5 +25,5 @@ export interface IClsStore extends ClsStore {
2625
permissions: Action[];
2726
// for share db adapter
2827
cookie?: string;
29-
oldField?: IFieldInstance;
28+
oldField?: IFieldVo;
3029
}

apps/nestjs-backend/test/record.e2e-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ describe('OpenAPI RecordController (e2e)', () => {
303303
anchorId: addRecord.id,
304304
position: 'after',
305305
});
306-
const record = await getRecord(table.id, duplicateRes.ids[0], undefined, 200);
306+
const record = await getRecord(table.id, duplicateRes.id, undefined, 200);
307307
expect(record.fields[table.fields[0].id]).toEqual(value1);
308308
});
309309
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { z } from 'zod';
2+
import { assertNever } from '../../asserts';
3+
import { FieldType } from './constant';
4+
import {
5+
attachmentCellValueSchema,
6+
autoNumberCellValueSchema,
7+
dataFieldCellValueSchema,
8+
getFormulaCellValueSchema,
9+
linkCellValueSchema,
10+
numberCellValueSchema,
11+
singleLineTextCelValueSchema,
12+
userCellValueSchema,
13+
} from './derivate';
14+
import type { IFieldVo } from './field.schema';
15+
16+
const validateWithSchema = (schema: z.ZodType, value: unknown) => {
17+
return z
18+
.union([z.array(schema).nonempty(), schema])
19+
.nullable()
20+
.safeParse(value);
21+
};
22+
23+
export const validateCellValue = (field: IFieldVo, cellValue: unknown) => {
24+
const { type, cellValueType } = field;
25+
26+
switch (type) {
27+
case FieldType.LongText:
28+
case FieldType.SingleLineText:
29+
case FieldType.SingleSelect:
30+
case FieldType.MultipleSelect:
31+
return validateWithSchema(singleLineTextCelValueSchema, cellValue);
32+
case FieldType.Number:
33+
return validateWithSchema(numberCellValueSchema, cellValue);
34+
case FieldType.Rating:
35+
case FieldType.AutoNumber:
36+
return validateWithSchema(autoNumberCellValueSchema, cellValue);
37+
case FieldType.Attachment:
38+
return attachmentCellValueSchema.nonempty().nullable().safeParse(cellValue);
39+
case FieldType.Date:
40+
case FieldType.CreatedTime:
41+
case FieldType.LastModifiedTime:
42+
return validateWithSchema(dataFieldCellValueSchema, cellValue);
43+
case FieldType.Checkbox:
44+
return validateWithSchema(z.literal(true), cellValue);
45+
case FieldType.Link:
46+
return validateWithSchema(linkCellValueSchema, cellValue);
47+
case FieldType.User:
48+
case FieldType.CreatedBy:
49+
case FieldType.LastModifiedBy:
50+
return validateWithSchema(userCellValueSchema, cellValue);
51+
case FieldType.Rollup:
52+
case FieldType.Formula: {
53+
const schema = getFormulaCellValueSchema(cellValueType);
54+
return validateWithSchema(schema, cellValue);
55+
}
56+
case FieldType.Button:
57+
case FieldType.Count:
58+
case FieldType.Duration:
59+
throw new Error('did not implement yet');
60+
default:
61+
assertNever(type);
62+
}
63+
};

packages/core/src/models/field/derivate/abstract/formula.field.abstract.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ import { dataFieldCellValueSchema } from '../date.field';
2121
import { numberCellValueSchema } from '../number.field';
2222
import { singleLineTextCelValueSchema } from '../single-line-text.field';
2323

24+
export const getFormulaCellValueSchema = (cellValueType: CellValueType) => {
25+
switch (cellValueType) {
26+
case CellValueType.Number:
27+
return numberCellValueSchema;
28+
case CellValueType.DateTime:
29+
return dataFieldCellValueSchema;
30+
case CellValueType.String:
31+
return singleLineTextCelValueSchema;
32+
case CellValueType.Boolean:
33+
return booleanCellValueSchema;
34+
default:
35+
assertNever(cellValueType);
36+
}
37+
};
38+
2439
export abstract class FormulaAbstractCore extends FieldCore {
2540
static parse(expression: string) {
2641
const inputStream = CharStreams.fromString(expression);
@@ -98,21 +113,7 @@ export abstract class FormulaAbstractCore extends FieldCore {
98113
}
99114

100115
validateCellValue(value: unknown) {
101-
const getFormulaCellValueSchema = () => {
102-
switch (this.cellValueType) {
103-
case CellValueType.Number:
104-
return numberCellValueSchema;
105-
case CellValueType.DateTime:
106-
return dataFieldCellValueSchema;
107-
case CellValueType.String:
108-
return singleLineTextCelValueSchema;
109-
case CellValueType.Boolean:
110-
return booleanCellValueSchema;
111-
default:
112-
assertNever(this.cellValueType);
113-
}
114-
};
115-
const schema = getFormulaCellValueSchema();
116+
const schema = getFormulaCellValueSchema(this.cellValueType);
116117

117118
if (this.isMultipleCellValue) {
118119
return z.array(schema).nullable().safeParse(value);

packages/core/src/models/field/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './formatting';
77
export * from './show-as';
88
export * from './field.schema';
99
export * from './field-validation';
10+
export * from './cell-value-validation';

packages/openapi/src/record/duplicate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { recordInsertOrderRoSchema } from './create';
77
export const DUPLICATE_URL = '/table/{tableId}/record/{recordId}';
88

99
export const duplicateVoSchema = z.object({
10-
ids: z.array(z.string()),
10+
id: z.string(),
1111
});
1212

1313
export type IDuplicateVo = z.infer<typeof duplicateVoSchema>;

packages/sdk/src/components/editor/select/components/OptionList.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ export const OptionList = (props: IOptionListProps) => {
5454
onSelect={() => onSelect?.(value)}
5555
>
5656
<SelectTag
57+
className="truncate"
5758
label={label || t('common.untitled')}
5859
backgroundColor={backgroundColor}
5960
color={color}
6061
/>
61-
{checkIsActive(value) && <Check className="ml-2 size-4" />}
62+
{checkIsActive(value) && <Check className="ml-2 size-4 shrink-0" />}
6263
</CommandItem>
6364
);
6465
})}

0 commit comments

Comments
 (0)