• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 10299037390

08 Aug 2024 08:55AM UTC coverage: 17.548% (-0.2%) from 17.728%
10299037390

push

github

web-flow
feat: record history (#793)

* feat: record history

* feat: table record history

* feat: the permission for record history

* perf: batch inventory record history

* fix: field constraints are lost during field conversion

* chore: update pnpm-lock file

* fix: the event merging error when updating link records

* fix: cell link UI rendering

* fix: repeated list rendering in formula editor filtering

* chore: db migration for record history

* chore: e2e testing for the record history

* chore: upgrade the dependencies of the Prisma

* chore: upgrade the dependencies of the Prisma

* chore: upgrade the dependencies of the Prisma

* chore: update the dependencies of the Prisma

* fix: date string convert

* chore: update record history E2E testing

* feat: record history supports filtering based on time

* chore: add date field value log

* fix: nested transactions

* chore: revert to the previous version of Prisma

* fix: import table error

* fix: delete table logic

* chore: update record history e2e testing

---------

Co-authored-by: tea artist <artist@teable.io>

1387 of 2823 branches covered (49.13%)

6 of 1035 new or added lines in 43 files covered. (0.58%)

4 existing lines in 4 files now uncovered.

14088 of 80283 relevant lines covered (17.55%)

1.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/sdk/src/components/expand-record/ExpandRecord.tsx
1
import type { IRecord } from '@teable/core';
×
NEW
2
import { Skeleton } from '@teable/ui-lib';
×
3
import { isEqual } from 'lodash';
×
4
import { useCallback, useMemo } from 'react';
×
5
import {
×
6
  useFieldCellEditable,
×
7
  useFields,
×
8
  useIsTouchDevice,
×
9
  useRecord,
×
10
  useViewId,
×
11
  useViews,
×
12
} from '../../hooks';
×
13
import type { GridView, IFieldInstance } from '../../model';
×
14
import { ExpandRecordHeader } from './ExpandRecordHeader';
×
15
import { ExpandRecordWrap } from './ExpandRecordWrap';
×
16
import { RecordEditor } from './RecordEditor';
×
NEW
17
import { RecordHistory } from './RecordHistory';
×
18
import { ExpandRecordModel } from './type';
×
19

×
20
interface IExpandRecordProps {
×
21
  recordId: string;
×
22
  recordIds?: string[];
×
23
  visible?: boolean;
×
24
  model?: ExpandRecordModel;
×
25
  serverData?: IRecord;
×
NEW
26
  recordHistoryVisible?: boolean;
×
27
  onClose?: () => void;
×
28
  onPrev?: (recordId: string) => void;
×
29
  onNext?: (recordId: string) => void;
×
30
  onCopyUrl?: () => void;
×
NEW
31
  onRecordHistoryToggle?: () => void;
×
32
}
×
33

×
34
export const ExpandRecord = (props: IExpandRecordProps) => {
×
35
  const {
×
36
    model,
×
37
    visible,
×
38
    recordId,
×
39
    recordIds,
×
40
    serverData,
×
NEW
41
    recordHistoryVisible,
×
42
    onPrev,
×
43
    onNext,
×
44
    onClose,
×
45
    onCopyUrl,
×
NEW
46
    onRecordHistoryToggle,
×
47
  } = props;
×
48
  const views = useViews() as (GridView | undefined)[];
×
49
  const defaultViewId = views?.[0]?.id;
×
50
  const viewId = useViewId() ?? defaultViewId;
×
51
  const allFields = useFields({ withHidden: true, withDenied: true });
×
52
  const showFields = useFields();
×
53
  const record = useRecord(recordId, serverData);
×
54
  const isTouchDevice = useIsTouchDevice();
×
55
  const fieldCellEditable = useFieldCellEditable();
×
56

×
57
  const fieldCellReadonly = useCallback(
×
58
    (field: IFieldInstance) => {
×
59
      return !fieldCellEditable(field);
×
60
    },
×
61
    [fieldCellEditable]
×
62
  );
×
63

×
64
  const showFieldsId = useMemo(() => new Set(showFields.map((field) => field.id)), [showFields]);
×
65

×
66
  const fields = useMemo(
×
67
    () => (viewId ? allFields.filter((field) => showFieldsId.has(field.id)) : []),
×
68
    [allFields, showFieldsId, viewId]
×
69
  );
×
70

×
71
  const hiddenFields = useMemo(
×
72
    () => (viewId ? allFields.filter((field) => !showFieldsId.has(field.id)) : []),
×
73
    [allFields, showFieldsId, viewId]
×
74
  );
×
75

×
76
  const nextRecordIndex = useMemo(() => {
×
77
    return recordIds?.length ? recordIds.findIndex((id) => recordId === id) + 1 : -1;
×
78
  }, [recordId, recordIds]);
×
79

×
80
  const prevRecordIndex = useMemo(() => {
×
81
    return recordIds?.length ? recordIds.findIndex((id) => recordId === id) - 1 : -1;
×
82
  }, [recordId, recordIds]);
×
83

×
84
  const onChange = (newValue: unknown, fieldId: string) => {
×
85
    if (isEqual(record?.getCellValue(fieldId), newValue)) {
×
86
      return;
×
87
    }
×
88
    if (Array.isArray(newValue) && newValue.length === 0) {
×
89
      return record?.updateCell(fieldId, null);
×
90
    }
×
91
    record?.updateCell(fieldId, newValue);
×
92
  };
×
93

×
94
  const onPrevInner = () => {
×
95
    if (!recordIds?.length || prevRecordIndex === -1) {
×
96
      return;
×
97
    }
×
98
    onPrev?.(recordIds[prevRecordIndex]);
×
99
  };
×
100

×
101
  const onNextInner = () => {
×
102
    if (!recordIds?.length || nextRecordIndex === -1) {
×
103
      return;
×
104
    }
×
105
    onNext?.(recordIds[nextRecordIndex]);
×
106
  };
×
107

×
108
  const disabledPrev = prevRecordIndex < 0;
×
109
  const disabledNext = !recordIds?.length || nextRecordIndex >= recordIds.length;
×
110

×
111
  return (
×
112
    <ExpandRecordWrap
×
113
      model={isTouchDevice ? ExpandRecordModel.Drawer : model ?? ExpandRecordModel.Modal}
×
114
      visible={visible}
×
115
      onClose={onClose}
×
116
    >
×
NEW
117
      <div className="flex h-full flex-col">
×
118
        <ExpandRecordHeader
×
119
          title={record?.name}
×
NEW
120
          recordHistoryVisible={recordHistoryVisible}
×
121
          disabledPrev={disabledPrev}
×
122
          disabledNext={disabledNext}
×
123
          onClose={onClose}
×
124
          onPrev={onPrevInner}
×
125
          onNext={onNextInner}
×
126
          onCopyUrl={onCopyUrl}
×
NEW
127
          onRecordHistoryToggle={onRecordHistoryToggle}
×
128
        />
×
NEW
129
        <div className="relative flex flex-1 overflow-hidden">
×
NEW
130
          {recordHistoryVisible ? (
×
NEW
131
            <div className="flex size-full overflow-hidden rounded-b bg-background">
×
NEW
132
              <RecordHistory recordId={recordId} />
×
NEW
133
            </div>
×
NEW
134
          ) : (
×
NEW
135
            <div className="w-full flex-1 overflow-y-auto px-9 pb-9 pt-6">
×
NEW
136
              {fields.length > 0 ? (
×
NEW
137
                <RecordEditor
×
NEW
138
                  record={record}
×
NEW
139
                  fields={fields}
×
NEW
140
                  hiddenFields={hiddenFields}
×
NEW
141
                  onChange={onChange}
×
NEW
142
                  readonly={fieldCellReadonly}
×
NEW
143
                />
×
NEW
144
              ) : (
×
NEW
145
                <Skeleton className="h-10 w-full rounded" />
×
NEW
146
              )}
×
147
            </div>
×
148
          )}
×
149
        </div>
×
150
      </div>
×
151
    </ExpandRecordWrap>
×
152
  );
×
153
};
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc