Import company and person from csv file (#1236)

* feat: wip implement back-end call csv import

* fix: rebase IconBrandTwitter missing

* feat: person and company csv import

* fix: test & clean

* fix: clean & test
This commit is contained in:
Jérémy M
2023-08-16 23:18:16 +02:00
committed by GitHub
parent 5890354d21
commit 8863bb0035
74 changed files with 950 additions and 312 deletions

View File

@ -99,6 +99,7 @@ type OwnProps<SortField> = {
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
onViewsChange?: (views: TableView[]) => void;
onImport?: () => void;
updateEntityMutation: any;
};
@ -108,6 +109,7 @@ export function EntityTable<SortField>({
onColumnsChange,
onSortsUpdate,
onViewsChange,
onImport,
updateEntityMutation,
}: OwnProps<SortField>) {
const tableBodyRef = useRef<HTMLDivElement>(null);
@ -136,6 +138,7 @@ export function EntityTable<SortField>({
onColumnsChange={onColumnsChange}
onSortsUpdate={onSortsUpdate}
onViewsChange={onViewsChange}
onImport={onImport}
/>
<StyledTableWrapper>
<StyledTable>

View File

@ -0,0 +1,34 @@
import { useRecoilCallback } from 'recoil';
import { tableEntitiesFamilyState } from '@/ui/table/states/tableEntitiesFamilyState';
export function useUpsertEntityTableItems() {
return useRecoilCallback(
({ set, snapshot }) =>
<T extends { id: string }>(entities: T[]) => {
// Create a map of new entities for quick lookup.
const newEntityMap = new Map(
entities.map((entity) => [entity.id, entity]),
);
// Filter out entities that are already the same in the state.
const entitiesToUpdate = entities.filter((entity) => {
const currentEntity = snapshot
.getLoadable(tableEntitiesFamilyState(entity.id))
.valueMaybe();
return (
!currentEntity ||
JSON.stringify(currentEntity) !==
JSON.stringify(newEntityMap.get(entity.id))
);
});
// Batch set state for the filtered entities.
for (const entity of entitiesToUpdate) {
set(tableEntitiesFamilyState(entity.id), entity);
}
},
[],
);
}

View File

@ -0,0 +1,18 @@
import { useRecoilCallback } from 'recoil';
import { tableRowIdsState } from '../states/tableRowIdsState';
export function useUpsertTableRowIds() {
return useRecoilCallback(
({ set, snapshot }) =>
(rowIds: string[]) => {
const currentRowIds = snapshot
.getLoadable(tableRowIdsState)
.valueOrThrow();
const uniqueRowIds = Array.from(new Set([...rowIds, ...currentRowIds]));
set(tableRowIdsState, uniqueRowIds);
},
[],
);
}

View File

@ -9,7 +9,6 @@ import { useTheme } from '@emotion/react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { v4 } from 'uuid';
import { useSpreadsheetImport } from '@/spreadsheet-import/hooks/useSpreadsheetImport';
import { IconButton } from '@/ui/button/components/IconButton';
import { DropdownMenuHeader } from '@/ui/dropdown/components/DropdownMenuHeader';
import { DropdownMenuInput } from '@/ui/dropdown/components/DropdownMenuInput';
@ -51,6 +50,7 @@ import { TableOptionsDropdownSection } from './TableOptionsDropdownSection';
type TableOptionsDropdownButtonProps = {
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
onViewsChange?: (views: TableView[]) => void;
onImport?: () => void;
HotkeyScope: TableOptionsHotkeyScope;
};
@ -61,12 +61,11 @@ enum Option {
export const TableOptionsDropdownButton = ({
onColumnsChange,
onViewsChange,
onImport,
HotkeyScope,
}: TableOptionsDropdownButtonProps) => {
const theme = useTheme();
const { openSpreadsheetImport } = useSpreadsheetImport();
const [isUnfolded, setIsUnfolded] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option | undefined>(
undefined,
@ -94,16 +93,6 @@ export const TableOptionsDropdownButton = ({
setHotkeyScopeAndMemorizePreviousScope,
} = usePreviousHotkeyScope();
function handleImport() {
openSpreadsheetImport({
onSubmit: (datam, file) => {
console.log('datam', datam);
console.log('file', file);
},
fields: [],
});
}
const handleColumnVisibilityChange = useCallback(
(columnId: string, nextIsVisible: boolean) => {
const nextColumns = columns.map((column) =>
@ -245,8 +234,8 @@ export const TableOptionsDropdownButton = ({
<IconTag size={theme.icon.size.md} />
Properties
</DropdownMenuItem>
{false && (
<DropdownMenuItem onClick={handleImport}>
{onImport && (
<DropdownMenuItem onClick={onImport}>
<IconFileImport size={theme.icon.size.md} />
Import
</DropdownMenuItem>

View File

@ -26,6 +26,7 @@ type OwnProps<SortField> = {
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
onViewsChange?: (views: TableView[]) => void;
onImport?: () => void;
};
export function TableHeader<SortField>({
@ -34,6 +35,7 @@ export function TableHeader<SortField>({
onColumnsChange,
onSortsUpdate,
onViewsChange,
onImport,
}: OwnProps<SortField>) {
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
sortScopedState,
@ -82,6 +84,7 @@ export function TableHeader<SortField>({
isPrimaryButton
/>
<TableOptionsDropdownButton
onImport={onImport}
onColumnsChange={onColumnsChange}
onViewsChange={onViewsChange}
HotkeyScope={TableOptionsHotkeyScope.Dropdown}