Complete Fix view work (#2272)
* Fix views * Make view sorts and view filters functional * Complete Company table view fix * Fix model creation * Start fixing board * Complete work
This commit is contained in:
@ -168,37 +168,35 @@ export const DataTableHeader = () => {
|
||||
>
|
||||
<SelectAllCheckbox />
|
||||
</th>
|
||||
{[...visibleTableColumns]
|
||||
.sort((columnA, columnB) => columnA.position - columnB.position)
|
||||
.map((column) => (
|
||||
<StyledColumnHeaderCell
|
||||
key={column.fieldId}
|
||||
isResizing={resizedFieldKey === column.fieldId}
|
||||
columnWidth={Math.max(
|
||||
tableColumnsByKey[column.fieldId].size +
|
||||
(resizedFieldKey === column.fieldId ? resizeFieldOffset : 0),
|
||||
COLUMN_MIN_WIDTH,
|
||||
)}
|
||||
>
|
||||
<StyledColumnHeadContainer>
|
||||
<ColumnHeadWithDropdown
|
||||
column={column}
|
||||
isFirstColumn={column.position === 1}
|
||||
isLastColumn={
|
||||
column.position === visibleTableColumns.length - 1
|
||||
}
|
||||
primaryColumnKey={primaryColumn?.fieldId || ''}
|
||||
/>
|
||||
</StyledColumnHeadContainer>
|
||||
<StyledResizeHandler
|
||||
className="cursor-col-resize"
|
||||
role="separator"
|
||||
onPointerDown={() => {
|
||||
setResizedFieldKey(column.fieldId);
|
||||
}}
|
||||
{visibleTableColumns.map((column) => (
|
||||
<StyledColumnHeaderCell
|
||||
key={column.fieldId}
|
||||
isResizing={resizedFieldKey === column.fieldId}
|
||||
columnWidth={Math.max(
|
||||
tableColumnsByKey[column.fieldId].size +
|
||||
(resizedFieldKey === column.fieldId ? resizeFieldOffset : 0),
|
||||
COLUMN_MIN_WIDTH,
|
||||
)}
|
||||
>
|
||||
<StyledColumnHeadContainer>
|
||||
<ColumnHeadWithDropdown
|
||||
column={column}
|
||||
isFirstColumn={column.position === 1}
|
||||
isLastColumn={
|
||||
column.position === visibleTableColumns.length - 1
|
||||
}
|
||||
primaryColumnKey={primaryColumn?.fieldId || ''}
|
||||
/>
|
||||
</StyledColumnHeaderCell>
|
||||
))}
|
||||
</StyledColumnHeadContainer>
|
||||
<StyledResizeHandler
|
||||
className="cursor-col-resize"
|
||||
role="separator"
|
||||
onPointerDown={() => {
|
||||
setResizedFieldKey(column.fieldId);
|
||||
}}
|
||||
/>
|
||||
</StyledColumnHeaderCell>
|
||||
))}
|
||||
<th>
|
||||
{hiddenTableColumns.length > 0 && (
|
||||
<StyledColumnHeadContainer>
|
||||
|
||||
@ -4,7 +4,7 @@ import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFami
|
||||
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
|
||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
||||
import { useView } from '@/views/hooks/useView';
|
||||
import { availableSortsScopedState } from '@/views/states/availableSortsScopedState';
|
||||
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
|
||||
|
||||
import { SortDefinition } from '../../sort/types/SortDefinition';
|
||||
import { isFetchingDataTableDataState } from '../states/isFetchingDataTableDataState';
|
||||
@ -54,7 +54,7 @@ export const useSetDataTableData = () => {
|
||||
setEntityCountInCurrentView(entityIds.length);
|
||||
|
||||
set(
|
||||
availableSortsScopedState({ scopeId: tableContextScopeId }),
|
||||
availableSortDefinitionsScopedState({ scopeId: tableContextScopeId }),
|
||||
sortDefinitionArray,
|
||||
);
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||
import { useView } from '@/views/hooks/useView';
|
||||
import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
|
||||
import { useViewGetStates } from '@/views/hooks/useViewGetStates';
|
||||
|
||||
import { useTableColumns } from '../../hooks/useTableColumns';
|
||||
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
@ -29,7 +29,7 @@ export const TableOptionsDropdownContent = ({
|
||||
onImport?: () => void;
|
||||
}) => {
|
||||
const { setViewEditMode, handleViewNameSubmit } = useView();
|
||||
const { viewEditMode, currentView } = useViewInternalStates();
|
||||
const { viewEditMode, currentView } = useViewGetStates();
|
||||
|
||||
const { closeDropdown } = useDropdown();
|
||||
|
||||
|
||||
@ -12,12 +12,13 @@ type FilterDropdownButtonProps = {
|
||||
export const FilterDropdownButton = ({
|
||||
hotkeyScope,
|
||||
}: FilterDropdownButtonProps) => {
|
||||
const { availableFilters } = useFilter();
|
||||
const { availableFilterDefinitions } = useFilter();
|
||||
|
||||
const hasOnlyOneEntityFilter =
|
||||
availableFilters.length === 1 && availableFilters[0].type === 'entity';
|
||||
availableFilterDefinitions.length === 1 &&
|
||||
availableFilterDefinitions[0].type === 'entity';
|
||||
|
||||
if (!availableFilters.length) {
|
||||
if (!availableFilterDefinitions.length) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useUpsertFilter } from '@/views/hooks/useUpsertFilter';
|
||||
|
||||
import { useFilter } from '../hooks/useFilter';
|
||||
|
||||
@ -8,19 +7,18 @@ export const FilterDropdownDateSearchInput = () => {
|
||||
filterDefinitionUsedInDropdown,
|
||||
selectedOperandInDropdown,
|
||||
setIsFilterDropdownUnfolded,
|
||||
selectFilter,
|
||||
} = useFilter();
|
||||
|
||||
const upsertFilter = useUpsertFilter();
|
||||
|
||||
const handleChange = (date: Date) => {
|
||||
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
upsertFilter({
|
||||
key: filterDefinitionUsedInDropdown.key,
|
||||
type: filterDefinitionUsedInDropdown.type,
|
||||
selectFilter?.({
|
||||
fieldId: filterDefinitionUsedInDropdown.fieldId,
|
||||
value: date.toISOString(),
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: date.toLocaleDateString(),
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
|
||||
setIsFilterDropdownUnfolded(false);
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useFilterCurrentlyEdited } from '@/ui/data/filter/hooks/useFilterCurrentlyEdited';
|
||||
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
|
||||
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
import { useRemoveFilter } from '@/views/hooks/useRemoveFilter';
|
||||
import { useUpsertFilter } from '@/views/hooks/useUpsertFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
|
||||
import { useFilter } from '../hooks/useFilter';
|
||||
@ -16,20 +13,16 @@ export const FilterDropdownEntitySearchSelect = ({
|
||||
entitiesForSelect: EntitiesForMultipleEntitySelect<EntityForSelect>;
|
||||
}) => {
|
||||
const {
|
||||
filterDropdownSelectedEntityId,
|
||||
setFilterDropdownSelectedEntityId,
|
||||
filterDefinitionUsedInDropdown,
|
||||
selectedOperandInDropdown,
|
||||
filterDropdownSearchInput,
|
||||
selectedFilter,
|
||||
selectFilter,
|
||||
} = useFilter();
|
||||
|
||||
const [isAllEntitySelected, setIsAllEntitySelected] = useState(false);
|
||||
|
||||
const upsertFilter = useUpsertFilter();
|
||||
const removeFilter = useRemoveFilter();
|
||||
|
||||
const filterCurrentlyEdited = useFilterCurrentlyEdited();
|
||||
|
||||
const handleUserSelected = (
|
||||
selectedEntity: EntityForSelect | null | undefined,
|
||||
) => {
|
||||
@ -45,24 +38,16 @@ export const FilterDropdownEntitySearchSelect = ({
|
||||
setIsAllEntitySelected(false);
|
||||
}
|
||||
|
||||
const clickedOnAlreadySelectedEntity =
|
||||
selectedEntity.id === filterDropdownSelectedEntityId;
|
||||
setFilterDropdownSelectedEntityId(selectedEntity.id);
|
||||
|
||||
if (clickedOnAlreadySelectedEntity) {
|
||||
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||
setFilterDropdownSelectedEntityId(null);
|
||||
} else {
|
||||
setFilterDropdownSelectedEntityId(selectedEntity.id);
|
||||
|
||||
upsertFilter({
|
||||
displayValue: selectedEntity.name,
|
||||
key: filterDefinitionUsedInDropdown.key,
|
||||
operand: selectedOperandInDropdown,
|
||||
type: filterDefinitionUsedInDropdown.type,
|
||||
value: selectedEntity.id,
|
||||
displayAvatarUrl: selectedEntity.avatarUrl,
|
||||
});
|
||||
}
|
||||
selectFilter?.({
|
||||
displayValue: selectedEntity.name,
|
||||
fieldId: filterDefinitionUsedInDropdown.fieldId,
|
||||
operand: selectedOperandInDropdown,
|
||||
value: selectedEntity.id,
|
||||
displayAvatarUrl: selectedEntity.avatarUrl,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
};
|
||||
|
||||
const isAllEntitySelectShown =
|
||||
@ -81,36 +66,30 @@ export const FilterDropdownEntitySearchSelect = ({
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (isAllEntitySelected) {
|
||||
setIsAllEntitySelected(false);
|
||||
|
||||
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||
} else {
|
||||
setIsAllEntitySelected(true);
|
||||
setIsAllEntitySelected(true);
|
||||
setFilterDropdownSelectedEntityId(null);
|
||||
|
||||
setFilterDropdownSelectedEntityId(null);
|
||||
|
||||
upsertFilter({
|
||||
displayValue: filterDefinitionUsedInDropdown.selectAllLabel,
|
||||
key: filterDefinitionUsedInDropdown.key,
|
||||
operand: ViewFilterOperand.IsNotNull,
|
||||
type: filterDefinitionUsedInDropdown.type,
|
||||
value: '',
|
||||
});
|
||||
}
|
||||
selectFilter?.({
|
||||
displayValue: filterDefinitionUsedInDropdown.selectAllLabel,
|
||||
fieldId: filterDefinitionUsedInDropdown.fieldId,
|
||||
operand: ViewFilterOperand.IsNotNull,
|
||||
value: '',
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!filterCurrentlyEdited) {
|
||||
if (!selectedFilter) {
|
||||
setFilterDropdownSelectedEntityId(null);
|
||||
} else {
|
||||
setFilterDropdownSelectedEntityId(filterCurrentlyEdited.value);
|
||||
setFilterDropdownSelectedEntityId(selectedFilter.value);
|
||||
setIsAllEntitySelected(
|
||||
filterCurrentlyEdited.operand === ViewFilterOperand.IsNotNull,
|
||||
selectedFilter.operand === ViewFilterOperand.IsNotNull,
|
||||
);
|
||||
}
|
||||
}, [
|
||||
filterCurrentlyEdited,
|
||||
selectedFilter,
|
||||
setFilterDropdownSelectedEntityId,
|
||||
entitiesForSelect.selectedEntities,
|
||||
]);
|
||||
|
||||
@ -11,32 +11,32 @@ export const FilterDropdownFilterSelect = () => {
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
setFilterDropdownSearchInput,
|
||||
availableFilters,
|
||||
availableFilterDefinitions,
|
||||
} = useFilter();
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
return (
|
||||
<DropdownMenuItemsContainer>
|
||||
{availableFilters.map((availableFilter, index) => (
|
||||
{availableFilterDefinitions.map((availableFilterDefinition, index) => (
|
||||
<MenuItem
|
||||
key={`select-filter-${index}`}
|
||||
testId={`select-filter-${index}`}
|
||||
onClick={() => {
|
||||
setFilterDefinitionUsedInDropdown(availableFilter);
|
||||
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
||||
|
||||
if (availableFilter.type === 'entity') {
|
||||
if (availableFilterDefinition.type === 'entity') {
|
||||
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
||||
}
|
||||
|
||||
setSelectedOperandInDropdown(
|
||||
getOperandsForFilterType(availableFilter.type)?.[0],
|
||||
getOperandsForFilterType(availableFilterDefinition.type)?.[0],
|
||||
);
|
||||
|
||||
setFilterDropdownSearchInput('');
|
||||
}}
|
||||
LeftIcon={availableFilter.Icon}
|
||||
text={availableFilter.label}
|
||||
LeftIcon={availableFilterDefinition.Icon}
|
||||
text={availableFilterDefinition.label}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
|
||||
@ -2,16 +2,14 @@ import { ChangeEvent } from 'react';
|
||||
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
|
||||
import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter';
|
||||
import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
|
||||
import { useFilter } from '../hooks/useFilter';
|
||||
|
||||
export const FilterDropdownNumberSearchInput = () => {
|
||||
const { selectedOperandInDropdown, filterDefinitionUsedInDropdown } =
|
||||
useFilter();
|
||||
|
||||
const upsertFilter = useUpsertFilter();
|
||||
const removeFilter = useRemoveFilter();
|
||||
const {
|
||||
selectedOperandInDropdown,
|
||||
filterDefinitionUsedInDropdown,
|
||||
selectFilter,
|
||||
} = useFilter();
|
||||
|
||||
return (
|
||||
filterDefinitionUsedInDropdown &&
|
||||
@ -21,17 +19,13 @@ export const FilterDropdownNumberSearchInput = () => {
|
||||
type="number"
|
||||
placeholder={filterDefinitionUsedInDropdown.label}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.value === '') {
|
||||
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||
} else {
|
||||
upsertFilter({
|
||||
key: filterDefinitionUsedInDropdown.key,
|
||||
type: filterDefinitionUsedInDropdown.type,
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
});
|
||||
}
|
||||
selectFilter?.({
|
||||
fieldId: filterDefinitionUsedInDropdown.fieldId,
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -2,9 +2,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
|
||||
import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
|
||||
import { useFilter } from '../hooks/useFilter';
|
||||
import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited';
|
||||
import { getOperandLabel } from '../utils/getOperandLabel';
|
||||
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
||||
|
||||
@ -14,27 +12,25 @@ export const FilterDropdownOperandSelect = () => {
|
||||
setSelectedOperandInDropdown,
|
||||
isFilterDropdownOperandSelectUnfolded,
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
selectedFilter,
|
||||
selectFilter,
|
||||
} = useFilter();
|
||||
|
||||
const operandsForFilterType = getOperandsForFilterType(
|
||||
filterDefinitionUsedInDropdown?.type,
|
||||
);
|
||||
|
||||
const filterCurrentlyEdited = useFilterCurrentlyEdited();
|
||||
|
||||
const upsertFilter = useUpsertFilter();
|
||||
|
||||
const handleOperangeChange = (newOperand: ViewFilterOperand) => {
|
||||
setSelectedOperandInDropdown(newOperand);
|
||||
setIsFilterDropdownOperandSelectUnfolded(false);
|
||||
|
||||
if (filterDefinitionUsedInDropdown && filterCurrentlyEdited) {
|
||||
upsertFilter({
|
||||
key: filterCurrentlyEdited.key,
|
||||
displayValue: filterCurrentlyEdited.displayValue,
|
||||
if (filterDefinitionUsedInDropdown && selectedFilter) {
|
||||
selectFilter?.({
|
||||
fieldId: selectedFilter.fieldId,
|
||||
displayValue: selectedFilter.displayValue,
|
||||
operand: newOperand,
|
||||
type: filterCurrentlyEdited.type,
|
||||
value: filterCurrentlyEdited.value,
|
||||
value: selectedFilter.value,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -2,10 +2,7 @@ import { ChangeEvent } from 'react';
|
||||
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
|
||||
import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter';
|
||||
import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
|
||||
import { useFilter } from '../hooks/useFilter';
|
||||
import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited';
|
||||
|
||||
export const FilterDropdownTextSearchInput = () => {
|
||||
const {
|
||||
@ -13,13 +10,10 @@ export const FilterDropdownTextSearchInput = () => {
|
||||
selectedOperandInDropdown,
|
||||
filterDropdownSearchInput,
|
||||
setFilterDropdownSearchInput,
|
||||
selectedFilter,
|
||||
selectFilter,
|
||||
} = useFilter();
|
||||
|
||||
const upsertFilter = useUpsertFilter();
|
||||
const removeFilter = useRemoveFilter();
|
||||
|
||||
const filterCurrentlyEdited = useFilterCurrentlyEdited();
|
||||
|
||||
return (
|
||||
filterDefinitionUsedInDropdown &&
|
||||
selectedOperandInDropdown && (
|
||||
@ -27,21 +21,17 @@ export const FilterDropdownTextSearchInput = () => {
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder={filterDefinitionUsedInDropdown.label}
|
||||
value={filterCurrentlyEdited?.value ?? filterDropdownSearchInput}
|
||||
value={selectedFilter?.value ?? filterDropdownSearchInput}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setFilterDropdownSearchInput(event.target.value);
|
||||
|
||||
if (event.target.value === '') {
|
||||
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||
} else {
|
||||
upsertFilter({
|
||||
key: filterDefinitionUsedInDropdown.key,
|
||||
type: filterDefinitionUsedInDropdown.type,
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
});
|
||||
}
|
||||
selectFilter?.({
|
||||
fieldId: filterDefinitionUsedInDropdown.fieldId,
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -21,13 +21,13 @@ export const SingleEntityFilterDropdownButton = ({
|
||||
hotkeyScope: HotkeyScope;
|
||||
}) => {
|
||||
const {
|
||||
availableFilters,
|
||||
selectedFilters,
|
||||
availableFilterDefinitions,
|
||||
selectedFilter,
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
} = useFilter();
|
||||
|
||||
const availableFilter = availableFilters[0];
|
||||
const availableFilter = availableFilterDefinitions[0];
|
||||
|
||||
React.useEffect(() => {
|
||||
setFilterDefinitionUsedInDropdown(availableFilter);
|
||||
@ -48,11 +48,11 @@ export const SingleEntityFilterDropdownButton = ({
|
||||
dropdownOffset={{ x: 0, y: -28 }}
|
||||
clickableComponent={
|
||||
<StyledHeaderDropdownButton>
|
||||
{selectedFilters[0] ? (
|
||||
{selectedFilter ? (
|
||||
<GenericEntityFilterChip
|
||||
filter={selectedFilters[0]}
|
||||
filter={selectedFilter}
|
||||
Icon={
|
||||
selectedFilters[0].operand === ViewFilterOperand.IsNotNull
|
||||
selectedFilter.operand === ViewFilterOperand.IsNotNull
|
||||
? availableFilter.SelectAllIcon
|
||||
: undefined
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { useScopeInternalContextOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow';
|
||||
|
||||
import { FilterScopeInternalContext } from '../scopes/scope-internal-context/FilterScopeInternalContext';
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
import { useFilterStates } from './useFilterStates';
|
||||
|
||||
@ -14,8 +18,8 @@ export const useFilter = (props?: UseFilterProps) => {
|
||||
props?.filterScopeId,
|
||||
);
|
||||
const {
|
||||
availableFilters,
|
||||
setAvailableFilters,
|
||||
availableFilterDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
filterDefinitionUsedInDropdown,
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
filterDropdownSearchInput,
|
||||
@ -26,16 +30,28 @@ export const useFilter = (props?: UseFilterProps) => {
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
isFilterDropdownUnfolded,
|
||||
setIsFilterDropdownUnfolded,
|
||||
selectedFilters,
|
||||
setSelectedFilters,
|
||||
selectedFilter,
|
||||
setSelectedFilter,
|
||||
selectedOperandInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
} = useFilterStates(scopeId);
|
||||
|
||||
const { onFilterSelect } = useScopeInternalContextOrThrow(
|
||||
FilterScopeInternalContext,
|
||||
);
|
||||
|
||||
const selectFilter = useCallback(
|
||||
(filter: Filter) => {
|
||||
setSelectedFilter(filter);
|
||||
onFilterSelect?.(filter);
|
||||
},
|
||||
[setSelectedFilter, onFilterSelect],
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
availableFilters,
|
||||
setAvailableFilters,
|
||||
availableFilterDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
filterDefinitionUsedInDropdown,
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
filterDropdownSearchInput,
|
||||
@ -46,9 +62,10 @@ export const useFilter = (props?: UseFilterProps) => {
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
isFilterDropdownUnfolded,
|
||||
setIsFilterDropdownUnfolded,
|
||||
selectedFilters,
|
||||
setSelectedFilters,
|
||||
selectedFilter,
|
||||
setSelectedFilter,
|
||||
selectedOperandInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
selectFilter,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useFilter } from './useFilter';
|
||||
|
||||
export const useFilterCurrentlyEdited = () => {
|
||||
const { selectedFilters, filterDefinitionUsedInDropdown } = useFilter();
|
||||
|
||||
return useMemo(() => {
|
||||
return selectedFilters?.find(
|
||||
(filter) => filter.key === filterDefinitionUsedInDropdown?.key,
|
||||
);
|
||||
}, [filterDefinitionUsedInDropdown?.key, selectedFilters]);
|
||||
};
|
||||
@ -1,19 +1,17 @@
|
||||
import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
|
||||
|
||||
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
||||
import { availableFilterDefinitionsScopedState } from '../states/availableFilterDefinitionsScopedState';
|
||||
import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
|
||||
import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
|
||||
import { filterDropdownSelectedEntityIdScopedState } from '../states/filterDropdownSelectedEntityIdScopedState';
|
||||
import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
|
||||
import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
|
||||
import { selectedFiltersScopedState } from '../states/selectedFiltersScopedState';
|
||||
import { selectedFilterScopedState } from '../states/selectedFilterScopedState';
|
||||
import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
|
||||
|
||||
export const useFilterStates = (scopeId: string) => {
|
||||
const [availableFilters, setAvailableFilters] = useRecoilScopedStateV2(
|
||||
availableFiltersScopedState,
|
||||
scopeId,
|
||||
);
|
||||
const [availableFilterDefinitions, setAvailableFilterDefinitions] =
|
||||
useRecoilScopedStateV2(availableFilterDefinitionsScopedState, scopeId);
|
||||
|
||||
const [filterDefinitionUsedInDropdown, setFilterDefinitionUsedInDropdown] =
|
||||
useRecoilScopedStateV2(filterDefinitionUsedInDropdownScopedState, scopeId);
|
||||
@ -35,8 +33,8 @@ export const useFilterStates = (scopeId: string) => {
|
||||
const [isFilterDropdownUnfolded, setIsFilterDropdownUnfolded] =
|
||||
useRecoilScopedStateV2(isFilterDropdownUnfoldedScopedState, scopeId);
|
||||
|
||||
const [selectedFilters, setSelectedFilters] = useRecoilScopedStateV2(
|
||||
selectedFiltersScopedState,
|
||||
const [selectedFilter, setSelectedFilter] = useRecoilScopedStateV2(
|
||||
selectedFilterScopedState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
@ -44,8 +42,8 @@ export const useFilterStates = (scopeId: string) => {
|
||||
useRecoilScopedStateV2(selectedOperandInDropdownScopedState, scopeId);
|
||||
|
||||
return {
|
||||
availableFilters,
|
||||
setAvailableFilters,
|
||||
availableFilterDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
filterDefinitionUsedInDropdown,
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
filterDropdownSearchInput,
|
||||
@ -56,8 +54,8 @@ export const useFilterStates = (scopeId: string) => {
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
isFilterDropdownUnfolded,
|
||||
setIsFilterDropdownUnfolded,
|
||||
selectedFilters,
|
||||
setSelectedFilters,
|
||||
selectedFilter,
|
||||
setSelectedFilter,
|
||||
selectedOperandInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
};
|
||||
|
||||
@ -2,25 +2,31 @@ import { ReactNode } from 'react';
|
||||
|
||||
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
import { FilterScopeInitEffect } from './init-effect/FilterScopeInitEffect';
|
||||
import { FilterScopeInternalContext } from './scope-internal-context/FilterScopeInternalContext';
|
||||
|
||||
type FilterScopeProps = {
|
||||
children: ReactNode;
|
||||
filterScopeId: string;
|
||||
availableFilters?: FilterDefinition[];
|
||||
availableFilterDefinitions?: FilterDefinition[];
|
||||
onFilterSelect?: (filter: Filter) => void;
|
||||
};
|
||||
|
||||
export const FilterScope = ({
|
||||
children,
|
||||
filterScopeId,
|
||||
availableFilters,
|
||||
availableFilterDefinitions,
|
||||
onFilterSelect,
|
||||
}: FilterScopeProps) => {
|
||||
return (
|
||||
<FilterScopeInternalContext.Provider value={{ scopeId: filterScopeId }}>
|
||||
<FilterScopeInternalContext.Provider
|
||||
value={{ scopeId: filterScopeId, onFilterSelect }}
|
||||
>
|
||||
<FilterScopeInitEffect
|
||||
filterScopeId={filterScopeId}
|
||||
availableFilters={availableFilters}
|
||||
availableFilterDefinitions={availableFilterDefinitions}
|
||||
/>
|
||||
{children}
|
||||
</FilterScopeInternalContext.Provider>
|
||||
|
||||
@ -6,20 +6,20 @@ import { useFilterStates } from '../../hooks/useFilterStates';
|
||||
|
||||
type FilterScopeInitEffectProps = {
|
||||
filterScopeId: string;
|
||||
availableFilters?: FilterDefinition[];
|
||||
availableFilterDefinitions?: FilterDefinition[];
|
||||
};
|
||||
|
||||
export const FilterScopeInitEffect = ({
|
||||
filterScopeId,
|
||||
availableFilters,
|
||||
availableFilterDefinitions,
|
||||
}: FilterScopeInitEffectProps) => {
|
||||
const { setAvailableFilters } = useFilterStates(filterScopeId);
|
||||
const { setAvailableFilterDefinitions } = useFilterStates(filterScopeId);
|
||||
|
||||
useEffect(() => {
|
||||
if (availableFilters) {
|
||||
setAvailableFilters(availableFilters);
|
||||
if (availableFilterDefinitions) {
|
||||
setAvailableFilterDefinitions(availableFilterDefinitions);
|
||||
}
|
||||
}, [availableFilters, setAvailableFilters]);
|
||||
}, [availableFilterDefinitions, setAvailableFilterDefinitions]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey';
|
||||
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
|
||||
|
||||
import { Filter } from '../../types/Filter';
|
||||
|
||||
type FilterScopeInternalContextProps = ScopedStateKey & {
|
||||
test?: string;
|
||||
onFilterSelect?: (sort: Filter) => void;
|
||||
};
|
||||
|
||||
export const FilterScopeInternalContext =
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
|
||||
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||
|
||||
export const availableFiltersScopedState = createScopedState<
|
||||
export const availableFilterDefinitionsScopedState = createScopedState<
|
||||
FilterDefinition[]
|
||||
>({
|
||||
key: 'availableFiltersScopedState',
|
||||
key: 'availableFilterDefinitionsScopedState',
|
||||
defaultValue: [],
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
export const selectedFilterScopedState = createScopedState<Filter | undefined>({
|
||||
key: 'selectedFilterScopedState',
|
||||
defaultValue: undefined,
|
||||
});
|
||||
@ -1,8 +0,0 @@
|
||||
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
export const selectedFiltersScopedState = createScopedState<Filter[]>({
|
||||
key: 'selectedFiltersScopedState',
|
||||
defaultValue: [],
|
||||
});
|
||||
@ -1,12 +1,12 @@
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
|
||||
import { FilterType } from './FilterType';
|
||||
import { FilterDefinition } from './FilterDefinition';
|
||||
|
||||
export type Filter = {
|
||||
key: string;
|
||||
type: FilterType;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
displayValue: string;
|
||||
displayAvatarUrl?: string;
|
||||
operand: ViewFilterOperand;
|
||||
definition: FilterDefinition;
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { FilterType } from './FilterType';
|
||||
|
||||
export type FilterDefinition = {
|
||||
key: string;
|
||||
fieldId: string;
|
||||
label: string;
|
||||
Icon: IconComponent;
|
||||
type: FilterType;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { FilterDefinition } from './FilterDefinition';
|
||||
|
||||
export type FilterDefinitionByEntity<T> = FilterDefinition & {
|
||||
key: keyof T;
|
||||
fieldId: keyof T;
|
||||
};
|
||||
|
||||
@ -3,28 +3,39 @@ import { QueryMode } from '~/generated/graphql';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
|
||||
export const turnFilterIntoWhereClause = (filter: Filter) => {
|
||||
type FilterToTurnIntoWhereClause = Omit<Filter, 'definition'> & {
|
||||
definition: {
|
||||
type: Filter['definition']['type'];
|
||||
};
|
||||
};
|
||||
|
||||
export const turnFilterIntoWhereClause = (
|
||||
filter: FilterToTurnIntoWhereClause | undefined,
|
||||
) => {
|
||||
if (!filter) {
|
||||
return {};
|
||||
}
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.IsNotNull:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
not: null,
|
||||
},
|
||||
};
|
||||
default:
|
||||
switch (filter.type) {
|
||||
switch (filter.definition.type) {
|
||||
case 'text':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Contains:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
contains: filter.value,
|
||||
mode: QueryMode.Insensitive,
|
||||
},
|
||||
};
|
||||
case ViewFilterOperand.DoesNotContain:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
not: {
|
||||
contains: filter.value,
|
||||
mode: QueryMode.Insensitive,
|
||||
@ -33,64 +44,64 @@ export const turnFilterIntoWhereClause = (filter: Filter) => {
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'number':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
gte: parseFloat(filter.value),
|
||||
},
|
||||
};
|
||||
case ViewFilterOperand.LessThan:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
lte: parseFloat(filter.value),
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'date':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
gte: filter.value,
|
||||
},
|
||||
};
|
||||
case ViewFilterOperand.LessThan:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
lte: filter.value,
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
case 'entity':
|
||||
switch (filter.operand) {
|
||||
case ViewFilterOperand.Is:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
equals: filter.value,
|
||||
},
|
||||
};
|
||||
case ViewFilterOperand.IsNot:
|
||||
return {
|
||||
[filter.key]: {
|
||||
[filter.fieldId]: {
|
||||
not: { equals: filter.value },
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${filter.operand} for ${filter.type} filter`,
|
||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||
);
|
||||
}
|
||||
default:
|
||||
|
||||
@ -35,7 +35,7 @@ export const SortDropdownButton = ({
|
||||
setSelectedSortDirection('asc');
|
||||
}, []);
|
||||
|
||||
const { availableSorts, onSortAdd, isSortSelected } = useSort();
|
||||
const { availableSortDefinitions, onSortSelect, isSortSelected } = useSort();
|
||||
|
||||
const { toggleDropdown } = useDropdown({
|
||||
dropdownScopeId: SortDropdownId,
|
||||
@ -48,8 +48,8 @@ export const SortDropdownButton = ({
|
||||
|
||||
const handleAddSort = (selectedSortDefinition: SortDefinition) => {
|
||||
toggleDropdown();
|
||||
onSortAdd?.({
|
||||
key: selectedSortDefinition.key,
|
||||
onSortSelect?.({
|
||||
fieldId: selectedSortDefinition.fieldId,
|
||||
direction: selectedSortDirection,
|
||||
definition: selectedSortDefinition,
|
||||
});
|
||||
@ -96,7 +96,7 @@ export const SortDropdownButton = ({
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
{availableSorts.map((availableSort, index) => (
|
||||
{availableSortDefinitions.map((availableSort, index) => (
|
||||
<MenuItem
|
||||
testId={`select-sort-${index}`}
|
||||
key={index}
|
||||
|
||||
@ -15,22 +15,22 @@ export const useSort = (props?: UseSortProps) => {
|
||||
props?.sortScopeId,
|
||||
);
|
||||
const {
|
||||
availableSorts,
|
||||
setAvailableSorts,
|
||||
availableSortDefinitions,
|
||||
setAvailableSortDefinitions,
|
||||
isSortSelected,
|
||||
setIsSortSelected,
|
||||
} = useSortStates(scopeId);
|
||||
|
||||
const { onSortAdd } = useScopeInternalContextOrThrow(
|
||||
const { onSortSelect } = useScopeInternalContextOrThrow(
|
||||
SortScopeInternalContext,
|
||||
);
|
||||
|
||||
return {
|
||||
onSortAdd,
|
||||
onSortSelect,
|
||||
scopeId,
|
||||
availableSorts,
|
||||
availableSortDefinitions,
|
||||
isSortSelected,
|
||||
setIsSortSelected,
|
||||
setAvailableSorts,
|
||||
setAvailableSortDefinitions,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
|
||||
import { availableSortsScopedState } from '@/views/states/availableSortsScopedState';
|
||||
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
|
||||
|
||||
import { isSortSelectedScopedState } from '../states/isSortSelectedScopedState';
|
||||
|
||||
export const useSortStates = (scopeId: string) => {
|
||||
const [availableSorts, setAvailableSorts] = useRecoilScopedStateV2(
|
||||
availableSortsScopedState,
|
||||
scopeId,
|
||||
);
|
||||
const [availableSortDefinitions, setAvailableSortDefinitions] =
|
||||
useRecoilScopedStateV2(availableSortDefinitionsScopedState, scopeId);
|
||||
|
||||
const [isSortSelected, setIsSortSelected] = useRecoilScopedStateV2(
|
||||
isSortSelectedScopedState,
|
||||
@ -15,8 +13,8 @@ export const useSortStates = (scopeId: string) => {
|
||||
);
|
||||
|
||||
return {
|
||||
availableSorts,
|
||||
setAvailableSorts,
|
||||
availableSortDefinitions,
|
||||
setAvailableSortDefinitions,
|
||||
isSortSelected,
|
||||
setIsSortSelected,
|
||||
};
|
||||
|
||||
@ -9,23 +9,23 @@ import { SortScopeInternalContext } from './scope-internal-context/SortScopeInte
|
||||
type SortScopeProps = {
|
||||
children: ReactNode;
|
||||
sortScopeId: string;
|
||||
availableSorts?: SortDefinition[];
|
||||
onSortAdd?: (sort: Sort) => void | Promise<void>;
|
||||
availableSortDefinitions?: SortDefinition[];
|
||||
onSortSelect?: (sort: Sort) => void | Promise<void>;
|
||||
};
|
||||
|
||||
export const SortScope = ({
|
||||
children,
|
||||
sortScopeId,
|
||||
availableSorts,
|
||||
onSortAdd,
|
||||
availableSortDefinitions,
|
||||
onSortSelect,
|
||||
}: SortScopeProps) => {
|
||||
return (
|
||||
<SortScopeInternalContext.Provider
|
||||
value={{ scopeId: sortScopeId, onSortAdd }}
|
||||
value={{ scopeId: sortScopeId, onSortSelect }}
|
||||
>
|
||||
<SortScopeInitEffect
|
||||
sortScopeId={sortScopeId}
|
||||
availableSorts={availableSorts}
|
||||
availableSortDefinitions={availableSortDefinitions}
|
||||
/>
|
||||
{children}
|
||||
</SortScopeInternalContext.Provider>
|
||||
|
||||
@ -6,20 +6,20 @@ import { useSortStates } from '../../hooks/useSortStates';
|
||||
|
||||
type SortScopeInitEffectProps = {
|
||||
sortScopeId: string;
|
||||
availableSorts?: SortDefinition[];
|
||||
availableSortDefinitions?: SortDefinition[];
|
||||
};
|
||||
|
||||
export const SortScopeInitEffect = ({
|
||||
sortScopeId,
|
||||
availableSorts,
|
||||
availableSortDefinitions,
|
||||
}: SortScopeInitEffectProps) => {
|
||||
const { setAvailableSorts } = useSortStates(sortScopeId);
|
||||
const { setAvailableSortDefinitions } = useSortStates(sortScopeId);
|
||||
|
||||
useEffect(() => {
|
||||
if (availableSorts) {
|
||||
setAvailableSorts(availableSorts);
|
||||
if (availableSortDefinitions) {
|
||||
setAvailableSortDefinitions(availableSortDefinitions);
|
||||
}
|
||||
}, [availableSorts, setAvailableSorts]);
|
||||
}, [availableSortDefinitions, setAvailableSortDefinitions]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -2,11 +2,9 @@ import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/type
|
||||
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
|
||||
|
||||
import { Sort } from '../../types/Sort';
|
||||
import { SortDefinition } from '../../types/SortDefinition';
|
||||
|
||||
type SortScopeInternalContextProps = ScopedStateKey & {
|
||||
onSortAdd?: (sort: Sort) => void;
|
||||
availableSorts?: SortDefinition[];
|
||||
onSortSelect?: (sort: Sort) => void;
|
||||
};
|
||||
|
||||
export const SortScopeInternalContext =
|
||||
|
||||
@ -2,7 +2,7 @@ import { SortDefinition } from './SortDefinition';
|
||||
import { SortDirection } from './SortDirection';
|
||||
|
||||
export type Sort = {
|
||||
key: string;
|
||||
fieldId: string;
|
||||
direction: SortDirection;
|
||||
definition: SortDefinition;
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { SortDirection } from './SortDirection';
|
||||
|
||||
export type SortDefinition = {
|
||||
key: string;
|
||||
fieldId: string;
|
||||
label: string;
|
||||
Icon?: IconComponent;
|
||||
getOrderByTemplate?: (direction: SortDirection) => any[];
|
||||
|
||||
@ -10,7 +10,7 @@ export const reduceSortsToOrderBy = (sorts: Sort[]): any[] =>
|
||||
if (sort.definition.getOrderByTemplate) {
|
||||
return sort.definition.getOrderByTemplate(direction);
|
||||
} else {
|
||||
return [{ [sort.definition.key]: direction }];
|
||||
return [{ [sort.definition.fieldId]: direction }];
|
||||
}
|
||||
})
|
||||
.flat();
|
||||
|
||||
@ -2,8 +2,9 @@ import { useView } from '@/views/hooks/useView';
|
||||
|
||||
import { Dropdown } from '../../dropdown/components/Dropdown';
|
||||
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
|
||||
import { BoardScopeIds } from '../types/enums/BoardScopeIds';
|
||||
import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
||||
|
||||
import { BoardOptionsDropdownId } from './constants/BoardOptionsDropdownId';
|
||||
import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton';
|
||||
import {
|
||||
BoardOptionsDropdownContent,
|
||||
@ -12,26 +13,22 @@ import {
|
||||
|
||||
type BoardOptionsDropdownProps = Pick<
|
||||
BoardOptionsDropdownContentProps,
|
||||
'customHotkeyScope' | 'onStageAdd'
|
||||
'onStageAdd'
|
||||
>;
|
||||
|
||||
export const BoardOptionsDropdown = ({
|
||||
customHotkeyScope,
|
||||
onStageAdd,
|
||||
}: BoardOptionsDropdownProps) => {
|
||||
const { setViewEditMode } = useView();
|
||||
|
||||
return (
|
||||
<DropdownScope dropdownScopeId={BoardScopeIds.OptionsDropdown}>
|
||||
<DropdownScope dropdownScopeId={BoardOptionsDropdownId}>
|
||||
<Dropdown
|
||||
clickableComponent={<BoardOptionsDropdownButton />}
|
||||
dropdownComponents={
|
||||
<BoardOptionsDropdownContent
|
||||
customHotkeyScope={customHotkeyScope}
|
||||
onStageAdd={onStageAdd}
|
||||
/>
|
||||
<BoardOptionsDropdownContent onStageAdd={onStageAdd} />
|
||||
}
|
||||
dropdownHotkeyScope={customHotkeyScope}
|
||||
dropdownHotkeyScope={{ scope: BoardOptionsHotkeyScope.Dropdown }}
|
||||
onClickOutside={() => setViewEditMode('none')}
|
||||
dropdownMenuWidth={170}
|
||||
/>
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
|
||||
import { BoardScopeIds } from '../types/enums/BoardScopeIds';
|
||||
|
||||
export const BoardOptionsDropdownButton = () => {
|
||||
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
||||
dropdownScopeId: BoardScopeIds.OptionsDropdown,
|
||||
});
|
||||
const { isDropdownOpen, toggleDropdown } = useDropdown();
|
||||
|
||||
const handleClick = () => {
|
||||
toggleDropdown();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useContext, useRef, useState } from 'react';
|
||||
import { useRecoilCallback, useRecoilState } from 'recoil';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
@ -22,25 +22,20 @@ import { MenuItemNavigate } from '@/ui/navigation/menu-item/components/MenuItemN
|
||||
import { MenuItemToggle } from '@/ui/navigation/menu-item/components/MenuItemToggle';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||
import { useView } from '@/views/hooks/useView';
|
||||
import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
|
||||
import { viewEditModeScopedState } from '@/views/states/viewEditModeScopedState';
|
||||
import { useViewGetStates } from '@/views/hooks/useViewGetStates';
|
||||
|
||||
import { useBoardCardFields } from '../hooks/useBoardCardFields';
|
||||
import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { isCompactViewEnabledState } from '../states/isCompactViewEnabledState';
|
||||
import { savedBoardCardFieldsFamilyState } from '../states/savedBoardCardFieldsFamilyState';
|
||||
import { hiddenBoardCardFieldsScopedSelector } from '../states/selectors/hiddenBoardCardFieldsScopedSelector';
|
||||
import { visibleBoardCardFieldsScopedSelector } from '../states/selectors/visibleBoardCardFieldsScopedSelector';
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
||||
|
||||
export type BoardOptionsDropdownContentProps = {
|
||||
customHotkeyScope: HotkeyScope;
|
||||
onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
|
||||
};
|
||||
|
||||
@ -54,15 +49,12 @@ type ColumnForCreate = {
|
||||
};
|
||||
|
||||
export const BoardOptionsDropdownContent = ({
|
||||
customHotkeyScope,
|
||||
onStageAdd,
|
||||
}: BoardOptionsDropdownContentProps) => {
|
||||
const { setViewEditMode, createView, currentViewId } = useView();
|
||||
const { viewEditMode, currentView } = useViewInternalStates();
|
||||
const { setViewEditMode, handleViewNameSubmit } = useView();
|
||||
const { viewEditMode, currentView } = useViewGetStates();
|
||||
const { BoardRecoilScopeContext } = useContext(BoardContext);
|
||||
|
||||
const boardRecoilScopeId = useRecoilScopeId(BoardRecoilScopeContext);
|
||||
|
||||
const stageInputRef = useRef<HTMLInputElement>(null);
|
||||
const viewEditInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -104,31 +96,6 @@ export const BoardOptionsDropdownContent = ({
|
||||
onStageAdd?.(columnToCreate);
|
||||
};
|
||||
|
||||
const handleViewNameSubmit = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
async () => {
|
||||
const viewEditMode = snapshot
|
||||
.getLoadable(viewEditModeScopedState({ scopeId: boardRecoilScopeId }))
|
||||
.getValue();
|
||||
|
||||
if (!viewEditMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const boardCardFields = await snapshot.getPromise(
|
||||
boardCardFieldsScopedState(boardRecoilScopeId),
|
||||
);
|
||||
const isCreateMode = viewEditMode === 'create';
|
||||
const name = viewEditInputRef.current?.value;
|
||||
|
||||
if (isCreateMode && name) {
|
||||
await createView(name);
|
||||
set(savedBoardCardFieldsFamilyState(currentViewId), boardCardFields);
|
||||
}
|
||||
},
|
||||
[boardRecoilScopeId, createView, currentViewId],
|
||||
);
|
||||
|
||||
const resetMenu = () => setCurrentMenu(undefined);
|
||||
|
||||
const handleMenuNavigate = (menu: BoardOptionsMenu) => {
|
||||
@ -146,43 +113,39 @@ export const BoardOptionsDropdownContent = ({
|
||||
setViewEditMode('none');
|
||||
closeDropdown();
|
||||
},
|
||||
customHotkeyScope.scope,
|
||||
BoardOptionsHotkeyScope.Dropdown,
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
() => {
|
||||
const name = viewEditInputRef.current?.value;
|
||||
resetMenu();
|
||||
setViewEditMode('none');
|
||||
closeDropdown();
|
||||
handleStageSubmit();
|
||||
handleViewNameSubmit();
|
||||
handleViewNameSubmit(name);
|
||||
closeDropdown();
|
||||
},
|
||||
customHotkeyScope.scope,
|
||||
BoardOptionsHotkeyScope.Dropdown,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!currentMenu && (
|
||||
<>
|
||||
{viewEditMode && (
|
||||
<DropdownMenuInput
|
||||
ref={viewEditInputRef}
|
||||
autoFocus={viewEditMode !== 'none'}
|
||||
placeholder={
|
||||
viewEditMode === 'create'
|
||||
? 'New view'
|
||||
: viewEditMode === 'edit'
|
||||
? 'View name'
|
||||
: ''
|
||||
}
|
||||
defaultValue={
|
||||
viewEditMode === 'create'
|
||||
? ''
|
||||
: viewEditMode === 'edit'
|
||||
? currentView?.name
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<DropdownMenuInput
|
||||
ref={viewEditInputRef}
|
||||
autoFocus={viewEditMode !== 'none'}
|
||||
placeholder={
|
||||
viewEditMode === 'create'
|
||||
? 'New view'
|
||||
: viewEditMode === 'edit'
|
||||
? 'View name'
|
||||
: ''
|
||||
}
|
||||
defaultValue={viewEditMode === 'create' ? '' : currentView?.name}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItemNavigate
|
||||
|
||||
@ -40,6 +40,8 @@ export type EntityBoardProps = {
|
||||
const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
// We should either apply the constant all caps case or maybe define a more general enum to store those ids ?
|
||||
export const BoardOptionsDropdownId = 'board-options';
|
||||
@ -7,6 +7,6 @@ import { PipelineProgress } from '~/generated/graphql';
|
||||
export type BoardOptions = {
|
||||
newCardComponent: React.ReactNode;
|
||||
CardComponent: ComponentType;
|
||||
filters: FilterDefinitionByEntity<PipelineProgress>[];
|
||||
sorts: SortDefinition[];
|
||||
filterDefinitions: FilterDefinitionByEntity<PipelineProgress>[];
|
||||
sortDefinitions: SortDefinition[];
|
||||
};
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export enum BoardScopeIds {
|
||||
OptionsDropdown = 'board-options',
|
||||
}
|
||||
Reference in New Issue
Block a user