@ -3,11 +3,12 @@ import { useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { useGenerateCreateOneObjectMutation } from '@/object-record/utils/generateCreateOneObjectMutation';
|
import { useGenerateCreateOneObjectMutation } from '@/object-record/utils/generateCreateOneObjectMutation';
|
||||||
import { useGenerateCacheFragment } from '@/object-record/utils/useGenerateCacheFragment';
|
|
||||||
import { useGenerateDeleteOneObjectMutation } from '@/object-record/utils/useGenerateDeleteOneObjectMutation';
|
import { useGenerateDeleteOneObjectMutation } from '@/object-record/utils/useGenerateDeleteOneObjectMutation';
|
||||||
import { useGenerateFindManyCustomObjectsQuery } from '@/object-record/utils/useGenerateFindManyCustomObjectsQuery';
|
import { useGenerateFindManyCustomObjectsQuery } from '@/object-record/utils/useGenerateFindManyCustomObjectsQuery';
|
||||||
import { useGenerateFindOneCustomObjectQuery } from '@/object-record/utils/useGenerateFindOneCustomObjectQuery';
|
import { useGenerateFindOneCustomObjectQuery } from '@/object-record/utils/useGenerateFindOneCustomObjectQuery';
|
||||||
import { useGenerateUpdateOneObjectMutation } from '@/object-record/utils/useGenerateUpdateOneObjectMutation';
|
import { useGenerateUpdateOneObjectMutation } from '@/object-record/utils/useGenerateUpdateOneObjectMutation';
|
||||||
|
import { useGetRecordFromCache } from '@/object-record/utils/useGetRecordFromCache';
|
||||||
|
import { useModifyRecordFromCache } from '@/object-record/utils/useModifyRecordFromCache';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
||||||
@ -37,7 +38,11 @@ export const useObjectMetadataItem = (
|
|||||||
|
|
||||||
const objectNotFoundInMetadata = !isDefined(objectMetadataItem);
|
const objectNotFoundInMetadata = !isDefined(objectMetadataItem);
|
||||||
|
|
||||||
const cacheFragment = useGenerateCacheFragment({
|
const getRecordFromCache = useGetRecordFromCache({
|
||||||
|
objectMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
|
const modifyRecordFromCache = useModifyRecordFromCache({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -74,7 +79,8 @@ export const useObjectMetadataItem = (
|
|||||||
basePathToShowPage,
|
basePathToShowPage,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
objectNotFoundInMetadata,
|
objectNotFoundInMetadata,
|
||||||
cacheFragment,
|
getRecordFromCache,
|
||||||
|
modifyRecordFromCache,
|
||||||
findManyQuery,
|
findManyQuery,
|
||||||
findOneQuery,
|
findOneQuery,
|
||||||
createOneMutation,
|
createOneMutation,
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export const useFindManyObjectRecords = <
|
|||||||
skip?: boolean;
|
skip?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const findManyQueryStateIdentifier =
|
const findManyQueryStateIdentifier =
|
||||||
objectNamePlural + JSON.stringify(filter);
|
objectNamePlural + JSON.stringify(filter) + JSON.stringify(orderBy) + limit;
|
||||||
|
|
||||||
const [lastCursor, setLastCursor] = useRecoilState(
|
const [lastCursor, setLastCursor] = useRecoilState(
|
||||||
cursorFamilyState(findManyQueryStateIdentifier),
|
cursorFamilyState(findManyQueryStateIdentifier),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useApolloClient, useMutation } from '@apollo/client';
|
import { useMutation } from '@apollo/client';
|
||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
@ -12,14 +12,12 @@ export const useUpdateOneObjectRecord = <T>({
|
|||||||
objectMetadataItem: foundObjectMetadataItem,
|
objectMetadataItem: foundObjectMetadataItem,
|
||||||
objectNotFoundInMetadata,
|
objectNotFoundInMetadata,
|
||||||
updateOneMutation,
|
updateOneMutation,
|
||||||
cacheFragment,
|
getRecordFromCache,
|
||||||
findManyQuery,
|
findManyQuery,
|
||||||
} = useObjectMetadataItem({
|
} = useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { cache } = useApolloClient();
|
|
||||||
|
|
||||||
// TODO: type this with a minimal type at least with Record<string, any>
|
// TODO: type this with a minimal type at least with Record<string, any>
|
||||||
const [mutate] = useMutation(updateOneMutation);
|
const [mutate] = useMutation(updateOneMutation);
|
||||||
|
|
||||||
@ -36,14 +34,7 @@ export const useUpdateOneObjectRecord = <T>({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedRecordId = cache.identify({
|
const cachedRecord = getRecordFromCache(idToUpdate);
|
||||||
__typename: capitalize(foundObjectMetadataItem?.nameSingular ?? ''),
|
|
||||||
id: idToUpdate,
|
|
||||||
});
|
|
||||||
const cachedRecord = cache.readFragment({
|
|
||||||
id: cachedRecordId,
|
|
||||||
fragment: cacheFragment,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedObject = await mutate({
|
const updatedObject = await mutate({
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
|
|
||||||
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
|
|
||||||
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
|
||||||
|
|
||||||
export const useGenerateCacheFragment = ({
|
|
||||||
objectMetadataItem,
|
|
||||||
}: {
|
|
||||||
objectMetadataItem: ObjectMetadataItem | undefined | null;
|
|
||||||
}) => {
|
|
||||||
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
|
|
||||||
|
|
||||||
if (!objectMetadataItem) {
|
|
||||||
return EMPTY_MUTATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular);
|
|
||||||
|
|
||||||
return gql`
|
|
||||||
fragment ${capitalizedObjectName}Fragment on ${capitalizedObjectName} {
|
|
||||||
id
|
|
||||||
${objectMetadataItem.fields
|
|
||||||
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
|
||||||
.join('\n')}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { gql, useApolloClient } from '@apollo/client';
|
||||||
|
|
||||||
|
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
|
||||||
|
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
export const useGetRecordFromCache = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
}: {
|
||||||
|
objectMetadataItem: ObjectMetadataItem | undefined | null;
|
||||||
|
}) => {
|
||||||
|
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
return (recordId: string) => {
|
||||||
|
if (!objectMetadataItem) {
|
||||||
|
return EMPTY_MUTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular);
|
||||||
|
|
||||||
|
const cacheReadFragment = gql`
|
||||||
|
fragment ${capitalizedObjectName}Fragment on ${capitalizedObjectName} {
|
||||||
|
id
|
||||||
|
${objectMetadataItem.fields
|
||||||
|
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
||||||
|
.join('\n')}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const cache = apolloClient.cache;
|
||||||
|
const cachedRecordId = cache.identify({
|
||||||
|
__typename: capitalize(objectMetadataItem?.nameSingular ?? ''),
|
||||||
|
id: recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return cache.readFragment({
|
||||||
|
id: cachedRecordId,
|
||||||
|
fragment: cacheReadFragment,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { Modifiers } from '@apollo/client/cache';
|
||||||
|
|
||||||
|
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
export const useModifyRecordFromCache = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
}: {
|
||||||
|
objectMetadataItem: ObjectMetadataItem | undefined | null;
|
||||||
|
}) => {
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
return (recordId: string, fieldModifiers: Modifiers) => {
|
||||||
|
if (!objectMetadataItem) {
|
||||||
|
return EMPTY_MUTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache = apolloClient.cache;
|
||||||
|
const cachedRecordId = cache.identify({
|
||||||
|
__typename: capitalize(objectMetadataItem?.nameSingular ?? ''),
|
||||||
|
id: recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.modify({
|
||||||
|
id: cachedRecordId,
|
||||||
|
fields: fieldModifiers,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -142,7 +142,7 @@ export const PeopleCard = ({
|
|||||||
isHovered={isHovered}
|
isHovered={isHovered}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
onClick={() => navigate(`/person/${person.id}`)}
|
onClick={() => navigate(`/object/person/${person.id}`)}
|
||||||
hasBottomBorder={hasBottomBorder}
|
hasBottomBorder={hasBottomBorder}
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@ -109,7 +109,6 @@ export const usePersistField = () => {
|
|||||||
fieldIsFullName
|
fieldIsFullName
|
||||||
) {
|
) {
|
||||||
const fieldName = fieldDefinition.metadata.fieldName;
|
const fieldName = fieldDefinition.metadata.fieldName;
|
||||||
|
|
||||||
set(
|
set(
|
||||||
entityFieldsFamilySelector({ entityId, fieldName }),
|
entityFieldsFamilySelector({ entityId, fieldName }),
|
||||||
valueToPersist,
|
valueToPersist,
|
||||||
|
|||||||
@ -30,6 +30,11 @@ const initializeValue = (
|
|||||||
currencyCode: 'USD',
|
currencyCode: 'USD',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fieldValue) {
|
||||||
|
return { amount: null, currencyCode: 'USD' };
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
amount: convertCurrencyMicrosToCurrency(fieldValue.amountMicros),
|
amount: convertCurrencyMicrosToCurrency(fieldValue.amountMicros),
|
||||||
currencyCode: fieldValue.currencyCode,
|
currencyCode: fieldValue.currencyCode,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { IconPlus } from '@/ui/display/icon';
|
import { IconPlus } from '@/ui/display/icon';
|
||||||
import { LightButton } from '@/ui/input/button/components/LightButton';
|
import { LightButton } from '@/ui/input/button/components/LightButton';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
|
||||||
|
|
||||||
import { ObjectFilterDropdownId } from '../constants/ObjectFilterDropdownId';
|
import { ObjectFilterDropdownId } from '../constants/ObjectFilterDropdownId';
|
||||||
|
|
||||||
@ -9,7 +10,10 @@ export const AddObjectFilterFromDetailsButton = () => {
|
|||||||
dropdownScopeId: ObjectFilterDropdownId,
|
dropdownScopeId: ObjectFilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { resetFilter } = useFilter();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
|
resetFilter();
|
||||||
toggleDropdown();
|
toggleDropdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,27 +5,15 @@ import { ObjectFilterDropdownId } from '../constants/ObjectFilterDropdownId';
|
|||||||
import { useFilter } from '../hooks/useFilter';
|
import { useFilter } from '../hooks/useFilter';
|
||||||
|
|
||||||
export const MultipleFiltersButton = () => {
|
export const MultipleFiltersButton = () => {
|
||||||
const {
|
const { resetFilter } = useFilter();
|
||||||
setFilterDefinitionUsedInDropdown,
|
|
||||||
setIsObjectFilterDropdownOperandSelectUnfolded,
|
|
||||||
setObjectFilterDropdownSearchInput,
|
|
||||||
setSelectedOperandInDropdown,
|
|
||||||
} = useFilter();
|
|
||||||
|
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
||||||
dropdownScopeId: ObjectFilterDropdownId,
|
dropdownScopeId: ObjectFilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const resetState = () => {
|
|
||||||
setIsObjectFilterDropdownOperandSelectUnfolded(false);
|
|
||||||
setFilterDefinitionUsedInDropdown(null);
|
|
||||||
setSelectedOperandInDropdown(null);
|
|
||||||
setObjectFilterDropdownSearchInput('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
toggleDropdown();
|
toggleDropdown();
|
||||||
resetState();
|
resetFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -42,7 +42,6 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setObjectFilterDropdownSelectedEntityId(selectedEntity.id);
|
setObjectFilterDropdownSelectedEntityId(selectedEntity.id);
|
||||||
closeDropdown();
|
|
||||||
|
|
||||||
selectFilter?.({
|
selectFilter?.({
|
||||||
displayValue: selectedEntity.name,
|
displayValue: selectedEntity.name,
|
||||||
@ -52,6 +51,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
displayAvatarUrl: selectedEntity.avatarUrl,
|
displayAvatarUrl: selectedEntity.avatarUrl,
|
||||||
definition: filterDefinitionUsedInDropdown,
|
definition: filterDefinitionUsedInDropdown,
|
||||||
});
|
});
|
||||||
|
closeDropdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAllEntitySelectShown =
|
const isAllEntitySelectShown =
|
||||||
|
|||||||
@ -52,8 +52,10 @@ export const useFilter = (props?: UseFilterProps) => {
|
|||||||
setObjectFilterDropdownSearchInput('');
|
setObjectFilterDropdownSearchInput('');
|
||||||
setObjectFilterDropdownSelectedEntityId(null);
|
setObjectFilterDropdownSelectedEntityId(null);
|
||||||
setSelectedFilter(undefined);
|
setSelectedFilter(undefined);
|
||||||
|
setFilterDefinitionUsedInDropdown(null);
|
||||||
setSelectedOperandInDropdown(null);
|
setSelectedOperandInDropdown(null);
|
||||||
}, [
|
}, [
|
||||||
|
setFilterDefinitionUsedInDropdown,
|
||||||
setObjectFilterDropdownSearchInput,
|
setObjectFilterDropdownSearchInput,
|
||||||
setObjectFilterDropdownSelectedEntityId,
|
setObjectFilterDropdownSelectedEntityId,
|
||||||
setSelectedFilter,
|
setSelectedFilter,
|
||||||
|
|||||||
@ -31,7 +31,6 @@ export const TableOptionsDropdownContent = ({
|
|||||||
|
|
||||||
const viewEditMode = useRecoilValue(viewEditModeState);
|
const viewEditMode = useRecoilValue(viewEditModeState);
|
||||||
const currentView = useRecoilValue(currentViewSelector);
|
const currentView = useRecoilValue(currentViewSelector);
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown();
|
const { closeDropdown } = useDropdown();
|
||||||
|
|
||||||
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
||||||
|
|||||||
@ -6,19 +6,21 @@ import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjec
|
|||||||
import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults';
|
import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
import { assertNotNull } from '~/utils/assert';
|
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||||
import { useView } from '../hooks/useView';
|
import { useView } from '../hooks/useView';
|
||||||
import { ViewField } from '../types/ViewField';
|
|
||||||
import { ViewFilter } from '../types/ViewFilter';
|
|
||||||
import { ViewSort } from '../types/ViewSort';
|
|
||||||
import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot';
|
import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot';
|
||||||
import { getViewScopedStateValuesFromSnapshot } from '../utils/getViewScopedStateValuesFromSnapshot';
|
|
||||||
|
|
||||||
export const ViewBarEffect = () => {
|
export const ViewBarEffect = () => {
|
||||||
const { scopeId: viewScopeId, loadView, changeViewInUrl } = useView();
|
const {
|
||||||
|
scopeId: viewScopeId,
|
||||||
|
loadView,
|
||||||
|
changeViewInUrl,
|
||||||
|
loadViewFields,
|
||||||
|
loadViewFilters,
|
||||||
|
loadViewSorts,
|
||||||
|
} = useView();
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const currentViewIdFromUrl = searchParams.get('view');
|
const currentViewIdFromUrl = searchParams.get('view');
|
||||||
@ -38,11 +40,7 @@ export const ViewBarEffect = () => {
|
|||||||
onCompleted: useRecoilCallback(
|
onCompleted: useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (data: PaginatedObjectTypeResults<GraphQLView>) => {
|
async (data: PaginatedObjectTypeResults<GraphQLView>) => {
|
||||||
const nextViews = data.edges.map((view) => ({
|
const nextViews = data.edges.map(({ node }) => node);
|
||||||
id: view.node.id,
|
|
||||||
name: view.node.name,
|
|
||||||
objectMetadataId: view.node.objectMetadataId,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { viewsState, currentViewIdState } =
|
const { viewsState, currentViewIdState } =
|
||||||
getViewScopedStatesFromSnapshot({
|
getViewScopedStatesFromSnapshot({
|
||||||
@ -52,7 +50,9 @@ export const ViewBarEffect = () => {
|
|||||||
|
|
||||||
const views = getSnapshotValue(snapshot, viewsState);
|
const views = getSnapshotValue(snapshot, viewsState);
|
||||||
|
|
||||||
if (!isDeeplyEqual(views, nextViews)) set(viewsState, nextViews);
|
if (!isDeeplyEqual(views, nextViews)) {
|
||||||
|
set(viewsState, nextViews);
|
||||||
|
}
|
||||||
|
|
||||||
const currentView =
|
const currentView =
|
||||||
data.edges
|
data.edges
|
||||||
@ -66,9 +66,9 @@ export const ViewBarEffect = () => {
|
|||||||
set(currentViewIdState, currentView.id);
|
set(currentViewIdState, currentView.id);
|
||||||
|
|
||||||
if (currentView?.viewFields) {
|
if (currentView?.viewFields) {
|
||||||
updateViewFields(currentView.viewFields, currentView.id);
|
loadViewFields(currentView.viewFields, currentView.id);
|
||||||
updateViewFilters(currentView.viewFilters, currentView.id);
|
loadViewFilters(currentView.viewFilters, currentView.id);
|
||||||
updateViewSorts(currentView.viewSorts, currentView.id);
|
loadViewSorts(currentView.viewSorts, currentView.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nextViews.length) return;
|
if (!nextViews.length) return;
|
||||||
@ -77,154 +77,6 @@ export const ViewBarEffect = () => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateViewFields = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
async (
|
|
||||||
data: PaginatedObjectTypeResults<ViewField>,
|
|
||||||
currentViewId: string,
|
|
||||||
) => {
|
|
||||||
const {
|
|
||||||
availableFieldDefinitions,
|
|
||||||
onViewFieldsChange,
|
|
||||||
savedViewFields,
|
|
||||||
isPersistingView,
|
|
||||||
} = getViewScopedStateValuesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { savedViewFieldsState, currentViewFieldsState } =
|
|
||||||
getViewScopedStatesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!availableFieldDefinitions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const queriedViewFields = data.edges
|
|
||||||
.map((viewField) => viewField.node)
|
|
||||||
.filter(assertNotNull);
|
|
||||||
|
|
||||||
if (isPersistingView) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
|
|
||||||
set(currentViewFieldsState, queriedViewFields);
|
|
||||||
set(savedViewFieldsState, queriedViewFields);
|
|
||||||
onViewFieldsChange?.(queriedViewFields);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[viewScopeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateViewFilters = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
async (
|
|
||||||
data: PaginatedObjectTypeResults<Required<ViewFilter>>,
|
|
||||||
currentViewId: string,
|
|
||||||
) => {
|
|
||||||
const {
|
|
||||||
availableFilterDefinitions,
|
|
||||||
savedViewFilters,
|
|
||||||
onViewFiltersChange,
|
|
||||||
} = getViewScopedStateValuesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { savedViewFiltersState, currentViewFiltersState } =
|
|
||||||
getViewScopedStatesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!availableFilterDefinitions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const queriedViewFilters = data.edges
|
|
||||||
.map(({ node }) => {
|
|
||||||
const availableFilterDefinition = availableFilterDefinitions.find(
|
|
||||||
(filterDefinition) =>
|
|
||||||
filterDefinition.fieldMetadataId === node.fieldMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!availableFilterDefinition) return null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...node,
|
|
||||||
displayValue: node.displayValue ?? node.value,
|
|
||||||
definition: availableFilterDefinition,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter(assertNotNull);
|
|
||||||
|
|
||||||
if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
|
|
||||||
set(savedViewFiltersState, queriedViewFilters);
|
|
||||||
set(currentViewFiltersState, queriedViewFilters);
|
|
||||||
onViewFiltersChange?.(queriedViewFilters);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[viewScopeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateViewSorts = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
async (
|
|
||||||
data: PaginatedObjectTypeResults<Required<ViewSort>>,
|
|
||||||
currentViewId: string,
|
|
||||||
) => {
|
|
||||||
const { availableSortDefinitions, savedViewSorts, onViewSortsChange } =
|
|
||||||
getViewScopedStateValuesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { savedViewSortsState, currentViewSortsState } =
|
|
||||||
getViewScopedStatesFromSnapshot({
|
|
||||||
snapshot,
|
|
||||||
viewScopeId,
|
|
||||||
viewId: currentViewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!availableSortDefinitions || !currentViewId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const queriedViewSorts = data.edges
|
|
||||||
.map(({ node }) => {
|
|
||||||
const availableSortDefinition = availableSortDefinitions.find(
|
|
||||||
(sort) => sort.fieldMetadataId === node.fieldMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!availableSortDefinition) return null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: node.id,
|
|
||||||
fieldMetadataId: node.fieldMetadataId,
|
|
||||||
direction: node.direction,
|
|
||||||
definition: availableSortDefinition,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter(assertNotNull);
|
|
||||||
|
|
||||||
if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
|
|
||||||
set(savedViewSortsState, queriedViewSorts);
|
|
||||||
set(currentViewSortsState, queriedViewSorts);
|
|
||||||
onViewSortsChange?.(queriedViewSorts);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[viewScopeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentViewIdFromUrl) return;
|
if (!currentViewIdFromUrl) return;
|
||||||
|
|
||||||
|
|||||||
@ -79,7 +79,7 @@ export const ViewsDropdownButton = ({
|
|||||||
entityCountInCurrentViewState,
|
entityCountInCurrentViewState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setViewEditMode } = useView();
|
const { setViewEditMode, setCurrentViewId, loadView } = useView();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isDropdownOpen: isViewsDropdownOpen,
|
isDropdownOpen: isViewsDropdownOpen,
|
||||||
@ -95,10 +95,10 @@ export const ViewsDropdownButton = ({
|
|||||||
const handleViewSelect = useRecoilCallback(
|
const handleViewSelect = useRecoilCallback(
|
||||||
() => async (viewId: string) => {
|
() => async (viewId: string) => {
|
||||||
changeViewInUrl(viewId);
|
changeViewInUrl(viewId);
|
||||||
|
loadView(viewId);
|
||||||
closeViewsDropdown();
|
closeViewsDropdown();
|
||||||
},
|
},
|
||||||
[changeViewInUrl, closeViewsDropdown],
|
[changeViewInUrl, closeViewsDropdown, loadView],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleAddViewButtonClick = () => {
|
const handleAddViewButtonClick = () => {
|
||||||
@ -114,6 +114,7 @@ export const ViewsDropdownButton = ({
|
|||||||
) => {
|
) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
changeViewInUrl(viewId);
|
changeViewInUrl(viewId);
|
||||||
|
setCurrentViewId(viewId);
|
||||||
setViewEditMode('edit');
|
setViewEditMode('edit');
|
||||||
onViewEditModeChange?.();
|
onViewEditModeChange?.();
|
||||||
closeViewsDropdown();
|
closeViewsDropdown();
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { getOperationName } from '@apollo/client/utilities';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
@ -12,7 +11,7 @@ export const useViewFields = (viewScopeId: string) => {
|
|||||||
objectNameSingular: 'viewField',
|
objectNameSingular: 'viewField',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { findManyQuery: findManyViewsQuery } = useObjectMetadataItem({
|
const { modifyRecordFromCache } = useObjectMetadataItem({
|
||||||
objectNameSingular: 'view',
|
objectNameSingular: 'view',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -21,14 +20,23 @@ export const useViewFields = (viewScopeId: string) => {
|
|||||||
const persistViewFields = useRecoilCallback(
|
const persistViewFields = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (viewFieldsToPersist: ViewField[], viewId?: string) => {
|
async (viewFieldsToPersist: ViewField[], viewId?: string) => {
|
||||||
const { viewObjectMetadataId, currentViewId, savedViewFieldsByKey } =
|
const {
|
||||||
getViewScopedStateValuesFromSnapshot({
|
viewObjectMetadataId,
|
||||||
snapshot,
|
currentViewId,
|
||||||
viewScopeId,
|
savedViewFieldsByKey,
|
||||||
viewId,
|
onViewFieldsChange,
|
||||||
});
|
views,
|
||||||
|
} = getViewScopedStateValuesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId,
|
||||||
|
viewId,
|
||||||
|
});
|
||||||
|
|
||||||
const { isPersistingViewState } = getViewScopedStatesFromSnapshot({
|
const {
|
||||||
|
isPersistingViewState,
|
||||||
|
currentViewFieldsState,
|
||||||
|
savedViewFieldsState,
|
||||||
|
} = getViewScopedStatesFromSnapshot({
|
||||||
snapshot,
|
snapshot,
|
||||||
viewScopeId,
|
viewScopeId,
|
||||||
viewId,
|
viewId,
|
||||||
@ -58,9 +66,6 @@ export const useViewFields = (viewScopeId: string) => {
|
|||||||
position: viewField.position,
|
position: viewField.position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO: implement optimistic response
|
|
||||||
refetchQueries: [getOperationName(findManyViewsQuery) ?? ''],
|
|
||||||
awaitRefetchQueries: true,
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -83,9 +88,6 @@ export const useViewFields = (viewScopeId: string) => {
|
|||||||
position: viewField.position,
|
position: viewField.position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO: implement optimistic response
|
|
||||||
refetchQueries: [getOperationName(findManyViewsQuery) ?? ''],
|
|
||||||
awaitRefetchQueries: true,
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -113,13 +115,38 @@ export const useViewFields = (viewScopeId: string) => {
|
|||||||
await _updateViewFields(viewFieldsToUpdate);
|
await _updateViewFields(viewFieldsToUpdate);
|
||||||
|
|
||||||
set(isPersistingViewState, false);
|
set(isPersistingViewState, false);
|
||||||
|
set(currentViewFieldsState, viewFieldsToPersist);
|
||||||
|
set(savedViewFieldsState, viewFieldsToPersist);
|
||||||
|
|
||||||
|
const existingView = views.find((view) => view.id === viewIdToPersist);
|
||||||
|
|
||||||
|
if (!existingView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRecordFromCache(viewIdToPersist ?? '', {
|
||||||
|
viewFields: () => ({
|
||||||
|
edges: viewFieldsToPersist.map((viewField) => ({
|
||||||
|
node: viewField,
|
||||||
|
cursor: '',
|
||||||
|
})),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
onViewFieldsChange?.(viewFieldsToPersist);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
viewScopeId,
|
||||||
|
modifyRecordFromCache,
|
||||||
apolloClient,
|
apolloClient,
|
||||||
createOneMutation,
|
createOneMutation,
|
||||||
updateOneMutation,
|
updateOneMutation,
|
||||||
viewScopeId,
|
|
||||||
findManyViewsQuery,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,11 @@ export const useViewFilters = (viewScopeId: string) => {
|
|||||||
useObjectMetadataItem({
|
useObjectMetadataItem({
|
||||||
objectNameSingular: 'viewFilter',
|
objectNameSingular: 'viewFilter',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { modifyRecordFromCache } = useObjectMetadataItem({
|
||||||
|
objectNameSingular: 'view',
|
||||||
|
});
|
||||||
|
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
const { currentViewFiltersState } = useViewScopedStates({
|
const { currentViewFiltersState } = useViewScopedStates({
|
||||||
@ -24,11 +29,15 @@ export const useViewFilters = (viewScopeId: string) => {
|
|||||||
const persistViewFilters = useRecoilCallback(
|
const persistViewFilters = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (viewId?: string) => {
|
async (viewId?: string) => {
|
||||||
const { currentViewId, currentViewFilters, savedViewFiltersByKey } =
|
const {
|
||||||
getViewScopedStateValuesFromSnapshot({
|
currentViewId,
|
||||||
snapshot,
|
currentViewFilters,
|
||||||
viewScopeId,
|
savedViewFiltersByKey,
|
||||||
});
|
views,
|
||||||
|
} = getViewScopedStateValuesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!currentViewId) {
|
if (!currentViewId) {
|
||||||
return;
|
return;
|
||||||
@ -129,11 +138,34 @@ export const useViewFilters = (viewScopeId: string) => {
|
|||||||
}),
|
}),
|
||||||
currentViewFilters,
|
currentViewFilters,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const existingViewId = viewId ?? currentViewId;
|
||||||
|
const existingView = views.find((view) => view.id === existingViewId);
|
||||||
|
|
||||||
|
if (!existingView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRecordFromCache(existingViewId, {
|
||||||
|
viewFilters: () => ({
|
||||||
|
edges: currentViewFilters.map((viewFilter) => ({
|
||||||
|
node: viewFilter,
|
||||||
|
cursor: '',
|
||||||
|
})),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
apolloClient,
|
apolloClient,
|
||||||
createOneMutation,
|
createOneMutation,
|
||||||
deleteOneMutation,
|
deleteOneMutation,
|
||||||
|
modifyRecordFromCache,
|
||||||
updateOneMutation,
|
updateOneMutation,
|
||||||
viewScopeId,
|
viewScopeId,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -15,6 +15,10 @@ export const useViewSorts = (viewScopeId: string) => {
|
|||||||
useObjectMetadataItem({
|
useObjectMetadataItem({
|
||||||
objectNameSingular: 'viewSort',
|
objectNameSingular: 'viewSort',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { modifyRecordFromCache } = useObjectMetadataItem({
|
||||||
|
objectNameSingular: 'view',
|
||||||
|
});
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
const { currentViewSortsState } = useViewScopedStates({
|
const { currentViewSortsState } = useViewScopedStates({
|
||||||
@ -24,7 +28,7 @@ export const useViewSorts = (viewScopeId: string) => {
|
|||||||
const persistViewSorts = useRecoilCallback(
|
const persistViewSorts = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (viewId?: string) => {
|
async (viewId?: string) => {
|
||||||
const { currentViewId, currentViewSorts, savedViewSortsByKey } =
|
const { currentViewId, currentViewSorts, savedViewSortsByKey, views } =
|
||||||
getViewScopedStateValuesFromSnapshot({
|
getViewScopedStateValuesFromSnapshot({
|
||||||
snapshot,
|
snapshot,
|
||||||
viewScopeId,
|
viewScopeId,
|
||||||
@ -122,11 +126,33 @@ export const useViewSorts = (viewScopeId: string) => {
|
|||||||
}),
|
}),
|
||||||
currentViewSorts,
|
currentViewSorts,
|
||||||
);
|
);
|
||||||
|
const existingViewId = viewId ?? currentViewId;
|
||||||
|
const existingView = views.find((view) => view.id === existingViewId);
|
||||||
|
|
||||||
|
if (!existingView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRecordFromCache(existingViewId, {
|
||||||
|
viewSorts: () => ({
|
||||||
|
edges: currentViewSorts.map((viewSort) => ({
|
||||||
|
node: viewSort,
|
||||||
|
cursor: '',
|
||||||
|
})),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
apolloClient,
|
apolloClient,
|
||||||
createOneMutation,
|
createOneMutation,
|
||||||
deleteOneMutation,
|
deleteOneMutation,
|
||||||
|
modifyRecordFromCache,
|
||||||
updateOneMutation,
|
updateOneMutation,
|
||||||
viewScopeId,
|
viewScopeId,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useApolloClient } from '@apollo/client';
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { View } from '@/views/types/View';
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot';
|
import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot';
|
||||||
|
|
||||||
export const useViews = (scopeId: string) => {
|
export const useViews = (scopeId: string) => {
|
||||||
@ -18,7 +18,7 @@ export const useViews = (scopeId: string) => {
|
|||||||
|
|
||||||
const createView = useRecoilCallback(
|
const createView = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
async (view: Pick<View, 'id' | 'name'>) => {
|
async (view: Pick<GraphQLView, 'id' | 'name'>) => {
|
||||||
const { viewObjectMetadataId, viewType } =
|
const { viewObjectMetadataId, viewType } =
|
||||||
getViewScopedStateValuesFromSnapshot({
|
getViewScopedStateValuesFromSnapshot({
|
||||||
snapshot,
|
snapshot,
|
||||||
@ -32,7 +32,8 @@ export const useViews = (scopeId: string) => {
|
|||||||
mutation: createOneMutation,
|
mutation: createOneMutation,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
...view,
|
id: view.id,
|
||||||
|
name: view.name,
|
||||||
objectMetadataId: viewObjectMetadataId,
|
objectMetadataId: viewObjectMetadataId,
|
||||||
type: viewType,
|
type: viewType,
|
||||||
},
|
},
|
||||||
@ -43,13 +44,14 @@ export const useViews = (scopeId: string) => {
|
|||||||
[scopeId, apolloClient, createOneMutation, findManyQuery],
|
[scopeId, apolloClient, createOneMutation, findManyQuery],
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateView = async (view: View) => {
|
const updateView = async (view: GraphQLView) => {
|
||||||
await apolloClient.mutate({
|
await apolloClient.mutate({
|
||||||
mutation: updateOneMutation,
|
mutation: updateOneMutation,
|
||||||
variables: {
|
variables: {
|
||||||
idToUpdate: view.id,
|
idToUpdate: view.id,
|
||||||
input: {
|
input: {
|
||||||
...view,
|
id: view.id,
|
||||||
|
name: view.name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: [findManyQuery],
|
refetchQueries: [findManyQuery],
|
||||||
|
|||||||
@ -3,7 +3,13 @@ import { useSearchParams } from 'react-router-dom';
|
|||||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults';
|
||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
|
import { ViewField } from '@/views/types/ViewField';
|
||||||
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
|
import { ViewSort } from '@/views/types/ViewSort';
|
||||||
|
import { assertNotNull } from '~/utils/assert';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
|
import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
|
||||||
import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
|
import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
|
||||||
@ -85,29 +91,174 @@ export const useView = (props?: UseViewProps) => {
|
|||||||
[setSearchParams],
|
[setSearchParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const loadViewFields = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (
|
||||||
|
data: PaginatedObjectTypeResults<ViewField>,
|
||||||
|
currentViewId: string,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
availableFieldDefinitions,
|
||||||
|
onViewFieldsChange,
|
||||||
|
savedViewFields,
|
||||||
|
isPersistingView,
|
||||||
|
} = getViewScopedStateValuesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { savedViewFieldsState, currentViewFieldsState } =
|
||||||
|
getViewScopedStatesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!availableFieldDefinitions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queriedViewFields = data.edges
|
||||||
|
.map((viewField) => viewField.node)
|
||||||
|
.filter(assertNotNull);
|
||||||
|
|
||||||
|
if (isPersistingView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
|
||||||
|
set(currentViewFieldsState, queriedViewFields);
|
||||||
|
set(savedViewFieldsState, queriedViewFields);
|
||||||
|
onViewFieldsChange?.(queriedViewFields);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[scopeId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const loadViewFilters = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (
|
||||||
|
data: PaginatedObjectTypeResults<Required<ViewFilter>>,
|
||||||
|
currentViewId: string,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
availableFilterDefinitions,
|
||||||
|
savedViewFilters,
|
||||||
|
onViewFiltersChange,
|
||||||
|
} = getViewScopedStateValuesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { savedViewFiltersState, currentViewFiltersState } =
|
||||||
|
getViewScopedStatesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!availableFilterDefinitions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queriedViewFilters = data.edges
|
||||||
|
.map(({ node }) => {
|
||||||
|
const availableFilterDefinition = availableFilterDefinitions.find(
|
||||||
|
(filterDefinition) =>
|
||||||
|
filterDefinition.fieldMetadataId === node.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!availableFilterDefinition) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
displayValue: node.displayValue ?? node.value,
|
||||||
|
definition: availableFilterDefinition,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(assertNotNull);
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
|
||||||
|
set(savedViewFiltersState, queriedViewFilters);
|
||||||
|
set(currentViewFiltersState, queriedViewFilters);
|
||||||
|
}
|
||||||
|
onViewFiltersChange?.(queriedViewFilters);
|
||||||
|
},
|
||||||
|
[scopeId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const loadViewSorts = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (
|
||||||
|
data: PaginatedObjectTypeResults<Required<ViewSort>>,
|
||||||
|
currentViewId: string,
|
||||||
|
) => {
|
||||||
|
const { availableSortDefinitions, savedViewSorts, onViewSortsChange } =
|
||||||
|
getViewScopedStateValuesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { savedViewSortsState, currentViewSortsState } =
|
||||||
|
getViewScopedStatesFromSnapshot({
|
||||||
|
snapshot,
|
||||||
|
viewScopeId: scopeId,
|
||||||
|
viewId: currentViewId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!availableSortDefinitions || !currentViewId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queriedViewSorts = data.edges
|
||||||
|
.map(({ node }) => {
|
||||||
|
const availableSortDefinition = availableSortDefinitions.find(
|
||||||
|
(sort) => sort.fieldMetadataId === node.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!availableSortDefinition) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: node.id,
|
||||||
|
fieldMetadataId: node.fieldMetadataId,
|
||||||
|
direction: node.direction,
|
||||||
|
definition: availableSortDefinition,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(assertNotNull);
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
|
||||||
|
set(savedViewSortsState, queriedViewSorts);
|
||||||
|
set(currentViewSortsState, queriedViewSorts);
|
||||||
|
}
|
||||||
|
onViewSortsChange?.(queriedViewSorts);
|
||||||
|
},
|
||||||
|
[scopeId],
|
||||||
|
);
|
||||||
|
|
||||||
const loadView = useRecoilCallback(
|
const loadView = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(viewId: string) => {
|
(viewId: string) => {
|
||||||
setCurrentViewId?.(viewId);
|
setCurrentViewId?.(viewId);
|
||||||
|
|
||||||
const {
|
const { currentView } = getViewScopedStateValuesFromSnapshot({
|
||||||
currentViewFields,
|
|
||||||
onViewFieldsChange,
|
|
||||||
currentViewFilters,
|
|
||||||
onViewFiltersChange,
|
|
||||||
currentViewSorts,
|
|
||||||
onViewSortsChange,
|
|
||||||
} = getViewScopedStateValuesFromSnapshot({
|
|
||||||
snapshot,
|
snapshot,
|
||||||
viewScopeId: scopeId,
|
viewScopeId: scopeId,
|
||||||
viewId,
|
viewId,
|
||||||
});
|
});
|
||||||
|
|
||||||
onViewFieldsChange?.(currentViewFields);
|
if (!currentView) {
|
||||||
onViewFiltersChange?.(currentViewFilters);
|
return;
|
||||||
onViewSortsChange?.(currentViewSorts);
|
}
|
||||||
|
|
||||||
|
loadViewFields(currentView.viewFields, viewId);
|
||||||
|
loadViewFilters(currentView.viewFilters, viewId);
|
||||||
|
loadViewSorts(currentView.viewSorts, viewId);
|
||||||
},
|
},
|
||||||
[setCurrentViewId, scopeId],
|
[setCurrentViewId, scopeId, loadViewFields, loadViewFilters, loadViewSorts],
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetViewBar = useRecoilCallback(
|
const resetViewBar = useRecoilCallback(
|
||||||
@ -246,12 +397,12 @@ export const useView = (props?: UseViewProps) => {
|
|||||||
|
|
||||||
if (viewEditMode === 'create' && name) {
|
if (viewEditMode === 'create' && name) {
|
||||||
await createView(name);
|
await createView(name);
|
||||||
} else {
|
|
||||||
await internalUpdateView({
|
|
||||||
...currentView,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await internalUpdateView({
|
||||||
|
...currentView,
|
||||||
|
name,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[createView, internalUpdateView, scopeId],
|
[createView, internalUpdateView, scopeId],
|
||||||
);
|
);
|
||||||
@ -284,5 +435,8 @@ export const useView = (props?: UseViewProps) => {
|
|||||||
persistViewFields,
|
persistViewFields,
|
||||||
changeViewInUrl,
|
changeViewInUrl,
|
||||||
loadView,
|
loadView,
|
||||||
|
loadViewFields,
|
||||||
|
loadViewFilters,
|
||||||
|
loadViewSorts,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,23 +1,21 @@
|
|||||||
import { createScopedSelector } from '@/ui/utilities/recoil-scope/utils/createScopedSelector';
|
import { createScopedSelector } from '@/ui/utilities/recoil-scope/utils/createScopedSelector';
|
||||||
import { View } from '@/views/types/View';
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
|
|
||||||
import { currentViewIdScopedState } from '../currentViewIdScopedState';
|
import { currentViewIdScopedState } from '../currentViewIdScopedState';
|
||||||
|
|
||||||
import { viewsByIdScopedSelector } from './viewsByIdScopedSelector';
|
import { viewsByIdScopedSelector } from './viewsByIdScopedSelector';
|
||||||
|
|
||||||
export const currentViewScopedSelector = createScopedSelector<View | undefined>(
|
export const currentViewScopedSelector = createScopedSelector<
|
||||||
{
|
GraphQLView | undefined
|
||||||
key: 'currentViewScopedSelector',
|
>({
|
||||||
get:
|
key: 'currentViewScopedSelector',
|
||||||
({ scopeId }: { scopeId: string }) =>
|
get:
|
||||||
({ get }) => {
|
({ scopeId }: { scopeId: string }) =>
|
||||||
const currentViewId = get(
|
({ get }) => {
|
||||||
currentViewIdScopedState({ scopeId: scopeId }),
|
const currentViewId = get(currentViewIdScopedState({ scopeId: scopeId }));
|
||||||
);
|
|
||||||
|
|
||||||
return currentViewId
|
return currentViewId
|
||||||
? get(viewsByIdScopedSelector(scopeId))[currentViewId]
|
? get(viewsByIdScopedSelector(scopeId))[currentViewId]
|
||||||
: undefined;
|
: undefined;
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
import { selectorFamily } from 'recoil';
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
import { View } from '@/views/types/View';
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
|
|
||||||
import { viewsScopedState } from '../viewsScopedState';
|
import { viewsScopedState } from '../viewsScopedState';
|
||||||
|
|
||||||
export const viewsByIdScopedSelector = selectorFamily<
|
export const viewsByIdScopedSelector = selectorFamily<
|
||||||
Record<string, View>,
|
Record<string, GraphQLView>,
|
||||||
string
|
string
|
||||||
>({
|
>({
|
||||||
key: 'viewsByIdScopedSelector',
|
key: 'viewsByIdScopedSelector',
|
||||||
get:
|
get:
|
||||||
(scopeId) =>
|
(scopeId) =>
|
||||||
({ get }) =>
|
({ get }) =>
|
||||||
get(viewsScopedState({ scopeId: scopeId })).reduce<Record<string, View>>(
|
get(viewsScopedState({ scopeId: scopeId })).reduce<
|
||||||
(result, view) => ({ ...result, [view.id]: view }),
|
Record<string, GraphQLView>
|
||||||
{},
|
>((result, view) => ({ ...result, [view.id]: view }), {}),
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||||
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
|
|
||||||
import { View } from '../types/View';
|
export const viewsScopedState = createScopedState<GraphQLView[]>({
|
||||||
|
|
||||||
export const viewsScopedState = createScopedState<View[]>({
|
|
||||||
key: 'viewsScopedState',
|
key: 'viewsScopedState',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user