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
84 changes: 44 additions & 40 deletions awx/ui/src/components/Schedule/Schedule.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { useEffect, useCallback } from 'react';
import { useLingui } from '@lingui/react/macro';

import { Link } from 'react-router-dom';
import {
Switch,
Routes,
Route,
Link,
Redirect,
Navigate,
useLocation,
useParams,
} from 'react-router-dom';
} from 'react-router-dom-v5-compat';
import { CaretLeftIcon } from '@patternfly/react-icons';
import { SchedulesAPI } from 'api';
import useRequest from 'hooks/useRequest';
Expand All @@ -31,7 +31,7 @@ function Schedule({

const { pathname } = useLocation();

const pathRoot = pathname.substr(0, pathname.indexOf('schedules'));
const pathRoot = pathname.substring(0, pathname.indexOf('schedules'));

const {
isLoading,
Expand Down Expand Up @@ -120,42 +120,46 @@ function Schedule({
return (
<>
{showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch>
<Redirect
from={`${pathRoot}schedules/:scheduleId`}
to={`${pathRoot}schedules/:scheduleId/details`}
exact
/>
{schedule && [
<Route key="edit" path={`${pathRoot}schedules/:id/edit`}>
<ScheduleEdit
hasDaysToKeepField={hasDaysToKeepField}
schedule={schedule}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
</Route>,
<Routes>
<Route index element={<Navigate to="details" replace />} />
{schedule && (
<Route
key="details"
path={`${pathRoot}schedules/:scheduleId/details`}
>
<ScheduleDetail
hasDaysToKeepField={hasDaysToKeepField}
schedule={schedule}
surveyConfig={surveyConfig}
/>
</Route>,
]}
<Route key="not-found" path="*">
<ContentError>
{resource && (
<Link to={`${pathRoot}details`}>{t`View Details`}</Link>
)}
</ContentError>
</Route>
</Switch>
path="edit"
element={
<ScheduleEdit
hasDaysToKeepField={hasDaysToKeepField}
schedule={schedule}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
}
/>
)}
{schedule && (
<Route
path="details"
element={
<ScheduleDetail
hasDaysToKeepField={hasDaysToKeepField}
schedule={schedule}
surveyConfig={surveyConfig}
/>
}
/>
)}
<Route
path="*"
element={
<ContentError>
{resource && (
<Link to={`${pathRoot}details`}>{t`View Details`}</Link>
)}
</ContentError>
}
/>
</Routes>
</>
);
}
Expand Down
78 changes: 45 additions & 33 deletions awx/ui/src/components/Schedule/Schedules.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Switch, Route, useRouteMatch } from 'react-router-dom';
import { Routes, Route } from 'react-router-dom-v5-compat';

import Schedule from './Schedule';
import ScheduleAdd from './ScheduleAdd';
Expand All @@ -15,7 +15,9 @@ function Schedules({
resource,
resourceDefaultCredentials,
}) {
const match = useRouteMatch();
// This component is mounted under a ".../schedules/*" route on several
// screens (templates, projects, inventory sources, management jobs), so its
// routes are relative to that parent and resolve under any of them.

// For some management jobs that delete data, we want to provide an additional
// field on the scheduler for configuring the number of days to retain.
Expand All @@ -26,37 +28,47 @@ function Schedules({
].includes(resource?.job_type);

return (
<Switch>
<Route path={`${match.path}/add`}>
<ScheduleAdd
hasDaysToKeepField={hasDaysToKeepField}
apiModel={apiModel}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
</Route>
<Route key="details" path={`${match.path}/:scheduleId`}>
<Schedule
hasDaysToKeepField={hasDaysToKeepField}
setBreadcrumb={setBreadcrumb}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
</Route>
<Route key="list" path={`${match.path}`}>
<ScheduleList
resource={resource}
loadSchedules={loadSchedules}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
loadScheduleOptions={loadScheduleOptions}
/>
</Route>
</Switch>
<Routes>
<Route
path="add"
element={
<ScheduleAdd
hasDaysToKeepField={hasDaysToKeepField}
apiModel={apiModel}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
}
/>
{/* so the nested <Schedule> route tree can match */}
<Route
path=":scheduleId/*"
element={
<Schedule
hasDaysToKeepField={hasDaysToKeepField}
setBreadcrumb={setBreadcrumb}
resource={resource}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resourceDefaultCredentials={resourceDefaultCredentials}
/>
}
/>
<Route
index
element={
<ScheduleList
resource={resource}
loadSchedules={loadSchedules}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
loadScheduleOptions={loadScheduleOptions}
/>
}
/>
</Routes>
);
}

Expand Down
31 changes: 18 additions & 13 deletions awx/ui/src/components/Schedule/Schedules.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import { Routes, Route } from 'react-router-dom-v5-compat';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import Schedules from './Schedules';

Expand All @@ -12,21 +13,25 @@ describe('<Schedules />', () => {
});
const jobTemplate = { id: 1, name: 'Mock JT' };

// Schedules uses relative routes, so mount it under its ".../schedules/*"
// parent route.
await act(async () => {
wrapper = mountWithContexts(
<Schedules
setBreadcrumb={() => {}}
jobTemplate={jobTemplate}
loadSchedules={() => {}}
loadScheduleOptions={() => {}}
apiModel={{ createSchedule: () => {} }}
/>,

{
context: {
router: { history, route: { location: history.location } },
},
}
<Routes>
<Route
path="/templates/job_template/:id/schedules/*"
element={
<Schedules
setBreadcrumb={() => {}}
jobTemplate={jobTemplate}
loadSchedules={() => {}}
loadScheduleOptions={() => {}}
apiModel={{ createSchedule: () => {} }}
/>
}
/>
</Routes>,
{ context: { router: { history } } }
);
});
expect(wrapper.length).toBe(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { Link, useParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom-v5-compat';
import { Link } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom-v5-compat';
import {
Button,
Chip,
Expand Down
9 changes: 5 additions & 4 deletions awx/ui/src/screens/Template/Survey/SurveyQuestionAdd.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useState } from 'react';
import { useRouteMatch } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { useNavigate } from 'react-router-dom-v5-compat';
import { CardBody } from 'components/Card';
import SurveyQuestionForm from './SurveyQuestionForm';

export default function SurveyQuestionAdd({ survey, updateSurvey }) {
const [formError, setFormError] = useState(null);
const navigate = useNavigate();
const match = useRouteMatch();
const { pathname } = useLocation();
const surveyUrl = pathname.replace('/add', '');

const handleSubmit = async (question) => {
const formData = { ...question };
Expand Down Expand Up @@ -41,14 +42,14 @@ export default function SurveyQuestionAdd({ survey, updateSurvey }) {
delete formData.formattedChoices;
const newSpec = survey?.spec ? survey.spec.concat(formData) : [formData];
await updateSurvey(newSpec);
navigate(match.url.replace('/add', ''));
navigate(surveyUrl);
} catch (err) {
setFormError(err);
}
};

const handleCancel = () => {
navigate(match.url.replace('/add', ''));
navigate(surveyUrl);
};

return (
Expand Down
15 changes: 5 additions & 10 deletions awx/ui/src/screens/Template/Survey/SurveyQuestionEdit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { useLocation, useRouteMatch } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { useNavigate, Navigate } from 'react-router-dom-v5-compat';
import ContentLoading from 'components/ContentLoading';
import { CardBody } from 'components/Card';
Expand All @@ -8,8 +8,8 @@ import SurveyQuestionForm from './SurveyQuestionForm';
export default function SurveyQuestionEdit({ survey, updateSurvey }) {
const [formError, setFormError] = useState(null);
const navigate = useNavigate();
const match = useRouteMatch();
const { search } = useLocation();
const { pathname, search } = useLocation();
const surveyUrl = `${pathname.substr(0, pathname.indexOf('survey'))}survey`;
const queryParams = new URLSearchParams(search);
const questionVariable = decodeURIComponent(
queryParams.get('question_variable')
Expand All @@ -22,16 +22,11 @@ export default function SurveyQuestionEdit({ survey, updateSurvey }) {
const question = survey.spec.find((q) => q.variable === questionVariable);

if (!question) {
return (
<Navigate
to={`/templates/${match.params.templateType}/${match.params.id}/survey`}
/>
);
return <Navigate to={surveyUrl} />;
}

const navigateToList = () => {
const index = match.url.indexOf('/edit');
navigate(match.url.substr(0, index));
navigate(surveyUrl);
};

const handleSubmit = async (formData) => {
Expand Down
7 changes: 4 additions & 3 deletions awx/ui/src/screens/Template/Survey/SurveyToolbar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { useRouteMatch } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { useLingui } from '@lingui/react/macro';

import styled from 'styled-components';
Expand Down Expand Up @@ -36,7 +36,8 @@ function SurveyToolbar({
}) {
const { t } = useLingui();
isDeleteDisabled = !canEdit || isDeleteDisabled;
const match = useRouteMatch();
const { pathname } = useLocation();
const surveyUrl = `${pathname.substr(0, pathname.indexOf('survey'))}survey`;
return (
<Toolbar id="survey-toolbar" ouiaId="survey-toolbar">
<ToolbarContent>
Expand All @@ -56,7 +57,7 @@ function SurveyToolbar({
<ToolbarItem>
<ToolbarAddButton
isDisabled={!canEdit}
linkTo={`${match.url}/add`}
linkTo={`${surveyUrl}/add`}
/>
</ToolbarItem>
{canEdit && onOpenOrderModal && (
Expand Down
Loading