Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Serverless nav] Remove trailing forward slash in Cloud URLs #170617

Merged
merged 1 commit into from
Nov 6, 2023
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
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
Loading