refactor: index ViewField by viewId and key (#1416)
* refactor: index ViewField by viewId and key Closes #1413 * refactor: rename ViewField properties
This commit is contained in:
@ -162,11 +162,11 @@ export function CompanyBoardCard() {
|
||||
<EditableFieldEntityIdContext.Provider value={boardCardId}>
|
||||
{viewFieldsDefinitions.map((viewField) => {
|
||||
return (
|
||||
<PreventSelectOnClickContainer key={viewField.id}>
|
||||
<PreventSelectOnClickContainer key={viewField.key}>
|
||||
<EditableFieldDefinitionContext.Provider
|
||||
value={{
|
||||
id: viewField.id,
|
||||
label: viewField.label,
|
||||
key: viewField.key,
|
||||
name: viewField.name,
|
||||
icon: viewField.icon,
|
||||
type: viewField.metadata.type,
|
||||
metadata: viewField.metadata,
|
||||
|
||||
@ -27,11 +27,11 @@ import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
||||
export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadata>[] =
|
||||
[
|
||||
{
|
||||
id: 'name',
|
||||
label: 'Name',
|
||||
key: 'name',
|
||||
name: 'Name',
|
||||
icon: <IconBuildingSkyscraper />,
|
||||
size: 180,
|
||||
order: 1,
|
||||
index: 0,
|
||||
metadata: {
|
||||
type: 'chip',
|
||||
urlFieldName: 'domainName',
|
||||
@ -41,11 +41,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} as ColumnDefinition<ViewFieldChipMetadata>,
|
||||
{
|
||||
id: 'domainName',
|
||||
label: 'URL',
|
||||
key: 'domainName',
|
||||
name: 'URL',
|
||||
icon: <IconLink />,
|
||||
size: 100,
|
||||
order: 2,
|
||||
index: 1,
|
||||
metadata: {
|
||||
type: 'url',
|
||||
fieldName: 'domainName',
|
||||
@ -54,11 +54,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} as ColumnDefinition<ViewFieldURLMetadata>,
|
||||
{
|
||||
id: 'accountOwner',
|
||||
label: 'Account Owner',
|
||||
key: 'accountOwner',
|
||||
name: 'Account Owner',
|
||||
icon: <IconUserCircle />,
|
||||
size: 150,
|
||||
order: 3,
|
||||
index: 2,
|
||||
metadata: {
|
||||
type: 'relation',
|
||||
fieldName: 'accountOwner',
|
||||
@ -67,11 +67,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} satisfies ColumnDefinition<ViewFieldRelationMetadata>,
|
||||
{
|
||||
id: 'createdAt',
|
||||
label: 'Creation',
|
||||
key: 'createdAt',
|
||||
name: 'Creation',
|
||||
icon: <IconCalendarEvent />,
|
||||
size: 150,
|
||||
order: 4,
|
||||
index: 3,
|
||||
metadata: {
|
||||
type: 'date',
|
||||
fieldName: 'createdAt',
|
||||
@ -79,11 +79,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} satisfies ColumnDefinition<ViewFieldDateMetadata>,
|
||||
{
|
||||
id: 'employees',
|
||||
label: 'Employees',
|
||||
key: 'employees',
|
||||
name: 'Employees',
|
||||
icon: <IconUsers />,
|
||||
size: 150,
|
||||
order: 5,
|
||||
index: 4,
|
||||
metadata: {
|
||||
type: 'number',
|
||||
fieldName: 'employees',
|
||||
@ -92,11 +92,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} satisfies ColumnDefinition<ViewFieldNumberMetadata>,
|
||||
{
|
||||
id: 'linkedin',
|
||||
label: 'LinkedIn',
|
||||
key: 'linkedin',
|
||||
name: 'LinkedIn',
|
||||
icon: <IconBrandLinkedin />,
|
||||
size: 170,
|
||||
order: 6,
|
||||
index: 5,
|
||||
metadata: {
|
||||
type: 'url',
|
||||
fieldName: 'linkedinUrl',
|
||||
@ -105,11 +105,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} satisfies ColumnDefinition<ViewFieldURLMetadata>,
|
||||
{
|
||||
id: 'address',
|
||||
label: 'Address',
|
||||
key: 'address',
|
||||
name: 'Address',
|
||||
icon: <IconMap />,
|
||||
size: 170,
|
||||
order: 7,
|
||||
index: 6,
|
||||
metadata: {
|
||||
type: 'text',
|
||||
fieldName: 'address',
|
||||
@ -118,11 +118,11 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: true,
|
||||
} satisfies ColumnDefinition<ViewFieldTextMetadata>,
|
||||
{
|
||||
id: 'idealCustomerProfile',
|
||||
label: 'ICP',
|
||||
key: 'idealCustomerProfile',
|
||||
name: 'ICP',
|
||||
icon: <IconTarget />,
|
||||
size: 150,
|
||||
order: 8,
|
||||
index: 7,
|
||||
metadata: {
|
||||
type: 'boolean',
|
||||
fieldName: 'idealCustomerProfile',
|
||||
@ -130,22 +130,22 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<ViewFieldMeta
|
||||
isVisible: false,
|
||||
} satisfies ColumnDefinition<ViewFieldBooleanMetadata>,
|
||||
{
|
||||
id: 'annualRecurringRevenue',
|
||||
label: 'ARR',
|
||||
key: 'annualRecurringRevenue',
|
||||
name: 'ARR',
|
||||
icon: <IconMoneybag />,
|
||||
size: 150,
|
||||
order: 8,
|
||||
index: 8,
|
||||
metadata: {
|
||||
type: 'moneyAmount',
|
||||
fieldName: 'annualRecurringRevenue',
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldMoneyMetadata>,
|
||||
{
|
||||
id: 'xUrl',
|
||||
label: 'Twitter',
|
||||
key: 'xUrl',
|
||||
name: 'Twitter',
|
||||
icon: <IconBrandX />,
|
||||
size: 150,
|
||||
order: 8,
|
||||
index: 9,
|
||||
metadata: {
|
||||
type: 'url',
|
||||
fieldName: 'xUrl',
|
||||
|
||||
@ -25,11 +25,11 @@ import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
||||
export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadata>[] =
|
||||
[
|
||||
{
|
||||
id: 'displayName',
|
||||
label: 'People',
|
||||
key: 'displayName',
|
||||
name: 'People',
|
||||
icon: <IconUser />,
|
||||
size: 210,
|
||||
order: 1,
|
||||
index: 0,
|
||||
metadata: {
|
||||
type: 'double-text-chip',
|
||||
firstValueFieldName: 'firstName',
|
||||
@ -41,11 +41,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldDoubleTextChipMetadata>,
|
||||
{
|
||||
id: 'email',
|
||||
label: 'Email',
|
||||
key: 'email',
|
||||
name: 'Email',
|
||||
icon: <IconMail />,
|
||||
size: 150,
|
||||
order: 2,
|
||||
index: 1,
|
||||
metadata: {
|
||||
type: 'email',
|
||||
fieldName: 'email',
|
||||
@ -53,11 +53,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldEmailMetadata>,
|
||||
{
|
||||
id: 'company',
|
||||
label: 'Company',
|
||||
key: 'company',
|
||||
name: 'Company',
|
||||
icon: <IconBuildingSkyscraper />,
|
||||
size: 150,
|
||||
order: 3,
|
||||
index: 2,
|
||||
metadata: {
|
||||
type: 'relation',
|
||||
fieldName: 'company',
|
||||
@ -65,11 +65,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldRelationMetadata>,
|
||||
{
|
||||
id: 'phone',
|
||||
label: 'Phone',
|
||||
key: 'phone',
|
||||
name: 'Phone',
|
||||
icon: <IconPhone />,
|
||||
size: 150,
|
||||
order: 4,
|
||||
index: 3,
|
||||
metadata: {
|
||||
type: 'phone',
|
||||
fieldName: 'phone',
|
||||
@ -77,22 +77,22 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldPhoneMetadata>,
|
||||
{
|
||||
id: 'createdAt',
|
||||
label: 'Creation',
|
||||
key: 'createdAt',
|
||||
name: 'Creation',
|
||||
icon: <IconCalendarEvent />,
|
||||
size: 150,
|
||||
order: 5,
|
||||
index: 4,
|
||||
metadata: {
|
||||
type: 'date',
|
||||
fieldName: 'createdAt',
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldDateMetadata>,
|
||||
{
|
||||
id: 'city',
|
||||
label: 'City',
|
||||
key: 'city',
|
||||
name: 'City',
|
||||
icon: <IconMap />,
|
||||
size: 150,
|
||||
order: 6,
|
||||
index: 5,
|
||||
metadata: {
|
||||
type: 'text',
|
||||
fieldName: 'city',
|
||||
@ -100,11 +100,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldTextMetadata>,
|
||||
{
|
||||
id: 'jobTitle',
|
||||
label: 'Job title',
|
||||
key: 'jobTitle',
|
||||
name: 'Job title',
|
||||
icon: <IconBriefcase />,
|
||||
size: 150,
|
||||
order: 7,
|
||||
index: 6,
|
||||
metadata: {
|
||||
type: 'text',
|
||||
fieldName: 'jobTitle',
|
||||
@ -112,11 +112,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldTextMetadata>,
|
||||
{
|
||||
id: 'linkedin',
|
||||
label: 'LinkedIn',
|
||||
key: 'linkedin',
|
||||
name: 'LinkedIn',
|
||||
icon: <IconBrandLinkedin />,
|
||||
size: 150,
|
||||
order: 8,
|
||||
index: 7,
|
||||
metadata: {
|
||||
type: 'url',
|
||||
fieldName: 'linkedinUrl',
|
||||
@ -124,11 +124,11 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<ViewFieldMetadat
|
||||
},
|
||||
} satisfies ColumnDefinition<ViewFieldURLMetadata>,
|
||||
{
|
||||
id: 'x',
|
||||
label: 'Twitter',
|
||||
key: 'x',
|
||||
name: 'Twitter',
|
||||
icon: <IconBrandX />,
|
||||
size: 150,
|
||||
order: 9,
|
||||
index: 8,
|
||||
metadata: {
|
||||
type: 'url',
|
||||
fieldName: 'xUrl',
|
||||
|
||||
@ -17,8 +17,8 @@ import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
export const pipelineAvailableFieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[] =
|
||||
[
|
||||
{
|
||||
id: 'closeDate',
|
||||
label: 'Close Date',
|
||||
key: 'closeDate',
|
||||
name: 'Close Date',
|
||||
icon: <IconCalendarEvent />,
|
||||
metadata: {
|
||||
type: 'date',
|
||||
@ -27,8 +27,8 @@ export const pipelineAvailableFieldDefinitions: ViewFieldDefinition<ViewFieldMet
|
||||
isVisible: true,
|
||||
} satisfies ViewFieldDefinition<ViewFieldDateMetadata>,
|
||||
{
|
||||
id: 'amount',
|
||||
label: 'Amount',
|
||||
key: 'amount',
|
||||
name: 'Amount',
|
||||
icon: <IconCurrencyDollar />,
|
||||
metadata: {
|
||||
type: 'number',
|
||||
@ -37,8 +37,8 @@ export const pipelineAvailableFieldDefinitions: ViewFieldDefinition<ViewFieldMet
|
||||
isVisible: true,
|
||||
} satisfies ViewFieldDefinition<ViewFieldNumberMetadata>,
|
||||
{
|
||||
id: 'probability',
|
||||
label: 'Probability',
|
||||
key: 'probability',
|
||||
name: 'Probability',
|
||||
icon: <IconProgressCheck />,
|
||||
metadata: {
|
||||
type: 'probability',
|
||||
@ -47,8 +47,8 @@ export const pipelineAvailableFieldDefinitions: ViewFieldDefinition<ViewFieldMet
|
||||
isVisible: true,
|
||||
} satisfies ViewFieldDefinition<ViewFieldProbabilityMetadata>,
|
||||
{
|
||||
id: 'pointOfContact',
|
||||
label: 'Point of Contact',
|
||||
key: 'pointOfContact',
|
||||
name: 'Point of Contact',
|
||||
icon: <IconUser />,
|
||||
metadata: {
|
||||
type: 'relation',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { FieldMetadata, FieldType } from './FieldMetadata';
|
||||
|
||||
export type FieldDefinition<T extends FieldMetadata | unknown> = {
|
||||
id: string;
|
||||
label: string;
|
||||
key: string;
|
||||
name: string;
|
||||
icon?: JSX.Element;
|
||||
type: FieldType;
|
||||
metadata: T;
|
||||
|
||||
@ -116,8 +116,8 @@ export type ViewFieldMetadata = { type: ViewFieldType } & (
|
||||
);
|
||||
|
||||
export type ViewFieldDefinition<T extends ViewFieldMetadata | unknown> = {
|
||||
id: string;
|
||||
label: string;
|
||||
key: string;
|
||||
name: string;
|
||||
icon?: JSX.Element;
|
||||
isVisible?: boolean;
|
||||
metadata: T;
|
||||
|
||||
@ -58,10 +58,10 @@ export const EntityTableColumnMenu = ({
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{hiddenColumns.map((column) => (
|
||||
<DropdownMenuItem
|
||||
key={column.id}
|
||||
key={column.key}
|
||||
actions={[
|
||||
<IconButton
|
||||
key={`add-${column.id}`}
|
||||
key={`add-${column.key}`}
|
||||
icon={<IconPlus size={theme.icon.size.sm} />}
|
||||
onClick={() => handleAddColumn(column)}
|
||||
/>,
|
||||
@ -71,7 +71,7 @@ export const EntityTableColumnMenu = ({
|
||||
cloneElement(column.icon, {
|
||||
size: theme.icon.size.md,
|
||||
})}
|
||||
{column.label}
|
||||
{column.name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
|
||||
@ -11,7 +11,7 @@ import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoi
|
||||
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import { resizeFieldOffsetState } from '../states/resizeFieldOffsetState';
|
||||
import { hiddenTableColumnsScopedSelector } from '../states/selectors/hiddenTableColumnsScopedSelector';
|
||||
import { tableColumnsByIdScopedSelector } from '../states/selectors/tableColumnsByIdScopedSelector';
|
||||
import { tableColumnsByKeyScopedSelector } from '../states/selectors/tableColumnsByKeyScopedSelector';
|
||||
import { visibleTableColumnsScopedSelector } from '../states/selectors/visibleTableColumnsScopedSelector';
|
||||
import { tableColumnsScopedState } from '../states/tableColumnsScopedState';
|
||||
|
||||
@ -76,8 +76,8 @@ export function EntityTableHeader() {
|
||||
tableColumnsScopedState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
const columnsById = useRecoilScopedValue(
|
||||
tableColumnsByIdScopedSelector,
|
||||
const columnsByKey = useRecoilScopedValue(
|
||||
tableColumnsByKeyScopedSelector,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
const hiddenColumns = useRecoilScopedValue(
|
||||
@ -92,7 +92,7 @@ export function EntityTableHeader() {
|
||||
const [initialPointerPositionX, setInitialPointerPositionX] = useState<
|
||||
number | null
|
||||
>(null);
|
||||
const [resizedFieldId, setResizedFieldId] = useState<string | null>(null);
|
||||
const [resizedFieldKey, setResizedFieldKey] = useState<string | null>(null);
|
||||
const [isColumnMenuOpen, setIsColumnMenuOpen] = useState(false);
|
||||
|
||||
const handleResizeHandlerStart = useCallback((positionX: number) => {
|
||||
@ -110,19 +110,19 @@ export function EntityTableHeader() {
|
||||
const handleResizeHandlerEnd = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
if (!resizedFieldId) return;
|
||||
if (!resizedFieldKey) return;
|
||||
|
||||
const nextWidth = Math.round(
|
||||
Math.max(
|
||||
columnsById[resizedFieldId].size +
|
||||
columnsByKey[resizedFieldKey].size +
|
||||
snapshot.getLoadable(resizeFieldOffsetState).valueOrThrow(),
|
||||
COLUMN_MIN_WIDTH,
|
||||
),
|
||||
);
|
||||
|
||||
if (nextWidth !== columnsById[resizedFieldId].size) {
|
||||
if (nextWidth !== columnsByKey[resizedFieldKey].size) {
|
||||
const nextColumns = columns.map((column) =>
|
||||
column.id === resizedFieldId
|
||||
column.key === resizedFieldKey
|
||||
? { ...column, size: nextWidth }
|
||||
: column,
|
||||
);
|
||||
@ -132,13 +132,13 @@ export function EntityTableHeader() {
|
||||
|
||||
set(resizeFieldOffsetState, 0);
|
||||
setInitialPointerPositionX(null);
|
||||
setResizedFieldId(null);
|
||||
setResizedFieldKey(null);
|
||||
},
|
||||
[resizedFieldId, columnsById, columns, setColumns],
|
||||
[resizedFieldKey, columnsByKey, columns, setColumns],
|
||||
);
|
||||
|
||||
useTrackPointer({
|
||||
shouldTrackPointer: resizedFieldId !== null,
|
||||
shouldTrackPointer: resizedFieldKey !== null,
|
||||
onMouseDown: handleResizeHandlerStart,
|
||||
onMouseMove: handleResizeHandlerMove,
|
||||
onMouseUp: handleResizeHandlerEnd,
|
||||
@ -163,20 +163,20 @@ export function EntityTableHeader() {
|
||||
|
||||
{visibleColumns.map((column) => (
|
||||
<StyledColumnHeaderCell
|
||||
key={column.id}
|
||||
isResizing={resizedFieldId === column.id}
|
||||
key={column.key}
|
||||
isResizing={resizedFieldKey === column.key}
|
||||
columnWidth={Math.max(
|
||||
columnsById[column.id].size +
|
||||
(resizedFieldId === column.id ? offset : 0),
|
||||
columnsByKey[column.key].size +
|
||||
(resizedFieldKey === column.key ? offset : 0),
|
||||
COLUMN_MIN_WIDTH,
|
||||
)}
|
||||
>
|
||||
<ColumnHead viewName={column.label} viewIcon={column.icon} />
|
||||
<ColumnHead viewName={column.name} viewIcon={column.icon} />
|
||||
<StyledResizeHandler
|
||||
className="cursor-col-resize"
|
||||
role="separator"
|
||||
onPointerDown={() => {
|
||||
setResizedFieldId(column.id);
|
||||
setResizedFieldKey(column.key);
|
||||
}}
|
||||
/>
|
||||
</StyledColumnHeaderCell>
|
||||
|
||||
@ -33,7 +33,7 @@ export function EntityTableRow({ rowId }: { rowId: string }) {
|
||||
</td>
|
||||
{columns.map((column, columnIndex) => {
|
||||
return (
|
||||
<ColumnContext.Provider value={column} key={column.id}>
|
||||
<ColumnContext.Provider value={column} key={column.key}>
|
||||
<EntityTableCell cellIndex={columnIndex} />
|
||||
</ColumnContext.Provider>
|
||||
);
|
||||
|
||||
@ -5,7 +5,7 @@ import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoi
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
|
||||
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import { tableColumnsByIdScopedSelector } from '../states/selectors/tableColumnsByIdScopedSelector';
|
||||
import { tableColumnsByKeyScopedSelector } from '../states/selectors/tableColumnsByKeyScopedSelector';
|
||||
import { tableColumnsScopedState } from '../states/tableColumnsScopedState';
|
||||
import type { ColumnDefinition } from '../types/ColumnDefinition';
|
||||
|
||||
@ -14,26 +14,26 @@ export const useTableColumns = () => {
|
||||
tableColumnsScopedState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
const tableColumnsById = useRecoilScopedValue(
|
||||
tableColumnsByIdScopedSelector,
|
||||
const tableColumnsByKey = useRecoilScopedValue(
|
||||
tableColumnsByKeyScopedSelector,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
|
||||
const handleColumnVisibilityChange = useCallback(
|
||||
(column: ColumnDefinition<ViewFieldMetadata>) => {
|
||||
const nextColumns = tableColumnsById[column.id]
|
||||
const nextColumns = tableColumnsByKey[column.key]
|
||||
? tableColumns.map((previousColumn) =>
|
||||
previousColumn.id === column.id
|
||||
previousColumn.key === column.key
|
||||
? { ...previousColumn, isVisible: !column.isVisible }
|
||||
: previousColumn,
|
||||
)
|
||||
: [...tableColumns, { ...column, isVisible: true }].sort(
|
||||
(columnA, columnB) => columnA.order - columnB.order,
|
||||
(columnA, columnB) => columnA.index - columnB.index,
|
||||
);
|
||||
|
||||
setTableColumns(nextColumns);
|
||||
},
|
||||
[setTableColumns, tableColumns, tableColumnsById],
|
||||
[setTableColumns, tableColumns, tableColumnsByKey],
|
||||
);
|
||||
|
||||
return { handleColumnVisibilityChange };
|
||||
|
||||
@ -95,7 +95,7 @@ export function TableOptionsDropdownContent({
|
||||
!column.isVisible || visibleColumns.length > 1
|
||||
? [
|
||||
<IconButton
|
||||
key={`action-${column.id}`}
|
||||
key={`action-${column.key}`}
|
||||
icon={
|
||||
column.isVisible ? (
|
||||
<IconMinus size={theme.icon.size.sm} />
|
||||
|
||||
@ -31,12 +31,12 @@ export function TableOptionsDropdownSection({
|
||||
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{columns.map((column) => (
|
||||
<DropdownMenuItem key={column.id} actions={renderActions(column)}>
|
||||
<DropdownMenuItem key={column.key} actions={renderActions(column)}>
|
||||
{column.icon &&
|
||||
cloneElement(column.icon, {
|
||||
size: theme.icon.size.md,
|
||||
})}
|
||||
{column.label}
|
||||
{column.name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
|
||||
@ -9,10 +9,10 @@ export const hiddenTableColumnsScopedSelector = selectorFamily({
|
||||
(scopeId: string) =>
|
||||
({ get }) => {
|
||||
const columns = get(tableColumnsScopedState(scopeId));
|
||||
const columnLabels = columns.map(({ label }) => label);
|
||||
const columnKeys = columns.map(({ key }) => key);
|
||||
const otherAvailableColumns = get(
|
||||
availableTableColumnsScopedState(scopeId),
|
||||
).filter(({ label }) => !columnLabels.includes(label));
|
||||
).filter(({ key }) => !columnKeys.includes(key));
|
||||
|
||||
return [
|
||||
...columns.filter((column) => !column.isVisible),
|
||||
|
||||
@ -5,12 +5,12 @@ import type { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
|
||||
import type { ColumnDefinition } from '../../types/ColumnDefinition';
|
||||
import { savedTableColumnsScopedState } from '../savedTableColumnsScopedState';
|
||||
|
||||
export const savedTableColumnsByIdScopedSelector = selectorFamily({
|
||||
key: 'savedTableColumnsByIdScopedSelector',
|
||||
export const savedTableColumnsByKeyScopedSelector = selectorFamily({
|
||||
key: 'savedTableColumnsByKeyScopedSelector',
|
||||
get:
|
||||
(viewId: string | undefined) =>
|
||||
({ get }) =>
|
||||
get(savedTableColumnsScopedState(viewId)).reduce<
|
||||
Record<string, ColumnDefinition<ViewFieldMetadata>>
|
||||
>((result, column) => ({ ...result, [column.id]: column }), {}),
|
||||
>((result, column) => ({ ...result, [column.key]: column }), {}),
|
||||
});
|
||||
@ -5,12 +5,12 @@ import type { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
|
||||
import type { ColumnDefinition } from '../../types/ColumnDefinition';
|
||||
import { tableColumnsScopedState } from '../tableColumnsScopedState';
|
||||
|
||||
export const tableColumnsByIdScopedSelector = selectorFamily({
|
||||
key: 'tableColumnsByIdScopedSelector',
|
||||
export const tableColumnsByKeyScopedSelector = selectorFamily({
|
||||
key: 'tableColumnsByKeyScopedSelector',
|
||||
get:
|
||||
(scopeId: string) =>
|
||||
({ get }) =>
|
||||
get(tableColumnsScopedState(scopeId)).reduce<
|
||||
Record<string, ColumnDefinition<ViewFieldMetadata>>
|
||||
>((result, column) => ({ ...result, [column.id]: column }), {}),
|
||||
>((result, column) => ({ ...result, [column.key]: column }), {}),
|
||||
});
|
||||
@ -6,5 +6,5 @@ import type {
|
||||
export type ColumnDefinition<T extends ViewFieldMetadata | unknown> =
|
||||
ViewFieldDefinition<T> & {
|
||||
size: number;
|
||||
order: number;
|
||||
index: number;
|
||||
};
|
||||
|
||||
@ -6,11 +6,11 @@ export const UPDATE_VIEW_FIELD = gql`
|
||||
$where: ViewFieldWhereUniqueInput!
|
||||
) {
|
||||
updateOneViewField(data: $data, where: $where) {
|
||||
id
|
||||
fieldName
|
||||
isVisible
|
||||
sizeInPx
|
||||
index
|
||||
isVisible
|
||||
key
|
||||
name
|
||||
size
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -6,11 +6,11 @@ export const GET_VIEW_FIELDS = gql`
|
||||
$orderBy: [ViewFieldOrderByWithRelationInput!]
|
||||
) {
|
||||
viewFields: findManyViewField(where: $where, orderBy: $orderBy) {
|
||||
id
|
||||
fieldName
|
||||
isVisible
|
||||
sizeInPx
|
||||
index
|
||||
isVisible
|
||||
key
|
||||
name
|
||||
size
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -8,7 +8,7 @@ import type {
|
||||
import { availableTableColumnsScopedState } from '@/ui/table/states/availableTableColumnsScopedState';
|
||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import { savedTableColumnsScopedState } from '@/ui/table/states/savedTableColumnsScopedState';
|
||||
import { savedTableColumnsByIdScopedSelector } from '@/ui/table/states/selectors/savedTableColumnsByIdScopedSelector';
|
||||
import { savedTableColumnsByKeyScopedSelector } from '@/ui/table/states/selectors/savedTableColumnsByKeyScopedSelector';
|
||||
import { tableColumnsScopedState } from '@/ui/table/states/tableColumnsScopedState';
|
||||
import { currentTableViewIdState } from '@/ui/table/states/tableViewsState';
|
||||
import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
||||
@ -29,21 +29,22 @@ const DEFAULT_VIEW_FIELD_METADATA: ViewFieldTextMetadata = {
|
||||
};
|
||||
|
||||
const toViewFieldInput = (
|
||||
objectName: 'company' | 'person',
|
||||
objectId: 'company' | 'person',
|
||||
fieldDefinition: ColumnDefinition<ViewFieldMetadata>,
|
||||
) => ({
|
||||
fieldName: fieldDefinition.label,
|
||||
index: fieldDefinition.order,
|
||||
key: fieldDefinition.key,
|
||||
name: fieldDefinition.name,
|
||||
index: fieldDefinition.index,
|
||||
isVisible: fieldDefinition.isVisible ?? true,
|
||||
objectName,
|
||||
sizeInPx: fieldDefinition.size,
|
||||
objectId,
|
||||
size: fieldDefinition.size,
|
||||
});
|
||||
|
||||
export const useTableViewFields = ({
|
||||
objectName,
|
||||
objectId,
|
||||
columnDefinitions,
|
||||
}: {
|
||||
objectName: 'company' | 'person';
|
||||
objectId: 'company' | 'person';
|
||||
columnDefinitions: ColumnDefinition<ViewFieldMetadata>[];
|
||||
}) => {
|
||||
const currentTableViewId = useRecoilScopedValue(
|
||||
@ -62,8 +63,8 @@ export const useTableViewFields = ({
|
||||
const setSavedTableColumns = useSetRecoilState(
|
||||
savedTableColumnsScopedState(currentTableViewId),
|
||||
);
|
||||
const savedTableColumnsById = useRecoilValue(
|
||||
savedTableColumnsByIdScopedSelector(currentTableViewId),
|
||||
const savedTableColumnsByKey = useRecoilValue(
|
||||
savedTableColumnsByKeyScopedSelector(currentTableViewId),
|
||||
);
|
||||
|
||||
const [createViewFieldsMutation] = useCreateViewFieldsMutation();
|
||||
@ -79,13 +80,13 @@ export const useTableViewFields = ({
|
||||
return createViewFieldsMutation({
|
||||
variables: {
|
||||
data: columns.map((column) => ({
|
||||
...toViewFieldInput(objectName, column),
|
||||
...toViewFieldInput(objectId, column),
|
||||
viewId,
|
||||
})),
|
||||
},
|
||||
});
|
||||
},
|
||||
[createViewFieldsMutation, currentTableViewId, objectName],
|
||||
[createViewFieldsMutation, currentTableViewId, objectId],
|
||||
);
|
||||
|
||||
const updateViewFields = useCallback(
|
||||
@ -98,9 +99,11 @@ export const useTableViewFields = ({
|
||||
variables: {
|
||||
data: {
|
||||
isVisible: column.isVisible,
|
||||
sizeInPx: column.size,
|
||||
size: column.size,
|
||||
},
|
||||
where: {
|
||||
viewId_key: { key: column.key, viewId: currentTableViewId },
|
||||
},
|
||||
where: { id: column.id },
|
||||
},
|
||||
}),
|
||||
),
|
||||
@ -114,8 +117,8 @@ export const useTableViewFields = ({
|
||||
variables: {
|
||||
orderBy: { index: SortOrder.Asc },
|
||||
where: {
|
||||
objectName: { equals: objectName },
|
||||
viewId: { equals: currentTableViewId ?? null },
|
||||
objectId: { equals: objectId },
|
||||
viewId: { equals: currentTableViewId },
|
||||
},
|
||||
},
|
||||
onCompleted: async (data) => {
|
||||
@ -128,13 +131,13 @@ export const useTableViewFields = ({
|
||||
const nextColumns = data.viewFields.map<
|
||||
ColumnDefinition<ViewFieldMetadata>
|
||||
>((viewField) => ({
|
||||
...(columnDefinitions.find(
|
||||
({ label: columnLabel }) => viewField.fieldName === columnLabel,
|
||||
) || { metadata: DEFAULT_VIEW_FIELD_METADATA }),
|
||||
id: viewField.id,
|
||||
label: viewField.fieldName,
|
||||
order: viewField.index,
|
||||
size: viewField.sizeInPx,
|
||||
...(columnDefinitions.find(({ key }) => viewField.key === key) || {
|
||||
metadata: DEFAULT_VIEW_FIELD_METADATA,
|
||||
}),
|
||||
key: viewField.key,
|
||||
name: viewField.name,
|
||||
index: viewField.index,
|
||||
size: viewField.size,
|
||||
isVisible: viewField.isVisible,
|
||||
}));
|
||||
|
||||
@ -153,15 +156,15 @@ export const useTableViewFields = ({
|
||||
if (!currentTableViewId) return;
|
||||
|
||||
const viewFieldsToCreate = tableColumns.filter(
|
||||
(column) => !savedTableColumnsById[column.id],
|
||||
(column) => !savedTableColumnsByKey[column.key],
|
||||
);
|
||||
await createViewFields(viewFieldsToCreate);
|
||||
|
||||
const viewFieldsToUpdate = tableColumns.filter(
|
||||
(column) =>
|
||||
savedTableColumnsById[column.id] &&
|
||||
(savedTableColumnsById[column.id].size !== column.size ||
|
||||
savedTableColumnsById[column.id].isVisible !== column.isVisible),
|
||||
savedTableColumnsByKey[column.key] &&
|
||||
(savedTableColumnsByKey[column.key].size !== column.size ||
|
||||
savedTableColumnsByKey[column.key].isVisible !== column.isVisible),
|
||||
);
|
||||
await updateViewFields(viewFieldsToUpdate);
|
||||
|
||||
@ -170,7 +173,7 @@ export const useTableViewFields = ({
|
||||
createViewFields,
|
||||
currentTableViewId,
|
||||
refetch,
|
||||
savedTableColumnsById,
|
||||
savedTableColumnsByKey,
|
||||
tableColumns,
|
||||
updateViewFields,
|
||||
]);
|
||||
|
||||
@ -45,7 +45,7 @@ export const useTableViews = <Entity, SortField>({
|
||||
);
|
||||
|
||||
const { createViewFields, persistColumns } = useTableViewFields({
|
||||
objectName: objectId,
|
||||
objectId,
|
||||
columnDefinitions,
|
||||
});
|
||||
const { createViewFilters, persistFilters } = useViewFilters({
|
||||
|
||||
Reference in New Issue
Block a user