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

[Refactor] Establish Pattern and Remove Routing Dependencies #1108

Closed
sandrahoang686 opened this issue Aug 16, 2024 · 8 comments
Closed

[Refactor] Establish Pattern and Remove Routing Dependencies #1108

sandrahoang686 opened this issue Aug 16, 2024 · 8 comments
Assignees
Labels
tech debt veda v2 VEDA Refactor Epic Work

Comments

@sandrahoang686
Copy link
Collaborator

sandrahoang686 commented Aug 16, 2024

We need to decouple react-router and navigation dependencies within our veda-ui components. This is because routing is not controlled at the instance level and react-router does not work for nextJs.

Components shouldn't manage any of the routing and should just return the selected filters in which the passed in callback from the instance side should handle the routing.

  • should we do it by core feature..?
@sandrahoang686 sandrahoang686 changed the title [VEDA2 Refactor] Establish Pattern and Remove Routing Dependencies from Data Catalog Feature [VEDA2 Refactor] Establish Pattern and Remove Routing Dependencies Aug 16, 2024
@hanbyul-here
Copy link
Collaborator

From Data Catalog implementation try, we could find the routing problems that need to be handled.

Base finding: react-router-dom component doesn't work with Next instance, and Next has its own Link component.

  1. <NavLink> of react-router-dom embedded in source code
    One of the possible solutions is to Pass Link Components from Consumer level

  2. Components using react-router for their behaviors (ex. sticky header using useLocation of react-router-dom to detect page transition )
    We should first identify these components and approach them holistically. ex. Do we need this behavior when it is not used in SPA environment?

  3. Query parameter manager needing react-router-dom (useQSState hook requires navigate from react-router-dom's useNavigate as a parameter)
    One of the possible solutions is to make this as a prop

  4. Make sure the link works with routings defined on the instance level. (ex. does dataset catalog card work with different DATACATALOG_PATH ?)

@aboydnw aboydnw added the veda v2 VEDA Refactor Epic Work label Aug 29, 2024
@sandrahoang686
Copy link
Collaborator Author

Update: This has been kindof been worked on when during breakout components by having the Link Component pass down as a prop. But there are some hacks in there that need to be clean up and we should relook at how we are doing this to see if it is the most optimal and clean...

Going to think about what we should do with this ticket...

@sandrahoang686 sandrahoang686 changed the title [VEDA2 Refactor] Establish Pattern and Remove Routing Dependencies [Refactor] Establish Pattern and Remove Routing Dependencies Oct 15, 2024
vgeorge added a commit that referenced this issue Nov 25, 2024
**Related Ticket:** Contributes to #1108

This aims to ensure catalog filters work correctly in Next.js.

### Description of Changes

Removes the usage of React Router's `useNavigate` hook in the library to
make it more agnostic of routing frameworks, allowing it to work better
with Next.js instances.

Changes included:

- Added a custom `commit` function to `useQsStateCreator`. It appears
this was the only place where the `useNavigate` function was effectively
in use. I tried using the default `commit` function from the
[qs-state-hook](https://github.com/danielfdsilva/qs-state-hook) library,
but it doesn't work with Next.js
- Formatted the touched files

### Validation / Testing

Using `veda-config`:

1. Visit the data catalog page
2. Click on filters, and URL params are updated as usual
3. Reload the page with filters selected; the filter panel is populated
as expected
4. Repeat the steps on the Exploration and Stories pages

Using `next-veda-ui` instance:

1. Link the source of this PR to the Next.js instance using the
instructions in `veda-ui/docs/development/REGISTRY.md`
2. Replace the file `app/(datasets)/data-catalog/catalog.tsx` (this
avoids build errors caused by type issues)

```js
'use client';
import React from 'react';
import { CatalogView, useFiltersWithQS } from '@lib';
import { usePathname } from 'next/navigation';
import Link from 'next/link';

export default function Catalog({ datasets }: { datasets: any }) {
  const pathname = usePathname();
  const controlVars = useFiltersWithQS();

  return (
    <CatalogView
      datasets={datasets}
      onFilterChanges={() => controlVars}
      pathname={pathname}
      linkProperties={{
        LinkElement: Link,
        pathAttributeKeyName: 'href',
      }}
    />
  );
}
```

3. Access `http://localhost:3000/data-catalog`. Filter changes are
reflected in the URL, and reloading populates the filter panel as
expected

This is ready for review.
@sandrahoang686
Copy link
Collaborator Author

sandrahoang686 commented Nov 26, 2024

@vgeorge some ideas we discussed beforehand were possibly creating a context provider similar to what was created for environment variables. Gjore's PR here. This would reduce the copious amounts of prop drilling we currently do with LinkProperties. But I think to tackle this more holistically and i'm unsure how much of a huge lift this is or if it should be done iteratively - I was thinking it probably makes more sense to remove all routing and navigation logic out from our components. It would be ideal to extract all this logic out into a callback fn which is then provided to the component. For current architecture, the callback would be passed from our high level container components (example E&A container) and then for refactor, we'd pass these callbacks from the instance which should manage routing.

My two cents on what I've seen best patterns wise but again we probably want to take time and effort into consideration. cc @dzole0311

vgeorge added a commit that referenced this issue Nov 28, 2024
…pendency from the Catalog (#1276)

**Related Ticket:** Contributes to
#1108

### Description of Changes

- Remove `react-router` dependency from the Catalog components
- Introduce custom `usePathname` hook
- Remove prop drilling of pathname from the Catalog

### Notes & Questions About Changes

The `pathname` prop is passed down for two things:

1. Generating a link to the dataset at
https://github.com/NASA-IMPACT/veda-ui/blob/820730fd7c1e25e68997b200d31bc4ee27525f7e/app/scripts/components/common/catalog/catalog-card.tsx#L126
2. Controlling scroll in the filters control at
https://github.com/NASA-IMPACT/veda-ui/blob/820730fd7c1e25e68997b200d31bc4ee27525f7e/app/scripts/components/common/catalog/filters-control.tsx#L57

I suspect that the usage on item 1 was intented to cover the use case of
an instance running on a subpath (e.g. `https://myinstance.org/veda`),
why is hard to replicate locally but this change shouldn't affect that.

### Validation / Testing

Using `veda-config`:

1. Visit the data catalog page
1. Clicking on cards should open the proper URL (same as before)
1. Visit Explorer page, clicking on cards selected them, instead of
visiting an URL (same as before)

Using `next-veda-ui` instance:

1. Link the source of this PR to the Next.js instance 
1. Visit the catalog page
1. Clicking on cards should open the proper URL  (same as before)
1. Visit Explorer page, clicking on cards selected them, instead of
visiting an URL (same as before)

This is ready for review.
@vgeorge
Copy link
Contributor

vgeorge commented Nov 28, 2024

I will have limited availability in the next few weeks and wanted to provide a status update in case someone else has time to tackle the remaining work.

In #1270 and #1276, we reduced the dependency on React Router. I believe the next steps are:

  1. Remove usage of the useLocation hook:
    This should be straightforward since most occurrences involve reading location.pathname. These can be replaced with the new custom usePathname hook.

  2. Refactor usage of linkProperties:
    I suggest focusing on making the components independent of routing and navigation logic, as proposed by @sandrahoang686. Adding a context provider might complicate usage in Next.js, so I'd avoid it.

    I'd recommend addressing this interactively at the leaf component level to prevent unintended breaks in different parts of the app. For example, the Catalog Card is a good starting point. We could introduce an href prop that, when provided, makes the card act as a link and ignores onClick events. We would still need a Link element to support both Next.js and SPAs. Below is a sample implementation of a CustomLink component:

   import React from 'react';

  // try loading dependencies during build time
   let NextLink: any;
   try {
     NextLink = require('next/link').default;
   } catch (e) {
     NextLink = null;
   }

   let ReactRouterLink: any;
   try {
     ReactRouterLink = require('react-router-dom').Link;
   } catch (e) {
     ReactRouterLink = null;
   }

   interface CustomLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
     to?: string;
     href?: string;
     children: React.ReactNode;
   }

   export const CustomLink = ({ to, href, children, ...props }: CustomLinkProps) => {
     const path = to || href;

     if (NextLink) {
       return (
         <NextLink href={path} {...props}>
           {children}
         </NextLink>
       );
     }

     if (ReactRouterLink) {
       return (
         <ReactRouterLink to={path} {...props}>
           {children}
         </ReactRouterLink>
       );
     }

     // Fallback to a regular anchor tag if no routing library is available
     return (
       <a href={path} {...props}>
         {children}
       </a>
     );
   };

@sandrahoang686
Copy link
Collaborator Author

@vgeorge wrong "Sandra" tagged 😄

@sandrahoang686
Copy link
Collaborator Author

sandrahoang686 commented Dec 9, 2024

Thanks for the input & thoughts @vgeorge 🙇‍♀ . I'm thinking if we are going to tackle the issue with routing coupled up with the components we should probably fully tackle it since this ticket was meant for that. I'm thinking the proposed solution above might still be some sort of bandage as it still worries about "how to navigate" in our veda-ui components when it'd be ideal to totally move away from that. But I agree with starting with the card component to iterate on removing routing entirely from our library. Another thing is, we are using Next in our template instance but ideally we dont want the veda-ui library to care or know - if someone wanted to use our library with Gatsby, they should be able too (I think gatsby works with react-router-dom though but has its own preferred routing mechanism). Thinking that creating some type custom routing controller component that handles based on framework isn't too scalable and is hence more bandagey?? I'll experiment with a first pass at removing routing in one of our components to see how that goes and we could bounce off ideas from that PR :)

PR experimentation here: https://github.com/NASA-IMPACT/veda-ui/pull/1310/files

@sandrahoang686
Copy link
Collaborator Author

sandrahoang686 commented Dec 16, 2024

This will be done in iterations as we work to remove components in veda-ui from being tightly integrated to routing/nav.
This can close after PR #1310 is merged.

Follow up tickets have been created here...

sandrahoang686 added a commit that referenced this issue Dec 17, 2024
**Related Ticket:** #1108
**Related PR:** developmentseed/next-veda-ui#25

 **v5.11.3-alpha.0** published from this branch

### Description of Changes
As part of the greater holistic approach - I think its best to move away
from having our library components tightly integrated w/ routing. This
is the first iteration to remove **linkProperties**. This PR only
worries about removing **linkProps** the **DataCatalog Component**.
DataCatalog view no longer has to pass in linkProperties or have to
directly worry about routing, we can just pass in a callback now that
decides what to do during some action.

This is an iterative approach, i've created tickets to remove routing
from the other core components. But we can't remove routing directly
from the Card component itself easily as GHG uses the card component
directly
[here](https://github.com/US-GHG-Center/veda-config-ghg/blob/dfe611f27f910bc6428a2b13fe50678710511e68/custom-pages/news-and-events/component.tsx#L5).
So that should be its own separate ticket BUT... we are to be redoing
the card component for the new instances - where its probably best to
rewrite it. As currently its not in an ideal place to scale... so i'll
create a placeholder ticket for card component for now but we can
probably tackle removing routing when rewriting the card component.

cc @vgeorge @hanbyul-here @dzole0311 

Follow-up tickets created: 
* #1325
* #1326
* #1327

### Notes & Questions About Changes
_{Add additonal notes and outstanding questions here related to changes
in this pull request}_

### Validation / Testing
- [ ] Validate DataCatalog cards are linking correctly
- [ ] Validate selecting cards in DatasetSelectorModal is working as it
should
@vgeorge
Copy link
Contributor

vgeorge commented Dec 17, 2024

@sandrahoang686 while I agree we shouldn't be handling every framework use case, I don't think relying only on event handlers like onDatasetClick is the ideal approach. This will make the components stop working as semantic links, affecting accessibility. One possible approach is to allow the parent component to pass an <a>, a Next.js <Link> or whatever element in a as property, a common approach on many component libraries. Let's follow up on this in #1327.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tech debt veda v2 VEDA Refactor Epic Work
Projects
None yet
Development

No branches or pull requests

5 participants