mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Fix unable to open host or user detail pages when their names conflict with tabs (#137719) (#138109)
* Fix Unable to open user detail pages when user names conflict with tabs
* Fix Unable to open host detail pages when host names conflict with tabs
* Preserve tab name on user and host compatibility redirect
(cherry picked from commit 4c690bb3a2
)
Co-authored-by: Pablo Machado <pablo.nevesmachado@elastic.co>
This commit is contained in:
parent
a39486710b
commit
f3dde77478
16 changed files with 65 additions and 31 deletions
|
@ -146,7 +146,7 @@ describe('ml conditional links', () => {
|
|||
visitWithoutDateRange(mlHostSingleHostNullKqlQuery);
|
||||
cy.url().should(
|
||||
'include',
|
||||
'/app/security/hosts/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
'/app/security/hosts/name/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -154,7 +154,7 @@ describe('ml conditional links', () => {
|
|||
visitWithoutDateRange(mlHostSingleHostKqlQueryVariable);
|
||||
cy.url().should(
|
||||
'include',
|
||||
'/app/security/hosts/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
'/app/security/hosts/name/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -162,7 +162,7 @@ describe('ml conditional links', () => {
|
|||
visitWithoutDateRange(mlHostSingleHostKqlQuery);
|
||||
cy.url().should(
|
||||
'include',
|
||||
'/app/security/hosts/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&query=(language:kuery,query:%27(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)%27)&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
'/app/security/hosts/name/siem-windows/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!(%27auditbeat-*%27)))&query=(language:kuery,query:%27(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)%27)&timerange=(global:(linkTo:!(timeline),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)),timeline:(linkTo:!(global),timerange:(from:%272019-06-06T06:00:00.000Z%27,kind:absolute,to:%272019-06-07T05:59:59.999Z%27)))'
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@ describe('url state', () => {
|
|||
cy.get(ANOMALIES_TAB).should(
|
||||
'have.attr',
|
||||
'href',
|
||||
"/app/security/hosts/siem-kibana/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!('auditbeat-*')))&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')),timeline:(linkTo:!(global),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')))&query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')"
|
||||
"/app/security/hosts/name/siem-kibana/anomalies?sourcerer=(default:(id:security-solution-default,selectedPatterns:!('auditbeat-*')))&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')),timeline:(linkTo:!(global),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')))&query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')"
|
||||
);
|
||||
|
||||
cy.get(BREADCRUMBS)
|
||||
|
@ -270,7 +270,7 @@ describe('url state', () => {
|
|||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
`/app/security/hosts/siem-kibana?sourcerer=(default:(id:security-solution-default,selectedPatterns:!('auditbeat-*')))&query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')),timeline:(linkTo:!(global),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')))`
|
||||
`/app/security/hosts/name/siem-kibana?sourcerer=(default:(id:security-solution-default,selectedPatterns:!('auditbeat-*')))&query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')),timeline:(linkTo:!(global),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2023-01-01T21:33:29.186Z')))`
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ export const getTabsOnHostsUrl = (tabName: HostsTableType, search?: string) =>
|
|||
`/${tabName}${appendSearch(search)}`;
|
||||
|
||||
export const getHostDetailsUrl = (detailName: string, search?: string) =>
|
||||
`/${detailName}${appendSearch(search)}`;
|
||||
`/name/${detailName}${appendSearch(search)}`;
|
||||
|
||||
export const getTabsOnHostDetailsUrl = (
|
||||
detailName: string,
|
||||
tabName: HostsTableType,
|
||||
search?: string
|
||||
) => `/${detailName}/${tabName}${appendSearch(search)}`;
|
||||
) => `/name/${detailName}/${tabName}${appendSearch(search)}`;
|
||||
|
|
|
@ -9,10 +9,10 @@ import type { UsersTableType } from '../../../users/store/model';
|
|||
import { appendSearch } from './helpers';
|
||||
|
||||
export const getUsersDetailsUrl = (detailName: string, search?: string) =>
|
||||
`/${detailName}${appendSearch(search)}`;
|
||||
`/name/${detailName}${appendSearch(search)}`;
|
||||
|
||||
export const getTabsOnUsersDetailsUrl = (
|
||||
detailName: string,
|
||||
tabName: UsersTableType,
|
||||
search?: string
|
||||
) => `/${detailName}/${tabName}${appendSearch(search)}`;
|
||||
) => `/name/${detailName}/${tabName}${appendSearch(search)}`;
|
||||
|
|
|
@ -60,13 +60,13 @@ describe('Custom Links', () => {
|
|||
describe('HostDetailsLink', () => {
|
||||
test('should render valid link to Host Details with hostName as the display text', () => {
|
||||
const wrapper = mount(<HostDetailsLink hostName={hostName} />);
|
||||
expect(wrapper.find('EuiLink').prop('href')).toEqual(`/${encodeURIComponent(hostName)}`);
|
||||
expect(wrapper.find('EuiLink').prop('href')).toEqual(`/name/${encodeURIComponent(hostName)}`);
|
||||
expect(wrapper.text()).toEqual(hostName);
|
||||
});
|
||||
|
||||
test('should render valid link to Host Details with child text as the display text', () => {
|
||||
const wrapper = mount(<HostDetailsLink hostName={hostName}>{hostName}</HostDetailsLink>);
|
||||
expect(wrapper.find('EuiLink').prop('href')).toEqual(`/${encodeURIComponent(hostName)}`);
|
||||
expect(wrapper.find('EuiLink').prop('href')).toEqual(`/name/${encodeURIComponent(hostName)}`);
|
||||
expect(wrapper.text()).toEqual(hostName);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -88,7 +88,9 @@ export const MlHostConditionalContainer = React.memo(() => {
|
|||
});
|
||||
|
||||
return (
|
||||
<Redirect to={`${HOSTS_PATH}/${hostName}/${HostsTableType.anomalies}?${reEncoded}`} />
|
||||
<Redirect
|
||||
to={`${HOSTS_PATH}/name/${hostName}/${HostsTableType.anomalies}?${reEncoded}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -240,7 +240,7 @@ describe('Navigation Breadcrumbs', () => {
|
|||
hostsBreadcrumbs,
|
||||
{
|
||||
text: 'siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/name/siem-kibana',
|
||||
},
|
||||
{ text: 'Authentications', href: '' },
|
||||
]);
|
||||
|
@ -458,7 +458,7 @@ describe('Navigation Breadcrumbs', () => {
|
|||
}),
|
||||
expect.objectContaining({
|
||||
text: 'siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/name/siem-kibana',
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
{
|
||||
|
@ -556,7 +556,7 @@ describe('Navigation Breadcrumbs', () => {
|
|||
hostsBreadcrumbs,
|
||||
{
|
||||
text: 'siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/name/siem-kibana',
|
||||
},
|
||||
{ text: 'Authentications', href: '' },
|
||||
]);
|
||||
|
@ -787,7 +787,7 @@ describe('Navigation Breadcrumbs', () => {
|
|||
}),
|
||||
expect.objectContaining({
|
||||
text: 'siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/siem-kibana',
|
||||
href: 'securitySolutionUI/hosts/name/siem-kibana',
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
{
|
||||
|
|
|
@ -89,7 +89,7 @@ describe('Table Navigation', () => {
|
|||
`EuiTab[data-test-subj="navigation-${HostsTableType.authentications}"]`
|
||||
);
|
||||
expect(firstTab.props().href).toBe(
|
||||
`/app/securitySolutionUI/hosts/siem-window/authentications${SEARCH_QUERY}`
|
||||
`/app/securitySolutionUI/hosts/name/siem-window/authentications${SEARCH_QUERY}`
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ describe('body', () => {
|
|||
test(`it should pass expected object properties to ${componentName}`, () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<MemoryRouter initialEntries={[`/hosts/host-1/${path}`]}>
|
||||
<MemoryRouter initialEntries={[`/hosts/name/host-1/${path}`]}>
|
||||
<HostDetailsTabs
|
||||
isInitializing={false}
|
||||
detailName={'host-1'}
|
||||
|
|
|
@ -12,7 +12,7 @@ import { HostsTableType } from '../../store/model';
|
|||
import { HOSTS_PATH } from '../../../../common/constants';
|
||||
|
||||
const getTabsOnHostDetailsUrl = (hostName: string, tabName: HostsTableType) =>
|
||||
`${HOSTS_PATH}/${hostName}/${tabName}`;
|
||||
`${HOSTS_PATH}/name/${hostName}/${tabName}`;
|
||||
|
||||
export const navTabsHostDetails = ({
|
||||
hasMlUserPermissions,
|
||||
|
|
|
@ -55,7 +55,7 @@ export const HostsContainer = React.memo(() => (
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
<Route // Redirect to the first tab when tabName is not present.
|
||||
path={hostDetailsPagePath}
|
||||
render={({
|
||||
match: {
|
||||
|
@ -65,14 +65,29 @@ export const HostsContainer = React.memo(() => (
|
|||
}) => (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: `${HOSTS_PATH}/${detailName}/${HostsTableType.authentications}`,
|
||||
pathname: `${HOSTS_PATH}/name/${detailName}/${HostsTableType.authentications}`,
|
||||
search,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Route
|
||||
<Route // Compatibility redirect for the old user detail path.
|
||||
path={`${HOSTS_PATH}/:detailName/:tabName?`}
|
||||
render={({
|
||||
match: {
|
||||
params: { detailName, tabName = HostsTableType.authentications },
|
||||
},
|
||||
location: { search = '' },
|
||||
}) => (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: `${HOSTS_PATH}/name/${detailName}/${tabName}`,
|
||||
search,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route // Redirect to the first tab when tabName is not present.
|
||||
path={HOSTS_PATH}
|
||||
render={({ location: { search = '' } }) => (
|
||||
<Redirect to={{ pathname: `${HOSTS_PATH}/${HostsTableType.hosts}`, search }} />
|
||||
|
|
|
@ -13,7 +13,7 @@ import type { GlobalTimeArgs } from '../../common/containers/use_global_time';
|
|||
import type { InputsModelId } from '../../common/store/inputs/constants';
|
||||
import { HOSTS_PATH } from '../../../common/constants';
|
||||
|
||||
export const hostDetailsPagePath = `${HOSTS_PATH}/:detailName`;
|
||||
export const hostDetailsPagePath = `${HOSTS_PATH}/name/:detailName`;
|
||||
|
||||
export type HostsTabsProps = GlobalTimeArgs & {
|
||||
filterQuery: string;
|
||||
|
|
|
@ -146,7 +146,7 @@ exports[`Field Renderers #hostIdRenderer it renders correctly against snapshot 1
|
|||
<a
|
||||
class="euiLink emotion-euiLink-primary"
|
||||
data-test-subj="host-details-button"
|
||||
href="securitySolutionUI/hosts/raspberrypi"
|
||||
href="securitySolutionUI/hosts/name/raspberrypi"
|
||||
rel="noreferrer"
|
||||
>
|
||||
raspberrypi
|
||||
|
@ -201,7 +201,7 @@ exports[`Field Renderers #hostNameRenderer it renders correctly against snapshot
|
|||
<a
|
||||
class="euiLink emotion-euiLink-primary"
|
||||
data-test-subj="host-details-button"
|
||||
href="securitySolutionUI/hosts/raspberrypi"
|
||||
href="securitySolutionUI/hosts/name/raspberrypi"
|
||||
rel="noreferrer"
|
||||
>
|
||||
raspberrypi
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { USERS_PATH } from '../../../common/constants';
|
||||
import { UsersTableType } from '../store/model';
|
||||
|
||||
export const usersDetailsPagePath = `${USERS_PATH}/:detailName`;
|
||||
export const usersDetailsPagePath = `${USERS_PATH}/name/:detailName`;
|
||||
|
||||
export const usersTabPath = `${USERS_PATH}/:tabName(${UsersTableType.allUsers}|${UsersTableType.authentications}|${UsersTableType.anomalies}|${UsersTableType.risk}|${UsersTableType.events}|)`;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { UsersTableType } from '../../store/model';
|
|||
import { USERS_PATH } from '../../../../common/constants';
|
||||
|
||||
const getTabsOnUsersDetailsUrl = (userName: string, tabName: UsersTableType) =>
|
||||
`${USERS_PATH}/${userName}/${tabName}`;
|
||||
`${USERS_PATH}/name/${userName}/${tabName}`;
|
||||
|
||||
export const navTabsUsersDetails = (
|
||||
userName: string,
|
||||
|
|
|
@ -34,7 +34,7 @@ export const UsersContainer = React.memo(() => {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
<Route // Redirect to the first tab when tabName is not present.
|
||||
path={usersDetailsPagePath}
|
||||
render={({
|
||||
match: {
|
||||
|
@ -44,13 +44,30 @@ export const UsersContainer = React.memo(() => {
|
|||
}) => (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: `${USERS_PATH}/${detailName}/${UsersTableType.authentications}`,
|
||||
pathname: `${USERS_PATH}/name/${detailName}/${UsersTableType.authentications}`,
|
||||
search,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
|
||||
<Route // Compatibility redirect for the old user detail path.
|
||||
path={`${USERS_PATH}/:detailName/:tabName?`}
|
||||
render={({
|
||||
match: {
|
||||
params: { detailName, tabName = UsersTableType.authentications },
|
||||
},
|
||||
location: { search = '' },
|
||||
}) => (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: `${USERS_PATH}/name/${detailName}/${tabName}`,
|
||||
search,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route // Redirect to the first tab when tabName is not present.
|
||||
path={USERS_PATH}
|
||||
render={({ location: { search = '' } }) => (
|
||||
<Redirect to={{ pathname: `${USERS_PATH}/${UsersTableType.allUsers}`, search }} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue