Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
259 changes: 155 additions & 104 deletions apps/nextjs-app/src/features/app/blocks/view/grid/GridViewBaseInner.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ interface IPrefillingRowContainerProps {
isLoading?: boolean;
onCancel?: () => void;
onClickOutside?: () => void;
onAddRow?: () => void;
}

export const PrefillingRowContainer = (props: IPrefillingRowContainerProps) => {
const { style, children, isLoading, onCancel, onClickOutside } = props;
const { style, children, isLoading, onCancel, onClickOutside, onAddRow } = props;
const prefillingGridContainerRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation(tableConfig.i18nNamespaces);

Expand All @@ -32,10 +33,10 @@ export const PrefillingRowContainer = (props: IPrefillingRowContainerProps) => {
return (
<div
ref={prefillingGridContainerRef}
className="absolute left-0 w-full border-y-2 border-violet-500 dark:border-violet-700"
className="absolute left-0 w-full border-t-2 border-primary"
style={style}
>
<div className="absolute left-0 top-[-32px] flex h-8 items-center rounded-ss-lg bg-violet-500 px-2 py-1 text-background dark:border-violet-700">
<div className="absolute left-0 top-[-32px] flex h-8 items-center rounded-t-lg bg-primary px-2 py-1 text-background">
{isLoading ? <Spin className="mr-1 size-4" /> : <Plus className="mr-1" />}
<span className="text-[13px]">{t('table:grid.prefillingRowTitle')}</span>
<TooltipProvider>
Expand All @@ -58,6 +59,19 @@ export const PrefillingRowContainer = (props: IPrefillingRowContainerProps) => {
</Button>
</div>
{children}
<div
className="flex h-8 w-full select-none items-center border-b-2 border-t border-b-primary border-t-gray-200 bg-background pl-[26px]"
onClick={() => onAddRow?.()}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
onAddRow?.();
}
}}
>
<Plus className="size-5 text-muted-foreground" />
Comment thread
Sky-FE marked this conversation as resolved.
</div>
</div>
);
};
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/de/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,9 @@
"pasteFileFailed": "Dateien können nur in ein Anhangsfeld eingefügt werden",
"copyError": {
"noFocus": "Bitte lassen Sie die Seite aktiv und wechseln Sie nicht das Fenster"
},
"pasteError": {
"noPermission": "Sie haben keine Berechtigung, Datensätze einzufügen"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/en/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@
"copyError": {
"noFocus": "Please keep the page active and do not switch windows",
"noPermission": "You don't have permission to copy records"
},
"pasteError": {
"noPermission": "You don't have permission to paste records"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/es/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@
"pasteFileFailed": "Los archivos solo se pueden pegar en un campo de archivo adjunto",
"copyError": {
"noFocus": "Mantenga la página activa y no cambie Windows"
},
"pasteError": {
"noPermission": "No tienes permiso para pegar registros"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/fr/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@
"pasteFileFailed": "Les fichiers ne peuvent être collés que dans un champ de pièces jointes",
"copyError": {
"noFocus": "Veuillez garder la page active et ne pas changer de fenêtre"
},
"pasteError": {
"noPermission": "Vous n'avez pas l'autorisation de coller des enregistrements"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/it/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,9 @@
"pasteFileFailed": "I file possono essere incollati solo in un campo di allegato",
"copyError": {
"noFocus": "Si prega di mantenere la pagina attiva e non cambiare finestra"
},
"pasteError": {
"noPermission": "Non hai l'autorizzazione per incollare i record"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/ja/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@
"pasteFileFailed": "ファイルは添付ファイル欄にのみ貼り付けることができます",
"copyError": {
"noFocus": "ページをアクティブに保ち、ウィンドウを切り替えないでください"
},
"pasteError": {
"noPermission": "レコードを貼り付ける権限がありません"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/ru/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@
"pasteFileFailed": "Файлы можно вставлять только в поле вложений",
"copyError": {
"noFocus": "Пожалуйста, не меняйте окно"
},
"pasteError": {
"noPermission": "У вас нет прав вставлять записи"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/tr/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@
"pasteFileFailed": "Dosyalar yalnızca bir ek alanına yapıştırılabilir",
"copyError": {
"noFocus": "Lütfen pencereyi değiştirmeyin"
},
"pasteError": {
"noPermission": "Kayıtları yapıştırma izniniz yok"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/uk/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,9 @@
"pasteFileFailed": "Файли можна вставляти лише в поле вкладення",
"copyError": {
"noFocus": "Будь ласка, тримайте сторінку активною та не перемикайте вікна"
},
"pasteError": {
"noPermission": "У вас немає дозволу вставляти записи"
}
},
"graph": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common-i18n/src/locales/zh/table.json
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@
"copyError": {
"noFocus": "请保持页面激活,不要切换窗口",
"noPermission": "您没有权限复制记录"
},
"pasteError": {
"noPermission": "您没有权限粘贴记录"
}
},
"graph": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const useGridPopupPosition = (rect: IEditorProps['rect'], maxHeight?: num
return {
top: isAbove ? 'unset' : height + 1,
bottom: isAbove ? height : 'unset',
maxHeight: finalHeight,
maxHeight: maxHeight ?? finalHeight,
};
}, [editorId, y, height, maxHeight]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,47 @@ export const useGridPrefillingRow = (columns: (IGridColumn & { id: string })[])

const [prefillingRowOrder, setPrefillingRowOrder] = useState<IUpdateOrderRo>();
const [prefillingRowIndex, setPrefillingRowIndex] = useState<number>();
const [prefillingFieldValueMap, setPrefillingFieldValueMap] = useState<
{ [fieldId: string]: unknown } | undefined
>();
const [prefillingRows, setPrefillingRows] = useState<
{ fields: { [fieldId: string]: unknown } }[]
>([]);

const localRecord = useMemo(() => {
if (prefillingFieldValueMap == null) {
return null;
}

const record = createRecordInstance({
id: '',
fields: prefillingFieldValueMap,
});
record.getCellValue = (fieldId: string) => {
return prefillingFieldValueMap[fieldId];
};
record.updateCell = (fieldId: string, newValue: unknown) => {
record.fields[fieldId] = newValue;
setPrefillingFieldValueMap({
...prefillingFieldValueMap,
[fieldId]: newValue,
const localRecords = useMemo(() => {
return prefillingRows.map((row, index) => {
const record = createRecordInstance({
id: '',
fields: row.fields as never,
});
return Promise.resolve();
};
record.getCellValue = (fieldId: string) => {
return prefillingRows[index]?.fields?.[fieldId];
};
record.updateCell = (fieldId: string, newValue: unknown) => {
setPrefillingRows((prev) => {
const next = [...prev];
const current = next[index] ?? { fields: {} };
next[index] = { fields: { ...current.fields, [fieldId]: newValue } };
return next;
});
return Promise.resolve();
};
return record;
});
}, [prefillingRows, setPrefillingRows]);

return record;
}, [prefillingFieldValueMap]);
const createCellValue2GridDisplay = useCreateCellValue2GridDisplay();
const getPrefillingCellContent = useCallback<(cell: ICellItem) => ICell>(
(cell) => {
const [columnIndex] = cell;
const [columnIndex, rowIndex] = cell;
const cellValue2GridDisplay = createCellValue2GridDisplay(fields);
if (localRecord != null) {
const fieldId = columns[columnIndex]?.id;
if (!fieldId) return { type: CellType.Loading };
return cellValue2GridDisplay(localRecord, columnIndex, true);
}
return { type: CellType.Loading };
const record = localRecords[rowIndex ?? 0];
if (!record) return { type: CellType.Loading };
if (columns[columnIndex]?.id == null) return { type: CellType.Loading };
return cellValue2GridDisplay(record, columnIndex, true);
},
[columns, createCellValue2GridDisplay, fields, localRecord]
[columns, createCellValue2GridDisplay, fields, localRecords]
);

useEffect(() => {
if (prefillingRowIndex == null) return;

const updateDefaultValue = async () => {
const fieldValue = await extractDefaultFieldsFromFilters({
filter,
Expand All @@ -74,12 +70,11 @@ export const useGridPrefillingRow = (columns: (IGridColumn & { id: string })[])
tableId,
isAsync: true,
});
setPrefillingFieldValueMap((prev) => {
if (prev == null) return;
return {
...prev,
...fieldValue,
};
setPrefillingRows((prev) => {
const next = prev.length ? [...prev] : [{ fields: {} }];
const first = next[0] ?? { fields: {} };
next[0] = { fields: { ...first.fields, ...fieldValue } };
return next;
});
};
updateDefaultValue();
Expand All @@ -88,13 +83,10 @@ export const useGridPrefillingRow = (columns: (IGridColumn & { id: string })[])

const onPrefillingCellEdited = useCallback(
(cell: ICellItem, newVal: IInnerCell) => {
if (localRecord == null) return;

const [col] = cell;
const [col, rowIndex = 0] = cell;
const fieldId = columns[col].id;
const { type, data } = newVal;
let newCellValue: unknown = null;

switch (type) {
case CellType.Select:
newCellValue = data?.length ? data : null;
Expand All @@ -105,35 +97,32 @@ export const useGridPrefillingRow = (columns: (IGridColumn & { id: string })[])
default:
newCellValue = data === '' ? null : data;
}
const oldCellValue = localRecord.getCellValue(fieldId) ?? null;
const record = localRecords[rowIndex];
const oldCellValue = record?.getCellValue(fieldId) ?? null;
if (isEqual(newCellValue, oldCellValue)) return;
localRecord.updateCell(fieldId, newCellValue);
return localRecord;
if (record?.updateCell) {
record.updateCell(fieldId, newCellValue);
} else {
setPrefillingRows((prev) => {
const next = prev.length ? [...prev] : [{ fields: {} }];
const row = next[rowIndex] ?? { fields: {} };
next[rowIndex] = { fields: { ...row.fields, [fieldId]: newCellValue } };
return next;
});
}
},
[localRecord, columns]
[columns, localRecords, setPrefillingRows]
);

return useMemo(() => {
return {
localRecord,
prefillingRowIndex,
prefillingRowOrder,
prefillingFieldValueMap,
setPrefillingRowIndex,
setPrefillingRowOrder,
onPrefillingCellEdited,
getPrefillingCellContent,
setPrefillingFieldValueMap,
};
}, [
localRecord,
return {
prefillingRows,
prefillingRowIndex,
prefillingRowOrder,
prefillingFieldValueMap,
localRecords,
setPrefillingRows,
setPrefillingRowIndex,
setPrefillingRowOrder,
onPrefillingCellEdited,
getPrefillingCellContent,
setPrefillingFieldValueMap,
]);
};
};
9 changes: 6 additions & 3 deletions packages/sdk/src/components/grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export interface IGridExternalProps {
smoothScrollY?: boolean;
scrollBufferX?: number;
scrollBufferY?: number;
scrollBarVisible?: boolean;
scrollBarXVisible?: boolean;
scrollBarYVisible?: boolean;
rowIndexVisible?: boolean;
collaborators?: ICollaborator;
// [rowIndex, colIndex]
Expand Down Expand Up @@ -194,7 +195,8 @@ const GridBase: ForwardRefRenderFunction<IGridRef, IGridProps> = (props, forward
smoothScrollY = true,
scrollBufferX = scrollBuffer,
scrollBufferY = scrollBuffer,
scrollBarVisible = true,
scrollBarXVisible = true,
scrollBarYVisible = true,
rowIndexVisible = true,
isMultiSelectionEnable = true,
style,
Expand Down Expand Up @@ -727,7 +729,8 @@ const GridBase: ForwardRefRenderFunction<IGridRef, IGridProps> = (props, forward
scrollHeight={totalHeight}
smoothScrollX={smoothScrollX}
smoothScrollY={smoothScrollY}
scrollBarVisible={scrollBarVisible}
scrollBarXVisible={scrollBarXVisible}
scrollBarYVisible={scrollBarYVisible}
containerRef={containerRef}
scrollState={scrollState}
scrollEnable={scrollEnable}
Expand Down
10 changes: 6 additions & 4 deletions packages/sdk/src/components/grid/InfiniteScroller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export interface ScrollerProps
IGridProps,
| 'smoothScrollX'
| 'smoothScrollY'
| 'scrollBarVisible'
| 'scrollBarXVisible'
| 'scrollBarYVisible'
| 'onScrollChanged'
| 'onVisibleRegionChanged'
> {
Expand Down Expand Up @@ -53,7 +54,8 @@ const InfiniteScrollerBase: ForwardRefRenderFunction<ScrollerRef, ScrollerProps>
containerRef,
smoothScrollX,
smoothScrollY,
scrollBarVisible,
scrollBarXVisible,
scrollBarYVisible,
scrollEnable = true,
scrollState,
getLinearRow,
Expand Down Expand Up @@ -282,7 +284,7 @@ const InfiniteScrollerBase: ForwardRefRenderFunction<ScrollerRef, ScrollerProps>
ref={horizontalScrollRef}
className={cn(
'scrollbar scrollbar-thumb-foreground/40 scrollbar-thumb-rounded-md scrollbar-h-[10px] absolute bottom-[2px] left-0 h-4 cursor-pointer overflow-y-hidden overflow-x-scroll will-change-transform',
!scrollBarVisible && 'opacity-0 pointer-events-none'
!scrollBarXVisible && 'opacity-0 pointer-events-none'
)}
style={{
left,
Expand All @@ -302,7 +304,7 @@ const InfiniteScrollerBase: ForwardRefRenderFunction<ScrollerRef, ScrollerProps>
ref={verticalScrollRef}
className={cn(
'scrollbar scrollbar-thumb-foreground/40 scrollbar-thumb-rounded-md scrollbar-w-[10px] scrollbar-min-thumb absolute right-[2px] w-4 cursor-pointer overflow-x-hidden overflow-y-scroll will-change-transform',
!scrollBarVisible && 'opacity-0 pointer-events-none'
!scrollBarYVisible && 'opacity-0 pointer-events-none'
)}
style={{
top,
Expand Down
Loading