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

Austenem/CAT-754 Refactor "My Lists" #3671

Open
wants to merge 54 commits into
base: main
Choose a base branch
from

Conversation

austenem
Copy link
Collaborator

@austenem austenem commented Jan 22, 2025

Summary

Broad update to the "My Lists" feature across the portal that leverages the new UKV API.

Major updates include:

  • Lists are now tied to a user's profile.
    • Lists will now persist across devices (previously, these were stored locally).
    • As a result, lists will be restricted to authenticated users going forward.
  • "Save to list" buttons are now present on all search pages, dataset tables, and processed dataset sections.
  • Language on all "My Lists" pages and alerts have been updated.
  • All associated files have been converted to TypeScript.

Design Documentation/Original Tickets

CAT-754 Jira ticket

Testing

Tested using the following checklist:

  • When logging in for the first time on a device with saved entities and lists, these are copied over.
  • Create new list with title and/or description
  • Save entities
    • From search pages
    • From entity header of detail pages
    • From processed dataset summary section of dataset detail pages
    • From derived entities tables
    • From Collections dataset tables
  • Delete entities
  • Add entities to list
    • From lists page
    • From entity header of detail pages
    • From processed dataset summary section of dataset detail pages
  • Remove entities from list
    • From list detail page
    • From entity header of detail pages
    • From processed dataset summary section of dataset detail pages
  • View list detail page without entities
  • View list detail page with entities
  • Edit list title/description
  • Delete list

Screenshots/Video

Updated Search page
Screenshot 2025-01-21 at 6 11 22 PM

Updated Collections dataset table
Screenshot 2025-01-22 at 12 41 41 PM

Updated "My Lists" page for logged-out users
Screenshot 2025-01-28 at 5 23 52 PM

Example of banner shown after transfer of local lists to a user's profile
Screenshot 2025-01-28 at 12 40 19 PM

Checklist

  • Code follows the project's coding standards
    • Lint checks pass locally
    • New CHANGELOG-your-feature-name-here.md is present in the root directory, describing the change(s) in full sentences.
  • Unit tests covering the new feature have been added
  • All existing tests pass
  • Any relevant documentation in JIRA/Confluence has been updated to reflect the new feature
  • Any new functionalities have appropriate analytics functionalities added

Copy link
Collaborator

@john-conroy john-conroy left a comment

Choose a reason for hiding this comment

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

I'm a little confused why we are continuing to use a store for the saved lists/entities. Maybe it would be helpful to have a chat between the three of us?

context/app/static/js/components/savedLists/api.ts Outdated Show resolved Hide resolved
context/app/static/js/components/savedLists/hooks.ts Outdated Show resolved Hide resolved
context/app/static/js/components/savedLists/hooks.ts Outdated Show resolved Hide resolved
context/app/static/js/components/savedLists/hooks.ts Outdated Show resolved Hide resolved
context/app/static/js/components/savedLists/hooks.ts Outdated Show resolved Hide resolved
context/app/static/js/components/savedLists/hooks.ts Outdated Show resolved Hide resolved
@austenem austenem requested a review from john-conroy January 28, 2025 22:56
Copy link
Collaborator

@john-conroy john-conroy left a comment

Choose a reason for hiding this comment

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

Wow, a lot of changes here! I still need to check this out locally.

Comment on lines +121 to +123
description: propDescription,
creationLabel: propCreationLabel,
creationDate: propCreationDate,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why rename the variables with prop*?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This was to avoid naming the final description/creation info variables in the function body like checkedDescription - this way they get to keep their intended names (description, etc) and there's a clear distinction between these and the optional prop variables.

function useSavedEntityData(savedEntities: SavedEntities, source: string[]) {
const query = useMemo(
() => ({
query: getIDsQuery(Object.keys(savedEntities)),
_source: source,
size: Object.keys(savedEntities).length,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would either bump this to 10000 when we are returning a source or set it to 0 for purely aggregations queries.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Got it - is this just a performance concern?

404: listUUID ? `No list with UUID ${listUUID} found.` : 'No lists for the current user were found.',
},
}),
{ revalidateOnFocus: hasAccess, refreshInterval: 1000 * 60 },
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to refresh this on an interval or only once the user has performed some action which might affect what's returned?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The refresh interval isn't needed - just removed. This was based on the workspaces fetcher function.

Comment on lines +11 to +24
function sortEntities(searchHits: Required<SearchHit<Entity>>[], savedEntities: SavedEntities) {
if (!searchHits) return [];

return [...searchHits].sort((a, b) => {
const entityA: SavedEntity = savedEntities[a._id] ?? { dateSaved: 0 };
const entityB: SavedEntity = savedEntities[b._id] ?? { dateSaved: 0 };

const dateA = entityA.dateSaved ?? 0;
const dateB = entityB.dateSaved ?? 0;

return dateB - dateA;
});
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we apply sort to the ES query?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't know of a good way to do this in the query (apart from maybe passing in a custom comparator function for the sort) - the dateSaved property is only accessible by looking up the UUID in the savedEntities object, and not from any info returned by ES. What would you recommend?

Copy link
Collaborator

@NickAkhmetov NickAkhmetov left a comment

Choose a reason for hiding this comment

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

Great improvements! I will also need to test this locally 😄

Comment on lines 48 to 50
handleSaveEntities({ entityUUIDs: uuids }).catch((error) => {
console.error(error);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be helpful to track errored attempts to save as well? @tsliaw

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've put together a list of lists-related events to track that Tiffany and I will go over together - that will be a separate PR (CAT-1113). I don't believe based on the event tracking doc that we are currently tracking errors for most events, but that's definitely an option to consider.

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't typically track error states, so I don't see the need to track this one unless we expect this error to occur often.

Comment on lines 36 to 42
let tooltip = '';

if (disabled) {
tooltip = allInSavedEntities ? `All ${entityLabel} are already saved.` : `Select ${entityTypes} to save.`;
} else {
tooltip = `Save ${entityLabel}.`;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we can pull this out into a helper function instead to keep things more readable? e.g.

// Outside of the component
function createTooltip(entityLabel: string, allInSavedEntities: boolean, disabled: boolean) {
  if (disabled) {
		return `Save ${entityLabel}.`
	}
	if (allInSavedEntities) {
		return `All ${entityLabel} are already saved.`
	}
	return `Select ${entityLabel}s to save.`
}

...

// Back inside the component
const tooltip = createTooltip(entityLabel, allInSavedEntities, disabled)

That would also let us add some unit tests if need be.

Comment on lines 46 to 51
onClick={() => {
trackSave({ action: 'Save To List', label: generateCommaList(Array.from(uuids)) });
handleSaveEntities({ entityUUIDs: uuids }).catch((error) => {
console.error(error);
});
}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

In my experience, useCallback is necessary whenever passing event handler functions down, since it breaks memoization otherwise.

We could also use useEventCallback from MUI (https://usehooks-ts.com/react-hook/use-event-callback - same hook, different library) which was designed to be easier to use than useCallback and address issues like facebook/react#14099.

@john-conroy
Copy link
Collaborator

@austenem can you merge main into this branch so the virtualenvs are aligned between the branches?

@austenem austenem requested a review from john-conroy February 4, 2025 21:44
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.

4 participants