diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 819f2ad195..5bf2732171 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,7 +28,6 @@ updates: - dependency-name: '@typescript-eslint/parser' - dependency-name: eslint #6784 - dependency-name: fetch-mock - - dependency-name: react-router-dom - dependency-name: react-datepicker - dependency-name: recharts - dependency-name: '@headlessui/react' diff --git a/app/react/App/App.js b/app/react/App/App.js index 12979af0db..2be88b110f 100644 --- a/app/react/App/App.js +++ b/app/react/App/App.js @@ -1,7 +1,7 @@ /* eslint-disable import/no-named-as-default */ import React, { useState, useMemo } from 'react'; import PropTypes from 'prop-types'; -import { Outlet, useLocation, useParams } from 'react-router-dom'; +import { Outlet, useLocation, useParams } from 'react-router'; import { useAtom } from 'jotai'; import Notifications from 'app/Notifications'; import Cookiepopup from 'app/App/Cookiepopup'; diff --git a/app/react/App/Menu.tsx b/app/react/App/Menu.tsx index a4abf9cbd6..1efa8b303f 100644 --- a/app/react/App/Menu.tsx +++ b/app/react/App/Menu.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router'; import { bindActionCreators, Dispatch } from 'redux'; import { connect, ConnectedProps } from 'react-redux'; import { fromJS } from 'immutable'; diff --git a/app/react/App/specs/Menu.spec.js b/app/react/App/specs/Menu.spec.js index 4484bc637e..d2ee88c072 100644 --- a/app/react/App/specs/Menu.spec.js +++ b/app/react/App/specs/Menu.spec.js @@ -3,8 +3,8 @@ import { I18NLink } from 'app/I18N'; import { renderConnected } from 'app/utils/test/renderConnected'; import { Menu } from '../Menu'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useLocation: () => ({ search: '?q=(searchTerm:%27asd%27)', }), diff --git a/app/react/Attachments/components/ViewDocumentLink.tsx b/app/react/Attachments/components/ViewDocumentLink.tsx index 8d591f52ea..c0cdfa0af5 100644 --- a/app/react/Attachments/components/ViewDocumentLink.tsx +++ b/app/react/Attachments/components/ViewDocumentLink.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link, useLocation } from 'react-router-dom'; +import { Link, useLocation } from 'react-router'; import { CurrentLocationLink } from 'app/Layout'; import { EntitySchema } from 'shared/types/entityType'; diff --git a/app/react/Attachments/components/specs/ViewDocumentLink.spec.tsx b/app/react/Attachments/components/specs/ViewDocumentLink.spec.tsx index b2fdfdd276..ead034137d 100644 --- a/app/react/Attachments/components/specs/ViewDocumentLink.spec.tsx +++ b/app/react/Attachments/components/specs/ViewDocumentLink.spec.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import React from 'react'; import { shallow } from 'enzyme'; @@ -13,8 +13,8 @@ const mockUseLocation = jest.fn().mockImplementation(() => ({ pathname: `?page=${pathname}`, })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useLocation: () => mockUseLocation(), })); const renderComponent = (entity: EntitySchema) => { diff --git a/app/react/Forms/components/MultiSelect.tsx b/app/react/Forms/components/MultiSelect.tsx index e437a6cd93..fa48a910e9 100644 --- a/app/react/Forms/components/MultiSelect.tsx +++ b/app/react/Forms/components/MultiSelect.tsx @@ -1,7 +1,7 @@ /* eslint-disable max-classes-per-file */ /* eslint-disable class-methods-use-this,max-lines */ -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import ShowIf from 'app/App/ShowIf'; import { filterOptions } from 'shared/optionsUtils'; import { t, Translate } from 'app/I18N'; diff --git a/app/react/I18N/I18NLinkV2.tsx b/app/react/I18N/I18NLinkV2.tsx index a418caa87f..e9501be751 100644 --- a/app/react/I18N/I18NLinkV2.tsx +++ b/app/react/I18N/I18NLinkV2.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { NavLinkProps, NavLink } from 'react-router'; import { useAtomValue } from 'jotai'; -import { NavLinkProps, NavLink } from 'react-router-dom'; import { localeAtom } from 'V2/atoms'; type I18NLinkProps = NavLinkProps & { to: string; activeClassname?: string }; diff --git a/app/react/I18N/components/I18NLink.tsx b/app/react/I18N/components/I18NLink.tsx index 338747c73c..e0ec9b3559 100644 --- a/app/react/I18N/components/I18NLink.tsx +++ b/app/react/I18N/components/I18NLink.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from 'react'; import { connect } from 'react-redux'; -import { useNavigate, NavLink, useLocation } from 'react-router-dom'; +import { useNavigate, NavLink, useLocation } from 'react-router'; import { omit } from 'lodash'; const defaultProps = { @@ -48,20 +48,20 @@ const I18NLink = (props: I18NLinkProps) => { }, delay); }; - const _navigate = () => { - navigate(to, { replace }); + const _navigate = async () => { + await navigate(to, { replace }); scrollToHashWithRetry(location.hash); }; - const onClickHandler = (e: { preventDefault: () => void }) => { + const onClickHandler = async (e: { preventDefault: () => void }) => { e.preventDefault(); if (disabled) return; if (onClick && confirmTitle) { props.mainContext.confirm({ - accept: () => { + accept: async () => { onClick(e); - _navigate(); + await _navigate(); }, title: confirmTitle, message: confirmMessage, @@ -71,10 +71,10 @@ const I18NLink = (props: I18NLinkProps) => { if (onClick) { onClick(e); - _navigate(); + await _navigate(); return; } - _navigate(); + await _navigate(); }; useEffect(() => { diff --git a/app/react/I18N/components/I18NMenu.tsx b/app/react/I18N/components/I18NMenu.tsx index 8d49d472c2..c3613e9705 100644 --- a/app/react/I18N/components/I18NMenu.tsx +++ b/app/react/I18N/components/I18NMenu.tsx @@ -1,14 +1,14 @@ /* eslint-disable react/no-multi-comp */ /* eslint-disable react-hooks/rules-of-hooks */ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { Location, useLocation } from 'react-router-dom'; +import { Location, useLocation } from 'react-router'; import { useAtom, useAtomValue } from 'jotai'; import { ChevronUpIcon, ChevronDownIcon } from '@heroicons/react/20/solid'; import { LanguagesListSchema } from 'shared/types/commonTypes'; -import { NeedAuthorization } from 'V2/Components/UI'; +import { Translate, t } from 'app/I18N'; import { useOnClickOutsideElement } from 'app/utils/useOnClickOutsideElementHook'; +import { NeedAuthorization } from 'V2/Components/UI'; import { inlineEditAtom, localeAtom, settingsAtom, userAtom } from 'V2/atoms'; -import { Translate, t } from 'app/I18N'; const locationSearch = (location: Location) => { const cleanSearch = location.search.split(/page=\d+|&page=\d+/).join(''); diff --git a/app/react/I18N/components/specs/I18NLink.spec.js b/app/react/I18N/components/specs/I18NLink.spec.js index 7f27c27261..6507c3b318 100644 --- a/app/react/I18N/components/specs/I18NLink.spec.js +++ b/app/react/I18N/components/specs/I18NLink.spec.js @@ -4,8 +4,8 @@ /* eslint-disable max-statements */ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; +import { MemoryRouter, Route, Routes } from 'react-router'; import { I18NLink } from '../I18NLink'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; describe('I18NLink', () => { let props; diff --git a/app/react/I18N/components/specs/I18NMenu.spec.tsx b/app/react/I18N/components/specs/I18NMenu.spec.tsx index e6743238da..801260dbc2 100644 --- a/app/react/I18N/components/specs/I18NMenu.spec.tsx +++ b/app/react/I18N/components/specs/I18NMenu.spec.tsx @@ -3,7 +3,7 @@ */ import React from 'react'; import { act, fireEvent, RenderResult, screen, render } from '@testing-library/react'; -import { Location, MemoryRouter } from 'react-router-dom'; +import { Location, MemoryRouter } from 'react-router'; import { createStore, Provider } from 'jotai'; import { ClientUserSchema } from 'app/apiResponseTypes'; import { inlineEditAtom, localeAtom, settingsAtom, userAtom } from 'V2/atoms'; diff --git a/app/react/I18N/specs/I18NLinkV2.spec.tsx b/app/react/I18N/specs/I18NLinkV2.spec.tsx index 1ae3d34cbe..4d2040b52f 100644 --- a/app/react/I18N/specs/I18NLinkV2.spec.tsx +++ b/app/react/I18N/specs/I18NLinkV2.spec.tsx @@ -4,7 +4,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; import { render, RenderResult } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; +import { BrowserRouter } from 'react-router'; import { TestAtomStoreProvider } from 'V2/testing'; import { localeAtom } from 'V2/atoms'; import { I18NLink } from '../I18NLinkV2'; diff --git a/app/react/Layout/CurrentLocationLink.js b/app/react/Layout/CurrentLocationLink.js index c79893e946..d2d4dd0069 100644 --- a/app/react/Layout/CurrentLocationLink.js +++ b/app/react/Layout/CurrentLocationLink.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Link, useLocation } from 'react-router-dom'; +import { Link, useLocation } from 'react-router'; const validProps = props => { const { to, ...valid } = props; diff --git a/app/react/Layout/DocumentsList.js b/app/react/Layout/DocumentsList.js index 80347d1b24..7301476c9e 100644 --- a/app/react/Layout/DocumentsList.js +++ b/app/react/Layout/DocumentsList.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { toUrlParams } from 'shared/JSONRequest'; import rison from 'rison-node'; import { SearchBar } from 'app/Library/components/SearchBar'; diff --git a/app/react/Layout/specs/CurrentLocationLink.spec.js b/app/react/Layout/specs/CurrentLocationLink.spec.js index 24a7179137..b7faf931b3 100644 --- a/app/react/Layout/specs/CurrentLocationLink.spec.js +++ b/app/react/Layout/specs/CurrentLocationLink.spec.js @@ -2,8 +2,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import { CurrentLocationLink } from '../CurrentLocationLink'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useLocation: () => ({ pathname: 'pathanem', search: 'param=value¶m2=value2' }), })); diff --git a/app/react/Library/Library.js b/app/react/Library/Library.js index eaa8d2210c..6ee9f92e2d 100644 --- a/app/react/Library/Library.js +++ b/app/react/Library/Library.js @@ -1,15 +1,13 @@ import React from 'react'; +import { Outlet, matchPath } from 'react-router'; import RouteHandler from 'app/App/RouteHandler'; import { actions } from 'app/BasicReducer'; import { enterLibrary, unsetDocuments, zoomIn, zoomOut } from 'app/Library/actions/libraryActions'; -import DocumentsList from 'app/Library/components/DocumentsList'; -import { requestState } from 'app/Library/helpers/requestState'; -import LibraryLayout from 'app/Library/LibraryLayout'; import { wrapDispatch } from 'app/Multireducer'; import { withRouter } from 'app/componentWrappers'; -import { trackPage } from 'app/App/GoogleAnalytics'; +import { routes as appRoutes } from 'app/appRoutes'; -class Library extends RouteHandler { +class LibraryRootComponent extends RouteHandler { constructor(props, context) { super(props, context); this.superComponentWillReceiveProps = super.componentWillReceiveProps; @@ -22,26 +20,51 @@ class Library extends RouteHandler { this.state = { scrollCount: 0 }; } - static async requestState(requestParams, globalResources) { - return requestState(requestParams, globalResources); - } - urlHasChanged(nextProps) { const nextSearchParams = new URLSearchParams(nextProps.location.search); const currentSearchParams = new URLSearchParams(this.props.location.search); return nextSearchParams.get('q') !== currentSearchParams.get('q'); } - componentWillUnmount() { - this.emptyState(); - } - componentDidUpdate(prevProps) { if (this.urlHasChanged(prevProps)) { this.getClientState(this.props); } } + findMatchingRoute = (pathname, routes, parentPath = '') => { + let result = null; + + routes.every(route => { + if (result !== null) { + return false; + } + + const currentPath = `${parentPath}/${route.path || ''}`.replace('//', '/'); + const match = matchPath({ path: currentPath, end: false }, pathname); + + if (match) { + if (currentPath === pathname && route.handle?.library) result = route; + + if (route.children) { + const childMatch = this.findMatchingRoute(pathname, route.children, currentPath); + if (childMatch) result = childMatch; + } + } + return true; + }); + + return result; + }; + + componentWillUnmount() { + const nextLocation = window?.location?.pathname; + const matchedRoute = this.findMatchingRoute(nextLocation, appRoutes); + if (!matchedRoute && !nextLocation.includes('library')) { + this.emptyState(); + } + } + emptyState() { wrapDispatch(this.context.store.dispatch, 'library')(unsetDocuments()); actions.set('library.sidepanel.quickLabelState', {}); @@ -56,26 +79,19 @@ class Library extends RouteHandler { } render() { - trackPage(); - return ( - - - - ); + if (this.props.children) { + return this.props.children; + } + + return ; } } -const SSRLibrary = withRouter(Library); +const SSRLibrary = withRouter(LibraryRootComponent); + +export const LibraryRoot = Object.assign(SSRLibrary, { + requestState: LibraryRootComponent.requestState, +}); -export const LibraryCards = Object.assign(SSRLibrary, { requestState: Library.requestState }); -export default Library; +export { LibraryRootComponent }; +export default LibraryRoot; diff --git a/app/react/Library/LibraryCards.js b/app/react/Library/LibraryCards.js new file mode 100644 index 0000000000..d97e655d32 --- /dev/null +++ b/app/react/Library/LibraryCards.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { LibraryRootComponent } from 'app/Library/Library'; +import LibraryLayout from 'app/Library/LibraryLayout'; +import DocumentsList from 'app/Library/components/DocumentsList'; +import { withRouter } from 'app/componentWrappers'; +import { trackPage } from 'app/App/GoogleAnalytics'; +import { requestState } from 'app/Library/helpers/requestState'; + +class LibraryCardsComponent extends LibraryRootComponent { + static async requestState(requestParams, globalResources) { + return requestState(requestParams, globalResources); + } + + render() { + trackPage(); + return ( + + + + ); + } +} + +const SSRLibraryComponent = withRouter(LibraryCardsComponent); + +const LibraryCards = Object.assign(SSRLibraryComponent, { + requestState: LibraryCardsComponent.requestState, +}); + +export { LibraryCardsComponent }; +export { LibraryCards }; diff --git a/app/react/Library/LibraryMap.js b/app/react/Library/LibraryMap.js index 71563b0c73..f7584aff66 100644 --- a/app/react/Library/LibraryMap.js +++ b/app/react/Library/LibraryMap.js @@ -2,12 +2,12 @@ import React from 'react'; import { withRouter } from 'app/componentWrappers'; import { requestState } from 'app/Library/helpers/requestState'; import { MapView } from 'app/Library/components/MapView'; +import { LibraryRootComponent } from 'app/Library/Library'; import LibraryLayout from 'app/Library/LibraryLayout'; -import Library from 'app/Library/Library'; import LibraryModeToggleButtons from 'app/Library/components/LibraryModeToggleButtons'; import { trackPage } from 'app/App/GoogleAnalytics'; -class LibraryMapComponent extends Library { +class LibraryMapComponent extends LibraryRootComponent { static async requestState(requestParams, globalResources) { return requestState(requestParams, globalResources, { geolocation: true }); } diff --git a/app/react/Library/LibraryTable.js b/app/react/Library/LibraryTable.js index 89af87cf03..7b39fabec1 100644 --- a/app/react/Library/LibraryTable.js +++ b/app/react/Library/LibraryTable.js @@ -1,13 +1,13 @@ import React from 'react'; import { TableViewer } from 'app/Layout/TableViewer'; -import Library from 'app/Library/Library'; +import { LibraryRootComponent } from 'app/Library/Library'; import LibraryLayout from 'app/Library/LibraryLayout'; import DocumentsList from 'app/Library/components/DocumentsList'; import { requestState } from 'app/Library/helpers/requestState'; import { withRouter } from 'app/componentWrappers'; import { trackPage } from 'app/App/GoogleAnalytics'; -class LibraryTableComponent extends Library { +class LibraryTableComponent extends LibraryRootComponent { static async requestState(requestParams, globalResources) { return requestState(requestParams, globalResources, { calculateTableColumns: true }); } diff --git a/app/react/Library/actions/libraryActions.js b/app/react/Library/actions/libraryActions.js index 5bd66756e8..a27f35847b 100644 --- a/app/react/Library/actions/libraryActions.js +++ b/app/react/Library/actions/libraryActions.js @@ -231,7 +231,7 @@ function encodeSearch(_search, appendQ = true) { return appendQ ? `?q=${encodedSearch}` : encodedSearch; } -function setSearchInUrl(searchParams, location, navigate) { +async function setSearchInUrl(searchParams, location, navigate) { const { pathname } = location; const path = `${pathname}/`.replace(/\/\//g, '/'); const query = new URLSearchParams(location.search); @@ -246,7 +246,7 @@ function searchDocuments( limit = 30, from = 0 ) { - return (dispatch, getState) => { + return async (dispatch, getState) => { const state = getState().library; const currentSearch = search || state.search; const currentFilters = filters || state.filters; diff --git a/app/react/Library/components/DocumentTypesList.js b/app/react/Library/components/DocumentTypesList.js index 97dead0228..bb5a62e167 100644 --- a/app/react/Library/components/DocumentTypesList.js +++ b/app/react/Library/components/DocumentTypesList.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import Immutable, { is } from 'immutable'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import rison from 'rison-node'; import ShowIf from 'app/App/ShowIf'; import { withRouter } from 'app/componentWrappers'; diff --git a/app/react/Library/components/DocumentsList.js b/app/react/Library/components/DocumentsList.js index 838fa5c402..104cd1e843 100644 --- a/app/react/Library/components/DocumentsList.js +++ b/app/react/Library/components/DocumentsList.js @@ -65,7 +65,8 @@ function mapStateToProps(state, props) { documents: state[props.storeKey].documents, filters: state[props.storeKey].filters, filtersPanel: state[props.storeKey].ui.get('filtersPanel'), - search: state[props.storeKey].search, + //TODO: Uncomment when rerendering is fixed + // search: state[props.storeKey].search, selectedDocuments: state[props.storeKey].ui.get('selectedDocuments'), multipleSelected: state[props.storeKey].ui.get('selectedDocuments').size > 1, rowListZoomLevel: state[props.storeKey].ui.get('zoomLevel'), diff --git a/app/react/Library/components/FiltersFromProperties.js b/app/react/Library/components/FiltersFromProperties.js index a882070574..6cc8f86a5a 100644 --- a/app/react/Library/components/FiltersFromProperties.js +++ b/app/react/Library/components/FiltersFromProperties.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router'; import rison from 'rison-node'; import Immutable from 'immutable'; import PropTypes from 'prop-types'; diff --git a/app/react/Library/components/SearchBar.tsx b/app/react/Library/components/SearchBar.tsx index a5b2fa4434..e8155c0000 100644 --- a/app/react/Library/components/SearchBar.tsx +++ b/app/react/Library/components/SearchBar.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { bindActionCreators, Dispatch } from 'redux'; import { actions as formActions } from 'react-redux-form'; import { connect, ConnectedProps } from 'react-redux'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router'; import { Icon } from 'UI'; import { diff --git a/app/react/Library/components/SortDropdown.tsx b/app/react/Library/components/SortDropdown.tsx index 59f43f5df3..977bb4c686 100644 --- a/app/react/Library/components/SortDropdown.tsx +++ b/app/react/Library/components/SortDropdown.tsx @@ -3,7 +3,7 @@ import { bindActionCreators, Dispatch } from 'redux'; import { connect, ConnectedProps } from 'react-redux'; import { actions } from 'react-redux-form'; import { risonDecodeOrIgnore } from 'app/utils'; -import { useLocation, useSearchParams } from 'react-router-dom'; +import { useLocation, useSearchParams } from 'react-router'; import { Icon } from 'UI'; import { I18NLink, t } from 'app/I18N'; import { wrapDispatch } from 'app/Multireducer'; diff --git a/app/react/Library/components/specs/FiltersFromProperties.spec.js b/app/react/Library/components/specs/FiltersFromProperties.spec.js index e67b805e0d..12356b4c7e 100644 --- a/app/react/Library/components/specs/FiltersFromProperties.spec.js +++ b/app/react/Library/components/specs/FiltersFromProperties.spec.js @@ -12,8 +12,8 @@ import SelectFilter from '../SelectFilter'; import TextFilter from '../TextFilter'; import { defaultProperties } from './fixtures/FiltersFromPropertiesFixtures'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useLocation: () => jest.fn(), })); jest.mock('app/I18N', () => ({ diff --git a/app/react/Library/components/specs/__snapshots__/SortDropdown.spec.tsx.snap b/app/react/Library/components/specs/__snapshots__/SortDropdown.spec.tsx.snap index 94f5d5f137..9d4879b0a8 100644 --- a/app/react/Library/components/specs/__snapshots__/SortDropdown.spec.tsx.snap +++ b/app/react/Library/components/specs/__snapshots__/SortDropdown.spec.tsx.snap @@ -37,6 +37,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Title @@ -45,6 +46,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Date added @@ -53,6 +55,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Date modified @@ -61,6 +64,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Search relevance @@ -69,6 +73,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Date @@ -77,6 +82,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Number @@ -85,6 +91,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • My select @@ -93,6 +100,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Sortable name @@ -101,6 +109,7 @@ exports[`Sort dropdown when there is an active search term should display sort b
  • Inherited 1 @@ -110,6 +119,7 @@ exports[`Sort dropdown when there is an active search term should display sort b diff --git a/app/react/Library/specs/Library.spec.js b/app/react/Library/specs/Library.spec.js index 1e80f9aa82..2e85bf4f99 100644 --- a/app/react/Library/specs/Library.spec.js +++ b/app/react/Library/specs/Library.spec.js @@ -1,10 +1,59 @@ +/** + * @jest-environment jsdom + */ import React from 'react'; import { shallow } from 'enzyme'; -import Library from 'app/Library/Library'; +import { LibraryRootComponent } from 'app/Library/Library'; import RouteHandler from 'app/App/RouteHandler'; import createStore from 'app/store'; -import DocumentsList from 'app/Library/components/DocumentsList'; -import LibraryLayout from 'app/Library/LibraryLayout'; + +const routes = [ + { + path: '/', + children: [ + { + children: [ + { index: true }, + { path: 'login' }, + { + path: 'library/*', + children: [ + { index: true, handle: { library: true } }, + { path: 'map', handle: { library: true } }, + { path: 'table', handle: { library: true } }, + ], + }, + ], + }, + { + path: 'en', + children: [ + { + children: [ + { index: true }, + { path: 'login' }, + { + path: 'library/*', + children: [ + { index: true, handle: { library: true } }, + { path: 'map', handle: { library: true } }, + { path: 'table', handle: { library: true } }, + ], + }, + ], + }, + { path: '*' }, + ], + handle: { library: true }, + }, + ], + handle: { library: true }, + }, +]; + +jest.mock('app/appRoutes', () => ({ + routes, +})); describe('Library', () => { const templates = [ @@ -35,15 +84,10 @@ describe('Library', () => { }, }; - component = shallow(, { context }); + component = shallow(, { context }); instance = component.instance(); }); - it('should render the DocumentsList (by default)', () => { - expect(component.find(DocumentsList).length).toBe(1); - expect(component.find(DocumentsList).props().storeKey).toBe('library'); - }); - describe('urlHasChanged', () => { it('return true when q has changed', () => { const nextProps = { location: { search: { q: '(a:2)' } } }; @@ -72,19 +116,36 @@ describe('Library', () => { }); }); - describe('scroll counting for mobile responsiveness', () => { - it('should increase the scroll count on scrolling event', () => { - const layout = component.find(LibraryLayout); - expect(component.state().scrollCount).toBe(0); - expect(component.find(DocumentsList).props().scrollCount).toBe(0); - layout - .props() - .scrollCallback({ target: { className: 'main-container document-viewer with-footer' } }); - layout.props().scrollCallback({ target: { className: 'other element' } }); - layout.props().scrollCallback({ target: { className: 'document-viewer' } }); + describe('cleanup', () => { + beforeEach(() => { + component = shallow(, { context }); + instance = component.instance(); + spyOn(instance, 'emptyState'); + }); + + it.each([ + ['/library/some-path', false], + ['/library/map', false], + ['/library/table', false], + ['/en/library/some-path', false], + ['/en/library/map', false], + ['/en/library/table', false], + ['/', false], + ['/en', false], + ['/some-path', true], + ['/no-match', true], + ])('should %s call emptyState when unmounting and route is %s', (pathname, shouldCall) => { + Object.defineProperty(window, 'location', { + writable: true, + value: { pathname }, + }); - expect(component.state().scrollCount).toBe(2); - expect(component.find(DocumentsList).props().scrollCount).toBe(2); + component.unmount(); + if (shouldCall) { + expect(instance.emptyState).toHaveBeenCalled(); + } else { + expect(instance.emptyState).not.toHaveBeenCalled(); + } }); }); }); diff --git a/app/react/Library/specs/LibraryCards.spec.js b/app/react/Library/specs/LibraryCards.spec.js new file mode 100644 index 0000000000..29f3ead2f2 --- /dev/null +++ b/app/react/Library/specs/LibraryCards.spec.js @@ -0,0 +1,94 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { LibraryCardsComponent } from 'app/Library/LibraryCards'; +import RouteHandler from 'app/App/RouteHandler'; +import createStore from 'app/store'; +import DocumentsList from 'app/Library/components/DocumentsList'; +import LibraryLayout from 'app/Library/LibraryLayout'; + +describe('Library', () => { + const templates = [ + { + name: 'Decision', + _id: 'abc1', + properties: [{ name: 'p', filter: true, type: 'text', prioritySorting: true }], + }, + { name: 'Ruling', _id: 'abc2', properties: [] }, + ]; + const thesauris = [{ name: 'countries', _id: '1', values: [] }]; + createStore({ templates, thesauris }); + let component; + let instance; + let context; + const props = { location: { search: { q: '(a:1)' } } }; + let dispatchCallsOrder = []; + + beforeEach(() => { + RouteHandler.renderedFromServer = true; + dispatchCallsOrder = []; + context = { + store: { + getState: () => ({}), + dispatch: jasmine.createSpy('dispatch').and.callFake(action => { + dispatchCallsOrder.push(action.type); + }), + }, + }; + + component = shallow(, { context }); + instance = component.instance(); + }); + + it('should render the DocumentsList (by default)', () => { + expect(component.find(DocumentsList).length).toBe(1); + expect(component.find(DocumentsList).props().storeKey).toBe('library'); + }); + + describe('urlHasChanged', () => { + it('return true when q has changed', () => { + const nextProps = { location: { search: { q: '(a:2)' } } }; + expect(instance.urlHasChanged(nextProps)).toBe(true); + }); + + it('should not update if "q" is the same', () => { + const nextProps = { location: { search: { q: '(a:1)' } } }; + expect(instance.urlHasChanged(nextProps)).toBe(false); + }); + }); + + describe('component update', () => { + it('should request the new state when the url changes', () => { + spyOn(instance, 'getClientState'); + const nextProps = { location: { search: { q: '(a:2)' } } }; + component.setProps(nextProps); + expect(instance.getClientState).toHaveBeenCalled(); + }); + + it('should not request the new state when the url hasnt change', () => { + spyOn(instance, 'getClientState'); + const nextProps = { location: { search: { q: '(a:1)' } } }; + component.setProps(nextProps); + expect(instance.getClientState).not.toHaveBeenCalled(); + }); + }); + + describe('scroll counting for mobile responsiveness', () => { + it('should increase the scroll count on scrolling event', () => { + const layout = component.find(LibraryLayout); + expect(component.state().scrollCount).toBe(0); + expect(component.find(DocumentsList).props().scrollCount).toBe(0); + layout + .props() + .scrollCallback({ target: { className: 'main-container document-viewer with-footer' } }); + layout.props().scrollCallback({ target: { className: 'other element' } }); + layout.props().scrollCallback({ target: { className: 'document-viewer' } }); + + expect(component.state().scrollCount).toBe(2); + expect(component.find(DocumentsList).props().scrollCount).toBe(2); + }); + }); + + describe('cleanup', () => { + it('should run cleanup function when navgating away from library', () => {}); + }); +}); diff --git a/app/react/Map/specs/LMap.spec.tsx b/app/react/Map/specs/LMap.spec.tsx index ee2a055cce..4104fd57db 100644 --- a/app/react/Map/specs/LMap.spec.tsx +++ b/app/react/Map/specs/LMap.spec.tsx @@ -12,8 +12,8 @@ jest.mock('app/Map/GoogleMapLayer', () => ({ getGoogleLayer: jest.fn(), })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useRouteError: () => () => undefined, })); diff --git a/app/react/Markdown/components/MarkdownLink.js b/app/react/Markdown/components/MarkdownLink.js index 1e5518b976..db5077cfda 100644 --- a/app/react/Markdown/components/MarkdownLink.js +++ b/app/react/Markdown/components/MarkdownLink.js @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { isClient } from 'app/utils'; import PropTypes from 'prop-types'; import React from 'react'; diff --git a/app/react/Markdown/components/PayPalDonateLink.js b/app/react/Markdown/components/PayPalDonateLink.js index 02a730bd7f..2d17679266 100644 --- a/app/react/Markdown/components/PayPalDonateLink.js +++ b/app/react/Markdown/components/PayPalDonateLink.js @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import PropTypes from 'prop-types'; import React from 'react'; diff --git a/app/react/Markdown/components/SearchBox.js b/app/react/Markdown/components/SearchBox.js index 046658a37e..b878084a83 100644 --- a/app/react/Markdown/components/SearchBox.js +++ b/app/react/Markdown/components/SearchBox.js @@ -1,5 +1,5 @@ import { Form, Field } from 'react-redux-form'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router'; import React from 'react'; import PropTypes from 'prop-types'; import rison from 'rison-node'; @@ -11,8 +11,8 @@ import { SearchTipsContent } from 'app/App/SearchTipsContent'; const SearchBox = ({ placeholder, classname }) => { const navigate = useNavigate(); - const search = ({ searchTerm }) => { - navigate(`/library/?q=${rison.encode({ searchTerm })}`); + const search = async ({ searchTerm }) => { + await navigate(`/library/?q=${rison.encode({ searchTerm })}`); }; return ( diff --git a/app/react/Markdown/components/index.js b/app/react/Markdown/components/index.js index f6d1eb5466..a434d35a37 100644 --- a/app/react/Markdown/components/index.js +++ b/app/react/Markdown/components/index.js @@ -1,6 +1,6 @@ import loadable from '@loadable/component'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Icon } from 'UI'; import Counter from './Counter'; import ContactForm from './ContactForm'; diff --git a/app/react/Markdown/components/specs/MarkdownLink.spec.js b/app/react/Markdown/components/specs/MarkdownLink.spec.js index db0ac42da4..da5a28b495 100644 --- a/app/react/Markdown/components/specs/MarkdownLink.spec.js +++ b/app/react/Markdown/components/specs/MarkdownLink.spec.js @@ -2,8 +2,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import MarkdownLink from '../MarkdownLink.js'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), // eslint-disable-next-line jsx-a11y/anchor-has-content, react/prop-types Link: props => , })); diff --git a/app/react/Markdown/components/specs/PayPalDonateLink.spec.js b/app/react/Markdown/components/specs/PayPalDonateLink.spec.js index e872cf3c32..bd75f78ccb 100644 --- a/app/react/Markdown/components/specs/PayPalDonateLink.spec.js +++ b/app/react/Markdown/components/specs/PayPalDonateLink.spec.js @@ -2,8 +2,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import PayPalDonateLink from '../PayPalDonateLink.js'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), // eslint-disable-next-line jsx-a11y/anchor-has-content, react/prop-types Link: props => , })); diff --git a/app/react/Markdown/components/specs/SearchBox.spec.js b/app/react/Markdown/components/specs/SearchBox.spec.js index 4d5fc8a7af..77284d7b11 100644 --- a/app/react/Markdown/components/specs/SearchBox.spec.js +++ b/app/react/Markdown/components/specs/SearchBox.spec.js @@ -8,8 +8,8 @@ import SearchBox from '../SearchBox'; const mockUseNavigate = jest.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useNavigate: () => mockUseNavigate, })); diff --git a/app/react/ProtectedRoute.tsx b/app/react/ProtectedRoute.tsx index b313c3d0b9..6b9267c0f2 100644 --- a/app/react/ProtectedRoute.tsx +++ b/app/react/ProtectedRoute.tsx @@ -1,5 +1,5 @@ import React, { ReactElement } from 'react'; -import { Navigate, Outlet } from 'react-router-dom'; +import { Navigate, Outlet } from 'react-router'; import { store } from 'app/store'; import { ClientSettings } from 'app/apiResponseTypes'; diff --git a/app/react/Routes.tsx b/app/react/Routes.tsx index fa26bd2bdc..0df5f656a7 100644 --- a/app/react/Routes.tsx +++ b/app/react/Routes.tsx @@ -1,17 +1,18 @@ /* eslint-disable max-lines */ import React from 'react'; -import { createRoutesFromElements, Route } from 'react-router-dom'; +import { createRoutesFromElements, Route } from 'react-router'; import { IncomingHttpHeaders } from 'http'; import { App } from 'app/App/App'; -import { LibraryCards } from 'app/Library/Library'; +import LibraryRoot from 'app/Library/Library'; import { LibraryMap } from 'app/Library/LibraryMap'; +import { LibraryCards } from 'app/Library/LibraryCards'; +import { LibraryTable } from 'app/Library/LibraryTable'; import { PreserveSettings, EntityTypesList, Settings } from 'app/Settings'; import { EditTemplate } from 'app/Templates/EditTemplate'; import NewTemplate from 'app/Templates/NewTemplate'; import { Login } from 'app/Users/Login'; import { Users, usersLoader, userAction } from 'V2/Routes/Settings/Users/Users'; import { Collection, collectionLoader } from 'V2/Routes/Settings/Collection/Collection'; -import { LibraryTable } from 'app/Library/LibraryTable'; import ViewerRoute from 'app/Viewer/ViewerRoute'; import { ClientSettings } from 'app/apiResponseTypes'; import { @@ -75,16 +76,35 @@ import { NewRelMigrationDashboard } from './Settings/components/relV2MigrationDa const getRoutesLayout = ( settings: ClientSettings | undefined, indexElement: React.ReactNode, - headers?: IncomingHttpHeaders + headers?: IncomingHttpHeaders, + defaultToLibrary?: boolean ) => ( }> - + } /> - , settings)} /> - , settings)} /> - , settings)} /> - , settings)} /> - , settings)} /> + , settings)}> + , settings)} handle={{ library: true }} /> + , settings)} + handle={{ library: true }} + /> + , settings)} + handle={{ library: true }} + /> + + , settings)}> + , settings)} /> + + , settings)}> + , settings)} /> + , settings)} /> } /> } /> @@ -244,8 +264,8 @@ const getRoutes = ( userId: string | undefined, headers?: IncomingHttpHeaders ) => { - const { element, parameters } = getIndexElement(settings, userId); - const layout = getRoutesLayout(settings, element, headers); + const { element, parameters, defaultToLibrary } = getIndexElement(settings, userId); + const layout = getRoutesLayout(settings, element, headers, defaultToLibrary); const languageKeys = settings?.languages?.map(lang => lang.key) || []; return createRoutesFromElements( }> diff --git a/app/react/Settings/Settings.js b/app/react/Settings/Settings.js index bd63f1fb2a..a949448cc9 100644 --- a/app/react/Settings/Settings.js +++ b/app/react/Settings/Settings.js @@ -1,6 +1,6 @@ import React from 'react'; import { Helmet } from 'react-helmet'; -import { Outlet } from 'react-router-dom'; +import { Outlet } from 'react-router'; import { withOutlet, withRouter } from 'app/componentWrappers'; import RouteHandler from 'app/App/RouteHandler'; import { actions } from 'app/BasicReducer'; diff --git a/app/react/Settings/components/EntityTypesList.js b/app/react/Settings/components/EntityTypesList.js index a2f22ab80f..5ee215c7f0 100644 --- a/app/react/Settings/components/EntityTypesList.js +++ b/app/react/Settings/components/EntityTypesList.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { withContext } from 'app/componentWrappers'; import { deleteTemplate, diff --git a/app/react/Settings/components/specs/EntityTypesList.spec.js b/app/react/Settings/components/specs/EntityTypesList.spec.js index 6bf69ece91..d00516c397 100644 --- a/app/react/Settings/components/specs/EntityTypesList.spec.js +++ b/app/react/Settings/components/specs/EntityTypesList.spec.js @@ -3,8 +3,8 @@ import { shallow } from 'enzyme'; import Immutable from 'immutable'; import { EntityTypesList } from '../EntityTypesList'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), // eslint-disable-next-line jsx-a11y/anchor-has-content, react/prop-types Link: props => , })); diff --git a/app/react/Templates/components/specs/MetadataTemplate.spec.js b/app/react/Templates/components/specs/MetadataTemplate.spec.js index 7a09fcd319..9ce6e6fcb4 100644 --- a/app/react/Templates/components/specs/MetadataTemplate.spec.js +++ b/app/react/Templates/components/specs/MetadataTemplate.spec.js @@ -2,6 +2,7 @@ * @jest-environment jsdom */ import React, { Component } from 'react'; +import { BrowserRouter } from 'react-router'; import { DragDropContext } from 'react-dnd-old'; import { Provider } from 'react-redux'; import { modelReducer, formReducer, Field, Control } from 'react-redux-form'; @@ -11,10 +12,8 @@ import Immutable from 'immutable'; import thunk from 'redux-thunk'; import { shallow } from 'enzyme'; import { TestBackend } from 'react-dnd-test-backend'; - import entitiesApi from 'app/Entities/EntitiesAPI'; import pagesApi from 'app/Pages/PagesAPI'; - import { MetadataTemplate, dropTarget, @@ -22,7 +21,6 @@ import { } from 'app/Templates/components/MetadataTemplate'; import MetadataProperty from 'app/Templates/components/MetadataProperty'; import { dragSource } from 'app/Templates/components/PropertyOption'; -import { BrowserRouter } from 'react-router-dom'; import * as templateActions from '../../actions/templateActions'; function sourceTargetTestContext(Target, Source, actions) { diff --git a/app/react/V2/Components/Analitycs/Matomo.tsx b/app/react/V2/Components/Analitycs/Matomo.tsx index 48cd3a9689..8d755133eb 100644 --- a/app/react/V2/Components/Analitycs/Matomo.tsx +++ b/app/react/V2/Components/Analitycs/Matomo.tsx @@ -1,7 +1,7 @@ /* eslint-disable max-statements */ import { useEffect, useRef } from 'react'; import { useAtomValue } from 'jotai'; -import { useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router'; import { globalMatomoAtom, settingsAtom } from 'V2/atoms'; import { isClient } from 'app/utils'; diff --git a/app/react/V2/Components/Analitycs/specs/Matomo.spec.tsx b/app/react/V2/Components/Analitycs/specs/Matomo.spec.tsx index ff77abe57b..1abfe2de45 100644 --- a/app/react/V2/Components/Analitycs/specs/Matomo.spec.tsx +++ b/app/react/V2/Components/Analitycs/specs/Matomo.spec.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; +import { MemoryRouter } from 'react-router'; import { globalMatomoAtom, settingsAtom } from 'V2/atoms'; import { TestAtomStoreProvider } from 'V2/testing'; import { Matomo } from '../Matomo'; diff --git a/app/react/V2/Components/ErrorHandling/GeneralError.tsx b/app/react/V2/Components/ErrorHandling/GeneralError.tsx index 28009af0f8..0a7d605395 100644 --- a/app/react/V2/Components/ErrorHandling/GeneralError.tsx +++ b/app/react/V2/Components/ErrorHandling/GeneralError.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Helmet } from 'react-helmet'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams, useSearchParams } from 'react-router'; import { has } from 'lodash'; import Footer from 'app/App/Footer'; import { searchParamsFromSearchParams } from 'app/utils/routeHelpers'; diff --git a/app/react/V2/Components/ErrorHandling/RouteErrorBoundary.tsx b/app/react/V2/Components/ErrorHandling/RouteErrorBoundary.tsx index c7b25677a2..ee4165fc1f 100644 --- a/app/react/V2/Components/ErrorHandling/RouteErrorBoundary.tsx +++ b/app/react/V2/Components/ErrorHandling/RouteErrorBoundary.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useRouteError } from 'react-router-dom'; +import { useRouteError } from 'react-router'; import { ErrorFallback } from './ErrorFallback'; interface ErrorBoundaryProps { diff --git a/app/react/V2/Components/ErrorHandling/specs/GeneralError.spec.tsx b/app/react/V2/Components/ErrorHandling/specs/GeneralError.spec.tsx index 7729981fcf..1df90ee549 100644 --- a/app/react/V2/Components/ErrorHandling/specs/GeneralError.spec.tsx +++ b/app/react/V2/Components/ErrorHandling/specs/GeneralError.spec.tsx @@ -22,8 +22,8 @@ const mockUseParams = jest.fn().mockImplementation(() => ({ errorCode, })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useLocation: () => ({ search: '?q=(requestId:%271234%27)', }), diff --git a/app/react/V2/Components/ErrorHandling/specs/RouteErrorBoundary.spec.tsx b/app/react/V2/Components/ErrorHandling/specs/RouteErrorBoundary.spec.tsx index 045d622746..e724b806ac 100644 --- a/app/react/V2/Components/ErrorHandling/specs/RouteErrorBoundary.spec.tsx +++ b/app/react/V2/Components/ErrorHandling/specs/RouteErrorBoundary.spec.tsx @@ -10,8 +10,8 @@ let error: any = null; const mockUseRouteError = jest.fn().mockImplementation(() => error); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), useRouteError: () => mockUseRouteError(), })); diff --git a/app/react/V2/Components/Layouts/specs/SettingsContent.cy.tsx b/app/react/V2/Components/Layouts/specs/SettingsContent.cy.tsx index 18c9ac9950..8c6541f189 100644 --- a/app/react/V2/Components/Layouts/specs/SettingsContent.cy.tsx +++ b/app/react/V2/Components/Layouts/specs/SettingsContent.cy.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { BrowserRouter } from 'react-router'; import 'cypress-axe'; -import { BrowserRouter } from 'react-router-dom'; import { mount } from '@cypress/react18'; import { SettingsContent } from '../SettingsContent'; diff --git a/app/react/V2/Components/UI/Paginator.tsx b/app/react/V2/Components/UI/Paginator.tsx index fc988cd970..490ca191d3 100644 --- a/app/react/V2/Components/UI/Paginator.tsx +++ b/app/react/V2/Components/UI/Paginator.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/20/solid'; import { Translate } from 'app/I18N'; diff --git a/app/react/V2/Components/UI/Sidepanel.tsx b/app/react/V2/Components/UI/Sidepanel.tsx index 8c997388d8..70e6bee133 100644 --- a/app/react/V2/Components/UI/Sidepanel.tsx +++ b/app/react/V2/Components/UI/Sidepanel.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; import { Transition } from '@headlessui/react'; -import { useParams } from 'react-router-dom'; +import { useParams } from 'react-router'; import { XMarkIcon } from '@heroicons/react/20/solid'; import { availableLanguages } from 'shared/language'; import { Translate } from 'app/I18N'; diff --git a/app/react/V2/Routes/Settings/Account/Account.tsx b/app/react/V2/Routes/Settings/Account/Account.tsx index f036e0d266..69190dc09a 100644 --- a/app/react/V2/Routes/Settings/Account/Account.tsx +++ b/app/react/V2/Routes/Settings/Account/Account.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useRef, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { useForm } from 'react-hook-form'; import { useSetAtom } from 'jotai'; import { ClientUserSchema } from 'app/apiResponseTypes'; @@ -62,7 +62,7 @@ const Account = () => { type: 'success', text: Account updated, }); - revalidator.revalidate(); + await revalidator.revalidate(); } resetField('password'); diff --git a/app/react/V2/Routes/Settings/Account/Components/TwoFactorSetup.tsx b/app/react/V2/Routes/Settings/Account/Components/TwoFactorSetup.tsx index f4243421fb..7085cf785c 100644 --- a/app/react/V2/Routes/Settings/Account/Components/TwoFactorSetup.tsx +++ b/app/react/V2/Routes/Settings/Account/Components/TwoFactorSetup.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import api from 'app/utils/api'; -import { useRevalidator } from 'react-router-dom'; +import { useRevalidator } from 'react-router'; import { useSetAtom } from 'jotai'; import { RequestParams } from 'app/utils/RequestParams'; @@ -57,7 +57,7 @@ const TwoFactorSetup = ({ closePanel, isOpen }: TwoFactorSetupProps) => { const enable2fa = async () => { try { await api.post('auth2fa-enable', new RequestParams({ token })); - revalidator.revalidate(); + await revalidator.revalidate(); closePanel(); setNotifications({ type: 'success', diff --git a/app/react/V2/Routes/Settings/ActivityLog/ActivityLog.tsx b/app/react/V2/Routes/Settings/ActivityLog/ActivityLog.tsx index e8c5f43174..9b3e1bbaa7 100644 --- a/app/react/V2/Routes/Settings/ActivityLog/ActivityLog.tsx +++ b/app/react/V2/Routes/Settings/ActivityLog/ActivityLog.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useEffect, useState } from 'react'; -import { useLoaderData, useLocation, useSearchParams } from 'react-router-dom'; +import { useLoaderData, useLocation, useSearchParams } from 'react-router'; import { Row, SortingState } from '@tanstack/react-table'; import { FunnelIcon } from '@heroicons/react/24/outline'; import { useAtomValue } from 'jotai'; diff --git a/app/react/V2/Routes/Settings/ActivityLog/ActivityLogLoader.ts b/app/react/V2/Routes/Settings/ActivityLog/ActivityLogLoader.ts index 160fd9af6f..8738a1d04c 100644 --- a/app/react/V2/Routes/Settings/ActivityLog/ActivityLogLoader.ts +++ b/app/react/V2/Routes/Settings/ActivityLog/ActivityLogLoader.ts @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ -import { LoaderFunction, SetURLSearchParams, createSearchParams, Location } from 'react-router-dom'; +import { LoaderFunction, SetURLSearchParams, createSearchParams, Location } from 'react-router'; import { IncomingHttpHeaders } from 'http'; import _, { isArray, isEqual, isObject } from 'lodash'; import moment from 'moment'; diff --git a/app/react/V2/Routes/Settings/Collection/Collection.tsx b/app/react/V2/Routes/Settings/Collection/Collection.tsx index 059b3f4559..0ce9059103 100644 --- a/app/react/V2/Routes/Settings/Collection/Collection.tsx +++ b/app/react/V2/Routes/Settings/Collection/Collection.tsx @@ -4,7 +4,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { useForm } from 'react-hook-form'; import { useSetAtom } from 'jotai'; import { isUndefined } from 'lodash'; @@ -112,7 +112,7 @@ const Collection = () => { text: Settings updated, }); } - revalidator.revalidate(); + await revalidator.revalidate(); }; const labelWithTip = (label: string, tip: React.ReactNode) => ( diff --git a/app/react/V2/Routes/Settings/CustomUploads/CustomUploads.tsx b/app/react/V2/Routes/Settings/CustomUploads/CustomUploads.tsx index 51382e40c3..f6c2571d0c 100644 --- a/app/react/V2/Routes/Settings/CustomUploads/CustomUploads.tsx +++ b/app/react/V2/Routes/Settings/CustomUploads/CustomUploads.tsx @@ -2,7 +2,7 @@ /* eslint-disable no-spaced-func */ /* eslint-disable max-statements */ import React, { useEffect, useState } from 'react'; -import { LoaderFunction, useBlocker, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useBlocker, useLoaderData, useRevalidator } from 'react-router'; import { IncomingHttpHeaders } from 'http'; import { useSetAtom } from 'jotai'; import { Translate } from 'app/I18N'; @@ -93,7 +93,7 @@ const CustomUploads = () => { setConfirmationModal(false); const response = await remove(file._id); notify([response], Deleted custom file); - revalidator.revalidate(); + await revalidator.revalidate(); }, }); }; @@ -104,7 +104,7 @@ const CustomUploads = () => { setSelectedRows([]); const responses = await Promise.all(filesToDelete.map(async fileId => remove(fileId))); notify(responses, Deleted custom file); - revalidator.revalidate(); + await revalidator.revalidate(); }; return ( diff --git a/app/react/V2/Routes/Settings/CustomUploads/components/DropzoneModal.tsx b/app/react/V2/Routes/Settings/CustomUploads/components/DropzoneModal.tsx index 258665d1f2..67271d9a57 100644 --- a/app/react/V2/Routes/Settings/CustomUploads/components/DropzoneModal.tsx +++ b/app/react/V2/Routes/Settings/CustomUploads/components/DropzoneModal.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useRevalidator } from 'react-router-dom'; +import { useRevalidator } from 'react-router'; import { useSetAtom } from 'jotai'; import { FetchResponseError } from 'shared/JSONRequest'; import { Translate } from 'app/I18N'; @@ -31,8 +31,8 @@ const DropzoneModal = ({ notify, isOpen, setIsOpen, uploadService }: DropzoneMod uploadService.onProgress((filename, progress) => { updateProgress({ filename, progress }); }); - uploadService.onUploadComplete(() => { - revalidator.revalidate(); + uploadService.onUploadComplete(async () => { + await revalidator.revalidate(); }); const results = await uploadService.upload([...filesToUpload]); updateProgress({ filename: undefined, progress: undefined }); diff --git a/app/react/V2/Routes/Settings/CustomUploads/components/EditFileSidepanel.tsx b/app/react/V2/Routes/Settings/CustomUploads/components/EditFileSidepanel.tsx index 261ee75166..e3cfe7b307 100644 --- a/app/react/V2/Routes/Settings/CustomUploads/components/EditFileSidepanel.tsx +++ b/app/react/V2/Routes/Settings/CustomUploads/components/EditFileSidepanel.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; import { useForm } from 'react-hook-form'; -import { useRevalidator } from 'react-router-dom'; +import { useRevalidator } from 'react-router'; import { useSetAtom } from 'jotai'; import { FileType } from 'shared/types/fileType'; import { Translate } from 'app/I18N'; @@ -58,7 +58,7 @@ const EditFileSidepanel = ({ showSidepanel, closeSidepanel, file }: EditFileSide const response = await update(updatedFile); closeSidepanel(); notify(response); - revalidator.revalidate(); + await revalidator.revalidate(); }; return ( diff --git a/app/react/V2/Routes/Settings/Customization/Customization.tsx b/app/react/V2/Routes/Settings/Customization/Customization.tsx index 7d816ca927..2b17e49424 100644 --- a/app/react/V2/Routes/Settings/Customization/Customization.tsx +++ b/app/react/V2/Routes/Settings/Customization/Customization.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { LoaderFunction, useBlocker, useLoaderData } from 'react-router-dom'; +import { LoaderFunction, useBlocker, useLoaderData } from 'react-router'; import { IncomingHttpHeaders } from 'http'; import { useSetAtom } from 'jotai'; import { FetchResponseError } from 'shared/JSONRequest'; diff --git a/app/react/V2/Routes/Settings/Dashboard/Dashboard.tsx b/app/react/V2/Routes/Settings/Dashboard/Dashboard.tsx index 3115dd7f92..a150db2c52 100644 --- a/app/react/V2/Routes/Settings/Dashboard/Dashboard.tsx +++ b/app/react/V2/Routes/Settings/Dashboard/Dashboard.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData } from 'react-router-dom'; +import { LoaderFunction, useLoaderData } from 'react-router'; import { Translate } from 'app/I18N'; import { SettingsContent } from 'app/V2/Components/Layouts/SettingsContent'; diff --git a/app/react/V2/Routes/Settings/Filters/FiltersTable.tsx b/app/react/V2/Routes/Settings/Filters/FiltersTable.tsx index 59d55131ca..98b99c3d1d 100644 --- a/app/react/V2/Routes/Settings/Filters/FiltersTable.tsx +++ b/app/react/V2/Routes/Settings/Filters/FiltersTable.tsx @@ -1,6 +1,6 @@ /* eslint-disable max-statements */ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { LoaderFunction, useBlocker, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useBlocker, useLoaderData, useRevalidator } from 'react-router'; import { useSetAtom } from 'jotai'; import { IncomingHttpHeaders } from 'http'; import { RowSelectionState } from '@tanstack/react-table'; @@ -114,7 +114,7 @@ const FiltersTable = () => { setSettings(response); setDisabled(false); setHasChanges(false); - revalidator.revalidate(); + await revalidator.revalidate(); return setNotifications({ type: 'success', text: Filters saved }); }; diff --git a/app/react/V2/Routes/Settings/Filters/components/FiltersSidepanel.tsx b/app/react/V2/Routes/Settings/Filters/components/FiltersSidepanel.tsx index 3421cd5aef..f6a6f4339d 100644 --- a/app/react/V2/Routes/Settings/Filters/components/FiltersSidepanel.tsx +++ b/app/react/V2/Routes/Settings/Filters/components/FiltersSidepanel.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useForm, Controller } from 'react-hook-form'; import { useAtomValue } from 'jotai'; -import { useLoaderData } from 'react-router-dom'; +import { useLoaderData } from 'react-router'; import uniqueID from 'shared/uniqueID'; import { Translate } from 'app/I18N'; import { ClientTemplateSchema } from 'app/istore'; diff --git a/app/react/V2/Routes/Settings/IX/IXDashboard.tsx b/app/react/V2/Routes/Settings/IX/IXDashboard.tsx index 214dce49ae..44c5d4b296 100644 --- a/app/react/V2/Routes/Settings/IX/IXDashboard.tsx +++ b/app/react/V2/Routes/Settings/IX/IXDashboard.tsx @@ -1,7 +1,7 @@ /* eslint-disable max-statements */ import React, { useMemo, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { useSetAtom } from 'jotai'; import * as extractorsAPI from 'app/V2/api/ix/extractors'; import * as templatesAPI from 'V2/api/templates'; @@ -71,7 +71,7 @@ const IXDashboard = () => { try { await extractorsAPI.remove(extractorIds); - revalidator.revalidate(); + await revalidator.revalidate(); setNotifications({ type: 'success', text: Extractor/s deleted, @@ -92,7 +92,7 @@ const IXDashboard = () => { try { await extractorsAPI.save(extractor); - revalidator.revalidate(); + await revalidator.revalidate(); setNotifications({ type: 'success', text: Saved successfully., diff --git a/app/react/V2/Routes/Settings/IX/IXSuggestions.tsx b/app/react/V2/Routes/Settings/IX/IXSuggestions.tsx index e71a3c7ec6..6088d97da0 100644 --- a/app/react/V2/Routes/Settings/IX/IXSuggestions.tsx +++ b/app/react/V2/Routes/Settings/IX/IXSuggestions.tsx @@ -9,7 +9,7 @@ import { useNavigate, useRevalidator, useSearchParams, -} from 'react-router-dom'; +} from 'react-router'; import { SortingState } from '@tanstack/react-table'; import { useSetAtom } from 'jotai'; import * as extractorsAPI from 'app/V2/api/ix/extractors'; @@ -124,10 +124,10 @@ const IXSuggestions = () => { useEffect(() => { socket.on( 'ix_model_status', - (extractorId: string, modelStatus: string, _: string, data: any) => { + async (extractorId: string, modelStatus: string, _: string, data: any) => { if (extractorId === extractor._id) { setStatus({ status: modelStatus as ixStatus, data }); - revalidate(); + await revalidate(); if ((data && data.total === data.processed) || modelStatus === 'ready') { setStatus({ status: 'ready' }); } @@ -145,8 +145,10 @@ const IXSuggestions = () => { }, [aggregation]); useEffect(() => { + const navigatePromise = async (path: string) => navigate(path, { replace: true }); + if (searchParams.has('sort') && !sorting.length) { - navigate(location.pathname, { replace: true }); + navigatePromise(location.pathname).catch(_e => {}); } if (sorting.length && sorting[0].id) { @@ -158,9 +160,9 @@ const IXSuggestions = () => { const order = sorting[0].desc ? 'desc' : 'asc'; - navigate(`${location.pathname}?sort={"property":"${_property}","order":"${order}"}`, { - replace: true, - }); + navigatePromise( + `${location.pathname}?sort={"property":"${_property}","order":"${order}"}` + ).catch(_e => {}); } }, [sorting]); @@ -225,7 +227,7 @@ const IXSuggestions = () => { } else { setStatus({ status: 'cancel' }); } - revalidate(); + await revalidate(); } } catch (error) {} }; diff --git a/app/react/V2/Routes/Settings/IX/components/FiltersSidepanel.tsx b/app/react/V2/Routes/Settings/IX/components/FiltersSidepanel.tsx index 8f96df6399..3d20ab8224 100644 --- a/app/react/V2/Routes/Settings/IX/components/FiltersSidepanel.tsx +++ b/app/react/V2/Routes/Settings/IX/components/FiltersSidepanel.tsx @@ -6,7 +6,7 @@ import { Translate } from 'app/I18N'; import { Button, Card, Sidepanel } from 'V2/Components/UI'; import { Checkbox } from 'app/V2/Components/Forms'; import { useForm } from 'react-hook-form'; -import { useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router'; interface FiltersSidepanelProps { showSidepanel: boolean; diff --git a/app/react/V2/Routes/Settings/IX/components/SuggestedValue.tsx b/app/react/V2/Routes/Settings/IX/components/SuggestedValue.tsx index 25dbee9c36..7a044f3a63 100644 --- a/app/react/V2/Routes/Settings/IX/components/SuggestedValue.tsx +++ b/app/react/V2/Routes/Settings/IX/components/SuggestedValue.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useParams } from 'react-router-dom'; +import { useParams } from 'react-router'; import { usePopper } from 'react-popper'; import { useAtomValue } from 'jotai'; import { Popover } from '@headlessui/react'; diff --git a/app/react/V2/Routes/Settings/IX/components/TableElements.tsx b/app/react/V2/Routes/Settings/IX/components/TableElements.tsx index ff249a3d71..63e46fc655 100644 --- a/app/react/V2/Routes/Settings/IX/components/TableElements.tsx +++ b/app/react/V2/Routes/Settings/IX/components/TableElements.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; import { Cell, CellContext, Row, createColumnHelper } from '@tanstack/react-table'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { CheckCircleIcon } from '@heroicons/react/24/outline'; import { Translate } from 'app/I18N'; import { Button, Pill } from 'V2/Components/UI'; diff --git a/app/react/V2/Routes/Settings/Languages/LanguagesList.tsx b/app/react/V2/Routes/Settings/Languages/LanguagesList.tsx index d122a99742..96025c7027 100644 --- a/app/react/V2/Routes/Settings/Languages/LanguagesList.tsx +++ b/app/react/V2/Routes/Settings/Languages/LanguagesList.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { useLoaderData, LoaderFunction } from 'react-router-dom'; +import { useLoaderData, LoaderFunction } from 'react-router'; import { useAtomValue } from 'jotai'; import { intersectionBy, keyBy, merge, values } from 'lodash'; import { Row, createColumnHelper } from '@tanstack/react-table'; diff --git a/app/react/V2/Routes/Settings/MenuConfig/MenuConfig.tsx b/app/react/V2/Routes/Settings/MenuConfig/MenuConfig.tsx index b6412639ad..c44d65a4d3 100644 --- a/app/react/V2/Routes/Settings/MenuConfig/MenuConfig.tsx +++ b/app/react/V2/Routes/Settings/MenuConfig/MenuConfig.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useState, useRef, useEffect } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator, useBlocker } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator, useBlocker } from 'react-router'; import { Row, RowSelectionState } from '@tanstack/react-table'; import { useSetAtom } from 'jotai'; import { cloneDeep, isEqual } from 'lodash'; @@ -69,7 +69,7 @@ const MenuConfig = () => { const save = async () => { const settings = await SettingsAPI.saveLinks(linkState.map(sanitizeIds)); setSettings(settings); - revalidator.revalidate(); + await revalidator.revalidate(); setNotifications({ type: 'success', text: Updated, diff --git a/app/react/V2/Routes/Settings/Pages/PageEditor.tsx b/app/react/V2/Routes/Settings/Pages/PageEditor.tsx index 0c96a21739..a4a1db5fb2 100644 --- a/app/react/V2/Routes/Settings/Pages/PageEditor.tsx +++ b/app/react/V2/Routes/Settings/Pages/PageEditor.tsx @@ -10,7 +10,7 @@ import { useLoaderData, useNavigate, useRevalidator, -} from 'react-router-dom'; +} from 'react-router'; import { useForm } from 'react-hook-form'; import { useSetAtom } from 'jotai'; import { debounce } from 'lodash'; @@ -83,13 +83,13 @@ const PageEditor = () => { }); }; - const handleRevalidate = (response: Page) => { + const handleRevalidate = async (response: Page) => { if (!page.sharedId) { - navigate(`/${response.language}/settings/pages/page/${response.sharedId}`, { + await navigate(`/${response.language}/settings/pages/page/${response.sharedId}`, { replace: true, }); } else { - revalidator.revalidate(); + await revalidator.revalidate(); } }; @@ -106,7 +106,7 @@ const PageEditor = () => { notify(response); if (!hasErrors) { - handleRevalidate(response); + await handleRevalidate(response); } }; @@ -119,7 +119,7 @@ const PageEditor = () => { if (!hasErrors) { const pageUrl = getPageUrl(response.sharedId!, response.title); window.open(`${window.location.origin}/${pageUrl}`); - handleRevalidate(response); + await handleRevalidate(response); } }; diff --git a/app/react/V2/Routes/Settings/Pages/PagesList.tsx b/app/react/V2/Routes/Settings/Pages/PagesList.tsx index 860927c1d1..8f16613b50 100644 --- a/app/react/V2/Routes/Settings/Pages/PagesList.tsx +++ b/app/react/V2/Routes/Settings/Pages/PagesList.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-multi-comp */ import React, { useState } from 'react'; -import { Link, LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { Link, LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { createColumnHelper } from '@tanstack/react-table'; import { IncomingHttpHeaders } from 'http'; import { useSetAtom } from 'jotai'; @@ -55,7 +55,7 @@ const PagesList = () => { ); const hasErrors = result.find(res => res instanceof FetchResponseError) !== undefined; setNotifications(deletionNotification(hasErrors)); - revalidator.revalidate(); + await revalidator.revalidate(); }; const columns = [ diff --git a/app/react/V2/Routes/Settings/Pages/components/PageEditorComponents.tsx b/app/react/V2/Routes/Settings/Pages/components/PageEditorComponents.tsx index 660ec9b3f7..1857df2957 100644 --- a/app/react/V2/Routes/Settings/Pages/components/PageEditorComponents.tsx +++ b/app/react/V2/Routes/Settings/Pages/components/PageEditorComponents.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { InformationCircleIcon, ExclamationTriangleIcon } from '@heroicons/react/20/solid'; import { Translate } from 'app/I18N'; diff --git a/app/react/V2/Routes/Settings/Pages/components/PageListTable.tsx b/app/react/V2/Routes/Settings/Pages/components/PageListTable.tsx index c18637a126..9193597d2b 100644 --- a/app/react/V2/Routes/Settings/Pages/components/PageListTable.tsx +++ b/app/react/V2/Routes/Settings/Pages/components/PageListTable.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { kebabCase } from 'lodash'; import { CellContext } from '@tanstack/react-table'; import { Button, Pill } from 'app/V2/Components/UI'; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/PXEntities.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/PXEntities.tsx index e6104a2522..33e56c89f4 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/PXEntities.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/PXEntities.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData } from 'react-router-dom'; +import { LoaderFunction, useLoaderData } from 'react-router'; import * as pxEntitiesApi from 'app/V2/api/paragraphExtractor/entities'; import { SettingsContent } from 'V2/Components/Layouts/SettingsContent'; import { Table } from 'V2/Components/UI'; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/PXParagraphs.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/PXParagraphs.tsx index 6a2589214a..7c73faa5d3 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/PXParagraphs.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/PXParagraphs.tsx @@ -1,16 +1,15 @@ import React, { useEffect, useMemo, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData } from 'react-router-dom'; +import { LoaderFunction, useLoaderData } from 'react-router'; import { useAtomValue } from 'jotai'; import { LanguageSchema } from 'shared/types/commonTypes'; +import { Translate, I18NApi } from 'app/I18N'; import { Template } from 'app/apiResponseTypes'; -import { I18NApi } from 'app/I18N'; import { RequestParams } from 'app/utils/RequestParams'; import * as pxParagraphApi from 'V2/api/paragraphExtractor/paragraphs'; import { SettingsContent } from 'V2/Components/Layouts/SettingsContent'; import { Table, Button } from 'V2/Components/UI'; import { Sidepanel } from 'V2/Components/UI/Sidepanel'; -import { Translate } from 'app/I18N'; import { templatesAtom } from 'V2/atoms'; import { tableBuilder } from './components/PXParagraphTableElements'; import { TableTitle } from './components/TableTitle'; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/ParagraphExtraction.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/ParagraphExtraction.tsx index ce73466cb3..37530642bf 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/ParagraphExtraction.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/ParagraphExtraction.tsx @@ -1,7 +1,7 @@ /* eslint-disable max-statements */ import React, { useMemo, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import * as extractorsAPI from 'app/V2/api/paragraphExtractor/extractors'; import { SettingsContent } from 'V2/Components/Layouts/SettingsContent'; import { Button, Table, ConfirmationModal } from 'V2/Components/UI'; @@ -52,7 +52,7 @@ const ParagraphExtractorDashboard = () => { try { await extractorsAPI.remove(extractorIds); - revalidator.revalidate(); + await revalidator.revalidate(); setNotifications({ type: 'success', text: Extractor/s deleted, @@ -69,7 +69,7 @@ const ParagraphExtractorDashboard = () => { }; const handleSave = async () => { - revalidator.revalidate(); + await revalidator.revalidate(); setNotifications({ type: 'success', text: Paragraph Extractor added, diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/components/ExtractorModal.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/components/ExtractorModal.tsx index 05221b45c7..a5e49012c7 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/components/ExtractorModal.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/components/ExtractorModal.tsx @@ -8,7 +8,7 @@ import { Translate } from 'app/I18N'; import { Template } from 'app/apiResponseTypes'; import { ParagraphExtractorApiPayload } from '../types'; import { NoQualifiedTemplatesMessage } from './NoQualifiedTemplate'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; interface ExtractorModalProps { setShowModal: React.Dispatch>; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXEntityTableElements.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXEntityTableElements.tsx index f3ab7a235d..080cc70351 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXEntityTableElements.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXEntityTableElements.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; import { CellContext, createColumnHelper } from '@tanstack/react-table'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Translate } from 'app/I18N'; import { Button, Pill } from 'V2/Components/UI'; import { PXEntityTable } from '../types'; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXTableElements.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXTableElements.tsx index 34f1907aeb..2a3635cc05 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXTableElements.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/components/PXTableElements.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/no-multi-comp */ import React from 'react'; import { CellContext, createColumnHelper } from '@tanstack/react-table'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Translate } from 'app/I18N'; import { Button, Pill } from 'V2/Components/UI'; import { PXTable } from '../types'; diff --git a/app/react/V2/Routes/Settings/ParagraphExtraction/components/ViewParagraph.tsx b/app/react/V2/Routes/Settings/ParagraphExtraction/components/ViewParagraph.tsx index b76a9d50d5..8bcedb4b4b 100644 --- a/app/react/V2/Routes/Settings/ParagraphExtraction/components/ViewParagraph.tsx +++ b/app/react/V2/Routes/Settings/ParagraphExtraction/components/ViewParagraph.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Translate } from 'app/I18N'; import { PXParagraphTable } from '../types'; import { DisplayPills } from './DisplayPills'; diff --git a/app/react/V2/Routes/Settings/RelationshipTypes/RelationshipTypes.tsx b/app/react/V2/Routes/Settings/RelationshipTypes/RelationshipTypes.tsx index 284edc3479..7e12ccf877 100644 --- a/app/react/V2/Routes/Settings/RelationshipTypes/RelationshipTypes.tsx +++ b/app/react/V2/Routes/Settings/RelationshipTypes/RelationshipTypes.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useEffect, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { Row } from '@tanstack/react-table'; import { useSetAtom, useAtomValue } from 'jotai'; import { Translate } from 'app/I18N'; @@ -86,7 +86,7 @@ const RelationshipTypes = () => { }); setIsSidepanelOpen(false); } - revalidator.revalidate(); + await revalidator.revalidate(); setRelationshipTypes(relationshipTypes); }; @@ -106,7 +106,7 @@ const RelationshipTypes = () => { }); setShowConfirmationModal(false); } - revalidator.revalidate(); + await revalidator.revalidate(); setRelationshipTypes(relationshipTypes); }; diff --git a/app/react/V2/Routes/Settings/Thesauri/EditThesaurus.tsx b/app/react/V2/Routes/Settings/Thesauri/EditThesaurus.tsx index f4bc769f75..eb4e4b2c07 100644 --- a/app/react/V2/Routes/Settings/Thesauri/EditThesaurus.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/EditThesaurus.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/jsx-props-no-spreading */ import React, { useCallback, useMemo, useState } from 'react'; -import { Location, useBlocker, useLoaderData, useNavigate } from 'react-router-dom'; +import { Location, useBlocker, useLoaderData, useNavigate } from 'react-router'; import { useForm } from 'react-hook-form'; import { useAtomValue, useSetAtom } from 'jotai'; import { Row } from '@tanstack/react-table'; @@ -168,13 +168,13 @@ const EditThesaurus = () => { }} disabled={isEmpty(getValues().name)} getThesaurus={getCurrentStatus} - onSuccess={(savedThesaurus: ThesaurusSchema) => { + onSuccess={async (savedThesaurus: ThesaurusSchema) => { setValue('_id', savedThesaurus._id); setNotifications({ type: 'success', text: Thesauri updated., }); - navigate(`../edit/${savedThesaurus._id}`); + await navigate(`../edit/${savedThesaurus._id}`); setIsImporting(false); }} onFailure={() => { diff --git a/app/react/V2/Routes/Settings/Thesauri/ThesauriList.tsx b/app/react/V2/Routes/Settings/Thesauri/ThesauriList.tsx index 777def9121..34d3fce905 100644 --- a/app/react/V2/Routes/Settings/Thesauri/ThesauriList.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/ThesauriList.tsx @@ -1,6 +1,6 @@ import React, { useMemo, useState } from 'react'; import { IncomingHttpHeaders } from 'http'; -import { Link, LoaderFunction, useLoaderData, useRevalidator } from 'react-router-dom'; +import { Link, LoaderFunction, useLoaderData, useRevalidator } from 'react-router'; import { useSetAtom, useAtomValue } from 'jotai'; import { Translate } from 'app/I18N'; import ThesauriAPI from 'app/V2/api/thesauri'; @@ -62,7 +62,7 @@ const ThesauriList = () => { text: e.message, }); } finally { - revalidator.revalidate(); + await revalidator.revalidate(); setShowConfirmationModal(false); } }; diff --git a/app/react/V2/Routes/Settings/Thesauri/ThesaurusForm.tsx b/app/react/V2/Routes/Settings/Thesauri/ThesaurusForm.tsx index 6ebf60c14c..1959914ff0 100644 --- a/app/react/V2/Routes/Settings/Thesauri/ThesaurusForm.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/ThesaurusForm.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; -import { useNavigate, useRevalidator } from 'react-router-dom'; +import { useNavigate, useRevalidator } from 'react-router'; import { SubmitHandler, UseFormReturn } from 'react-hook-form'; import { useAtom, useSetAtom } from 'jotai'; import { isEqual, remove } from 'lodash'; @@ -43,11 +43,11 @@ const ThesaurusForm = ({ const [thesauri, setThesauri] = useAtom(thesauriAtom); const setNotifications = useSetAtom(notificationAtom); - const handleRevalidate = (savedThesaurus: ClientThesaurus) => { + const handleRevalidate = async (savedThesaurus: ClientThesaurus) => { if (!thesaurus?._id) { - navigate(`../edit/${savedThesaurus._id}`); + await navigate(`../edit/${savedThesaurus._id}`); } else { - revalidator.revalidate(); + await revalidator.revalidate(); } }; @@ -68,7 +68,7 @@ const ThesaurusForm = ({ Thesauri added. ), }); - handleRevalidate(savedThesaurus); + await handleRevalidate(savedThesaurus); }; const formSubmit: SubmitHandler = async data => { diff --git a/app/react/V2/Routes/Settings/Thesauri/components/ThesauriTable.tsx b/app/react/V2/Routes/Settings/Thesauri/components/ThesauriTable.tsx index a158f2fd1a..90cce92a4f 100644 --- a/app/react/V2/Routes/Settings/Thesauri/components/ThesauriTable.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/components/ThesauriTable.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router'; import { Row } from '@tanstack/react-table'; import { Translate } from 'app/I18N'; import { Table } from 'V2/Components/UI'; @@ -21,8 +21,8 @@ interface ThesauriTableProps { const ThesauriTable = ({ currentThesauri, setSelectedThesauri }: ThesauriTableProps) => { const navigate = useNavigate(); - const navigateToEditThesaurus = (thesaurus: Row) => { - navigate(`./edit/${thesaurus.original._id}`); + const navigateToEditThesaurus = async (thesaurus: Row) => { + await navigate(`./edit/${thesaurus.original._id}`); }; return ( diff --git a/app/react/V2/Routes/Settings/Thesauri/components/ThesaurusActions.tsx b/app/react/V2/Routes/Settings/Thesauri/components/ThesaurusActions.tsx index 352c618f3e..f18a032245 100644 --- a/app/react/V2/Routes/Settings/Thesauri/components/ThesaurusActions.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/components/ThesaurusActions.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-multi-comp */ import React, { Dispatch, SetStateAction } from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Translate } from 'app/I18N'; import { Button, ConfirmationModal } from 'app/V2/Components/UI'; import { ConfirmationCallback } from '../helpers'; diff --git a/app/react/V2/Routes/Settings/Thesauri/helpers.ts b/app/react/V2/Routes/Settings/Thesauri/helpers.ts index 0b62859fa3..a005f5fdf6 100644 --- a/app/react/V2/Routes/Settings/Thesauri/helpers.ts +++ b/app/react/V2/Routes/Settings/Thesauri/helpers.ts @@ -1,5 +1,5 @@ import { SetStateAction } from 'react'; -import { LoaderFunction } from 'react-router-dom'; +import { LoaderFunction } from 'react-router'; import { IncomingHttpHeaders } from 'http'; import { Row, RowSelectionState } from '@tanstack/react-table'; import { assign, isEqual, orderBy, remove } from 'lodash'; diff --git a/app/react/V2/Routes/Settings/Thesauri/specs/Thesauri.spec.tsx b/app/react/V2/Routes/Settings/Thesauri/specs/Thesauri.spec.tsx index 571d27efaa..3b9c701f5f 100644 --- a/app/react/V2/Routes/Settings/Thesauri/specs/Thesauri.spec.tsx +++ b/app/react/V2/Routes/Settings/Thesauri/specs/Thesauri.spec.tsx @@ -13,7 +13,7 @@ import { render, cleanup, } from '@testing-library/react/pure'; -import { createMemoryRouter, RouterProvider } from 'react-router-dom'; +import { createMemoryRouter, RouterProvider } from 'react-router'; import { has } from 'lodash'; import { templatesAtom } from 'V2/atoms'; import { TestAtomStoreProvider } from 'V2/testing'; diff --git a/app/react/V2/Routes/Settings/Thesauri/specs/__snapshots__/Thesauri.spec.tsx.snap b/app/react/V2/Routes/Settings/Thesauri/specs/__snapshots__/Thesauri.spec.tsx.snap index 32324de5e0..f4b305451f 100644 --- a/app/react/V2/Routes/Settings/Thesauri/specs/__snapshots__/Thesauri.spec.tsx.snap +++ b/app/react/V2/Routes/Settings/Thesauri/specs/__snapshots__/Thesauri.spec.tsx.snap @@ -664,23 +664,6 @@ exports[`Settings Thesauri ThesauriList render existing thesauri should show a l - -