Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions console/src/components/InstallPatternPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useHistory, useRouteMatch } from 'react-router-dom';
import { useNavigateCompat } from '../hooks/useNavigateCompat';
import { useParamsCompat } from '../hooks/useParamsCompat';
import {
ActionGroup,
Alert,
Expand Down Expand Up @@ -56,9 +57,8 @@ const PatternModel = {

export default function InstallPatternPage() {
const { t } = useTranslation('plugin__patterns-operator-console-plugin');
const history = useHistory();
const match = useRouteMatch<{ name: string }>('/patterns/install/:name');
const name = match?.params?.name;
const navigate = useNavigateCompat();
const { name } = useParamsCompat('/patterns/install/:name');

// Secret form state (integrated inline instead of separate page)

Expand Down Expand Up @@ -251,11 +251,11 @@ export default function InstallPatternPage() {
if (hasSecrets && vaultJobStatus?.status !== 'succeeded') return;

const timer = setTimeout(() => {
history.push('/patterns');
navigate('/patterns');
}, 3000);

return () => clearTimeout(timer);
}, [patternStatus, history, secretTemplate, secretFormData, vaultJobStatus]);
}, [patternStatus, navigate, secretTemplate, secretFormData, vaultJobStatus]);

const handleSubmit = async () => {
console.log('🚀 [InstallPatternPage] Starting pattern installation process');
Expand Down Expand Up @@ -410,7 +410,7 @@ export default function InstallPatternPage() {
return t('Your pattern has been created. The operator is now reconciling it.');
})()}
</p>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Back to catalog')}
</Button>
</Alert>
Expand Down Expand Up @@ -612,7 +612,7 @@ export default function InstallPatternPage() {
>
{t('Install')}
</Button>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Cancel')}
</Button>
</ActionGroup>
Expand Down
12 changes: 6 additions & 6 deletions console/src/components/ManageSecretsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useHistory, useRouteMatch } from 'react-router-dom';
import { useNavigateCompat } from '../hooks/useNavigateCompat';
import { useParamsCompat } from '../hooks/useParamsCompat';
import {
ActionGroup,
Alert,
Expand Down Expand Up @@ -29,9 +30,8 @@ import './SecretForm/SecretForm.css';

export default function ManageSecretsPage() {
const { t } = useTranslation('plugin__patterns-operator-console-plugin');
const history = useHistory();
const match = useRouteMatch<{ name: string }>('/patterns/secrets/:name');
const name = match?.params?.name;
const navigate = useNavigateCompat();
const { name } = useParamsCompat('/patterns/secrets/:name');

const [loading, setLoading] = React.useState(true);
const [fetchError, setFetchError] = React.useState<string | null>(null);
Expand Down Expand Up @@ -171,7 +171,7 @@ export default function ManageSecretsPage() {
<PageSection>
<Alert variant="info" title={t('No secrets configured')}>
<p>{t('This pattern does not have a secret template defined.')}</p>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Back to catalog')}
</Button>
</Alert>
Expand Down Expand Up @@ -234,7 +234,7 @@ export default function ManageSecretsPage() {
<Button variant="primary" type="submit" isLoading={submitting} isDisabled={submitting}>
{t('Inject Secrets')}
</Button>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Back to catalog')}
</Button>
</ActionGroup>
Expand Down
10 changes: 5 additions & 5 deletions console/src/components/PatternCatalogPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { useNavigateCompat } from '../hooks/useNavigateCompat';

import {
Alert,
Expand Down Expand Up @@ -166,7 +166,7 @@ const TIER_DESCRIPTIONS: Record<string, string> = {

export default function PatternCatalogPage() {
const { t } = useTranslation('plugin__patterns-operator-console-plugin');
const history = useHistory();
const navigate = useNavigateCompat();
const [patterns, setPatterns] = React.useState<Pattern[]>([]);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
Expand Down Expand Up @@ -488,7 +488,7 @@ export default function PatternCatalogPage() {
<Button
variant="secondary"
onClick={() =>
history.push(
navigate(
`/patterns/secrets/${pattern.catalogKey || pattern.name}`,
)
}
Expand All @@ -499,7 +499,7 @@ export default function PatternCatalogPage() {
{isInstalled && (
<Button
variant="danger"
onClick={() => history.push(`/patterns/uninstall/${pattern.name}`)}
onClick={() => navigate(`/patterns/uninstall/${pattern.name}`)}
>
{t('Uninstall')}
</Button>
Expand All @@ -515,7 +515,7 @@ export default function PatternCatalogPage() {
variant="primary"
isDisabled={isDisabled}
onClick={() =>
history.push(
navigate(
`/patterns/install/${pattern.catalogKey || pattern.name}`,
)
}
Expand Down
12 changes: 6 additions & 6 deletions console/src/components/UninstallPatternPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useHistory, useRouteMatch } from 'react-router-dom';
import { useNavigateCompat } from '../hooks/useNavigateCompat';
import { useParamsCompat } from '../hooks/useParamsCompat';
import {
Alert,
Button,
Expand Down Expand Up @@ -29,9 +30,8 @@ const DELETION_PHASES: Record<string, { label: string; order: number }> = {

export default function UninstallPatternPage() {
const { t } = useTranslation('plugin__patterns-operator-console-plugin');
const history = useHistory();
const match = useRouteMatch<{ name: string }>('/patterns/uninstall/:name');
const name = match?.params?.name;
const navigate = useNavigateCompat();
const { name } = useParamsCompat('/patterns/uninstall/:name');

const [status, setStatus] = React.useState<PatternCRStatus | null>(null);
const [deleting, setDeleting] = React.useState(false);
Expand Down Expand Up @@ -127,7 +127,7 @@ export default function UninstallPatternPage() {
{deleted && (
<Alert variant="success" title={t('Pattern successfully removed')}>
<p>{t('The pattern and all its associated resources have been fully deleted.')}</p>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Back to catalog')}
</Button>
</Alert>
Expand Down Expand Up @@ -187,7 +187,7 @@ export default function UninstallPatternPage() {
>
{t('Confirm Uninstall')}
</Button>
<Button variant="link" onClick={() => history.push('/patterns')}>
<Button variant="link" onClick={() => navigate('/patterns')}>
{t('Cancel')}
</Button>
</div>
Expand Down
16 changes: 16 additions & 0 deletions console/src/hooks/useNavigateCompat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import * as ReactRouterDom from 'react-router-dom';

const hasUseNavigate = typeof (ReactRouterDom as any).useNavigate === 'function';

// React Router v6 removed useHistory in favor of useNavigate.
// OCP 4.22+ ships v6; OCP 4.21 and earlier ship v5.
export const useNavigateCompat: () => (path: string) => void = hasUseNavigate
? () => {
const navigate = (ReactRouterDom as any).useNavigate();
return React.useCallback((path: string) => navigate(path), [navigate]);
}
: () => {
const history = (ReactRouterDom as any).useHistory();
return React.useCallback((path: string) => history.push(path), [history]);
};
14 changes: 14 additions & 0 deletions console/src/hooks/useParamsCompat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as ReactRouterDom from 'react-router-dom';

const isV6 = typeof (ReactRouterDom as any).useNavigate === 'function';

// React Router v5 (OCP < 4.22): useParams may not work if the console
// framework doesn't expose route params through the standard context.
// useRouteMatch explicitly matches the current URL against the given pattern.
// React Router v6 (OCP 4.22+): useParams is the standard API.
export const useParamsCompat: (pattern: string) => Record<string, string> = isV6
? () => (ReactRouterDom as any).useParams()
: (pattern: string) => {
const match = (ReactRouterDom as any).useRouteMatch(pattern);
return match?.params || {};
};