Skip to content

Commit

Permalink
Update page for missing Short URL Part II (#172422)
Browse files Browse the repository at this point in the history
## Summary

This PR re-opens #171679 which had
to be reverted due to CI instability at the time it was originally
mergted.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
tsullivan and kibanamachine authored Dec 5, 2023
1 parent 13bdcb5 commit 1e93160
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 67 deletions.
1 change: 1 addition & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ enabled:
- test/functional/apps/kibana_overview/config.ts
- test/functional/apps/management/config.ts
- test/functional/apps/saved_objects_management/config.ts
- test/functional/apps/sharing/config.ts
- test/functional/apps/status_page/config.ts
- test/functional/apps/visualize/group1/config.ts
- test/functional/apps/visualize/group2/config.ts
Expand Down
13 changes: 13 additions & 0 deletions src/plugins/share/public/lib/get_home_href.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { HttpSetup, IUiSettingsClient } from '@kbn/core/public';

export function getHomeHref(http: HttpSetup, uiSettings: IUiSettingsClient) {
return http.basePath.prepend(uiSettings.get('defaultRoute'));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as React from 'react';

import { EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { ChromeDocTitle } from '@kbn/core-chrome-browser';
import { NotFoundPrompt } from '@kbn/shared-ux-prompt-not-found';

const defaultTitle = i18n.translate('share.urlService.redirect.components.Error.title', {
defaultMessage: 'Unable to open URL',
description:
'Title displayed to user in redirect endpoint when redirection cannot be performed successfully.',
});

const defaultBody = i18n.translate('share.urlService.redirect.components.Error.body', {
defaultMessage:
`Sorry, the object you're looking for can't be found at this URL.` +
` It might have been removed or maybe it never existed.`,
});

export interface ErrorProps {
title?: string;
body?: string;
homeHref: string;
docTitle: ChromeDocTitle;
error: Error;
}

export const RedirectEmptyPrompt: React.FC<ErrorProps> = ({
title = defaultTitle,
body = defaultBody,
homeHref,
docTitle,
error,
}) => {
// eslint-disable-next-line no-console
console.error('Short URL redirect error', error);

docTitle.change(
i18n.translate('share.urlService.redirect.components.docTitle', { defaultMessage: 'Not Found' })
);

return (
<NotFoundPrompt
title={<h2>{title}</h2>}
body={<p data-test-subj="redirectErrorEmptyPromptBody">{body}</p>}
actions={
<EuiButtonEmpty
iconType="arrowLeft"
href={homeHref}
data-test-subj="redirectErrorEmptyPromptButton"
>
{i18n.translate('share.urlService.redirect.components.Error.homeButton', {
defaultMessage: 'Back to home',
})}
</EuiButtonEmpty>
}
/>
);
};
53 changes: 0 additions & 53 deletions src/plugins/share/public/url_service/redirect/components/error.tsx

This file was deleted.

24 changes: 17 additions & 7 deletions src/plugins/share/public/url_service/redirect/components/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,39 @@

import * as React from 'react';
import useObservable from 'react-use/lib/useObservable';

import { EuiPageTemplate } from '@elastic/eui';
import { ThemeServiceSetup } from '@kbn/core/public';
import type { CustomBrandingSetup } from '@kbn/core-custom-branding-browser';
import type { ChromeDocTitle, ThemeServiceSetup } from '@kbn/core/public';
import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme';
import { CustomBrandingStart } from '@kbn/core-custom-branding-browser';
import { Error } from './error';
import { RedirectManager } from '../redirect_manager';

import type { RedirectManager } from '../redirect_manager';
import { RedirectEmptyPrompt } from './empty_prompt';
import { Spinner } from './spinner';

export interface PageProps {
homeHref: string;
docTitle: ChromeDocTitle;
customBranding: CustomBrandingSetup;
manager: Pick<RedirectManager, 'error$'>;
theme: ThemeServiceSetup;
customBranding: CustomBrandingStart;
}

export const Page: React.FC<PageProps> = ({ manager, theme, customBranding }) => {
export const Page: React.FC<PageProps> = ({
manager,
homeHref,
customBranding,
docTitle,
theme,
}) => {
const error = useObservable(manager.error$);
const hasCustomBranding = useObservable(customBranding.hasCustomBranding$);

if (error) {
return (
<KibanaThemeProvider theme={{ theme$: theme.theme$ }}>
<EuiPageTemplate>
<Error error={error} />
<RedirectEmptyPrompt docTitle={docTitle} error={error} homeHref={homeHref} />
</EuiPageTemplate>
</KibanaThemeProvider>
);
Expand Down
22 changes: 16 additions & 6 deletions src/plugins/share/public/url_service/redirect/redirect_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@

import type { CoreSetup } from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import { BehaviorSubject } from 'rxjs';
import type { Location } from 'history';
import { migrateToLatest } from '@kbn/kibana-utils-plugin/common';
import type { Location } from 'history';
import { BehaviorSubject } from 'rxjs';
import type { UrlService } from '../../../common/url_service';
import { parseSearchParams, RedirectOptions } from '../../../common/url_service/locators/redirect';
import {
LEGACY_SHORT_URL_LOCATOR_ID,
LegacyShortUrlLocatorParams,
} from '../../../common/url_service/locators/legacy_short_url_locator';
import { parseSearchParams, RedirectOptions } from '../../../common/url_service/locators/redirect';
import { getHomeHref } from '../../lib/get_home_href';

export interface RedirectManagerDependencies {
url: UrlService;
Expand All @@ -28,18 +29,27 @@ export class RedirectManager {
constructor(public readonly deps: RedirectManagerDependencies) {}

public registerLocatorRedirectApp(core: CoreSetup) {
core.application.register({
const { application, customBranding, http, theme } = core;

application.register({
id: 'r',
title: 'Redirect endpoint',
chromeless: true,
mount: async (params) => {
const { render } = await import('./render');
const [start] = await core.getStartServices();
const { chrome, uiSettings } = start;

const unmount = render(params.element, {
manager: this,
theme: core.theme,
customBranding: core.customBranding,
customBranding,
docTitle: chrome.docTitle,
theme,
homeHref: getHomeHref(http, uiSettings),
});

this.onMount(params.history.location);

return () => {
unmount();
};
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/share/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"@kbn/react-kibana-context-theme",
"@kbn/core-analytics-browser",
"@kbn/shared-ux-error-boundary",
"@kbn/core-chrome-browser",
"@kbn/shared-ux-prompt-not-found",
],
"exclude": [
"target/**/*",
Expand Down
51 changes: 51 additions & 0 deletions test/functional/apps/sharing/_short_urls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getPageObjects, getService }: FtrProviderContext) {
describe('Short URLs', () => {
const PageObjects = getPageObjects(['common']);
const browser = getService('browser');
const log = getService('log');
const testSubjects = getService('testSubjects');
const retry = getService('retry');

it('shows Page for missing short URL', async () => {
await PageObjects.common.navigateToApp('home');

// go to 404
const currentUrl = await browser.getCurrentUrl();
log.info('Changing URL to missing short URL...');
const newUrl = currentUrl.replace(/\/app\/home/, '/app/r/s/foofoo');
await browser.get(newUrl);

// check the page for 404 contents
log.info('Checking page title...');
await retry.try(async () => {
const title = await browser.getTitle();
expect(title).to.be('Not Found - Elastic');
});

await retry.try(async () => {
await testSubjects.existOrFail('redirectErrorEmptyPromptBody');
});

// click "back to home" button
log.info('Clicking the prompt button...');
await testSubjects.click('redirectErrorEmptyPromptButton');

// check the page
await retry.try(async () => {
const title = await browser.getTitle();
expect(title).to.be('Home - Elastic');
});
});
});
}
18 changes: 18 additions & 0 deletions test/functional/apps/sharing/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { FtrConfigProviderContext } from '@kbn/test';

export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(require.resolve('../../config.base.js'));

return {
...functionalConfig.getAll(),
testFiles: [require.resolve('.')],
};
}
15 changes: 15 additions & 0 deletions test/functional/apps/sharing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ loadTestFile }: FtrProviderContext) {
describe('Sharing features', () => {
loadTestFile(require.resolve('./_short_urls'));
});
}
2 changes: 1 addition & 1 deletion x-pack/plugins/canvas/shareable_runtime/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ module.exports = {
loader: 'expose-loader?jQuery!expose-loader?$',
},
{
test: /\.(woff|woff2|ttf|eot|svg|ico)(\?|$)/,
test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/,
loader: 'url-loader',
sideEffects: false,
},
Expand Down

0 comments on commit 1e93160

Please sign in to comment.