Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify last visited #10259

Merged
merged 8 commits into from
Feb 17, 2025
Merged

Simplify last visited #10259

merged 8 commits into from
Feb 17, 2025

Conversation

charlesBochet
Copy link
Member

@charlesBochet charlesBochet commented Feb 17, 2025

In this PR, I'm simplifying the lastVisitedView / Object logic:

  • removing fallback logic as it's not useful
  • splitting hooks into smaller hooks (to avoir re-renders)
  • removing componentState on those states that are global

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR significantly simplifies the navigation state management system by removing and consolidating last visited functionality.

  • Removes useLastVisitedObjectMetadataItem hook and related selectors, replacing with simpler useSetLastVisitedObjectMetadataId hook
  • Simplifies useLastVisitedView to only provide getter functionality, removing workspace-specific state management
  • Changes state management from createComponentState to createState in lastVisitedObjectMetadataItemIdState.ts, modifying type from Record<string, string> to string | null
  • Introduces potential issue in useSetLastVisitedViewForObjectMetadataNamePlural using incorrect state for view tracking
  • Removes accidental debug console.log in RecordIndexContainer.tsx

16 file(s) reviewed, 5 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines 20 to 23
console.log(
'mainContextStoreComponentInstanceIdToSet',
mainContextStoreComponentInstanceIdToSet,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: console.log statement should be removed before merging to production

Suggested change
console.log(
'mainContextStoreComponentInstanceIdToSet',
mainContextStoreComponentInstanceIdToSet,
);

Comment on lines 25 to 27
const lastVisitedViewPerObjectMetadataItem = snapshot
.getLoadable(lastVisitedObjectMetadataItemIdState)
.getValue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: incorrect state usage - lastVisitedObjectMetadataItemIdState should contain IDs, not views. Should use lastVisitedViewPerObjectMetadataItemState instead to get the last visited view

Suggested change
const lastVisitedViewPerObjectMetadataItem = snapshot
.getLoadable(lastVisitedObjectMetadataItemIdState)
.getValue();
const lastVisitedViewPerObjectMetadataItem = snapshot
.getLoadable(lastVisitedViewPerObjectMetadataItemState)
.getValue();

Comment on lines 33 to 35
set(lastVisitedViewPerObjectMetadataItemState, {
[objectMetadataItem.id]: viewId,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: this overwrites the entire state object instead of merging with existing entries. Should spread existing state: set(lastVisitedViewPerObjectMetadataItemState, (prev) => ({ ...prev, [objectMetadataItem.id]: viewId }))

Suggested change
set(lastVisitedViewPerObjectMetadataItemState, {
[objectMetadataItem.id]: viewId,
});
set(lastVisitedViewPerObjectMetadataItemState, (prev) => ({
...prev,
[objectMetadataItem.id]: viewId,
}));

@@ -187,6 +187,8 @@ export const RecordIndexContainer = () => {
FeatureFlagKey.IsCommandMenuV2Enabled,
);

console.log(columnDefinitions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Remove debug console.log statement before merging to production

Suggested change
console.log(columnDefinitions);

@@ -143,19 +131,6 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {

formConfig.reset(undefined, { keepValues: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: reset is called before navigation, could lead to state inconsistency if navigation fails

import { isDefined } from 'twenty-shared';

export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
const { records: views, findManyRecords } = useLazyPrefetchedData<View>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

introducing this hook but I think we should use a state and stop reading from apollo cache here

@prastoin
Copy link
Contributor

prastoin commented Feb 17, 2025

@greptileai trigger

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

(updates since last review)

This PR continues to refine the navigation state management system with additional changes focused on view handling and prefetching. Here are the key new changes:

  • Added new useLazyPrefetchedData hook in prefetch/hooks/useLazyPrefetchData.ts for optimized data loading with operation signature factory support
  • Modified MainContextStoreProvider to include robust view fallback logic using indexView when no view ID is available
  • Removed redundant state checks and optional chaining in useSetLastVisitedViewForObjectMetadataNamePlural hook
  • Simplified SettingsObjectSummaryCard by removing useLastVisitedView hook and its fallback logic
  • Fixed state update in useSetLastVisitedViewForObjectMetadataNamePlural where it overwrites entire state instead of merging entries

7 file(s) reviewed, 4 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines 53 to 57
const navigationPath = getAppPath(
AppPath.RecordIndexPage,
{ objectNamePlural: objectMetadataItem.namePlural },
viewId ? { viewId } : undefined,
lastVisitedViewId ? { viewId: lastVisitedViewId } : undefined,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: navigationPath now uses lastVisitedViewId while active states use contextStoreCurrentViewId, which could cause inconsistent UI state

Comment on lines +59 to +62
setLastVisitedViewForObjectMetadataNamePlural({
objectNamePlural: objectMetadataItem.namePlural,
viewId: viewId,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: setLastVisitedViewForObjectMetadataNamePlural is called unconditionally on every effect run. Consider adding a condition to only update when values change.

Comment on lines +64 to +66
setLastVisitedObjectMetadataId({
objectMetadataItemId: objectMetadataItem.id,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: setLastVisitedObjectMetadataId is called unconditionally on every effect run. Consider adding a condition to only update when the ID changes.

Comment on lines +19 to +20
const recordGqlFields =
operationSignatureFactory({ objectMetadataItem }).fields ?? filter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The nullish coalescing operator here could be problematic if operationSignatureFactory().fields is an empty object - it would not fall back to the filter. Consider checking for empty object as well.

@prastoin prastoin self-requested a review February 17, 2025 14:55
Copy link
Contributor

@prastoin prastoin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactor ! Only nitpicks

isNavigationDrawerExpandedState,
);
const [, setCurrentMobileNavigationDrawer] = useRecoilState(
const setCurrentMobileNavigationDrawer = useSetRecoilState(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise: Nice

}) => {
await findManyRecords();

const view = views.find((view: View) => view.id === viewId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Redundant arg typing

lastVisitedViewPerObjectMetadataItem?.[objectMetadataItem?.id];

if (isDefined(objectMetadataItem) && lastVisitedViewId !== viewId) {
set(lastVisitedViewPerObjectMetadataItemState, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Could avoid making findManyRecords each run

Comment on lines +34 to 41
const mainContextStoreComponentInstanceId = useRecoilValue(
mainContextStoreComponentInstanceIdState,
);

const lastVisitedViewId = getLastVisitedViewIdFromObjectMetadataItemId(
objectMetadataItem.id,
const contextStoreCurrentViewId = useRecoilComponentValueV2(
contextStoreCurrentViewIdComponentState,
mainContextStoreComponentInstanceId,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Could be unused ?

const { filterableFieldMetadataItems } =
useFilterableFieldMetadataItemsInRecordIndexContext();
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
objectMetadataItem?.id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: We should not use any on the following fields

export type Scalars = {
  ID: { input: string; output: string; }
  String: { input: string; output: string; }
  Boolean: { input: boolean; output: boolean; }
  Int: { input: number; output: number; }
  Float: { input: number; output: number; }
  /** Cursor for paging through collections */
  ConnectionCursor: { input: any; output: any; }
  /** A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. */
  DateTime: { input: any; output: any; }
  /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
  JSON: { input: any; output: any; }
  /** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
  JSONObject: { input: any; output: any; }
  /** A UUID scalar type */
  UUID: { input: unknown; output: unknown; }
  /** The `Upload` scalar type represents a file upload. */
  Upload: { input: any; output: any; }
};

Using unknown on UUID shows possible runtime error here 431 tsc-errors
About to create an issue to address this

@charlesBochet charlesBochet merged commit 5b4cb4b into main Feb 17, 2025
47 checks passed
@charlesBochet charlesBochet deleted the simplify-last-visited branch February 17, 2025 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants