diff --git a/.changeset/famous-wombats-happen.md b/.changeset/famous-wombats-happen.md new file mode 100644 index 0000000000..9d8a2f0b0e --- /dev/null +++ b/.changeset/famous-wombats-happen.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-cloudbuild': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-tech-insights': patch +'@backstage/plugin-techdocs': patch +--- + +Internal refactor to use more type safe code when dealing with route parameters. diff --git a/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts b/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts index 0b244f8b69..549ab1eaf2 100644 --- a/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts +++ b/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useParams } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { cloudbuildApiRef } from '../../api'; -import { useApi } from '@backstage/core-plugin-api'; +import { useApi, useRouteRefParams } from '@backstage/core-plugin-api'; +import { buildRouteRef } from '../../routes'; export const useWorkflowRunsDetails = (projectId: string) => { const api = useApi(cloudbuildApiRef); - const { id } = useParams(); + const { id } = useRouteRefParams(buildRouteRef); const details = useAsync(async () => { return projectId ? api.getWorkflowRun({ diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index ac35c4dcd7..0aa04b93d0 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -15,7 +15,7 @@ */ import React, { ComponentType, useEffect } from 'react'; -import { Routes, Route, useOutlet, Navigate, useParams } from 'react-router'; +import { Routes, Route, useOutlet, Navigate } from 'react-router'; import { Entity } from '@backstage/catalog-model'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { ScaffolderPage } from './ScaffolderPage'; @@ -31,7 +31,11 @@ import { FIELD_EXTENSION_KEY, DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS, } from '../extensions'; -import { useElementFilter, useRouteRef } from '@backstage/core-plugin-api'; +import { + useElementFilter, + useRouteRef, + useRouteRefParams, +} from '@backstage/core-plugin-api'; import { actionsRouteRef, editRouteRef, @@ -105,7 +109,7 @@ export const Router = (props: RouterProps) => { * This component can be deleted once the older routes have been deprecated. */ const RedirectingComponent = () => { - const { templateName } = useParams(); + const { templateName } = useRouteRefParams(legacySelectedTemplateRouteRef); const newLink = useRouteRef(selectedTemplateRouteRef); useEffect( () => diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index 7073157f25..3dd54e1d09 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -23,7 +23,7 @@ import { LogViewer, Progress, } from '@backstage/core-components'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { useRouteRef, useRouteRefParams } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import { Button, @@ -45,9 +45,13 @@ import classNames from 'classnames'; import { DateTime, Interval } from 'luxon'; import qs from 'qs'; import React, { memo, useEffect, useMemo, useState } from 'react'; -import { useNavigate, useParams } from 'react-router'; +import { useNavigate } from 'react-router'; import useInterval from 'react-use/lib/useInterval'; -import { rootRouteRef, selectedTemplateRouteRef } from '../../routes'; +import { + rootRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; import { ScaffolderTaskStatus, ScaffolderTaskOutput } from '../../types'; import { useTaskEventStream } from '../hooks/useEventStream'; import { TaskPageLinks } from './TaskPageLinks'; @@ -246,7 +250,7 @@ export const TaskPage = ({ loadingText }: TaskPageProps) => { const [lastActiveStepId, setLastActiveStepId] = useState( undefined, ); - const { taskId } = useParams(); + const { taskId } = useRouteRefParams(scaffolderTaskRouteRef); const taskStream = useTaskEventStream(taskId); const completed = taskStream.completed; const steps = useMemo( diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index f694688801..03ce57136f 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -18,12 +18,15 @@ import { IChangeEvent } from '@rjsf/core'; import qs from 'qs'; import React, { useCallback, useContext, useState } from 'react'; import { Navigate, useNavigate } from 'react-router'; -import { useParams } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { scaffolderApiRef } from '../../api'; import { FieldExtensionOptions } from '../../extensions'; import { SecretsContext } from '../secrets/SecretsContext'; -import { rootRouteRef, scaffolderTaskRouteRef } from '../../routes'; +import { + rootRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; import { MultistepJsonForm } from '../MultistepJsonForm'; import { createValidator } from './createValidator'; @@ -33,6 +36,7 @@ import { useApi, useApiHolder, useRouteRef, + useRouteRefParams, } from '@backstage/core-plugin-api'; import { stringifyEntityRef } from '@backstage/catalog-model'; @@ -54,7 +58,9 @@ export const TemplatePage = ({ const secretsContext = useContext(SecretsContext); const errorApi = useApi(errorApiRef); const scaffolderApi = useApi(scaffolderApiRef); - const { templateName, namespace } = useParams(); + const { templateName, namespace } = useRouteRefParams( + selectedTemplateRouteRef, + ); const templateRef = stringifyEntityRef({ name: templateName, kind: 'template', diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index f8733061e4..468db438d5 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -23,15 +23,20 @@ import { MarkdownContent, } from '@backstage/core-components'; import { FieldExtensionOptions } from '../../extensions'; -import { Navigate, useParams } from 'react-router'; +import { Navigate } from 'react-router'; import { stringifyEntityRef } from '@backstage/catalog-model'; -import { errorApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + errorApiRef, + useApi, + useRouteRef, + useRouteRefParams, +} from '@backstage/core-plugin-api'; import { scaffolderApiRef } from '../../api'; import useAsync from 'react-use/lib/useAsync'; import { makeStyles } from '@material-ui/core'; import { Stepper } from './Stepper'; import { BackstageTheme } from '@backstage/theme'; -import { nextRouteRef } from '../../routes'; +import { nextRouteRef, selectedTemplateRouteRef } from '../../routes'; export interface TemplateWizardPageProps { customFieldExtensions: FieldExtensionOptions[]; @@ -62,7 +67,9 @@ const useTemplateParameterSchema = (templateRef: string) => { export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const styles = useStyles(); const rootRef = useRouteRef(nextRouteRef); - const { templateName, namespace } = useParams(); + const { templateName, namespace } = useRouteRefParams( + selectedTemplateRouteRef, + ); const errorApi = useApi(errorApiRef); const { loading, manifest, error } = useTemplateParameterSchema( stringifyEntityRef({ diff --git a/plugins/tech-insights/src/components/ScorecardsCard/ScorecardsCard.tsx b/plugins/tech-insights/src/components/ScorecardsCard/ScorecardsCard.tsx index 57b8915b58..679c8d2080 100644 --- a/plugins/tech-insights/src/components/ScorecardsCard/ScorecardsCard.tsx +++ b/plugins/tech-insights/src/components/ScorecardsCard/ScorecardsCard.tsx @@ -15,13 +15,14 @@ */ import React from 'react'; -import { useParams } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { Progress } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import { ScorecardInfo } from '../ScorecardsInfo'; import Alert from '@material-ui/lab/Alert'; import { techInsightsApiRef } from '../../api/TechInsightsApi'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { getCompoundEntityRef } from '@backstage/catalog-model'; export const ScorecardsCard = (props: { title?: string; @@ -30,7 +31,7 @@ export const ScorecardsCard = (props: { }) => { const { title, description, checksId } = props; const api = useApi(techInsightsApiRef); - const { namespace, kind, name } = useParams(); + const { namespace, kind, name } = getCompoundEntityRef(useEntity().entity); const { value, loading, error } = useAsync( async () => await api.runChecks({ namespace, kind, name }, checksId), ); diff --git a/plugins/tech-insights/src/components/ScorecardsContent/ScorecardContent.tsx b/plugins/tech-insights/src/components/ScorecardsContent/ScorecardContent.tsx index c3d02c938f..0159601332 100644 --- a/plugins/tech-insights/src/components/ScorecardsContent/ScorecardContent.tsx +++ b/plugins/tech-insights/src/components/ScorecardsContent/ScorecardContent.tsx @@ -15,7 +15,6 @@ */ import React from 'react'; -import { useParams } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { Content, Page, Progress } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; @@ -23,6 +22,8 @@ import { ScorecardInfo } from '../ScorecardsInfo'; import Alert from '@material-ui/lab/Alert'; import { techInsightsApiRef } from '../../api/TechInsightsApi'; import { makeStyles } from '@material-ui/core'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { getCompoundEntityRef } from '@backstage/catalog-model'; const useStyles = makeStyles(() => ({ contentScorecards: { @@ -39,7 +40,7 @@ export const ScorecardsContent = (props: { const { title, description, checksId } = props; const classes = useStyles(); const api = useApi(techInsightsApiRef); - const { namespace, kind, name } = useParams(); + const { namespace, kind, name } = getCompoundEntityRef(useEntity().entity); const { value, loading, error } = useAsync( async () => await api.runChecks({ namespace, kind, name }, checksId), ); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx index 9f69dcb8d8..cbeb667417 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx @@ -15,7 +15,7 @@ */ import React, { ReactNode, ReactChild, Children } from 'react'; -import { useOutlet, useParams } from 'react-router-dom'; +import { useOutlet } from 'react-router-dom'; import { Page } from '@backstage/core-components'; import { CompoundEntityRef } from '@backstage/catalog-model'; @@ -29,6 +29,8 @@ import { TechDocsReaderPageRenderFunction } from '../../../types'; import { TechDocsReaderPageContent } from '../TechDocsReaderPageContent'; import { TechDocsReaderPageHeader } from '../TechDocsReaderPageHeader'; import { TechDocsReaderPageSubheader } from '../TechDocsReaderPageSubheader'; +import { rootDocsRouteRef } from '../../../routes'; +import { useRouteRefParams } from '@backstage/core-plugin-api'; type Extension = ReactChild & { type: { @@ -83,7 +85,7 @@ export type TechDocsReaderPageProps = { * @public */ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { - const { kind, name, namespace } = useParams(); + const { kind, name, namespace } = useRouteRefParams(rootDocsRouteRef); const { children, entityRef = { kind, name, namespace } } = props; const outlet = useOutlet();