Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

ARTESCA-13970 // Migration to React 18 #799

Merged
merged 8 commits into from
Jan 17, 2025
325 changes: 173 additions & 152 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@
"@storybook/storybook-deployer": "^2.8.16",
"@storybook/theming": "^8.3.6",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/react": "^15.0.7",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.0",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3",
"@types/react-table": "^7.7.11",
Expand Down Expand Up @@ -110,16 +110,17 @@
"framer-motion": "^4.1.17",
"polished": "3.4.1",
"pretty-bytes": "^5.6.0",
"react": "^17.0.2",
"react": "^18.3.1",
"react-debounce-input": "3.2.2",
"react-dom": "^17.0.2",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.49.2",
"react-query": "^3.34.0",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
"react-router": "7.0.1",
"react-router-dom": "7.0.1",
"react-select": "4.3.1",
"react-table": "^7.7.0",
"react-test-renderer": "^18.3.1",
"react-virtualized": "9.22.3",
"react-virtualized-auto-sizer": "^1.0.24",
"react-window": "^1.8.6",
Expand Down
4 changes: 4 additions & 0 deletions setupTests.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import 'jest-canvas-mock';
import '@testing-library/jest-dom/extend-expect';
import 'regenerator-runtime/runtime';

import { TextEncoder, TextDecoder } from 'util';

Object.assign(global, { TextDecoder, TextEncoder });
6 changes: 3 additions & 3 deletions src/lib/components/emptystate/Emptystate.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Button } from '../buttonv2/Buttonv2.component';
import { Icon, IconName } from '../icon/Icon.component';
import { LargeText } from '../text/Text.component';
import { CoreUITheme } from '../../style/theme';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';

export type Props = {
listedResource: {
Expand Down Expand Up @@ -48,7 +48,7 @@ export const ActionWrapper = styled.div`
function EmptyState(props: Props) {
const { icon, listedResource, link, resourceToCreate, backgroundColor } =
props;
const history = useHistory();
const navigate = useNavigate();
return (
<EmptystateContainer
className="sc-emptystate"
Expand All @@ -74,7 +74,7 @@ function EmptyState(props: Props) {
icon={<Icon name="Create-add" />}
type="button"
variant="primary"
onClick={() => history.push(link)}
onClick={() => navigate(link)}
/>
</ActionWrapper>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/inputlist/InputList.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Input } from '../inputv2/inputv2';
import { AddButton, SubButton } from './InputButtons';

export type InputListProps<T> = Omit<HTMLProps<HTMLInputElement>, 'size'> & {
ref: RefCallBack;
ref?: RefCallBack;
min?: string | number;
max?: string | number;
maxLength?: number;
Expand Down
12 changes: 6 additions & 6 deletions src/lib/components/linetemporalchart/MetricTimespanProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react';
import { useEffect, useState, createContext, useContext } from 'react';
import { useLocation } from 'react-router-dom';
import { QueryTimeSpan } from '../constants';
import { queryTimeSpansCodes } from '../constants';
import { createContext, useContext, useEffect, useState } from 'react';
import { QueryTimeSpan, queryTimeSpansCodes } from '../constants';
import { useLocation } from 'react-router';
export const MetricsTimeSpanContext = createContext<QueryTimeSpan | null>(null);
export const MetricsTimeSpanProvider = ({
children,
location,
}: {
children: JSX.Element;
location?: ReturnType<typeof useLocation>;
}) => {
// the default timespan is the last 24h
const [queryTimeSpanCode, setQueryTimeSpanCode] = useState(
queryTimeSpansCodes[1],
);
const urlSearchParams = new URLSearchParams(useLocation().search);
const urlSearchParams = new URLSearchParams(location?.search);
const queryTimeSpan = urlSearchParams.get('from');
// Sync url timespan to local timespan
useEffect(() => {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/tablev2/SearchWithQueryParams.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router';
import { TableSearch as Search, SearchProps } from './Search';

export type SearchWithQueryParamsProps = {
Expand All @@ -10,15 +10,15 @@ export type SearchWithQueryParamsProps = {
export function SearchWithQueryParams(props: SearchWithQueryParamsProps) {
const { queryParams = 'search', onChange, ...rest } = props;
const { search, pathname } = useLocation();
const history = useHistory();
const navigate = useNavigate();
const params = new URLSearchParams(search);
const initialValue = params.get(queryParams) || '';
const [value, setValue] = useState(initialValue);

function handleOnChange(value: string) {
const { onChange } = props;
params.set(queryParams, value);
history.replace(`${pathname}?${params.toString()}`);
navigate(`${pathname}?${params.toString()}`, { replace: true });
setValue(value);

if (typeof onChange === 'function') {
Expand Down
4 changes: 3 additions & 1 deletion src/lib/components/tablev2/TableCommon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ type VirtualizedRowsType<
DATA_ROW extends Record<string, unknown> = Record<string, unknown>,
> = {
rows: Row<DATA_ROW>[];
RenderRow: ComponentType<ListChildComponentProps<Row<DATA_ROW>[]>>;
RenderRow: ComponentType<
React.PropsWithChildren<ListChildComponentProps<Row<DATA_ROW>[]>>
>;
rowHeight: TableHeightKeyType;
setHasScrollbar: React.Dispatch<React.SetStateAction<boolean>>;
hasScrollbar?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/tablev2/Tablev2.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ const DefaultRenderer = ({ value }) => {
rowHeight === 'h32'
? 1
: rowHeight === 'h40' || rowHeight === 'h48'
? 2
: 3;
? 2
: 3;
return (
<Box mr={4}>
<ConstrainedText text={value} lineClamp={lineClamp} />
Expand Down
120 changes: 64 additions & 56 deletions src/lib/components/tabsv2/Tabsv2.component.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import React, {
createContext,
ReactElement,
useCallback,
useEffect,
useState,
useCallback,
ReactElement,
} from 'react';
import {
TabBar,
matchPath,
Outlet,
Route,
Routes,
useLocation,
useNavigate,
useRoutes,
} from 'react-router';
import styled from 'styled-components';
import { ButtonIcon } from '../buttonv2/Buttonv2.component';
import { BasicText, EmphaseText, SecondaryText } from '../text/Text.component';
import { ScrollButton } from './ScrollButton';
import {
ScrollableContainer,
TabBar,
TabContent,
TabItem,
TabsContainer,
TabsScroller,
} from './StyledTabs';
import {
useHistory,
useLocation,
useRouteMatch,
matchPath,
Route,
Switch,
} from 'react-router-dom';
import { SecondaryText, BasicText, EmphaseText } from '../text/Text.component';
import { ScrollButton } from './ScrollButton';
import { Tab } from './Tab';
import { TabProps, Query } from './Tab';
import { Query, Tab, TabProps } from './Tab';
import { useScrollingTabs } from './useScrollingTabs';
import { ButtonIcon } from '../buttonv2/Buttonv2.component';
import styled from 'styled-components';

type TabsProps = {
activeTabColor?: string;
Expand Down Expand Up @@ -59,8 +59,8 @@ function Tabs({
...rest
}: TabsProps) {
const location = useLocation();
const history = useHistory();
const { url } = useRouteMatch();
const navigate = useNavigate();
const url = location.pathname;
const [selectedTabIndex, setSelectedTabIndex] = useState<
number | null | undefined
>(null);
Expand Down Expand Up @@ -101,24 +101,26 @@ function Tabs({
};

const getPushHistoryPath = (path: string, query?: Query): string => {
const sanitizedSegment = path.replace(/^\/+/, '');
const replaceUrl = location.pathname.replace(/[^/]+$/, sanitizedSegment);

if (path.startsWith('/')) {
return `${path}${serialize(query)}`;
return `${replaceUrl}${serialize(query)}`;
}
return `${url}/${path}${serialize(query)}`;

return `${path}${serialize(query)}`;
};

useEffect(() => {
let hasSelectedTab = false;
filteredTabsChildren.forEach((child, index) => {
const isSelected =
!!matchPath(location.pathname, {
path: child.props.path.startsWith('/')
!!matchPath(
(child.props.path.startsWith('/')
? child.props.path
: url + '/' + child.props.path,
exact: child.props.exact,
strict: child.props.strict,
sensitive: child.props.sensitive,
}) && (child.props.query ? matchQuery(child.props.query) : true);
: url + '/' + child.props.path) + '*',
location.pathname,
) && (child.props.query ? matchQuery(child.props.query) : true);

if (isSelected) {
setSelectedTabIndex(index);
Expand All @@ -127,6 +129,7 @@ function Tabs({
});
if (!hasSelectedTab) setSelectedTabIndex(null);
}, [location.pathname, filteredTabsChildren, matchQuery]);

const {
scrollButtonEndRef,
scrollButtonStartRef,
Expand All @@ -138,6 +141,7 @@ function Tabs({
handleKeyDown,
displayScroll,
} = useScrollingTabs(selectedTabIndex);

const tabItems = filteredTabsChildren.map((child, index) => {
const {
path,
Expand All @@ -149,12 +153,13 @@ function Tabs({
...childRest
}: TabProps = child.props;
const isSelected = selectedTabIndex === index;
const realPath = path.startsWith('/') ? `/${path.split('/').pop()}` : path;
return (
<TabItem
className={`sc-tabs-item ${isSelected ? 'selected' : ''}`}
key={index}
role="tab"
onClick={() => history.push(getPushHistoryPath(path, query))}
onClick={() => navigate(getPushHistoryPath(realPath, query))}
selected={isSelected}
tabHoverColor={tabHoverColor}
inactiveTabColor={inactiveTabColor}
Expand All @@ -168,7 +173,7 @@ function Tabs({
event.key === 'Spacebar'
) {
event.preventDefault();
history.push(getPushHistoryPath(path, query));
navigate(getPushHistoryPath(realPath, query));
}
}}
{...childRest}
Expand Down Expand Up @@ -218,38 +223,41 @@ function Tabs({
/>
)}
</ScrollableContainer>
<Routes>
{filteredTabsChildren.map((tab, index) => {
const path = tab.props.path.split('/').pop();

{filteredTabsChildren.map((tab, index) => (
<Route
exact={tab.props.exact}
sensitive={tab.props.sensitive}
strict={tab.props.strict}
path={
tab.props.path.startsWith('/')
? tab.props.path
: url + '/' + tab.props.path
if (tab.props.query && !matchQuery(tab.props.query)) {
return <></>;
}
key={index}
>
{!tab.props.query ||
(tab.props.query && matchQuery(tab.props.query)) ? (
<TabContent
className="sc-tabs-item-content"
tabContentColor={tabContentColor}
withoutPadding={tab.props.withoutPadding}
>
{tab.props.children}
</TabContent>
) : (
<></>
)}
</Route>
))}

return (
<Route
key={index}
path={
tab.props.path.startsWith('/') ? '/' + path : path
}
element={
<>
<TabContent
className="sc-tabs-item-content"
tabContentColor={tabContentColor}
withoutPadding={tab.props.withoutPadding}
>
{tab.props.children}
</TabContent>
<Outlet />
</>
}
/>
);
})}
</Routes>
</TabsContainer>
</TabsContext.Provider>
);
}

Tabs.Tab = Tab;
// re-export Tab
export { Tabs, Tab };
export { Tab, Tabs };
2 changes: 1 addition & 1 deletion src/lib/components/toast/ToastProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const ToastContext = createContext<ToastContextType | undefined>(
interface ToastProviderProps {
children: ReactNode;
}
export const ToastProvider: React.FC<ToastProviderProps> = ({ children }) => {
export const ToastProvider: React.FC<React.PropsWithChildren<ToastProviderProps>> = ({ children }) => {
const [toastProps, setToastProps] = useState<ToastContextState | null>(null);

const showToast = (toastProps: ToastContextState) => {
Expand Down
Loading
Loading