Skip to content
This repository has been archived by the owner on Jan 16, 2025. It is now read-only.

Commit

Permalink
Support both react-router-dom v5 history and v6 navigate
Browse files Browse the repository at this point in the history
Change-type: minor
  • Loading branch information
myarmolinsky committed Jan 2, 2025
1 parent 000fef0 commit 3ce7f12
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 40 deletions.
61 changes: 43 additions & 18 deletions src/AutoUI/Filters/PersistentFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import qs from 'qs';
import type { JSONSchema7 as JSONSchema } from 'json-schema';
import type { History } from 'history';
import type { FiltersProps } from '../../components/Filters';
import { Filters } from '../../components/Filters';
import type { FilterDescription } from '../../components/Filters/SchemaSieve';
Expand All @@ -13,7 +12,6 @@ import {
} from '../../components/Filters/SchemaSieve';
import { isJSONSchema } from '../../AutoUI/schemaOps';
import { useAnalyticsContext } from '@balena/ui-shared-components';
import { useLocation } from 'react-router';

export interface ListQueryStringFilterObject {
n: string;
Expand Down Expand Up @@ -52,15 +50,15 @@ export function listFilterQuery(filters: JSONSchema[], stringify = true) {
filter.title === FULL_TEXT_SLUG
? [parseFilterDescription(filter)].filter(
(f): f is FilterDescription => !!f,
)
)
: filter.anyOf
?.filter((f): f is JSONSchema => isJSONSchema(f))
.map(
(f) =>
({
...parseFilterDescription(f),
operatorSlug: f.title,
}) as FilterDescription & { operatorSlug?: string },
} as FilterDescription & { operatorSlug?: string }),
)
.filter((f) => !!f);

Expand All @@ -80,14 +78,14 @@ export function listFilterQuery(filters: JSONSchema[], stringify = true) {
return stringify
? qs.stringify(queryStringFilters, {
strictNullHandling: true,
})
})
: queryStringFilters;
}

export const loadRulesFromUrl = (
searchLocation: string,
schema: JSONSchema,
history: History,
history: unknown,
): JSONSchema[] => {
const { properties } = schema;
if (!searchLocation || !properties) {
Expand Down Expand Up @@ -158,7 +156,18 @@ export const loadRulesFromUrl = (

// In case of invalid signatures, remove search params to avoid Errors.
if (isSignaturesInvalid) {
history.replace({ search: '' });
if (
history != null &&
typeof history === 'object' &&
'replace' in history &&
typeof history.replace === 'function'
) {
// react-router-dom v5 history object
history?.replace?.({ search: '' });
} else if (typeof history === 'function') {
// react-router-dom v6 navigate function
history({ search: '' }, { replace: true });
}
return;
}

Expand All @@ -181,7 +190,7 @@ export const loadRulesFromUrl = (
};

interface PersistentFiltersProps extends FiltersProps {
history: History;
history: unknown;
}

export const PersistentFilters = ({
Expand All @@ -196,11 +205,10 @@ export const PersistentFilters = ({
}: PersistentFiltersProps &
Required<Pick<PersistentFiltersProps, 'renderMode'>>) => {
const { state: analytics } = useAnalyticsContext();
const { pathname } = useLocation();
const locationSearch = history?.location?.search ?? '';
const { pathname, search } = document.location;
const storedFilters = React.useMemo(() => {
return loadRulesFromUrl(locationSearch, schema, history);
}, [locationSearch, schema, history]);
return loadRulesFromUrl(search, schema, history);
}, [schema, history]);

const onFiltersUpdate = React.useCallback(
(updatedFilters: JSONSchema[]) => {
Expand All @@ -210,22 +218,39 @@ export const PersistentFilters = ({
strictNullHandling: true,
});

history?.replace?.({
pathname,
search: filterQuery,
});
if (
history != null &&
typeof history === 'object' &&
'replace' in history &&
typeof history.replace === 'function'
) {
// react-router-dom v5 history object
history.replace({
pathname,
search: filterQuery,
});
} else if (typeof history === 'function') {
// react-router-dom v6 navigate function
history(
{
pathname,
search: filterQuery,
},
{ replace: true },
);
}

onFiltersChange?.(updatedFilters);

if (filterQuery !== locationSearch.substring(1)) {
if (filterQuery !== search.substring(1)) {
analytics.webTracker?.track('Update table filters', {
current_url: location.origin + location.pathname,
// Need to reduce to a nested object instead of nested array for Amplitude to pick up on the property
filters: Object.assign({}, parsedFilters),
});
}
},
[onFiltersChange, analytics.webTracker, history, locationSearch, pathname],
[onFiltersChange, analytics.webTracker, history],
);

// When the component mounts, filters from the page URL,
Expand Down
38 changes: 24 additions & 14 deletions src/AutoUI/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export const AutoUI = <T extends AutoUIBaseResource<T>>({
$skip: page * itemsPerPage,
},
(v) => v != null,
)
)
: null;
setInternalPineFilter(pineFilter);
onChange?.({
Expand Down Expand Up @@ -284,7 +284,7 @@ export const AutoUI = <T extends AutoUIBaseResource<T>>({
...oldState,
affectedEntries: items,
checkedState: newCheckedState,
}
}
: undefined,
);
},
Expand All @@ -295,8 +295,8 @@ export const AutoUI = <T extends AutoUIBaseResource<T>>({
const totalItems = serverSide
? pagination.totalItems
: Array.isArray(data)
? data.length
: undefined;
? data.length
: undefined;

const hideUtils = React.useMemo(
() =>
Expand Down Expand Up @@ -367,7 +367,17 @@ export const AutoUI = <T extends AutoUIBaseResource<T>>({
const url = new URL(getBaseUrl(row));
window.open(url.toString(), '_blank');
} catch {
history.push?.(getBaseUrl(row));
if (
typeof history === 'object' &&
'push' in history &&
typeof history.push === 'function'
) {
// react-router-dom v5 history object
history.push(getBaseUrl(row));
} else if (typeof history === 'function') {
// react-router-dom v6 navigate function
history(getBaseUrl(row));
}
}
}
},
Expand Down Expand Up @@ -407,7 +417,7 @@ export const AutoUI = <T extends AutoUIBaseResource<T>>({
sdkTags,
t,
),
}
}
: null;

return {
Expand Down Expand Up @@ -754,8 +764,8 @@ const hasPropertyEnabled = (
return Array.isArray(value) && value.some((v) => v === propertyKey)
? true
: typeof value === 'boolean'
? true
: false;
? true
: false;
};

const getColumnsFromSchema = <T extends AutoUIBaseResource<T>>({
Expand Down Expand Up @@ -827,10 +837,10 @@ const getColumnsFromSchema = <T extends AutoUIBaseResource<T>>({
)
? 'primary'
: definedPriorities.secondary.find(
(prioritizedKey) => prioritizedKey === key,
)
? 'secondary'
: 'tertiary';
(prioritizedKey) => prioritizedKey === key,
)
? 'secondary'
: 'tertiary';

const widgetSchema = { ...val, title: undefined };
// TODO: Refactor this logic to create an object structure and retrieve the correct property using the refScheme.
Expand Down Expand Up @@ -869,8 +879,8 @@ const getColumnsFromSchema = <T extends AutoUIBaseResource<T>>({
xNoSort || val.format === 'tag'
? false
: typeof fieldCustomSort === 'function'
? fieldCustomSort
: getSortingFunction<T>(key, val),
? fieldCustomSort
: getSortingFunction<T>(key, val),
render: (fieldVal: string, entry: T) => {
const calculatedField = autoUIAdaptRefScheme(fieldVal, val);
return (
Expand Down
13 changes: 12 additions & 1 deletion src/AutoUIApp/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,18 @@ export const Content = ({ openApiJson, openActionSidebar }: ContentProps) => {
data={memoizedData}
{...(!endsWithValidId && {
onEntityClick: (entity) => {
history.push(`${pathname}/${entity.id}`);
if (
history != null &&
typeof history === 'object' &&
'push' in history &&
typeof history.push === 'function'
) {
// react-router-dom v5 history object
history.push(`${pathname}/${entity.id}`);
} else if (typeof history === 'function') {
// react-router-dom v6 navigate function
history(`${pathname}/${entity.id}`);
}
},
})}
/>
Expand Down
17 changes: 14 additions & 3 deletions src/AutoUIApp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Navbar } from './Navbar';
import { Sidebar } from './Sidebar';
import { Router, Switch, Route } from 'react-router-dom';
import { Router, Switch, Route, BrowserRouter } from 'react-router-dom';
import { Content } from './Content';
import { createGlobalStyle } from 'styled-components';
import type { OpenApiJson } from './openApiJson';
Expand All @@ -11,6 +11,7 @@ import { Provider } from 'rendition';
import { useHistory } from '../hooks/useHistory';
import { Material } from '@balena/ui-shared-components';
import { useClickOutsideOrEsc } from '../hooks/useClickOutsideOrEsc';
import { History } from 'history';
const { Box } = Material;

const SIDEBAR_WIDTH = 166;
Expand Down Expand Up @@ -56,9 +57,19 @@ export const AutoUIApp = ({ openApiJson, title, logo }: AutoUIAppProps) => {
'openApiJson'
> | null>();

const RouterComponent = React.useCallback(
({ children }: { children: Array<JSX.Element> }) =>
typeof history === 'object' ? (
<Router history={history as History}>{children}</Router>
) : (
<BrowserRouter>{children}</BrowserRouter>
),
[history],
);

return (
<Provider>
<Router history={history}>
<RouterComponent>
<GlobalStyle />
<Navbar height={NAVBAR_HEIGHT} title={title} logo={logo} />
<Box sx={{ display: 'flex', position: 'relative' }}>
Expand Down Expand Up @@ -106,7 +117,7 @@ export const AutoUIApp = ({ openApiJson, title, logo }: AutoUIAppProps) => {
</Box>
)}
</Box>
</Router>
</RouterComponent>
</Provider>
);
};
12 changes: 11 additions & 1 deletion src/components/Filters/FocusSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,17 @@ export const FocusSearch = <T extends { id: number; [key: string]: any }>({
const url = new URL(autouiContext.getBaseUrl(entity));
window.open(url.toString(), '_blank');
} catch {
history.push?.(autouiContext.getBaseUrl(entity));
if (
typeof history === 'object' &&
'push' in history &&
typeof history.push === 'function'
) {
// react-router-dom v5 history object
history.push(autouiContext.getBaseUrl(entity));
} else if (typeof history === 'function') {
// react-router-dom v6 navigate function
history(autouiContext.getBaseUrl(entity));
}
}
}
}}
Expand Down
5 changes: 2 additions & 3 deletions src/contexts/ContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import type { History } from 'history';
import { createContext } from 'react';
import type { Dictionary } from '../common';
import type { TFunction } from '../hooks/useTranslation';
export interface ContextProviderInterface {
history: History;
history: unknown;
t?: TFunction;
externalTranslationMap?: Dictionary<string>;
}

export const ContextProvider = createContext<ContextProviderInterface>({
history: {} as History,
history: {},
});

0 comments on commit 3ce7f12

Please sign in to comment.