mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
Persistent list filters (#12229)
* add PersistentFilters component * add PersistentFilters test * add persistent filters to all list pages * update tests * clear sessionStorage on logout * fix persistent filter on wfjt detail; cleanup
This commit is contained in:
parent
faa5df19ca
commit
fdd560747d
@ -11,7 +11,7 @@
|
||||
},
|
||||
"babelOptions": {
|
||||
"presets": ["@babel/preset-react"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": ["react-hooks", "jsx-a11y", "i18next", "@babel"],
|
||||
"extends": [
|
||||
@ -96,9 +96,18 @@
|
||||
"modifier",
|
||||
"data-cy",
|
||||
"fieldName",
|
||||
"splitButtonVariant"
|
||||
"splitButtonVariant",
|
||||
"pageKey"
|
||||
],
|
||||
"ignore": [
|
||||
"Ansible",
|
||||
"Tower",
|
||||
"JSON",
|
||||
"YAML",
|
||||
"lg",
|
||||
"hh:mm AM/PM",
|
||||
"Twilio"
|
||||
],
|
||||
"ignore": ["Ansible", "Tower", "JSON", "YAML", "lg", "hh:mm AM/PM", "Twilio"],
|
||||
"ignoreComponent": [
|
||||
"AboutModal",
|
||||
"code",
|
||||
@ -139,7 +148,7 @@
|
||||
"object-curly-newline": "off",
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-unused-expressions": ["error", { "allowShortCircuit": true }],
|
||||
"react/jsx-props-no-spreading":["off"],
|
||||
"react/jsx-props-no-spreading": ["off"],
|
||||
"react/prefer-stateless-function": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/sort-comp": ["error", {}],
|
||||
|
||||
33
awx/ui/src/components/PersistentFilters/PersistentFilters.js
Normal file
33
awx/ui/src/components/PersistentFilters/PersistentFilters.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation, useHistory } from 'react-router';
|
||||
import { PERSISTENT_FILTER_KEY } from '../../constants';
|
||||
|
||||
export default function PersistentFilters({ pageKey, children }) {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
if (!location.search.includes('restoreFilters=true')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterString = sessionStorage.getItem(PERSISTENT_FILTER_KEY);
|
||||
const filter = filterString ? JSON.parse(filterString) : { qs: '' };
|
||||
|
||||
if (filter.pageKey === pageKey) {
|
||||
history.replace(`${location.pathname}${filter.qs}`);
|
||||
} else {
|
||||
history.replace(location.pathname);
|
||||
}
|
||||
}, [history, location, pageKey]);
|
||||
|
||||
useEffect(() => {
|
||||
const filter = {
|
||||
pageKey,
|
||||
qs: location.search,
|
||||
};
|
||||
sessionStorage.setItem(PERSISTENT_FILTER_KEY, JSON.stringify(filter));
|
||||
}, [location.search, pageKey]);
|
||||
|
||||
return children;
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
import React from 'react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { Router, Route } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import PersistentFilters from './PersistentFilters';
|
||||
|
||||
const KEY = 'awx-persistent-filter';
|
||||
|
||||
describe('PersistentFilters', () => {
|
||||
test('should initialize filter in sessionStorage', () => {
|
||||
expect(sessionStorage.getItem(KEY)).toEqual(null);
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates'],
|
||||
});
|
||||
render(
|
||||
<Router history={history}>
|
||||
<PersistentFilters pageKey="templates">test</PersistentFilters>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(JSON.parse(sessionStorage.getItem(KEY))).toEqual({
|
||||
pageKey: 'templates',
|
||||
qs: '',
|
||||
});
|
||||
});
|
||||
|
||||
test('should restore filters from sessionStorage', () => {
|
||||
expect(
|
||||
sessionStorage.setItem(
|
||||
KEY,
|
||||
JSON.stringify({
|
||||
pageKey: 'templates',
|
||||
qs: '?page=2&name=foo',
|
||||
})
|
||||
)
|
||||
);
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates?restoreFilters=true'],
|
||||
});
|
||||
render(
|
||||
<Router history={history}>
|
||||
<PersistentFilters pageKey="templates">test</PersistentFilters>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(history.location.search).toEqual('?page=2&name=foo');
|
||||
});
|
||||
|
||||
test('should not restore filters without restoreFilters query param', () => {
|
||||
expect(
|
||||
sessionStorage.setItem(
|
||||
KEY,
|
||||
JSON.stringify({
|
||||
pageKey: 'templates',
|
||||
qs: '?page=2&name=foo',
|
||||
})
|
||||
)
|
||||
);
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates'],
|
||||
});
|
||||
render(
|
||||
<Router history={history}>
|
||||
<PersistentFilters pageKey="templates">test</PersistentFilters>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(history.location.search).toEqual('');
|
||||
});
|
||||
|
||||
test("should not restore filters if page key doesn't match", () => {
|
||||
expect(
|
||||
sessionStorage.setItem(
|
||||
KEY,
|
||||
JSON.stringify({
|
||||
pageKey: 'projects',
|
||||
qs: '?page=2&name=foo',
|
||||
})
|
||||
)
|
||||
);
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates?restoreFilters=true'],
|
||||
});
|
||||
render(
|
||||
<Router history={history}>
|
||||
<PersistentFilters pageKey="templates">test</PersistentFilters>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(history.location.search).toEqual('');
|
||||
});
|
||||
|
||||
test('should update stored filters when qs changes', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates'],
|
||||
});
|
||||
render(
|
||||
<Router history={history}>
|
||||
<PersistentFilters pageKey="templates">test</PersistentFilters>
|
||||
</Router>
|
||||
);
|
||||
|
||||
history.push('/templates?page=3');
|
||||
await waitFor(() => true);
|
||||
|
||||
expect(JSON.parse(sessionStorage.getItem(KEY))).toEqual({
|
||||
pageKey: 'templates',
|
||||
qs: '?page=3',
|
||||
});
|
||||
});
|
||||
});
|
||||
1
awx/ui/src/components/PersistentFilters/index.js
Normal file
1
awx/ui/src/components/PersistentFilters/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './PersistentFilters';
|
||||
@ -24,7 +24,11 @@ function RoutedTabs({ tabsArray }) {
|
||||
const handleTabSelect = (event, eventKey) => {
|
||||
const match = tabsArray.find((tab) => tab.id === eventKey);
|
||||
if (match) {
|
||||
history.push(match.link);
|
||||
event.preventDefault();
|
||||
const link = match.isBackButton
|
||||
? `${match.link}?restoreFilters=true`
|
||||
: match.link;
|
||||
history.push(link);
|
||||
}
|
||||
};
|
||||
|
||||
@ -39,7 +43,7 @@ function RoutedTabs({ tabsArray }) {
|
||||
aria-label={typeof tab.name === 'string' ? tab.name : null}
|
||||
eventKey={tab.id}
|
||||
key={tab.id}
|
||||
link={tab.link}
|
||||
href={`#${tab.link}`}
|
||||
title={<TabTitleText>{tab.name}</TabTitleText>}
|
||||
aria-controls=""
|
||||
ouiaId={`${tab.name}-tab`}
|
||||
|
||||
@ -37,7 +37,12 @@ describe('<RoutedTabs />', () => {
|
||||
});
|
||||
|
||||
test('should update history when new tab selected', async () => {
|
||||
wrapper.find('Tabs').invoke('onSelect')({}, 2);
|
||||
wrapper.find('Tabs').invoke('onSelect')(
|
||||
{
|
||||
preventDefault: () => {},
|
||||
},
|
||||
2
|
||||
);
|
||||
wrapper.update();
|
||||
|
||||
expect(history.location.pathname).toEqual('/organizations/19/access');
|
||||
|
||||
@ -119,9 +119,10 @@ describe('<Schedule />', () => {
|
||||
});
|
||||
|
||||
test('expect all tabs to exist, including Back to Schedules', async () => {
|
||||
expect(
|
||||
wrapper.find('button[link="/templates/job_template/1/schedules"]').length
|
||||
).toBe(1);
|
||||
expect(wrapper.find('button[aria-label="Details"]').length).toBe(1);
|
||||
const routedTabs = wrapper.find('RoutedTabs');
|
||||
const tabs = routedTabs.prop('tabsArray');
|
||||
|
||||
expect(tabs[0].link).toEqual('/templates/job_template/1/schedules');
|
||||
expect(tabs[1].name).toEqual('Details');
|
||||
});
|
||||
});
|
||||
|
||||
@ -10,3 +10,4 @@ export const JOB_TYPE_URL_SEGMENTS = {
|
||||
|
||||
export const SESSION_TIMEOUT_KEY = 'awx-session-timeout';
|
||||
export const SESSION_REDIRECT_URL = 'awx-redirect-url';
|
||||
export const PERSISTENT_FILTER_KEY = 'awx-persistent-filter';
|
||||
|
||||
@ -102,6 +102,7 @@ function SessionProvider({ children }) {
|
||||
if (!isSessionExpired.current) {
|
||||
setAuthRedirectTo('/logout');
|
||||
}
|
||||
sessionStorage.clear();
|
||||
await RootAPI.logout();
|
||||
setSessionTimeout(0);
|
||||
setSessionCountdown(0);
|
||||
|
||||
@ -74,6 +74,7 @@ function Application({ setBreadcrumb }) {
|
||||
),
|
||||
link: '/applications',
|
||||
id: 0,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `/applications/${id}/details`, id: 1 },
|
||||
{ name: t`Tokens`, link: `/applications/${id}/tokens`, id: 2 },
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import { Detail, DetailList } from 'components/DetailList';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import ApplicationsList from './ApplicationsList';
|
||||
import ApplicationAdd from './ApplicationAdd';
|
||||
import Application from './Application';
|
||||
@ -56,7 +57,9 @@ function Applications() {
|
||||
<Application setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/applications">
|
||||
<ApplicationsList />
|
||||
<PersistentFilters pageKey="applications">
|
||||
<ApplicationsList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
{applicationModalSource && (
|
||||
|
||||
@ -67,6 +67,7 @@ function Credential({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/credentials`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `/credentials/${id}/details`, id: 0 },
|
||||
{
|
||||
|
||||
@ -4,6 +4,7 @@ import { Route, Switch } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Config } from 'contexts/Config';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import Credential from './Credential';
|
||||
import CredentialAdd from './CredentialAdd';
|
||||
import { CredentialList } from './CredentialList';
|
||||
@ -44,7 +45,9 @@ function Credentials() {
|
||||
<Credential setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/credentials">
|
||||
<CredentialList />
|
||||
<PersistentFilters pageKey="credentials">
|
||||
<CredentialList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -57,6 +57,7 @@ function CredentialType({ setBreadcrumb }) {
|
||||
),
|
||||
link: '/credential_types',
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
|
||||
@ -2,7 +2,7 @@ import React, { useState, useCallback } from 'react';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import CredentialTypeAdd from './CredentialTypeAdd';
|
||||
import CredentialTypeList from './CredentialTypeList';
|
||||
@ -40,7 +40,9 @@ function CredentialTypes() {
|
||||
<CredentialType setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/credential_types">
|
||||
<CredentialTypeList />
|
||||
<PersistentFilters pageKey="credentialTypes">
|
||||
<CredentialTypeList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -59,6 +59,7 @@ function ExecutionEnvironment({ setBreadcrumb }) {
|
||||
),
|
||||
link: '/execution_environments',
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
|
||||
@ -2,7 +2,7 @@ import React, { useState, useCallback } from 'react';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import ExecutionEnvironment from './ExecutionEnvironment';
|
||||
import ExecutionEnvironmentAdd from './ExecutionEnvironmentAdd';
|
||||
@ -40,7 +40,9 @@ function ExecutionEnvironments() {
|
||||
<ExecutionEnvironment setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/execution_environments">
|
||||
<ExecutionEnvironmentList />
|
||||
<PersistentFilters pageKey="executionEnvironments">
|
||||
<ExecutionEnvironmentList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -52,6 +52,7 @@ function Host({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/hosts`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
|
||||
import { Config } from 'contexts/Config';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import HostList from './HostList';
|
||||
import HostAdd from './HostAdd';
|
||||
import Host from './Host';
|
||||
@ -47,7 +46,9 @@ function Hosts() {
|
||||
</Config>
|
||||
</Route>
|
||||
<Route path="/hosts">
|
||||
<HostList />
|
||||
<PersistentFilters pageKey="hosts">
|
||||
<HostList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -63,6 +63,7 @@ function InstanceGroup({ setBreadcrumb }) {
|
||||
),
|
||||
link: '/instance_groups',
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
|
||||
@ -9,6 +9,7 @@ import useRequest from 'hooks/useRequest';
|
||||
import { SettingsAPI } from 'api';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import ContentLoading from 'components/ContentLoading';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import InstanceGroupAdd from './InstanceGroupAdd';
|
||||
import InstanceGroupList from './InstanceGroupList';
|
||||
import InstanceGroup from './InstanceGroup';
|
||||
@ -103,11 +104,13 @@ function InstanceGroups() {
|
||||
<InstanceGroup setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/instance_groups">
|
||||
<InstanceGroupList
|
||||
isKubernetes={isKubernetes}
|
||||
isSettingsRequestLoading={isSettingsRequestLoading}
|
||||
settingsRequestError={settingsRequestError}
|
||||
/>
|
||||
<PersistentFilters pageKey="instanceGroups">
|
||||
<InstanceGroupList
|
||||
isKubernetes={isKubernetes}
|
||||
isSettingsRequestLoading={isSettingsRequestLoading}
|
||||
settingsRequestError={settingsRequestError}
|
||||
/>
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
)}
|
||||
|
||||
@ -20,6 +20,7 @@ function Instance({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/instances`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details`, id: 0 },
|
||||
];
|
||||
|
||||
@ -3,6 +3,7 @@ import React, { useCallback, useState } from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import { InstanceList } from './InstanceList';
|
||||
import Instance from './Instance';
|
||||
|
||||
@ -30,7 +31,9 @@ function Instances() {
|
||||
<Instance setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/instances">
|
||||
<InstanceList />
|
||||
<PersistentFilters pageKey="instances">
|
||||
<InstanceList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -5,6 +5,7 @@ import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { Config } from 'contexts/Config';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import { InventoryList } from './InventoryList';
|
||||
import Inventory from './Inventory';
|
||||
import SmartInventory from './SmartInventory';
|
||||
@ -119,7 +120,9 @@ function Inventories() {
|
||||
<SmartInventory setBreadcrumb={setBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/inventories">
|
||||
<InventoryList />
|
||||
<PersistentFilters pageKey="inventories">
|
||||
<InventoryList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -59,6 +59,7 @@ function Inventory({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/inventories`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details`, id: 0 },
|
||||
{ name: t`Access`, link: `${match.url}/access`, id: 1 },
|
||||
|
||||
@ -59,12 +59,14 @@ describe('<InventoryGroup />', () => {
|
||||
});
|
||||
|
||||
test('expect all tabs to exist, including Back to Groups', async () => {
|
||||
expect(
|
||||
wrapper.find('button[link="/inventories/inventory/1/groups"]').length
|
||||
).toBe(1);
|
||||
expect(wrapper.find('button[aria-label="Details"]').length).toBe(1);
|
||||
expect(wrapper.find('button[aria-label="Related Groups"]').length).toBe(1);
|
||||
expect(wrapper.find('button[aria-label="Hosts"]').length).toBe(1);
|
||||
const routedTabs = wrapper.find('RoutedTabs');
|
||||
expect(routedTabs).toHaveLength(1);
|
||||
|
||||
const tabs = routedTabs.prop('tabsArray');
|
||||
expect(tabs[0].link).toEqual('/inventories/inventory/1/groups');
|
||||
expect(tabs[1].name).toEqual('Details');
|
||||
expect(tabs[2].name).toEqual('Related Groups');
|
||||
expect(tabs[3].name).toEqual('Hosts');
|
||||
});
|
||||
|
||||
test('should show content error when user attempts to navigate to erroneous route', async () => {
|
||||
|
||||
@ -111,6 +111,7 @@ function Job({ setBreadcrumb }) {
|
||||
</>
|
||||
),
|
||||
link: `/jobs`,
|
||||
isBackButton: true,
|
||||
id: 99,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details`, id: 0 },
|
||||
|
||||
@ -5,6 +5,7 @@ import { t } from '@lingui/macro';
|
||||
import { PageSection } from '@patternfly/react-core';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import JobList from 'components/JobList';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import Job from './Job';
|
||||
import JobTypeRedirect from './JobTypeRedirect';
|
||||
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||
@ -41,7 +42,9 @@ function Jobs() {
|
||||
<Switch>
|
||||
<Route exact path={match.path}>
|
||||
<PageSection>
|
||||
<JobList showTypeColumn />
|
||||
<PersistentFilters pageKey="jobs">
|
||||
<JobList showTypeColumn />
|
||||
</PersistentFilters>
|
||||
</PageSection>
|
||||
</Route>
|
||||
<Route path={`${match.path}/:id/details`}>
|
||||
|
||||
@ -98,6 +98,7 @@ function ManagementJob({ setBreadcrumb }) {
|
||||
{t`Back to management jobs`}
|
||||
</>
|
||||
),
|
||||
isBackButton: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import ManagementJob from './ManagementJob';
|
||||
import ManagementJobList from './ManagementJobList';
|
||||
|
||||
@ -37,7 +36,9 @@ function ManagementJobs() {
|
||||
<ManagementJob setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path={basePath}>
|
||||
<ManagementJobList setBreadcrumb={buildBreadcrumbConfig} />
|
||||
<PersistentFilters pageKey="managementJobs">
|
||||
<ManagementJobList setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -78,6 +78,7 @@ function NotificationTemplate({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/notification_templates`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
|
||||
@ -3,6 +3,7 @@ import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import NotificationTemplateList from './NotificationTemplateList';
|
||||
import NotificationTemplateAdd from './NotificationTemplateAdd';
|
||||
import NotificationTemplate from './NotificationTemplate';
|
||||
@ -39,7 +40,9 @@ function NotificationTemplates() {
|
||||
<NotificationTemplate setBreadcrumb={updateBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path={`${match.url}`}>
|
||||
<NotificationTemplateList />
|
||||
<PersistentFilters pageKey="notificationTemplates">
|
||||
<NotificationTemplateList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -118,6 +118,7 @@ function Organization({ setBreadcrumb, me }) {
|
||||
),
|
||||
link: `/organizations`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details`, id: 0 },
|
||||
{ name: t`Access`, link: `${match.url}/access`, id: 1 },
|
||||
|
||||
@ -5,7 +5,7 @@ import { t } from '@lingui/macro';
|
||||
|
||||
import { Config } from 'contexts/Config';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import OrganizationsList from './OrganizationList/OrganizationList';
|
||||
import OrganizationAdd from './OrganizationAdd/OrganizationAdd';
|
||||
import Organization from './Organization';
|
||||
@ -54,7 +54,9 @@ function Organizations() {
|
||||
</Config>
|
||||
</Route>
|
||||
<Route path={`${match.path}`}>
|
||||
<OrganizationsList />
|
||||
<PersistentFilters pageKey="organizations">
|
||||
<OrganizationsList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -99,6 +99,7 @@ function Project({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/projects`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `/projects/${id}/details` },
|
||||
{ name: t`Access`, link: `/projects/${id}/access` },
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Route, withRouter, Switch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import ProjectsList from './ProjectList/ProjectList';
|
||||
import ProjectAdd from './ProjectAdd/ProjectAdd';
|
||||
import Project from './Project';
|
||||
@ -49,7 +47,9 @@ function Projects() {
|
||||
<Project setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/projects">
|
||||
<ProjectsList />
|
||||
<PersistentFilters pageKey="projects">
|
||||
<ProjectsList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -52,6 +52,7 @@ function Team({ setBreadcrumb }) {
|
||||
),
|
||||
link: `/teams`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `/teams/${id}/details`, id: 0 },
|
||||
{ name: t`Access`, link: `/teams/${id}/access`, id: 1 },
|
||||
|
||||
@ -5,6 +5,7 @@ import { t } from '@lingui/macro';
|
||||
|
||||
import { Config } from 'contexts/Config';
|
||||
import ScreenHeader from 'components/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import TeamList from './TeamList';
|
||||
import TeamAdd from './TeamAdd';
|
||||
import Team from './Team';
|
||||
@ -43,9 +44,11 @@ function Teams() {
|
||||
<Team setBreadcrumb={buildBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path="/teams">
|
||||
<Config>
|
||||
{({ me }) => <TeamList path="/teams" me={me || {}} />}
|
||||
</Config>
|
||||
<PersistentFilters pageKey="teams">
|
||||
<Config>
|
||||
{({ me }) => <TeamList path="/teams" me={me || {}} />}
|
||||
</Config>
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -129,6 +129,7 @@ function Template({ setBreadcrumb }) {
|
||||
</>
|
||||
),
|
||||
link: `/templates`,
|
||||
isBackButton: true,
|
||||
id: 99,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details` },
|
||||
|
||||
@ -6,6 +6,7 @@ import { PageSection } from '@patternfly/react-core';
|
||||
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import TemplateList from 'components/TemplateList';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import Template from './Template';
|
||||
import WorkflowJobTemplate from './WorkflowJobTemplate';
|
||||
import JobTemplateAdd from './JobTemplateAdd';
|
||||
@ -78,7 +79,9 @@ function Templates() {
|
||||
</Route>
|
||||
<Route path="/templates">
|
||||
<PageSection>
|
||||
<TemplateList />
|
||||
<PersistentFilters pageKey="templates">
|
||||
<TemplateList />
|
||||
</PersistentFilters>
|
||||
</PageSection>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
@ -111,6 +111,7 @@ function WorkflowJobTemplate({ setBreadcrumb }) {
|
||||
</>
|
||||
),
|
||||
link: `/templates`,
|
||||
isBackButton: true,
|
||||
id: 99,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details` },
|
||||
|
||||
@ -59,6 +59,7 @@ function User({ setBreadcrumb, me }) {
|
||||
),
|
||||
link: `/users`,
|
||||
id: 99,
|
||||
isBackButton: true,
|
||||
},
|
||||
{ name: t`Details`, link: `${match.url}/details`, id: 0 },
|
||||
{
|
||||
|
||||
@ -4,8 +4,8 @@ import { Route, useRouteMatch, Switch } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import { Config } from 'contexts/Config';
|
||||
|
||||
import UsersList from './UserList/UserList';
|
||||
import UserAdd from './UserAdd/UserAdd';
|
||||
import User from './User';
|
||||
@ -51,7 +51,9 @@ function Users() {
|
||||
</Config>
|
||||
</Route>
|
||||
<Route path={`${match.path}`}>
|
||||
<UsersList />
|
||||
<PersistentFilters pageKey="users">
|
||||
<UsersList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
@ -70,6 +70,7 @@ function WorkflowApproval({ setBreadcrumb }) {
|
||||
</>
|
||||
),
|
||||
link: `/workflow_approvals`,
|
||||
isBackButton: true,
|
||||
id: 99,
|
||||
},
|
||||
{
|
||||
|
||||
@ -3,6 +3,7 @@ import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import ScreenHeader from 'components/ScreenHeader/ScreenHeader';
|
||||
import PersistentFilters from 'components/PersistentFilters';
|
||||
import WorkflowApprovalList from './WorkflowApprovalList';
|
||||
import WorkflowApproval from './WorkflowApproval';
|
||||
|
||||
@ -35,7 +36,9 @@ function WorkflowApprovals() {
|
||||
<WorkflowApproval setBreadcrumb={updateBreadcrumbConfig} />
|
||||
</Route>
|
||||
<Route path={`${match.url}`}>
|
||||
<WorkflowApprovalList />
|
||||
<PersistentFilters pageKey="workflowApprovals">
|
||||
<WorkflowApprovalList />
|
||||
</PersistentFilters>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user