Skip to content

Commit

Permalink
[Serverless nav] Remove trailing forward slash in Cloud URLs (#170617)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga committed Nov 6, 2023
1 parent 42fc7ea commit b562839
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import {
type TestType,
type ProjectNavigationChangeListener,
} from './utils';
import { getServicesMock } from '../mocks/src/jest';

const { cloudLinks: mockCloudLinks } = getServicesMock();

describe('builds navigation tree', () => {
test('render reference UI and build the navigation tree', async () => {
Expand Down Expand Up @@ -675,21 +678,41 @@ describe('builds navigation tree', () => {
});

test('should render the cloud links', async () => {
const stripLastChar = (str: string = '') => str.substring(0, str.length - 1);

const runTests = async (type: TestType, { findByTestId }: RenderResult) => {
try {
expect(await findByTestId(/nav-item-group1.cloudLink1/)).toBeVisible();
expect(await findByTestId(/nav-item-group1.cloudLink2/)).toBeVisible();
expect(await findByTestId(/nav-item-group1.cloudLink3/)).toBeVisible();

expect((await findByTestId(/nav-item-group1.cloudLink1/)).textContent).toBe(
'Mock Users & RolesExternal link'
);
expect((await findByTestId(/nav-item-group1.cloudLink2/)).textContent).toBe(
'Mock PerformanceExternal link'
);
expect((await findByTestId(/nav-item-group1.cloudLink3/)).textContent).toBe(
'Mock Billing & SubscriptionsExternal link'
);
{
const userAndRolesLink = await findByTestId(/nav-item-group1.cloudLink1/);
expect(userAndRolesLink.textContent).toBe('Mock Users & RolesExternal link');
const href = userAndRolesLink.getAttribute('href');
expect(href).toBe(stripLastChar(mockCloudLinks.userAndRoles?.href));
}

{
const performanceLink = await findByTestId(/nav-item-group1.cloudLink2/);
expect(performanceLink.textContent).toBe('Mock PerformanceExternal link');
const href = performanceLink.getAttribute('href');
expect(href).toBe(stripLastChar(mockCloudLinks.performance?.href));
}

{
const billingLink = await findByTestId(/nav-item-group1.cloudLink3/);
expect(billingLink.textContent).toBe('Mock Billing & SubscriptionsExternal link');
const href = billingLink.getAttribute('href');
expect(href).toBe(stripLastChar(mockCloudLinks.billingAndSub?.href));
}

{
const deploymentLink = await findByTestId(/nav-item-group1.cloudLink4/);
expect(deploymentLink.textContent).toBe('Mock DeploymentExternal link');
const href = deploymentLink.getAttribute('href');
expect(href).toBe(stripLastChar(mockCloudLinks.deployment?.href));
}
} catch (e) {
errorHandler(type)(e);
}
Expand All @@ -706,6 +729,7 @@ describe('builds navigation tree', () => {
{ id: 'cloudLink1', cloudLink: 'userAndRoles' },
{ id: 'cloudLink2', cloudLink: 'performance' },
{ id: 'cloudLink3', cloudLink: 'billingAndSub' },
{ id: 'cloudLink4', cloudLink: 'deployment' },
],
},
];
Expand All @@ -727,6 +751,7 @@ describe('builds navigation tree', () => {
<Navigation.Item id="cloudLink1" cloudLink="userAndRoles" />
<Navigation.Item id="cloudLink2" cloudLink="performance" />
<Navigation.Item id="cloudLink3" cloudLink="billingAndSub" />
<Navigation.Item id="cloudLink4" cloudLink="deployment" />
</Navigation.Group>
</Navigation>
),
Expand Down
10 changes: 7 additions & 3 deletions packages/shared-ux/chrome/navigation/mocks/src/jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,19 @@ export const getServicesMock = ({
cloudLinks: {
billingAndSub: {
title: 'Mock Billing & Subscriptions',
href: 'https://cloud.elastic.co/account/billing',
href: 'https://cloud.elastic.co/account/billing/',
},
performance: {
title: 'Mock Performance',
href: 'https://cloud.elastic.co/deployments/123456789/performance',
href: 'https://cloud.elastic.co/deployments/123456789/performance/',
},
userAndRoles: {
title: 'Mock Users & Roles',
href: 'https://cloud.elastic.co/deployments/123456789/security/users',
href: 'https://cloud.elastic.co/deployments/123456789/security/users/',
},
deployment: {
title: 'Mock Deployment',
href: 'https://cloud.elastic.co/deployments/123456789/',
},
},
};
Expand Down
10 changes: 6 additions & 4 deletions packages/shared-ux/chrome/navigation/src/cloud_links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { i18n } from '@kbn/i18n';
import type { CloudLinkId } from '@kbn/core-chrome-browser';
import type { CloudStart } from '@kbn/cloud-plugin/public';

export interface CloudLink {
title: string;
href: string;
}

export type CloudLinks = {
[id in CloudLinkId]?: {
title: string;
href: string;
};
[id in CloudLinkId]?: CloudLink;
};

export const getCloudLinks = (cloud: CloudStart): CloudLinks => {
Expand Down
39 changes: 36 additions & 3 deletions packages/shared-ux/chrome/navigation/src/services.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,45 @@
import React, { FC, useContext, useMemo } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { NavigationKibanaDependencies, NavigationServices } from '../types';
import { CloudLinks, getCloudLinks } from './cloud_links';
import { CloudLink, CloudLinks, getCloudLinks } from './cloud_links';

const Context = React.createContext<NavigationServices | null>(null);

const stripTrailingForwardSlash = (str: string) => {
return str[str.length - 1] === '/' ? str.substring(0, str.length - 1) : str;
};

const parseCloudURLs = (cloudLinks: CloudLinks): CloudLinks => {
const { userAndRoles, billingAndSub, deployment, performance } = cloudLinks;

// We remove potential trailing forward slash ("/") at the end of the URL
// because it breaks future navigation in Cloud console once we navigate there.
const parseLink = (link?: CloudLink): CloudLink | undefined => {
if (!link) return undefined;
return { ...link, href: stripTrailingForwardSlash(link.href) };
};

return {
...cloudLinks,
userAndRoles: parseLink(userAndRoles),
billingAndSub: parseLink(billingAndSub),
deployment: parseLink(deployment),
performance: parseLink(performance),
};
};

/**
* A Context Provider that provides services to the component and its dependencies.
*/
export const NavigationProvider: FC<NavigationServices> = ({ children, ...services }) => {
return <Context.Provider value={services}>{children}</Context.Provider>;
const servicesParsed = useMemo<NavigationServices>(() => {
return {
...services,
cloudLinks: parseCloudURLs(services.cloudLinks),
};
}, [services]);

return <Context.Provider value={servicesParsed}>{children}</Context.Provider>;
};

/**
Expand All @@ -32,7 +62,10 @@ export const NavigationKibanaProvider: FC<NavigationKibanaDependencies> = ({
const { basePath } = http;
const { navigateToUrl } = core.application;

const cloudLinks: CloudLinks = useMemo(() => (cloud ? getCloudLinks(cloud) : {}), [cloud]);
const cloudLinks: CloudLinks = useMemo(
() => (cloud ? parseCloudURLs(getCloudLinks(cloud)) : {}),
[cloud]
);
const isSideNavCollapsed = useObservable(chrome.getIsSideNavCollapsed$(), true);

const value: NavigationServices = {
Expand Down

0 comments on commit b562839

Please sign in to comment.