mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Switch to core application service (#63443)
This commit is contained in:
parent
3cbb8491c1
commit
b7e87c2c8b
339 changed files with 2239 additions and 1706 deletions
|
@ -29,7 +29,7 @@ The API returns the following:
|
|||
"id": "discover",
|
||||
"name": "Discover",
|
||||
"icon": "discoverApp",
|
||||
"navLinkId": "kibana:discover",
|
||||
"navLinkId": "discover",
|
||||
"app": [
|
||||
"kibana"
|
||||
],
|
||||
|
@ -74,7 +74,7 @@ The API returns the following:
|
|||
"id": "visualize",
|
||||
"name": "Visualize",
|
||||
"icon": "visualizeApp",
|
||||
"navLinkId": "kibana:visualize",
|
||||
"navLinkId": "visualize",
|
||||
"app": [
|
||||
"kibana"
|
||||
],
|
||||
|
@ -121,7 +121,7 @@ The API returns the following:
|
|||
"id": "dashboard",
|
||||
"name": "Dashboard",
|
||||
"icon": "dashboardApp",
|
||||
"navLinkId": "kibana:dashboard",
|
||||
"navLinkId": "dashboards",
|
||||
"app": [
|
||||
"kibana"
|
||||
],
|
||||
|
@ -173,7 +173,7 @@ The API returns the following:
|
|||
"id": "dev_tools",
|
||||
"name": "Dev Tools",
|
||||
"icon": "devToolsApp",
|
||||
"navLinkId": "kibana:dev_tools",
|
||||
"navLinkId": "dev_tools",
|
||||
"app": [
|
||||
"kibana"
|
||||
],
|
||||
|
|
|
@ -153,7 +153,7 @@ init(server) {
|
|||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
icon: 'devToolsApp',
|
||||
navLinkId: 'kibana:dev_tools',
|
||||
navLinkId: 'dev_tools',
|
||||
app: ['kibana'],
|
||||
catalogue: ['console', 'searchprofiler', 'grokdebugger'],
|
||||
privileges: {
|
||||
|
@ -216,7 +216,7 @@ init(server) {
|
|||
}),
|
||||
order: 100,
|
||||
icon: 'discoverApp',
|
||||
navLinkId: 'kibana:discover',
|
||||
navLinkId: 'discover',
|
||||
app: ['kibana'],
|
||||
catalogue: ['discover'],
|
||||
privileges: {
|
||||
|
|
|
@ -174,7 +174,7 @@ to view an embedded dashboard.
|
|||
* Generate a PNG report
|
||||
|
||||
TIP: To create a link to a dashboard by title, use: +
|
||||
`${domain}/${basepath?}/app/kibana#/dashboards?title=${yourdashboardtitle}`
|
||||
`${domain}/${basepath?}/app/dashboards#/list?title=${yourdashboardtitle}`
|
||||
|
||||
TIP: When sharing a link to a dashboard snapshot, use the *Short URL*. Snapshot
|
||||
URLs are long and can be problematic for Internet Explorer and other
|
||||
|
|
|
@ -192,7 +192,7 @@ export class ChromeService {
|
|||
forceAppSwitcherNavigation$={navLinks.getForceAppSwitcherNavigation$()}
|
||||
helpExtension$={helpExtension$.pipe(takeUntil(this.stop$))}
|
||||
helpSupportUrl$={helpSupportUrl$.pipe(takeUntil(this.stop$))}
|
||||
homeHref={http.basePath.prepend('/app/kibana#/home')}
|
||||
homeHref={http.basePath.prepend('/app/home')}
|
||||
isVisible$={this.isVisible$}
|
||||
kibanaVersion={injectedMetadata.getKibanaVersion()}
|
||||
legacyMode={injectedMetadata.getLegacyMode()}
|
||||
|
|
|
@ -116,6 +116,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
navigateToApp={[Function]}
|
||||
onIsLockedUpdate={[Function]}
|
||||
onIsOpenUpdate={[Function]}
|
||||
recentNavLinks={
|
||||
|
@ -2993,6 +2994,7 @@ exports[`CollapsibleNav renders the default nav 1`] = `
|
|||
isLocked={false}
|
||||
isOpen={false}
|
||||
navLinks={Array []}
|
||||
navigateToApp={[Function]}
|
||||
onIsLockedUpdate={[Function]}
|
||||
onIsOpenUpdate={[Function]}
|
||||
recentNavLinks={Array []}
|
||||
|
@ -3023,6 +3025,7 @@ exports[`CollapsibleNav renders the default nav 2`] = `
|
|||
isLocked={false}
|
||||
isOpen={true}
|
||||
navLinks={Array []}
|
||||
navigateToApp={[Function]}
|
||||
onIsLockedUpdate={[Function]}
|
||||
onIsOpenUpdate={[Function]}
|
||||
recentNavLinks={Array []}
|
||||
|
@ -3589,6 +3592,7 @@ exports[`CollapsibleNav renders the default nav 3`] = `
|
|||
isLocked={true}
|
||||
isOpen={true}
|
||||
navLinks={Array []}
|
||||
navigateToApp={[Function]}
|
||||
onIsLockedUpdate={[Function]}
|
||||
onIsOpenUpdate={[Function]}
|
||||
recentNavLinks={Array []}
|
||||
|
|
|
@ -63,6 +63,7 @@ function mockProps() {
|
|||
storage: new StubBrowserStorage(),
|
||||
onIsOpenUpdate: () => {},
|
||||
onIsLockedUpdate: () => {},
|
||||
navigateToApp: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ interface Props {
|
|||
storage?: Storage;
|
||||
onIsLockedUpdate: OnIsLockedUpdate;
|
||||
onIsOpenUpdate: (isOpen?: boolean) => void;
|
||||
navigateToApp: (appId: string) => void;
|
||||
}
|
||||
|
||||
export function CollapsibleNav({
|
||||
|
@ -89,6 +90,7 @@ export function CollapsibleNav({
|
|||
onIsOpenUpdate,
|
||||
homeHref,
|
||||
id,
|
||||
navigateToApp,
|
||||
storage = window.localStorage,
|
||||
}: Props) {
|
||||
const lockRef = useRef<HTMLButtonElement>(null);
|
||||
|
@ -124,7 +126,19 @@ export function CollapsibleNav({
|
|||
label: 'Home',
|
||||
iconType: 'home',
|
||||
href: homeHref,
|
||||
onClick: () => onIsOpenUpdate(false),
|
||||
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
onIsOpenUpdate(false);
|
||||
if (
|
||||
event.isDefaultPrevented() ||
|
||||
event.altKey ||
|
||||
event.metaKey ||
|
||||
event.ctrlKey
|
||||
) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
navigateToApp('home');
|
||||
},
|
||||
},
|
||||
]}
|
||||
maxWidth="none"
|
||||
|
|
|
@ -247,6 +247,7 @@ export class Header extends Component<HeaderProps, State> {
|
|||
href={this.props.homeHref}
|
||||
forceNavigation={this.state.forceNavigation}
|
||||
navLinks={navLinks}
|
||||
navigateToApp={this.props.application.navigateToApp}
|
||||
/>
|
||||
</EuiHeaderSectionItem>
|
||||
|
||||
|
@ -287,6 +288,7 @@ export class Header extends Component<HeaderProps, State> {
|
|||
this.toggleCollapsibleNavRef.current.focus();
|
||||
}
|
||||
}}
|
||||
navigateToApp={this.props.application.navigateToApp}
|
||||
/>
|
||||
) : (
|
||||
// TODO #64541
|
||||
|
|
|
@ -41,7 +41,8 @@ function findClosestAnchor(element: HTMLElement): HTMLAnchorElement | void {
|
|||
function onClick(
|
||||
event: React.MouseEvent<HTMLAnchorElement>,
|
||||
forceNavigation: boolean,
|
||||
navLinks: NavLink[]
|
||||
navLinks: NavLink[],
|
||||
navigateToApp: (appId: string) => void
|
||||
) {
|
||||
const anchor = findClosestAnchor((event as any).nativeEvent.target);
|
||||
if (!anchor) {
|
||||
|
@ -54,32 +55,31 @@ function onClick(
|
|||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!forceNavigation ||
|
||||
event.isDefaultPrevented() ||
|
||||
event.altKey ||
|
||||
event.metaKey ||
|
||||
event.ctrlKey
|
||||
) {
|
||||
if (event.isDefaultPrevented() || event.altKey || event.metaKey || event.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toParsed = Url.parse(anchor.href);
|
||||
const fromParsed = Url.parse(document.location.href);
|
||||
const sameProto = toParsed.protocol === fromParsed.protocol;
|
||||
const sameHost = toParsed.host === fromParsed.host;
|
||||
const samePath = toParsed.path === fromParsed.path;
|
||||
if (forceNavigation) {
|
||||
const toParsed = Url.parse(anchor.href);
|
||||
const fromParsed = Url.parse(document.location.href);
|
||||
const sameProto = toParsed.protocol === fromParsed.protocol;
|
||||
const sameHost = toParsed.host === fromParsed.host;
|
||||
const samePath = toParsed.path === fromParsed.path;
|
||||
|
||||
if (sameProto && sameHost && samePath) {
|
||||
if (toParsed.hash) {
|
||||
document.location.reload();
|
||||
if (sameProto && sameHost && samePath) {
|
||||
if (toParsed.hash) {
|
||||
document.location.reload();
|
||||
}
|
||||
|
||||
// event.preventDefault() keeps the browser from seeing the new url as an update
|
||||
// and even setting window.location does not mimic that behavior, so instead
|
||||
// we use stopPropagation() to prevent angular from seeing the click and
|
||||
// starting a digest cycle/attempting to handle it in the router.
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
// event.preventDefault() keeps the browser from seeing the new url as an update
|
||||
// and even setting window.location does not mimic that behavior, so instead
|
||||
// we use stopPropagation() to prevent angular from seeing the click and
|
||||
// starting a digest cycle/attempting to handle it in the router.
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
navigateToApp('home');
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,14 +87,15 @@ interface Props {
|
|||
href: string;
|
||||
navLinks: NavLink[];
|
||||
forceNavigation: boolean;
|
||||
navigateToApp: (appId: string) => void;
|
||||
}
|
||||
|
||||
export function HeaderLogo({ href, forceNavigation, navLinks }: Props) {
|
||||
export function HeaderLogo({ href, forceNavigation, navLinks, navigateToApp }: Props) {
|
||||
return (
|
||||
<EuiHeaderLogo
|
||||
data-test-subj="logo"
|
||||
iconType="logoElastic"
|
||||
onClick={e => onClick(e, forceNavigation, navLinks)}
|
||||
onClick={e => onClick(e, forceNavigation, navLinks, navigateToApp)}
|
||||
href={href}
|
||||
aria-label={i18n.translate('core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel', {
|
||||
defaultMessage: 'Go to home page',
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('default route provider', () => {
|
|||
|
||||
expect(status).toEqual(302);
|
||||
expect(header).toMatchObject({
|
||||
location: '/hello/app/kibana',
|
||||
location: '/hello/app/home',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -71,7 +71,7 @@ describe('default route provider', () => {
|
|||
const { status, header } = await kbnTestServer.request.get(root, '/');
|
||||
expect(status).toEqual(302);
|
||||
expect(header).toMatchObject({
|
||||
location: '/hello/app/kibana',
|
||||
location: '/hello/app/home',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@ export default function(kibana) {
|
|||
},
|
||||
|
||||
uiExports: {
|
||||
hacks: ['plugins/kibana/dev_tools'],
|
||||
app: {
|
||||
id: 'kibana',
|
||||
title: 'Kibana',
|
||||
|
@ -61,49 +60,6 @@ export default function(kibana) {
|
|||
},
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
links: [
|
||||
{
|
||||
id: 'kibana:discover',
|
||||
title: i18n.translate('kbn.discoverTitle', {
|
||||
defaultMessage: 'Discover',
|
||||
}),
|
||||
order: 2000,
|
||||
url: `${kbnBaseUrl}#/discover`,
|
||||
euiIconType: 'discoverApp',
|
||||
disableSubUrlTracking: true,
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
},
|
||||
{
|
||||
id: 'kibana:visualize',
|
||||
title: i18n.translate('kbn.visualizeTitle', {
|
||||
defaultMessage: 'Visualize',
|
||||
}),
|
||||
order: 7000,
|
||||
url: `${kbnBaseUrl}#/visualize`,
|
||||
euiIconType: 'visualizeApp',
|
||||
disableSubUrlTracking: true,
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
},
|
||||
{
|
||||
id: 'kibana:dashboard',
|
||||
title: i18n.translate('kbn.dashboardTitle', {
|
||||
defaultMessage: 'Dashboard',
|
||||
}),
|
||||
order: 1000,
|
||||
url: `${kbnBaseUrl}#/dashboards`,
|
||||
euiIconType: 'dashboardApp',
|
||||
disableSubUrlTracking: true,
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
},
|
||||
{
|
||||
id: 'kibana:dev_tools',
|
||||
title: i18n.translate('kbn.devToolsTitle', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
order: 9001,
|
||||
url: '/app/kibana#/dev_tools',
|
||||
euiIconType: 'devToolsApp',
|
||||
category: DEFAULT_APP_CATEGORIES.management,
|
||||
},
|
||||
{
|
||||
id: 'kibana:stack_management',
|
||||
title: i18n.translate('kbn.managementTitle', {
|
||||
|
|
|
@ -24,6 +24,8 @@ import 'ui/private';
|
|||
import { pluginInstance } from './legacy';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import hits from 'fixtures/real_hits';
|
||||
import { setScopedHistory } from '../../../../../../plugins/discover/public/kibana_services';
|
||||
import { createBrowserHistory } from 'history';
|
||||
|
||||
let $parentScope;
|
||||
|
||||
|
@ -58,6 +60,7 @@ const destroy = function() {
|
|||
describe('docTable', function() {
|
||||
let $elem;
|
||||
|
||||
before(() => setScopedHistory(createBrowserHistory()));
|
||||
beforeEach(() => pluginInstance.initializeInnerAngular());
|
||||
beforeEach(() => pluginInstance.initializeServices());
|
||||
beforeEach(ngMock.module('app/discover'));
|
||||
|
|
|
@ -25,6 +25,8 @@ import { getFakeRow, getFakeRowVals } from 'fixtures/fake_row';
|
|||
import $ from 'jquery';
|
||||
import { pluginInstance } from './legacy';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import { setScopedHistory } from '../../../../../../plugins/discover/public/kibana_services';
|
||||
import { createBrowserHistory } from 'history';
|
||||
|
||||
describe('Doc Table', function() {
|
||||
let $parentScope;
|
||||
|
@ -37,6 +39,7 @@ describe('Doc Table', function() {
|
|||
let stubFieldFormatConverter;
|
||||
beforeEach(() => pluginInstance.initializeServices());
|
||||
beforeEach(() => pluginInstance.initializeInnerAngular());
|
||||
before(() => setScopedHistory(createBrowserHistory()));
|
||||
beforeEach(ngMock.module('app/discover'));
|
||||
beforeEach(
|
||||
ngMock.inject(function($rootScope, Private) {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
This folder is just a left-over of the things that can't be moved to Kibana platform just yet:
|
||||
|
||||
* Check whether there are no dev tools and hide the link in the nav bar (this can be moved as soon as all dev tools are moved)
|
|
@ -11,9 +11,6 @@
|
|||
// bad cascading in the Editor layout
|
||||
@import '../../../../plugins/maps_legacy/public/index';
|
||||
|
||||
// Home styles
|
||||
@import '../../../../plugins/home/public/application/index';
|
||||
|
||||
// Management styles
|
||||
@import './management/index';
|
||||
|
||||
|
|
|
@ -21,19 +21,15 @@
|
|||
|
||||
// preloading (for faster webpack builds)
|
||||
import routes from 'ui/routes';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
|
||||
// import the uiExports that we want to "use"
|
||||
import 'uiExports/home';
|
||||
import 'uiExports/visualize';
|
||||
import 'uiExports/savedObjectTypes';
|
||||
import 'uiExports/fieldFormatEditors';
|
||||
import 'uiExports/navbarExtensions';
|
||||
import 'uiExports/contextMenuActions';
|
||||
import 'uiExports/managementSections';
|
||||
import 'uiExports/indexManagement';
|
||||
import 'uiExports/docViews';
|
||||
import 'uiExports/embeddableFactories';
|
||||
import 'uiExports/embeddableActions';
|
||||
import 'uiExports/inspectorViews';
|
||||
|
@ -43,8 +39,6 @@ import 'uiExports/interpreter';
|
|||
|
||||
import 'ui/autoload/all';
|
||||
import './management';
|
||||
import './dev_tools';
|
||||
import { showAppRedirectNotification } from '../../../../plugins/kibana_legacy/public';
|
||||
import { localApplicationService } from './local_application_service';
|
||||
|
||||
npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('doc', 'discover', { keepPrefix: true });
|
||||
|
@ -58,7 +52,3 @@ const { config } = npSetup.plugins.kibanaLegacy;
|
|||
routes.otherwise({
|
||||
redirectTo: `/${config.defaultAppId || 'discover'}`,
|
||||
});
|
||||
|
||||
uiModules
|
||||
.get('kibana')
|
||||
.run($location => showAppRedirectNotification($location, npSetup.core.notifications.toasts));
|
||||
|
|
|
@ -106,7 +106,9 @@ export class LocalApplicationService {
|
|||
template: '<span></span>',
|
||||
controller($location: ILocationService) {
|
||||
const newPath = forwardDefinition.rewritePath($location.url());
|
||||
npStart.core.application.navigateToApp(forwardDefinition.newAppId, { path: newPath });
|
||||
window.location.replace(
|
||||
npStart.core.http.basePath.prepend(`/app/${forwardDefinition.newAppId}${newPath}`)
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -111,6 +111,7 @@ exports[`CreateIndexPatternWizard renders the empty state when there are no indi
|
|||
/>
|
||||
<EmptyState
|
||||
onRefresh={[Function]}
|
||||
prependBasePath={[MockFunction]}
|
||||
/>
|
||||
</div>
|
||||
<EuiGlobalToastList
|
||||
|
|
|
@ -19,7 +19,7 @@ exports[`EmptyState should render normally 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"getStartedLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="/app/home#/tutorial_directory/sampleData"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="get started with some sample data sets."
|
||||
|
@ -28,7 +28,7 @@ exports[`EmptyState should render normally 1`] = `
|
|||
/>
|
||||
</ForwardRef>,
|
||||
"learnHowLink": <ForwardRef
|
||||
href="#/home/tutorial_directory"
|
||||
href="/app/home#/tutorial_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn how"
|
||||
|
|
|
@ -24,7 +24,7 @@ import sinon from 'sinon';
|
|||
|
||||
describe('EmptyState', () => {
|
||||
it('should render normally', () => {
|
||||
const component = shallow(<EmptyState onRefresh={() => {}} />);
|
||||
const component = shallow(<EmptyState onRefresh={() => {}} prependBasePath={x => x} />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
@ -34,7 +34,9 @@ describe('EmptyState', () => {
|
|||
it('is called when refresh button is clicked', () => {
|
||||
const onRefreshHandler = sinon.stub();
|
||||
|
||||
const component = shallow(<EmptyState onRefresh={onRefreshHandler} />);
|
||||
const component = shallow(
|
||||
<EmptyState onRefresh={onRefreshHandler} prependBasePath={x => x} />
|
||||
);
|
||||
|
||||
component.find('[data-test-subj="refreshIndicesButton"]').simulate('click');
|
||||
|
||||
|
|
|
@ -22,8 +22,15 @@ import React from 'react';
|
|||
import { EuiCallOut, EuiTextColor, EuiLink, EuiButton } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { IBasePath } from 'kibana/public';
|
||||
|
||||
export const EmptyState = ({ onRefresh }: { onRefresh: () => void }) => (
|
||||
export const EmptyState = ({
|
||||
onRefresh,
|
||||
prependBasePath,
|
||||
}: {
|
||||
onRefresh: () => void;
|
||||
prependBasePath: IBasePath['prepend'];
|
||||
}) => (
|
||||
<div>
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
|
@ -48,7 +55,7 @@ export const EmptyState = ({ onRefresh }: { onRefresh: () => void }) => (
|
|||
</EuiTextColor>
|
||||
),
|
||||
learnHowLink: (
|
||||
<EuiLink href="#/home/tutorial_directory">
|
||||
<EuiLink href={prependBasePath('/app/home#/tutorial_directory')}>
|
||||
<FormattedMessage
|
||||
id="kbn.management.createIndexPattern.emptyStateLabel.learnHowLink"
|
||||
defaultMessage="Learn how"
|
||||
|
@ -56,7 +63,7 @@ export const EmptyState = ({ onRefresh }: { onRefresh: () => void }) => (
|
|||
</EuiLink>
|
||||
),
|
||||
getStartedLink: (
|
||||
<EuiLink href="#/home/tutorial_directory/sampleData">
|
||||
<EuiLink href={prependBasePath('/app/home#/tutorial_directory/sampleData')}>
|
||||
<FormattedMessage
|
||||
id="kbn.management.createIndexPattern.emptyStateLabel.getStartedLink"
|
||||
defaultMessage="get started with some sample data sets."
|
||||
|
|
|
@ -57,6 +57,7 @@ const services = {
|
|||
changeUrl: jest.fn(),
|
||||
openConfirm: overlays.openConfirm,
|
||||
indexPatternCreationType: mockIndexPatternCreationType,
|
||||
prependBasePath: jest.fn(x => x),
|
||||
};
|
||||
|
||||
describe('CreateIndexPatternWizard', () => {
|
||||
|
|
|
@ -35,6 +35,7 @@ import {
|
|||
SavedObjectsClient,
|
||||
IUiSettingsClient,
|
||||
OverlayStart,
|
||||
IBasePath,
|
||||
} from '../../../../../../../../core/public';
|
||||
import { DataPublicPluginStart } from '../../../../../../../../plugins/data/public';
|
||||
import { IndexPatternCreationConfig } from '../../../../../../../../plugins/index_pattern_management/public';
|
||||
|
@ -50,6 +51,7 @@ interface CreateIndexPatternWizardProps {
|
|||
uiSettings: IUiSettingsClient;
|
||||
changeUrl: (url: string) => void;
|
||||
openConfirm: OverlayStart['openConfirm'];
|
||||
prependBasePath: IBasePath['prepend'];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -235,7 +237,12 @@ export class CreateIndexPatternWizard extends Component<
|
|||
|
||||
const hasDataIndices = allIndices.some(({ name }: MatchedIndex) => !name.startsWith('.'));
|
||||
if (!hasDataIndices && !isIncludingSystemIndices && !remoteClustersExist) {
|
||||
return <EmptyState onRefresh={this.fetchData} />;
|
||||
return (
|
||||
<EmptyState
|
||||
onRefresh={this.fetchData}
|
||||
prependBasePath={this.props.services.prependBasePath}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (step === 1) {
|
||||
|
|
|
@ -45,6 +45,7 @@ uiRoutes.when('/management/kibana/index_pattern', {
|
|||
$scope.$evalAsync(() => kbnUrl.changePath(url));
|
||||
},
|
||||
openConfirm: npStart.core.overlays.openConfirm,
|
||||
prependBasePath: npStart.core.http.basePath.prepend,
|
||||
};
|
||||
|
||||
const initialQuery = $routeParams.id ? decodeURIComponent($routeParams.id) : undefined;
|
||||
|
|
|
@ -85,7 +85,7 @@ const savedObjectsManagement = getManagementaMock({
|
|||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/visualize/edit/${encodeURIComponent(obj.id)}`,
|
||||
path: `/app/visualize#/edit/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
};
|
||||
},
|
||||
|
@ -101,7 +101,7 @@ const savedObjectsManagement = getManagementaMock({
|
|||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/discover/${encodeURIComponent(obj.id)}`,
|
||||
path: `/app/discover#//${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
};
|
||||
},
|
||||
|
@ -200,7 +200,7 @@ describe('findRelationships', () => {
|
|||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/1',
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -214,7 +214,7 @@ describe('findRelationships', () => {
|
|||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/2',
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -228,7 +228,7 @@ describe('findRelationships', () => {
|
|||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/3',
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -453,7 +453,7 @@ describe('findRelationships', () => {
|
|||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/1',
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -467,7 +467,7 @@ describe('findRelationships', () => {
|
|||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/2',
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -481,7 +481,7 @@ describe('findRelationships', () => {
|
|||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/3',
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -567,7 +567,7 @@ describe('findRelationships', () => {
|
|||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/1',
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -581,7 +581,7 @@ describe('findRelationships', () => {
|
|||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/2',
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -595,7 +595,7 @@ describe('findRelationships', () => {
|
|||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/visualize/edit/3',
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
|
@ -609,7 +609,7 @@ describe('findRelationships', () => {
|
|||
title: 'My Saved Search',
|
||||
editUrl: '/management/kibana/objects/savedSearches/1',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/discover/1',
|
||||
path: '/app/discover#//1',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -69,7 +69,7 @@ export function getUiSettingDefaults() {
|
|||
name: i18n.translate('kbn.advancedSettings.defaultRoute.defaultRouteTitle', {
|
||||
defaultMessage: 'Default route',
|
||||
}),
|
||||
value: '/app/kibana',
|
||||
value: '/app/home',
|
||||
schema: schema.string({
|
||||
validate(value) {
|
||||
if (!value.startsWith('/') || !isRelativeUrl(value)) {
|
||||
|
|
|
@ -11,7 +11,5 @@
|
|||
@import './accessibility/index';
|
||||
@import './directives/index';
|
||||
@import './error_url_overflow/index';
|
||||
@import './exit_full_screen/index';
|
||||
@import './field_editor/index';
|
||||
@import './style_compile/index';
|
||||
@import '../../../plugins/management/public/components/index';
|
||||
|
|
|
@ -25,7 +25,6 @@ import '../private';
|
|||
import '../promises';
|
||||
import '../state_management/app_state';
|
||||
import '../state_management/global_state';
|
||||
import '../style_compile';
|
||||
import '../url';
|
||||
import '../directives/watch_multi';
|
||||
import '../react_components';
|
||||
|
|
|
@ -112,66 +112,28 @@ describe('chrome nav apis', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('internals.trackPossibleSubUrl()', function() {
|
||||
it('injects the globalState of the current url to all links for the same app', function() {
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
fakedLinks = [
|
||||
{
|
||||
id: 'kibana:discover',
|
||||
baseUrl: `${baseUrl}/app/kibana#discover`,
|
||||
subUrlBase: '/app/kibana#discover',
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
id: 'kibana:visualize',
|
||||
baseUrl: `${baseUrl}/app/kibana#visualize`,
|
||||
subUrlBase: '/app/kibana#visualize',
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
id: 'kibana:dashboard',
|
||||
baseUrl: `${baseUrl}/app/kibana#dashboards`,
|
||||
subUrlBase: '/app/kibana#dashboard',
|
||||
legacy: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { internals } = init({ appUrlStore });
|
||||
internals.trackPossibleSubUrl(`${baseUrl}/app/kibana#dashboard?_g=globalstate`);
|
||||
|
||||
expect(fakedLinks[0].url).to.be(`${baseUrl}/app/kibana#discover?_g=globalstate`);
|
||||
expect(fakedLinks[0].active).to.be(false);
|
||||
|
||||
expect(fakedLinks[1].url).to.be(`${baseUrl}/app/kibana#visualize?_g=globalstate`);
|
||||
expect(fakedLinks[1].active).to.be(false);
|
||||
|
||||
expect(fakedLinks[2].url).to.be(`${baseUrl}/app/kibana#dashboard?_g=globalstate`);
|
||||
expect(fakedLinks[2].active).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('chrome.trackSubUrlForApp()', function() {
|
||||
it('injects a manual app url', function() {
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
fakedLinks = [
|
||||
{
|
||||
id: 'kibana:visualize',
|
||||
baseUrl: `${baseUrl}/app/kibana#visualize`,
|
||||
url: `${baseUrl}/app/kibana#visualize`,
|
||||
subUrlBase: '/app/kibana#visualize',
|
||||
id: 'visualize',
|
||||
baseUrl: `${baseUrl}/app/visualize#`,
|
||||
url: `${baseUrl}/app/visualize#`,
|
||||
subUrlBase: '/app/visualize#',
|
||||
legacy: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { chrome } = init({ appUrlStore });
|
||||
const kibanaParsedUrl = absoluteToParsedUrl(
|
||||
`${baseUrl}/xyz/app/kibana#visualize/1234?_g=globalstate`,
|
||||
`${baseUrl}/xyz/app/visualize#/1234?_g=globalstate`,
|
||||
'/xyz'
|
||||
);
|
||||
chrome.trackSubUrlForApp('kibana:visualize', kibanaParsedUrl);
|
||||
chrome.trackSubUrlForApp('visualize', kibanaParsedUrl);
|
||||
expect(
|
||||
coreNavLinks.update.calledWith('kibana:visualize', {
|
||||
url: `${baseUrl}/xyz/app/kibana#visualize/1234?_g=globalstate`,
|
||||
coreNavLinks.update.calledWith('visualize', {
|
||||
url: `${baseUrl}/xyz/app/visualize#/1234?_g=globalstate`,
|
||||
})
|
||||
).to.be(true);
|
||||
});
|
||||
|
|
|
@ -357,9 +357,6 @@ export const npStart = {
|
|||
registerRenderer: sinon.fake(),
|
||||
registerType: sinon.fake(),
|
||||
},
|
||||
devTools: {
|
||||
getSortedDevTools: () => [],
|
||||
},
|
||||
kibanaLegacy: {
|
||||
getApps: () => [],
|
||||
getForwards: () => [],
|
||||
|
|
|
@ -39,7 +39,7 @@ import {
|
|||
Start as InspectorStart,
|
||||
} from '../../../../plugins/inspector/public';
|
||||
import { ChartsPluginSetup, ChartsPluginStart } from '../../../../plugins/charts/public';
|
||||
import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/public';
|
||||
import { DevToolsSetup } from '../../../../plugins/dev_tools/public';
|
||||
import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public';
|
||||
import { HomePublicPluginSetup } from '../../../../plugins/home/public';
|
||||
import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public';
|
||||
|
@ -105,7 +105,6 @@ export interface PluginsStart {
|
|||
inspector: InspectorStart;
|
||||
uiActions: UiActionsStart;
|
||||
navigation: NavigationPublicPluginStart;
|
||||
devTools: DevToolsStart;
|
||||
kibanaLegacy: KibanaLegacyStart;
|
||||
share: SharePluginStart;
|
||||
management: ManagementStart;
|
||||
|
|
|
@ -64,6 +64,7 @@ export function setStartServices(npStart: NpStart) {
|
|||
);
|
||||
visualizationsServices.setCapabilities(npStart.core.application.capabilities);
|
||||
visualizationsServices.setHttp(npStart.core.http);
|
||||
visualizationsServices.setApplication(npStart.core.application);
|
||||
visualizationsServices.setSavedObjects(npStart.core.savedObjects);
|
||||
visualizationsServices.setIndexPatterns(npStart.plugins.data.indexPatterns);
|
||||
visualizationsServices.setFilterManager(npStart.plugins.data.query.filterManager);
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
describe('styleCompile directive', function() {
|
||||
let config;
|
||||
let $rootScope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function($injector) {
|
||||
config = $injector.get('config');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
})
|
||||
);
|
||||
|
||||
it('exports a few config values as css', function() {
|
||||
const $style = $('#style-compile');
|
||||
|
||||
config.set('truncate:maxHeight', 0);
|
||||
$rootScope.$apply();
|
||||
expect($style.html().trim()).to.be(
|
||||
[
|
||||
'.truncate-by-height {',
|
||||
' max-height: none;',
|
||||
' display: inline-block;',
|
||||
'}',
|
||||
'.truncate-by-height:before {',
|
||||
' top: -15px;',
|
||||
'}',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
config.set('truncate:maxHeight', 15);
|
||||
$rootScope.$apply();
|
||||
expect($style.html().trim()).to.be(
|
||||
[
|
||||
'.truncate-by-height {',
|
||||
' max-height: 15px !important;',
|
||||
' display: inline-block;',
|
||||
'}',
|
||||
'.truncate-by-height:before {',
|
||||
' top: 0px;',
|
||||
'}',
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
style-compile {
|
||||
display: none;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
.truncate-by-height {
|
||||
max-height: <%= truncateMaxHeight %>;
|
||||
display: inline-block;
|
||||
}
|
||||
.truncate-by-height:before {
|
||||
top: <%= truncateGradientTop %>;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import '../config';
|
||||
import { uiModules } from '../modules';
|
||||
import cssTmpl from './style_compile.css.tmpl';
|
||||
|
||||
const $style = $('<style>')
|
||||
.appendTo('head')
|
||||
.attr('id', 'style-compile');
|
||||
|
||||
uiModules.get('kibana').run(function($rootScope, config) {
|
||||
const truncateGradientHeight = 15;
|
||||
const template = _.template(cssTmpl);
|
||||
const locals = {};
|
||||
|
||||
// watch the value of the truncate:maxHeight config param
|
||||
$rootScope.$watch(
|
||||
function() {
|
||||
return config.get('truncate:maxHeight');
|
||||
},
|
||||
function(maxHeight) {
|
||||
if (maxHeight > 0) {
|
||||
locals.truncateMaxHeight = maxHeight + 'px !important';
|
||||
locals.truncateGradientTop = maxHeight - truncateGradientHeight + 'px';
|
||||
} else {
|
||||
locals.truncateMaxHeight = 'none';
|
||||
locals.truncateGradientTop = '-' + truncateGradientHeight + 'px';
|
||||
}
|
||||
|
||||
$style.html(template(locals));
|
||||
}
|
||||
);
|
||||
});
|
|
@ -24,9 +24,9 @@ import { KibanaParsedUrl } from './kibana_parsed_url';
|
|||
|
||||
/**
|
||||
*
|
||||
* @param absoluteUrl - an absolute url, e.g. https://localhost:5601/gra/app/kibana#/visualize/edit/viz_id?hi=bye
|
||||
* @param absoluteUrl - an absolute url, e.g. https://localhost:5601/gra/app/visualize#/edit/viz_id?hi=bye
|
||||
* @param basePath - An optional base path for kibana. If supplied, should start with a "/".
|
||||
* e.g. in https://localhost:5601/gra/app/kibana#/visualize/edit/viz_id the basePath is
|
||||
* e.g. in https://localhost:5601/gra/app/visualize#/edit/viz_id the basePath is
|
||||
* "/gra".
|
||||
* @return {KibanaParsedUrl}
|
||||
*/
|
||||
|
|
|
@ -25,22 +25,22 @@ import { prependPath } from './prepend_path';
|
|||
interface Options {
|
||||
/**
|
||||
* An optional base path for kibana. If supplied, should start with a "/".
|
||||
* e.g. in https://localhost:5601/gra/app/kibana#/visualize/edit/viz_id the
|
||||
* e.g. in https://localhost:5601/gra/app/visualize#/edit/viz_id the
|
||||
* basePath is "/gra"
|
||||
*/
|
||||
basePath?: string;
|
||||
|
||||
/**
|
||||
* The app id.
|
||||
* e.g. in https://localhost:5601/gra/app/kibana#/visualize/edit/viz_id the app id is "kibana".
|
||||
* e.g. in https://localhost:5601/gra/app/visualize#/edit/viz_id the app id is "kibana".
|
||||
*/
|
||||
appId: string;
|
||||
|
||||
/**
|
||||
* The path for a page in the the app. Should start with a "/". Don't include the hash sign. Can
|
||||
* include all query parameters.
|
||||
* e.g. in https://localhost:5601/gra/app/kibana#/visualize/edit/viz_id?g=state the appPath is
|
||||
* "/visualize/edit/viz_id?g=state"
|
||||
* e.g. in https://localhost:5601/gra/app/visualize#/edit/viz_id?g=state the appPath is
|
||||
* "/edit/viz_id?g=state"
|
||||
*/
|
||||
appPath?: string;
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ import { i18n } from '@kbn/i18n';
|
|||
import { uiModules } from '../modules';
|
||||
import { AppStateProvider } from '../state_management/app_state';
|
||||
|
||||
uiModules.get('kibana/url').service('kbnUrl', function(Private) {
|
||||
uiModules.get('kibana/url').service('kbnUrl', function(Private, $injector) {
|
||||
//config is not directly used but registers global event listeners to kbnUrl to function
|
||||
$injector.get('config');
|
||||
return Private(KbnUrlProvider);
|
||||
});
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ describe('UiNavLink', () => {
|
|||
describe('constructor', () => {
|
||||
it('initializes the object properties as expected', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
euiIconType: 'discoverApp',
|
||||
hidden: true,
|
||||
disabled: true,
|
||||
|
@ -56,9 +56,9 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the order property to 0 when order is not specified in the spec', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
||||
|
@ -67,10 +67,10 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the linkToLastSubUrl property to false when false is specified in the spec', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
linkToLastSubUrl: false,
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
@ -80,10 +80,10 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the linkToLastSubUrl property to true by default', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
||||
|
@ -92,10 +92,10 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the hidden property to false by default', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
||||
|
@ -104,10 +104,10 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the disabled property to false by default', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
||||
|
@ -116,10 +116,10 @@ describe('UiNavLink', () => {
|
|||
|
||||
it('initializes the tooltip property to an empty string by default', () => {
|
||||
const spec = {
|
||||
id: 'kibana:discover',
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
order: -1003,
|
||||
url: '/app/kibana#/discover',
|
||||
url: '/app/discover#/',
|
||||
};
|
||||
const link = new UiNavLink(spec);
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@ export function send(method: string, path: string, data: any) {
|
|||
|
||||
const options: JQuery.AjaxSettings = {
|
||||
url: '../api/console/proxy?' + stringify({ path, method }, { sort: false }),
|
||||
headers: {
|
||||
'kbn-xsrf': 'kibana',
|
||||
},
|
||||
data,
|
||||
contentType: getContentType(data),
|
||||
cache: false,
|
||||
|
|
|
@ -155,6 +155,9 @@ export function setActiveApi(api) {
|
|||
$.ajax({
|
||||
url: '../api/console/api_server',
|
||||
dataType: 'json', // disable automatic guessing
|
||||
headers: {
|
||||
'kbn-xsrf': 'kibana',
|
||||
},
|
||||
}).then(
|
||||
function(data) {
|
||||
setActiveApi(loadApisFromJson(data));
|
||||
|
|
|
@ -41,7 +41,7 @@ export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDepen
|
|||
defaultMessage: 'Skip cURL and use this JSON interface to work with your data directly.',
|
||||
}),
|
||||
icon: 'consoleApp',
|
||||
path: '/app/kibana#/dev_tools/console',
|
||||
path: '/app/dev_tools#/console',
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.ADMIN,
|
||||
});
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
CoreStart,
|
||||
SavedObjectsClientContract,
|
||||
PluginInitializerContext,
|
||||
ScopedHistory,
|
||||
} from 'kibana/public';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
|
||||
import { Storage } from '../../../kibana_utils/public';
|
||||
|
@ -43,6 +44,11 @@ import { SharePluginStart } from '../../../share/public';
|
|||
import { KibanaLegacyStart, configureAppAngularModule } from '../../../kibana_legacy/public';
|
||||
import { SavedObjectLoader } from '../../../saved_objects/public';
|
||||
|
||||
// required for i18nIdDirective
|
||||
import 'angular-sanitize';
|
||||
// required for ngRoute
|
||||
import 'angular-route';
|
||||
|
||||
export interface RenderDeps {
|
||||
pluginInitializerContext: PluginInitializerContext;
|
||||
core: CoreStart;
|
||||
|
@ -65,6 +71,8 @@ export interface RenderDeps {
|
|||
share?: SharePluginStart;
|
||||
config: KibanaLegacyStart['config'];
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
navigateToDefaultApp: KibanaLegacyStart['navigateToDefaultApp'];
|
||||
scopedHistory: () => ScopedHistory;
|
||||
}
|
||||
|
||||
let angularModuleInstance: IModule | null = null;
|
||||
|
@ -76,7 +84,8 @@ export const renderApp = (element: HTMLElement, appBasePath: string, deps: Rende
|
|||
configureAppAngularModule(
|
||||
angularModuleInstance,
|
||||
{ core: deps.core, env: deps.pluginInitializerContext.env },
|
||||
true
|
||||
true,
|
||||
deps.scopedHistory
|
||||
);
|
||||
initDashboardApp(angularModuleInstance, deps);
|
||||
}
|
||||
|
@ -84,11 +93,12 @@ export const renderApp = (element: HTMLElement, appBasePath: string, deps: Rende
|
|||
const $injector = mountDashboardApp(appBasePath, element);
|
||||
|
||||
return () => {
|
||||
($injector.get('kbnUrlStateStorage') as any).cancel();
|
||||
$injector.get('$rootScope').$destroy();
|
||||
};
|
||||
};
|
||||
|
||||
const mainTemplate = (basePath: string) => `<div ng-view class="kbnLocalApplicationWrapper">
|
||||
const mainTemplate = (basePath: string) => `<div ng-view class="dshAppContainer">
|
||||
<base href="${basePath}" />
|
||||
</div>`;
|
||||
|
||||
|
@ -98,7 +108,7 @@ const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react'];
|
|||
|
||||
function mountDashboardApp(appBasePath: string, element: HTMLElement) {
|
||||
const mountpoint = document.createElement('div');
|
||||
mountpoint.setAttribute('class', 'kbnLocalApplicationWrapper');
|
||||
mountpoint.setAttribute('class', 'dshAppContainer');
|
||||
// eslint-disable-next-line
|
||||
mountpoint.innerHTML = mainTemplate(appBasePath);
|
||||
// bootstrap angular into detached element and attach it later to
|
||||
|
|
|
@ -90,10 +90,16 @@ export function initDashboardApp(app, deps) {
|
|||
};
|
||||
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
redirectTo: DashboardConstants.LANDING_PAGE_PATH,
|
||||
})
|
||||
.when(DashboardConstants.LANDING_PAGE_PATH, {
|
||||
...defaults,
|
||||
template: dashboardListingTemplate,
|
||||
controller: function($scope, kbnUrlStateStorage, history) {
|
||||
deps.core.chrome.docTitle.change(
|
||||
i18n.translate('dashboard.dashboardPageTitle', { defaultMessage: 'Dashboards' })
|
||||
);
|
||||
const service = deps.savedDashboards;
|
||||
const dashboardConfig = deps.dashboardConfig;
|
||||
|
||||
|
@ -178,6 +184,7 @@ export function initDashboardApp(app, deps) {
|
|||
.catch(
|
||||
redirectWhenMissing({
|
||||
history,
|
||||
navigateToApp: deps.core.application.navigateToApp,
|
||||
mapping: {
|
||||
dashboard: DashboardConstants.LANDING_PAGE_PATH,
|
||||
},
|
||||
|
@ -236,6 +243,7 @@ export function initDashboardApp(app, deps) {
|
|||
.catch(
|
||||
redirectWhenMissing({
|
||||
history,
|
||||
navigateToApp: deps.core.application.navigateToApp,
|
||||
mapping: {
|
||||
dashboard: DashboardConstants.LANDING_PAGE_PATH,
|
||||
},
|
||||
|
@ -245,11 +253,11 @@ export function initDashboardApp(app, deps) {
|
|||
},
|
||||
},
|
||||
})
|
||||
.when(`dashboard/:tail*?`, {
|
||||
redirectTo: `/${deps.config.defaultAppId}`,
|
||||
})
|
||||
.when(`dashboards/:tail*?`, {
|
||||
redirectTo: `/${deps.config.defaultAppId}`,
|
||||
.otherwise({
|
||||
template: '<span></span>',
|
||||
controller: function() {
|
||||
deps.navigateToDefaultApp();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,24 +21,24 @@ import { getDashboardIdFromUrl } from './url';
|
|||
|
||||
test('getDashboardIdFromUrl', () => {
|
||||
let url =
|
||||
"http://localhost:5601/wev/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
|
||||
"http://localhost:5601/wev/app/dashboards#/create?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
|
||||
expect(getDashboardIdFromUrl(url)).toEqual(undefined);
|
||||
|
||||
url =
|
||||
"http://localhost:5601/wev/app/kibana#/dashboard/625357282?_a=(description:'',filters:!()&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||
"http://localhost:5601/wev/app/dashboards#/view/625357282?_a=(description:'',filters:!()&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||
expect(getDashboardIdFromUrl(url)).toEqual('625357282');
|
||||
|
||||
url = 'http://myserver.mydomain.com:5601/wev/app/kibana#/dashboard/777182';
|
||||
url = 'http://myserver.mydomain.com:5601/wev/app/dashboards#/view/777182';
|
||||
expect(getDashboardIdFromUrl(url)).toEqual('777182');
|
||||
|
||||
url =
|
||||
"http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
|
||||
"http://localhost:5601/app/dashboards#/create?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
|
||||
expect(getDashboardIdFromUrl(url)).toEqual(undefined);
|
||||
|
||||
url = '/dashboard/test/?_g=(refreshInterval:';
|
||||
url = '/view/test/?_g=(refreshInterval:';
|
||||
expect(getDashboardIdFromUrl(url)).toEqual('test');
|
||||
|
||||
url = 'dashboard/test/?_g=(refreshInterval:';
|
||||
url = 'view/test/?_g=(refreshInterval:';
|
||||
expect(getDashboardIdFromUrl(url)).toEqual('test');
|
||||
|
||||
url = '/other-app/test/';
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* output: 39292992
|
||||
*/
|
||||
export function getDashboardIdFromUrl(url: string): string | undefined {
|
||||
const [, dashboardId] = url.match(/dashboard\/(.*?)(\/|\?|$)/) ?? [
|
||||
const [, dashboardId] = url.match(/view\/(.*?)(\/|\?|$)/) ?? [
|
||||
undefined, // full match
|
||||
undefined, // group with dashboardId
|
||||
];
|
||||
|
|
|
@ -102,7 +102,7 @@ exports[`after fetch initialFilter 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"sampleDataInstallLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install some sample data"
|
||||
|
@ -203,7 +203,7 @@ exports[`after fetch renders call to action when no dashboards exist 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"sampleDataInstallLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install some sample data"
|
||||
|
@ -304,7 +304,7 @@ exports[`after fetch renders table rows 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"sampleDataInstallLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install some sample data"
|
||||
|
@ -405,7 +405,7 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"sampleDataInstallLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install some sample data"
|
||||
|
@ -506,7 +506,7 @@ exports[`renders empty page in before initial fetch to avoid flickering 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"sampleDataInstallLink": <ForwardRef
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install some sample data"
|
||||
|
|
|
@ -112,7 +112,13 @@ export class DashboardListing extends React.Component {
|
|||
defaultMessage="New to Kibana? {sampleDataInstallLink} to take a test drive."
|
||||
values={{
|
||||
sampleDataInstallLink: (
|
||||
<EuiLink href="#/home/tutorial_directory/sampleData">
|
||||
<EuiLink
|
||||
onClick={() =>
|
||||
this.props.core.application.navigateTo('home', {
|
||||
path: '#/tutorial_directory/sampleData',
|
||||
})
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="dashboard.listing.createNewDashboard.sampleDataInstallLinkText"
|
||||
defaultMessage="Install some sample data"
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
export const DashboardConstants = {
|
||||
LANDING_PAGE_PATH: '/dashboards',
|
||||
CREATE_NEW_DASHBOARD_URL: '/dashboard',
|
||||
LANDING_PAGE_PATH: '/list',
|
||||
CREATE_NEW_DASHBOARD_URL: '/create',
|
||||
ADD_EMBEDDABLE_ID: 'addEmbeddableId',
|
||||
ADD_EMBEDDABLE_TYPE: 'addEmbeddableType',
|
||||
DASHBOARDS_ID: 'dashboards',
|
||||
|
@ -27,5 +27,5 @@ export const DashboardConstants = {
|
|||
};
|
||||
|
||||
export function createDashboardEditUrl(id: string) {
|
||||
return `/dashboard/${id}`;
|
||||
return `/view/${id}`;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import {
|
|||
PluginInitializerContext,
|
||||
Plugin,
|
||||
SavedObjectsClientContract,
|
||||
AppUpdater,
|
||||
ScopedHistory,
|
||||
} from 'src/core/public';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
|
||||
import {
|
||||
|
@ -58,12 +60,12 @@ import {
|
|||
} from '../../../plugins/kibana_react/public';
|
||||
import { createKbnUrlTracker, Storage } from '../../../plugins/kibana_utils/public';
|
||||
import {
|
||||
AngularRenderedAppUpdater,
|
||||
KibanaLegacySetup,
|
||||
KibanaLegacyStart,
|
||||
initAngularBootstrap,
|
||||
} from '../../../plugins/kibana_legacy/public';
|
||||
import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../../plugins/home/public';
|
||||
import { DEFAULT_APP_CATEGORIES } from '../../../core/public';
|
||||
|
||||
import {
|
||||
DashboardContainerFactory,
|
||||
|
@ -85,6 +87,7 @@ import {
|
|||
} from './url_generator';
|
||||
import { createSavedDashboardLoader } from './saved_dashboards';
|
||||
import { DashboardConstants } from './dashboard_constants';
|
||||
import { addEmbeddableToDashboardUrl } from './url_utils/url_helper';
|
||||
import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder';
|
||||
|
||||
declare module '../../share/public' {
|
||||
|
@ -120,6 +123,10 @@ export type Setup = void;
|
|||
|
||||
export interface DashboardStart {
|
||||
getSavedDashboardLoader: () => SavedObjectLoader;
|
||||
addEmbeddableToDashboard: (options: {
|
||||
embeddableId: string;
|
||||
embeddableType: string;
|
||||
}) => void | undefined;
|
||||
dashboardUrlGenerator?: DashboardUrlGenerator;
|
||||
}
|
||||
|
||||
|
@ -135,8 +142,10 @@ export class DashboardPlugin
|
|||
implements Plugin<Setup, DashboardStart, SetupDependencies, StartDependencies> {
|
||||
constructor(private initializerContext: PluginInitializerContext) {}
|
||||
|
||||
private appStateUpdater = new BehaviorSubject<AngularRenderedAppUpdater>(() => ({}));
|
||||
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
|
||||
private stopUrlTracking: (() => void) | undefined = undefined;
|
||||
private getActiveUrl: (() => string) | undefined = undefined;
|
||||
private currentHistory: ScopedHistory | undefined = undefined;
|
||||
|
||||
private dashboardUrlGenerator?: DashboardUrlGenerator;
|
||||
|
||||
|
@ -154,7 +163,7 @@ export class DashboardPlugin
|
|||
createDashboardUrlGenerator(async () => {
|
||||
const [coreStart, , selfStart] = await startServices;
|
||||
return {
|
||||
appBasePath: coreStart.application.getUrlForApp('dashboard'),
|
||||
appBasePath: coreStart.application.getUrlForApp('dashboards'),
|
||||
useHashedUrl: coreStart.uiSettings.get('state:storeInSessionStorage'),
|
||||
savedDashboardLoader: selfStart.getSavedDashboardLoader(),
|
||||
};
|
||||
|
@ -195,16 +204,9 @@ export class DashboardPlugin
|
|||
const placeholderFactory = new PlaceholderEmbeddableFactory();
|
||||
embeddable.registerEmbeddableFactory(placeholderFactory.type, placeholderFactory);
|
||||
|
||||
const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({
|
||||
baseUrl: core.http.basePath.prepend('/app/kibana'),
|
||||
const { appMounted, appUnMounted, stop: stopUrlTracker, getActiveUrl } = createKbnUrlTracker({
|
||||
baseUrl: core.http.basePath.prepend('/app/dashboards'),
|
||||
defaultSubUrl: `#${DashboardConstants.LANDING_PAGE_PATH}`,
|
||||
shouldTrackUrlUpdate: pathname => {
|
||||
const targetAppName = pathname.split('/')[1];
|
||||
return (
|
||||
targetAppName === DashboardConstants.DASHBOARDS_ID ||
|
||||
targetAppName === DashboardConstants.DASHBOARD_ID
|
||||
);
|
||||
},
|
||||
storageKey: `lastUrl:${core.http.basePath.get()}:dashboard`,
|
||||
navLinkUpdater$: this.appStateUpdater,
|
||||
toastNotifications: core.notifications.toasts,
|
||||
|
@ -222,30 +224,39 @@ export class DashboardPlugin
|
|||
),
|
||||
},
|
||||
],
|
||||
getHistory: () => this.currentHistory!,
|
||||
});
|
||||
|
||||
this.getActiveUrl = getActiveUrl;
|
||||
this.stopUrlTracking = () => {
|
||||
stopUrlTracker();
|
||||
};
|
||||
|
||||
const app: App = {
|
||||
id: '',
|
||||
title: 'Dashboards',
|
||||
id: DashboardConstants.DASHBOARDS_ID,
|
||||
title: 'Dashboard',
|
||||
order: -1001,
|
||||
euiIconType: 'dashboardApp',
|
||||
defaultPath: `#${DashboardConstants.LANDING_PAGE_PATH}`,
|
||||
updater$: this.appStateUpdater,
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
mount: async (params: AppMountParameters) => {
|
||||
const [coreStart, pluginsStart, dashboardStart] = await core.getStartServices();
|
||||
this.currentHistory = params.history;
|
||||
appMounted();
|
||||
const {
|
||||
embeddable: embeddableStart,
|
||||
navigation,
|
||||
share: shareStart,
|
||||
data: dataStart,
|
||||
kibanaLegacy: { dashboardConfig },
|
||||
kibanaLegacy: { dashboardConfig, navigateToDefaultApp },
|
||||
} = pluginsStart;
|
||||
|
||||
const deps: RenderDeps = {
|
||||
pluginInitializerContext: this.initializerContext,
|
||||
core: coreStart,
|
||||
dashboardConfig,
|
||||
navigateToDefaultApp,
|
||||
navigation,
|
||||
share: shareStart,
|
||||
data: dataStart,
|
||||
|
@ -264,10 +275,12 @@ export class DashboardPlugin
|
|||
},
|
||||
localStorage: new Storage(localStorage),
|
||||
usageCollection,
|
||||
scopedHistory: () => this.currentHistory!,
|
||||
};
|
||||
// make sure the index pattern list is up to date
|
||||
await dataStart.indexPatterns.clearCache();
|
||||
const { renderApp } = await import('./application/application');
|
||||
params.element.classList.add('dshAppContainer');
|
||||
const unmount = renderApp(params.element, params.appBasePath, deps);
|
||||
return () => {
|
||||
unmount();
|
||||
|
@ -278,14 +291,33 @@ export class DashboardPlugin
|
|||
|
||||
initAngularBootstrap();
|
||||
|
||||
kibanaLegacy.registerLegacyApp({
|
||||
...app,
|
||||
id: DashboardConstants.DASHBOARD_ID,
|
||||
// only register the updater in once app, otherwise all updates would happen twice
|
||||
updater$: this.appStateUpdater.asObservable(),
|
||||
navLinkId: 'kibana:dashboard',
|
||||
});
|
||||
kibanaLegacy.registerLegacyApp({ ...app, id: DashboardConstants.DASHBOARDS_ID });
|
||||
core.application.register(app);
|
||||
kibanaLegacy.forwardApp(
|
||||
DashboardConstants.DASHBOARD_ID,
|
||||
DashboardConstants.DASHBOARDS_ID,
|
||||
path => {
|
||||
const [, id, tail] = /dashboard\/?(.*?)($|\?.*)/.exec(path) || [];
|
||||
if (!id && !tail) {
|
||||
// unrecognized sub url
|
||||
return '#/list';
|
||||
}
|
||||
if (!id && tail) {
|
||||
// unsaved dashboard, but probably state in URL
|
||||
return `#/create${tail || ''}`;
|
||||
}
|
||||
// persisted dashboard, probably with url state
|
||||
return `#/view/${id}${tail || ''}`;
|
||||
}
|
||||
);
|
||||
kibanaLegacy.forwardApp(
|
||||
DashboardConstants.DASHBOARDS_ID,
|
||||
DashboardConstants.DASHBOARDS_ID,
|
||||
path => {
|
||||
const [, tail] = /(\?.*)/.exec(path) || [];
|
||||
// carry over query if it exists
|
||||
return `#/list${tail || ''}`;
|
||||
}
|
||||
);
|
||||
|
||||
if (home) {
|
||||
home.featureCatalogue.register({
|
||||
|
@ -297,13 +329,30 @@ export class DashboardPlugin
|
|||
defaultMessage: 'Display and share a collection of visualizations and saved searches.',
|
||||
}),
|
||||
icon: 'dashboardApp',
|
||||
path: `/app/kibana#${DashboardConstants.LANDING_PAGE_PATH}`,
|
||||
path: `/app/dashboards#${DashboardConstants.LANDING_PAGE_PATH}`,
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private addEmbeddableToDashboard(
|
||||
core: CoreStart,
|
||||
{ embeddableId, embeddableType }: { embeddableId: string; embeddableType: string }
|
||||
) {
|
||||
if (!this.getActiveUrl) {
|
||||
throw new Error('dashboard is not ready yet.');
|
||||
}
|
||||
|
||||
const lastDashboardUrl = this.getActiveUrl();
|
||||
const dashboardUrl = addEmbeddableToDashboardUrl(
|
||||
lastDashboardUrl,
|
||||
embeddableId,
|
||||
embeddableType
|
||||
);
|
||||
core.application.navigateToApp('dashboards', { path: dashboardUrl });
|
||||
}
|
||||
|
||||
public start(core: CoreStart, plugins: StartDependencies): DashboardStart {
|
||||
const { notifications } = core;
|
||||
const {
|
||||
|
@ -335,6 +384,7 @@ export class DashboardPlugin
|
|||
});
|
||||
return {
|
||||
getSavedDashboardLoader: () => savedDashboardLoader,
|
||||
addEmbeddableToDashboard: this.addEmbeddableToDashboard.bind(this, core),
|
||||
dashboardUrlGenerator: this.dashboardUrlGenerator,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ export function createSavedDashboardClass(
|
|||
refreshInterval: undefined,
|
||||
},
|
||||
});
|
||||
this.getFullPath = () => `/app/kibana#${createDashboardEditUrl(String(this.id))}`;
|
||||
this.getFullPath = () => `/app/dashboards#${createDashboardEditUrl(String(this.id))}`;
|
||||
}
|
||||
|
||||
getQuery() {
|
||||
|
|
|
@ -24,7 +24,7 @@ import { mockStorage } from '../../kibana_utils/public/storage/hashed_item_store
|
|||
import { esFilters, Filter } from '../../data/public';
|
||||
import { SavedObjectLoader } from '../../saved_objects/public';
|
||||
|
||||
const APP_BASE_PATH: string = 'xyz/app/kibana';
|
||||
const APP_BASE_PATH: string = 'xyz/app/dashboards';
|
||||
|
||||
const createMockDashboardLoader = (
|
||||
dashboardToFilters: {
|
||||
|
@ -63,7 +63,7 @@ describe('dashboard url generator', () => {
|
|||
})
|
||||
);
|
||||
const url = await generator.createUrl!({});
|
||||
expect(url).toMatchInlineSnapshot(`"xyz/app/kibana#/dashboard?_a=()&_g=()"`);
|
||||
expect(url).toMatchInlineSnapshot(`"xyz/app/dashboards#/create?_a=()&_g=()"`);
|
||||
});
|
||||
|
||||
test('creates a link with global time range set up', async () => {
|
||||
|
@ -78,7 +78,7 @@ describe('dashboard url generator', () => {
|
|||
timeRange: { to: 'now', from: 'now-15m', mode: 'relative' },
|
||||
});
|
||||
expect(url).toMatchInlineSnapshot(
|
||||
`"xyz/app/kibana#/dashboard?_a=()&_g=(time:(from:now-15m,mode:relative,to:now))"`
|
||||
`"xyz/app/dashboards#/create?_a=()&_g=(time:(from:now-15m,mode:relative,to:now))"`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -118,7 +118,7 @@ describe('dashboard url generator', () => {
|
|||
query: { query: 'bye', language: 'kuery' },
|
||||
});
|
||||
expect(url).toMatchInlineSnapshot(
|
||||
`"xyz/app/kibana#/dashboard/123?_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),query:(language:kuery,query:bye))&_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))"`
|
||||
`"xyz/app/dashboards#/view/123?_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),query:(language:kuery,query:bye))&_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))"`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -265,7 +265,7 @@ describe('dashboard url generator', () => {
|
|||
expect(url).not.toEqual(expect.stringContaining('query:savedfilter1'));
|
||||
expect(url).not.toEqual(expect.stringContaining('query:appliedfilter'));
|
||||
expect(url).toMatchInlineSnapshot(
|
||||
`"xyz/app/kibana#/dashboard/dashboard1?_a=(filters:!())&_g=(filters:!())"`
|
||||
`"xyz/app/dashboards#/view/dashboard1?_a=(filters:!())&_g=(filters:!())"`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -284,7 +284,7 @@ describe('dashboard url generator', () => {
|
|||
dashboardId: 'dashboard1',
|
||||
});
|
||||
expect(url).not.toEqual(expect.stringContaining('filters'));
|
||||
expect(url).toMatchInlineSnapshot(`"xyz/app/kibana#/dashboard/dashboard1?_a=()&_g=()"`);
|
||||
expect(url).toMatchInlineSnapshot(`"xyz/app/dashboards#/view/dashboard1?_a=()&_g=()"`);
|
||||
});
|
||||
|
||||
test('can turn off preserving filters', async () => {
|
||||
|
|
|
@ -87,7 +87,7 @@ export const createDashboardUrlGenerator = (
|
|||
const startServices = await getStartServices();
|
||||
const useHash = state.useHash ?? startServices.useHashedUrl;
|
||||
const appBasePath = startServices.appBasePath;
|
||||
const hash = state.dashboardId ? `dashboard/${state.dashboardId}` : `dashboard`;
|
||||
const hash = state.dashboardId ? `view/${state.dashboardId}` : `create`;
|
||||
|
||||
const getSavedFiltersFromDestinationDashboardIfNeeded = async (): Promise<Filter[]> => {
|
||||
if (state.preserveSavedFilters === false) return [];
|
||||
|
|
|
@ -23,17 +23,17 @@ describe('', () => {
|
|||
it('addEmbeddableToDashboardUrl when dashboard is not saved', () => {
|
||||
const id = '123eb456cd';
|
||||
const url =
|
||||
"/pep/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!())";
|
||||
expect(addEmbeddableToDashboardUrl(url, id)).toEqual(
|
||||
`/dashboard?_a=%28description%3A%27%27%2Cfilters%3A%21%28%29%29&_g=%28refreshInterval%3A%28pause%3A%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3Anow-15m%2Cto%3Anow%29%29&addEmbeddableId=${id}&addEmbeddableType=visualization`
|
||||
"/pep/app/dashboards#/create?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!())";
|
||||
expect(addEmbeddableToDashboardUrl(url, id, 'visualization')).toEqual(
|
||||
`/pep/app/dashboards#/create?_a=%28description%3A%27%27%2Cfilters%3A%21%28%29%29&_g=%28refreshInterval%3A%28pause%3A%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3Anow-15m%2Cto%3Anow%29%29&addEmbeddableId=${id}&addEmbeddableType=visualization`
|
||||
);
|
||||
});
|
||||
it('addEmbeddableToDashboardUrl when dashboard is saved', () => {
|
||||
const id = '123eb456cd';
|
||||
const url =
|
||||
"/pep/app/kibana#/dashboard/9b780cd0-3dd3-11e8-b2b9-5d5dc1715159?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!())";
|
||||
expect(addEmbeddableToDashboardUrl(url, id)).toEqual(
|
||||
`/dashboard/9b780cd0-3dd3-11e8-b2b9-5d5dc1715159?_a=%28description%3A%27%27%2Cfilters%3A%21%28%29%29&_g=%28refreshInterval%3A%28pause%3A%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3Anow-15m%2Cto%3Anow%29%29&addEmbeddableId=${id}&addEmbeddableType=visualization`
|
||||
"/pep/app/dashboards#/view/9b780cd0-3dd3-11e8-b2b9-5d5dc1715159?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!())";
|
||||
expect(addEmbeddableToDashboardUrl(url, id, 'visualization')).toEqual(
|
||||
`/pep/app/dashboards#/view/9b780cd0-3dd3-11e8-b2b9-5d5dc1715159?_a=%28description%3A%27%27%2Cfilters%3A%21%28%29%29&_g=%28refreshInterval%3A%28pause%3A%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3Anow-15m%2Cto%3Anow%29%29&addEmbeddableId=${id}&addEmbeddableType=visualization`
|
||||
);
|
||||
});
|
||||
});
|
|
@ -18,25 +18,28 @@
|
|||
*/
|
||||
|
||||
import { parseUrl, stringify } from 'query-string';
|
||||
import { DashboardConstants } from '../../../../../dashboard/public';
|
||||
import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../visualizations/public';
|
||||
import { DashboardConstants } from '../index';
|
||||
|
||||
/** *
|
||||
* Returns relative dashboard URL with added embeddableType and embeddableId query params
|
||||
* eg.
|
||||
* input: url: lol/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now)), embeddableId: 12345
|
||||
* output: /dashboard?addEmbeddableType=visualization&addEmbeddableId=12345&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))
|
||||
* @param url dasbhoard absolute url
|
||||
* @param embeddableId id of the saved visualization
|
||||
* input: url: #/create?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now)), embeddableId: 12345
|
||||
* output: #/create?addEmbeddableType=visualization&addEmbeddableId=12345&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))
|
||||
* @param url dasbhoard hash part of the url
|
||||
* @param embeddableId id of the saved embeddable
|
||||
* @param embeddableType type of the embeddable
|
||||
*/
|
||||
export function addEmbeddableToDashboardUrl(dashboardUrl: string, embeddableId: string) {
|
||||
export function addEmbeddableToDashboardUrl(
|
||||
dashboardUrl: string,
|
||||
embeddableId: string,
|
||||
embeddableType: string
|
||||
) {
|
||||
const { url, query } = parseUrl(dashboardUrl);
|
||||
const [, dashboardId] = url.split(DashboardConstants.CREATE_NEW_DASHBOARD_URL);
|
||||
|
||||
if (embeddableId) {
|
||||
query[DashboardConstants.ADD_EMBEDDABLE_TYPE] = VISUALIZE_EMBEDDABLE_TYPE;
|
||||
query[DashboardConstants.ADD_EMBEDDABLE_TYPE] = embeddableType;
|
||||
query[DashboardConstants.ADD_EMBEDDABLE_ID] = embeddableId;
|
||||
}
|
||||
|
||||
return `${DashboardConstants.CREATE_NEW_DASHBOARD_URL}${dashboardId}?${stringify(query)}`;
|
||||
return `${url}?${stringify(query)}`;
|
||||
}
|
|
@ -36,7 +36,7 @@ export const dashboardSavedObjectType: SavedObjectsType = {
|
|||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/dashboard/${encodeURIComponent(obj.id)}`,
|
||||
path: `/app/dashboards#/view/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
};
|
||||
},
|
||||
|
|
|
@ -246,18 +246,18 @@ describe('UrlFormat', () => {
|
|||
test('should support multiple types of relative urls', () => {
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana.host.com',
|
||||
pathname: '/nbc/app/kibana#/discover',
|
||||
pathname: '/nbc/app/discover#/',
|
||||
basePath: '/nbc',
|
||||
};
|
||||
const url = new UrlFormat({ parsedUrl });
|
||||
const converter = url.getConverterFor(HTML_CONTEXT_TYPE) as Function;
|
||||
|
||||
expect(converter('#/foo')).toBe(
|
||||
'<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover#/foo" target="_blank" rel="noopener noreferrer">#/foo</a></span>'
|
||||
'<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/discover#/#/foo" target="_blank" rel="noopener noreferrer">#/foo</a></span>'
|
||||
);
|
||||
|
||||
expect(converter('/nbc/app/kibana#/discover')).toBe(
|
||||
'<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover" target="_blank" rel="noopener noreferrer">/nbc/app/kibana#/discover</a></span>'
|
||||
expect(converter('/nbc/app/discover#/')).toBe(
|
||||
'<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/discover#/" target="_blank" rel="noopener noreferrer">/nbc/app/discover#/</a></span>'
|
||||
);
|
||||
|
||||
expect(converter('../foo/bar')).toBe(
|
||||
|
|
|
@ -61,26 +61,25 @@ export const createEnsureDefaultIndexPattern = (core: CoreStart) => {
|
|||
core.uiSettings.set('defaultIndex', defaultId);
|
||||
} else {
|
||||
const canManageIndexPatterns = core.application.capabilities.management.kibana.index_patterns;
|
||||
const redirectTarget = canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home';
|
||||
const redirectTarget = canManageIndexPatterns ? 'management' : 'home';
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
const bannerMessage = i18n.translate(
|
||||
'data.indexPatterns.ensureDefaultIndexPattern.bannerLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
"In order to visualize and explore data in Kibana, you'll need to create an index pattern to retrieve data from Elasticsearch.",
|
||||
}
|
||||
);
|
||||
|
||||
// Avoid being hostile to new users who don't have an index pattern setup yet
|
||||
// give them a friendly info message instead of a terse error message
|
||||
bannerId = core.overlays.banners.replace(
|
||||
bannerId,
|
||||
toMountPoint(
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
iconType="iInCircle"
|
||||
title={i18n.translate('data.indexPatterns.ensureDefaultIndexPattern.bannerLabel', {
|
||||
defaultMessage:
|
||||
"In order to visualize and explore data in Kibana, you'll need to create an index pattern to retrieve data from Elasticsearch.",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
toMountPoint(<EuiCallOut color="warning" iconType="iInCircle" title={bannerMessage} />)
|
||||
);
|
||||
|
||||
// hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
|
||||
|
@ -89,7 +88,13 @@ export const createEnsureDefaultIndexPattern = (core: CoreStart) => {
|
|||
timeoutId = undefined;
|
||||
}, 15000);
|
||||
|
||||
history.push(redirectTarget);
|
||||
if (redirectTarget === 'home') {
|
||||
core.application.navigateToApp('home');
|
||||
} else {
|
||||
window.location.href = core.http.basePath.prepend(
|
||||
`/app/kibana#/management/kibana/index_pattern?bannerMessage=${bannerMessage}`
|
||||
);
|
||||
}
|
||||
|
||||
// return never-resolving promise to stop resolving and wait for the url change
|
||||
return new Promise(() => {});
|
||||
|
|
|
@ -32,7 +32,7 @@ export const querySavedObjectType: SavedObjectsType = {
|
|||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/discover?_a=(savedQuery:'${encodeURIComponent(obj.id)}')`,
|
||||
path: `/app/discover#/?_a=(savedQuery:'${encodeURIComponent(obj.id)}')`,
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
};
|
||||
},
|
||||
|
|
|
@ -36,7 +36,7 @@ export const searchSavedObjectType: SavedObjectsType = {
|
|||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/discover/${encodeURIComponent(obj.id)}`,
|
||||
path: `/app/discover#/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
};
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
The ui/registry/dev_tools is removed in favor of the `devTools` plugin which exposes a register method in the setup contract.
|
||||
Registering app works mostly the same as registering apps in core.application.register.
|
||||
Routing will be handled by the id of the dev tool - your dev tool will be mounted when the URL matches `/app/kibana#/dev_tools/<YOUR ID>`.
|
||||
Routing will be handled by the id of the dev tool - your dev tool will be mounted when the URL matches `/app/dev_tools#/<YOUR ID>`.
|
||||
This API doesn't support angular, for registering angular dev tools, bootstrap a local module on mount into the given HTML element.
|
||||
|
||||
During the migration this plugin exposes the registered dev tools in the start contract. This is necessary to keep the dev tools app
|
||||
|
|
|
@ -24,7 +24,7 @@ import * as React from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { AppMountContext, AppMountDeprecated } from 'kibana/public';
|
||||
import { AppMountContext, AppMountDeprecated, ScopedHistory } from 'kibana/public';
|
||||
import { DevToolApp } from './dev_tool';
|
||||
|
||||
interface DevToolsWrapperProps {
|
||||
|
@ -67,7 +67,7 @@ function DevToolsWrapper({
|
|||
isSelected={currentDevTool === activeDevTool}
|
||||
onClick={() => {
|
||||
if (!currentDevTool.isDisabled()) {
|
||||
updateRoute(`/dev_tools/${currentDevTool.id}`);
|
||||
updateRoute(`/${currentDevTool.id}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -114,7 +114,7 @@ function DevToolsWrapper({
|
|||
|
||||
function redirectOnMissingCapabilities(appMountContext: AppMountContext) {
|
||||
if (!appMountContext.core.application.capabilities.dev_tools.show) {
|
||||
window.location.hash = '/home';
|
||||
appMountContext.core.application.navigateToApp('home');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -135,13 +135,21 @@ function setBadge(appMountContext: AppMountContext) {
|
|||
});
|
||||
}
|
||||
|
||||
function setTitle(appMountContext: AppMountContext) {
|
||||
appMountContext.core.chrome.docTitle.change(
|
||||
i18n.translate('devTools.pageTitle', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function setBreadcrumbs(appMountContext: AppMountContext) {
|
||||
appMountContext.core.chrome.setBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('devTools.k7BreadcrumbsDevToolsLabel', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
href: '#/dev_tools',
|
||||
href: '#/',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -149,7 +157,7 @@ function setBreadcrumbs(appMountContext: AppMountContext) {
|
|||
export function renderApp(
|
||||
element: HTMLElement,
|
||||
appMountContext: AppMountContext,
|
||||
basePath: string,
|
||||
history: ScopedHistory,
|
||||
devTools: readonly DevToolApp[]
|
||||
) {
|
||||
if (redirectOnMissingCapabilities(appMountContext)) {
|
||||
|
@ -157,6 +165,7 @@ export function renderApp(
|
|||
}
|
||||
setBadge(appMountContext);
|
||||
setBreadcrumbs(appMountContext);
|
||||
setTitle(appMountContext);
|
||||
ReactDOM.render(
|
||||
<I18nProvider>
|
||||
<Router>
|
||||
|
@ -167,7 +176,7 @@ export function renderApp(
|
|||
.map(devTool => (
|
||||
<Route
|
||||
key={devTool.id}
|
||||
path={`/dev_tools/${devTool.id}`}
|
||||
path={`/${devTool.id}`}
|
||||
exact={!devTool.enableRouting}
|
||||
render={props => (
|
||||
<DevToolsWrapper
|
||||
|
@ -179,8 +188,8 @@ export function renderApp(
|
|||
)}
|
||||
/>
|
||||
))}
|
||||
<Route path="/dev_tools">
|
||||
<Redirect to={`/dev_tools/${devTools[0].id}`} />
|
||||
<Route path="/">
|
||||
<Redirect to={`/${devTools[0].id}`} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
|
@ -188,7 +197,16 @@ export function renderApp(
|
|||
element
|
||||
);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
// dispatch synthetic hash change event to update hash history objects
|
||||
// this is necessary because hash updates triggered by using popState won't trigger this event naturally.
|
||||
const unlisten = history.listen(() => {
|
||||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
});
|
||||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(element);
|
||||
unlisten();
|
||||
};
|
||||
}
|
||||
|
||||
function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
|
||||
|
|
|
@ -19,3 +19,9 @@
|
|||
.devApp {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.devAppWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -17,10 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { CoreSetup, Plugin } from 'kibana/public';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { AppUpdater, CoreSetup, Plugin } from 'kibana/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { sortBy } from 'lodash';
|
||||
import { KibanaLegacySetup } from '../../kibana_legacy/public';
|
||||
import { CreateDevToolArgs, DevToolApp, createDevToolApp } from './dev_tool';
|
||||
import { AppNavLinkStatus, DEFAULT_APP_CATEGORIES } from '../../../core/public';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
|
@ -38,42 +41,34 @@ export interface DevToolsSetup {
|
|||
register: (devTool: CreateDevToolArgs) => DevToolApp;
|
||||
}
|
||||
|
||||
export interface DevToolsStart {
|
||||
/**
|
||||
* Returns all registered dev tools in an ordered array.
|
||||
* This function is only exposed because the dev tools app
|
||||
* actually rendering the tool has to stay in the legacy platform
|
||||
* for now. Once it is moved into this plugin, this function
|
||||
* becomes an implementation detail.
|
||||
* @deprecated
|
||||
*/
|
||||
getSortedDevTools: () => readonly DevToolApp[];
|
||||
}
|
||||
|
||||
export class DevToolsPlugin implements Plugin<DevToolsSetup, DevToolsStart> {
|
||||
export class DevToolsPlugin implements Plugin<DevToolsSetup, void> {
|
||||
private readonly devTools = new Map<string, DevToolApp>();
|
||||
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
|
||||
|
||||
private getSortedDevTools(): readonly DevToolApp[] {
|
||||
return sortBy([...this.devTools.values()], 'order');
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, { kibanaLegacy }: { kibanaLegacy: KibanaLegacySetup }) {
|
||||
kibanaLegacy.registerLegacyApp({
|
||||
core.application.register({
|
||||
id: 'dev_tools',
|
||||
title: 'Dev Tools',
|
||||
title: i18n.translate('devTools.devToolsTitle', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
updater$: this.appStateUpdater,
|
||||
euiIconType: 'devToolsApp',
|
||||
order: 9001,
|
||||
category: DEFAULT_APP_CATEGORIES.management,
|
||||
mount: async (appMountContext, params) => {
|
||||
if (!this.getSortedDevTools) {
|
||||
throw new Error('not started yet');
|
||||
}
|
||||
const { renderApp } = await import('./application');
|
||||
return renderApp(
|
||||
params.element,
|
||||
appMountContext,
|
||||
params.appBasePath,
|
||||
this.getSortedDevTools()
|
||||
);
|
||||
params.element.classList.add('devAppWrapper');
|
||||
return renderApp(params.element, appMountContext, params.history, this.getSortedDevTools());
|
||||
},
|
||||
});
|
||||
kibanaLegacy.forwardApp('dev_tools', 'dev_tools');
|
||||
|
||||
return {
|
||||
register: (devToolArgs: CreateDevToolArgs) => {
|
||||
|
@ -91,9 +86,9 @@ export class DevToolsPlugin implements Plugin<DevToolsSetup, DevToolsStart> {
|
|||
}
|
||||
|
||||
public start() {
|
||||
return {
|
||||
getSortedDevTools: this.getSortedDevTools.bind(this),
|
||||
};
|
||||
if (this.getSortedDevTools().length === 0) {
|
||||
this.appStateUpdater.next(() => ({ navLinkStatus: AppNavLinkStatus.hidden }));
|
||||
}
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
.dscAppWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
discover-app {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<context-app
|
||||
anchor-id="contextAppRoute.anchorId"
|
||||
columns="contextAppRoute.state.columns"
|
||||
discover-url="contextAppRoute.discoverUrl"
|
||||
index-pattern="contextAppRoute.indexPattern"
|
||||
filters="contextAppRoute.filters"
|
||||
predecessor-count="contextAppRoute.state.predecessorCount"
|
||||
|
|
|
@ -47,10 +47,10 @@ getAngularModule().config($routeProvider => {
|
|||
$routeProvider
|
||||
// deprecated route, kept for compatibility
|
||||
// should be removed in the future
|
||||
.when('/discover/context/:indexPatternId/:type/:id*', {
|
||||
redirectTo: '/discover/context/:indexPatternId/:id',
|
||||
.when('/context/:indexPatternId/:type/:id*', {
|
||||
redirectTo: '/context/:indexPatternId/:id',
|
||||
})
|
||||
.when('/discover/context/:indexPatternId/:id*', {
|
||||
.when('/context/:indexPatternId/:id*', {
|
||||
controller: ContextAppRouteController,
|
||||
k7Breadcrumbs,
|
||||
controllerAs: 'contextAppRoute',
|
||||
|
@ -86,7 +86,6 @@ function ContextAppRouteController($routeParams, $scope, $route) {
|
|||
this.state = { ...appState.getState() };
|
||||
this.anchorId = $routeParams.id;
|
||||
this.indexPattern = indexPattern;
|
||||
this.discoverUrl = getServices().chrome.navLinks.get('kibana:discover').url;
|
||||
filterManager.setFilters(_.cloneDeep(getFilters()));
|
||||
startStateSync();
|
||||
|
||||
|
|
|
@ -44,20 +44,8 @@
|
|||
>
|
||||
<span
|
||||
i18n-id="discover.context.reloadPageDescription.reloadOrVisitTextMessage"
|
||||
i18n-default-message="Please reload or visit"
|
||||
i18n-description="Part of composite text discover.context.reloadPageDescription.reloadOrVisitTextMessage + discover.context.reloadPageDescription.discoverLinkText + discover.context.reloadPageDescription.selectValidAnchorDocumentTextMessage"
|
||||
i18n-default-message="Please reload or go back to the document list to select a valid anchor document."
|
||||
></span>
|
||||
<a
|
||||
ng-href="{{ contextApp.state.navigation.discover.url }}"
|
||||
i18n-id="discover.context.reloadPageDescription.discoverLinkText"
|
||||
i18n-default-message="Discover"
|
||||
i18n-description="Part of composite text discover.context.reloadPageDescription.reloadOrVisitTextMessage + discover.context.reloadPageDescription.discoverLinkText + discover.context.reloadPageDescription.selectValidAnchorDocumentTextMessage"
|
||||
></a>
|
||||
<span
|
||||
i18n-id="discover.context.reloadPageDescription.selectValidAnchorDocumentTextMessage"
|
||||
i18n-default-message="to select a valid anchor document."
|
||||
i18n-description="Part of composite text discover.context.reloadPageDescription.reloadOrVisitTextMessage + discover.context.reloadPageDescription.discoverLinkText + discover.context.reloadPageDescription.selectValidAnchorDocumentTextMessage"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -51,7 +51,6 @@ module.directive('contextApp', function ContextApp() {
|
|||
predecessorCount: '=',
|
||||
successorCount: '=',
|
||||
sort: '=',
|
||||
discoverUrl: '=',
|
||||
},
|
||||
template: contextAppTemplate,
|
||||
};
|
||||
|
@ -63,8 +62,7 @@ function ContextAppController($scope, Private) {
|
|||
const queryActions = Private(QueryActionsProvider);
|
||||
this.state = createInitialState(
|
||||
parseInt(uiSettings.get('context:step'), 10),
|
||||
getFirstSortableField(this.indexPattern, uiSettings.get('context:tieBreakerFields')),
|
||||
this.discoverUrl
|
||||
getFirstSortableField(this.indexPattern, uiSettings.get('context:tieBreakerFields'))
|
||||
);
|
||||
|
||||
this.actions = _.mapValues(
|
||||
|
@ -129,7 +127,7 @@ function ContextAppController($scope, Private) {
|
|||
);
|
||||
}
|
||||
|
||||
function createInitialState(defaultStepSize, tieBreakerField, discoverUrl) {
|
||||
function createInitialState(defaultStepSize, tieBreakerField) {
|
||||
return {
|
||||
queryParameters: createInitialQueryParametersState(defaultStepSize, tieBreakerField),
|
||||
rows: {
|
||||
|
@ -139,10 +137,5 @@ function createInitialState(defaultStepSize, tieBreakerField, discoverUrl) {
|
|||
successors: [],
|
||||
},
|
||||
loadingStatus: createInitialLoadingStatusState(),
|
||||
navigation: {
|
||||
discover: {
|
||||
url: discoverUrl,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ app.config($routeProvider => {
|
|||
};
|
||||
},
|
||||
};
|
||||
$routeProvider.when('/discover/:id?', {
|
||||
$routeProvider.when('/:id?', {
|
||||
...defaults,
|
||||
template: indexTemplate,
|
||||
reloadOnSearch: false,
|
||||
|
@ -151,14 +151,17 @@ app.config($routeProvider => {
|
|||
.catch(
|
||||
redirectWhenMissing({
|
||||
history,
|
||||
navigateToApp: core.application.navigateToApp,
|
||||
mapping: {
|
||||
search: '/discover',
|
||||
'index-pattern':
|
||||
'/management/kibana/objects/savedSearches/' + $route.current.params.id,
|
||||
search: '/',
|
||||
'index-pattern': {
|
||||
app: 'kibana',
|
||||
path: `#/management/kibana/objects/savedSearches/${$route.current.params.id}`,
|
||||
},
|
||||
},
|
||||
toastNotifications,
|
||||
onBeforeRedirect() {
|
||||
getUrlTracker().setTrackedUrl('/discover');
|
||||
getUrlTracker().setTrackedUrl('/');
|
||||
},
|
||||
})
|
||||
),
|
||||
|
@ -259,11 +262,11 @@ function discoverController(
|
|||
}
|
||||
});
|
||||
|
||||
// this listener is waiting for such a path http://localhost:5601/app/kibana#/discover
|
||||
// this listener is waiting for such a path http://localhost:5601/app/discover#/
|
||||
// which could be set through pressing "New" button in top nav or go to "Discover" plugin from the sidebar
|
||||
// to reload the page in a right way
|
||||
const unlistenHistoryBasePath = history.listen(({ pathname, search, hash }) => {
|
||||
if (!search && !hash && pathname === '/discover') {
|
||||
if (!search && !hash && pathname === '/') {
|
||||
$route.reload();
|
||||
}
|
||||
});
|
||||
|
@ -338,7 +341,7 @@ function discoverController(
|
|||
}),
|
||||
run: function() {
|
||||
$scope.$evalAsync(() => {
|
||||
history.push('/discover');
|
||||
history.push('/');
|
||||
});
|
||||
},
|
||||
testId: 'discoverNewButton',
|
||||
|
@ -408,7 +411,7 @@ function discoverController(
|
|||
testId: 'discoverOpenButton',
|
||||
run: () => {
|
||||
showOpenSearchPanel({
|
||||
makeUrl: searchId => `#/discover/${encodeURIComponent(searchId)}`,
|
||||
makeUrl: searchId => `#/${encodeURIComponent(searchId)}`,
|
||||
I18nContext: core.i18n.Context,
|
||||
});
|
||||
},
|
||||
|
@ -497,7 +500,7 @@ function discoverController(
|
|||
chrome.setBreadcrumbs([
|
||||
{
|
||||
text: discoverBreadcrumbsTitle,
|
||||
href: '#/discover',
|
||||
href: '#/',
|
||||
},
|
||||
{ text: savedSearch.title },
|
||||
]);
|
||||
|
@ -755,7 +758,7 @@ function discoverController(
|
|||
});
|
||||
|
||||
if (savedSearch.id !== $route.current.params.id) {
|
||||
history.push(`/discover/${encodeURIComponent(savedSearch.id)}`);
|
||||
history.push(`/${encodeURIComponent(savedSearch.id)}`);
|
||||
} else {
|
||||
// Update defaults so that "reload saved query" functions correctly
|
||||
setAppState(getStateDefaults());
|
||||
|
@ -926,11 +929,11 @@ function discoverController(
|
|||
};
|
||||
|
||||
$scope.resetQuery = function() {
|
||||
history.push(`/discover/${encodeURIComponent($route.current.params.id)}`);
|
||||
history.push(`/${encodeURIComponent($route.current.params.id)}`);
|
||||
};
|
||||
|
||||
$scope.newQuery = function() {
|
||||
history.push('/discover');
|
||||
history.push('/');
|
||||
};
|
||||
|
||||
$scope.updateDataSource = () => {
|
||||
|
|
|
@ -44,11 +44,11 @@ app.directive('discoverDoc', function(reactDirective: any) {
|
|||
|
||||
app.config(($routeProvider: any) => {
|
||||
$routeProvider
|
||||
.when('/discover/doc/:indexPattern/:index/:type', {
|
||||
redirectTo: '/discover/doc/:indexPattern/:index',
|
||||
.when('/doc/:indexPattern/:index/:type', {
|
||||
redirectTo: '/doc/:indexPattern/:index',
|
||||
})
|
||||
// the new route, es 7 deprecated types, es 8 removed them
|
||||
.when('/discover/doc/:indexPattern/:index', {
|
||||
.when('/doc/:indexPattern/:index', {
|
||||
// have to be written as function expression, because it's not compiled in dev mode
|
||||
// eslint-disable-next-line object-shorthand
|
||||
controller: function($scope: LazyScope, $route: any, es: any) {
|
||||
|
|
|
@ -106,9 +106,9 @@ export function createTableRowDirective($compile: ng.ICompileService, $httpParam
|
|||
};
|
||||
|
||||
$scope.getContextAppHref = () => {
|
||||
const path = `#/discover/context/${encodeURIComponent(
|
||||
$scope.indexPattern.id
|
||||
)}/${encodeURIComponent($scope.row._id)}`;
|
||||
const path = `#/context/${encodeURIComponent($scope.indexPattern.id)}/${encodeURIComponent(
|
||||
$scope.row._id
|
||||
)}`;
|
||||
const globalFilters: any = getServices().filterManager.getGlobalFilters();
|
||||
const appFilters: any = getServices().filterManager.getAppFilters();
|
||||
const hash = $httpParamSerializer({
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<a
|
||||
class="euiLink"
|
||||
data-test-subj="docTableRowAction"
|
||||
ng-href="#/discover/doc/{{indexPattern.id}}/{{row._index}}?id={{uriEncodedId}}"
|
||||
ng-href="#/doc/{{indexPattern.id}}/{{row._index}}?id={{uriEncodedId}}"
|
||||
i18n-id="discover.docTable.tableRow.viewSingleDocumentLinkText"
|
||||
i18n-default-message="View single document"
|
||||
></a>
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
// required for i18nIdDirective
|
||||
import 'angular-sanitize';
|
||||
// required for ngRoute
|
||||
import 'angular-route';
|
||||
|
||||
import './discover';
|
||||
import './doc';
|
||||
import './context';
|
||||
|
|
|
@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { DiscoverFieldBucket } from './discover_field_bucket';
|
||||
import { getWarnings } from './lib/get_warnings';
|
||||
import { Bucket, FieldDetails } from './types';
|
||||
import { getServices } from '../../../kibana_services';
|
||||
import { IndexPatternField, IndexPattern } from '../../../../../data/public';
|
||||
|
||||
interface DiscoverFieldDetailsProps {
|
||||
|
@ -79,7 +80,11 @@ export function DiscoverFieldDetails({
|
|||
<>
|
||||
<EuiSpacer size={'s'} />
|
||||
<EuiLink
|
||||
href={details.visualizeUrl}
|
||||
onClick={() => {
|
||||
getServices().core.application.navigateToApp(details.visualizeUrl.app, {
|
||||
path: details.visualizeUrl.path,
|
||||
});
|
||||
}}
|
||||
className="kuiButton kuiButton--secondary kuiButton--small kuiVerticalRhythmSmall"
|
||||
data-test-subj={`fieldVisualize-${field.name}`}
|
||||
>
|
||||
|
|
|
@ -29,13 +29,6 @@ import { AppState } from '../../../angular/discover_state';
|
|||
import { DiscoverServices } from '../../../../build_services';
|
||||
import { VisualizationsStart, VisTypeAlias } from '../../../../../../visualizations/public';
|
||||
|
||||
function getMapsAppBaseUrl(visualizations: VisualizationsStart) {
|
||||
const mapsAppVisAlias = visualizations.getAliases().find(({ name }) => {
|
||||
return name === 'maps';
|
||||
});
|
||||
return mapsAppVisAlias ? mapsAppVisAlias.aliasUrl : null;
|
||||
}
|
||||
|
||||
export function isMapsAppRegistered(visualizations: VisualizationsStart) {
|
||||
return visualizations.getAliases().some(({ name }: VisTypeAlias) => {
|
||||
return name === 'maps';
|
||||
|
@ -60,13 +53,12 @@ export function getMapsAppUrl(
|
|||
field: IFieldType,
|
||||
indexPattern: IIndexPattern,
|
||||
appState: AppState,
|
||||
columns: string[],
|
||||
services: DiscoverServices
|
||||
columns: string[]
|
||||
) {
|
||||
const mapAppParams = new URLSearchParams();
|
||||
|
||||
// Copy global state
|
||||
const locationSplit = window.location.href.split('discover?');
|
||||
const locationSplit = window.location.hash.split('?');
|
||||
if (locationSplit.length > 1) {
|
||||
const discoverParams = new URLSearchParams(locationSplit[1]);
|
||||
const globalStateUrlValue = discoverParams.get('_g');
|
||||
|
@ -109,9 +101,10 @@ export function getMapsAppUrl(
|
|||
])
|
||||
);
|
||||
|
||||
return services.addBasePath(
|
||||
`${getMapsAppBaseUrl(services.visualizations)}?${mapAppParams.toString()}`
|
||||
);
|
||||
return {
|
||||
app: 'maps',
|
||||
path: `#/map?${mapAppParams.toString()}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function getVisualizeUrl(
|
||||
|
@ -128,7 +121,7 @@ export function getVisualizeUrl(
|
|||
(field.type === KBN_FIELD_TYPES.GEO_POINT || field.type === KBN_FIELD_TYPES.GEO_SHAPE) &&
|
||||
isMapsAppRegistered(services.visualizations)
|
||||
) {
|
||||
return getMapsAppUrl(field, indexPattern, state, columns, services);
|
||||
return getMapsAppUrl(field, indexPattern, state, columns);
|
||||
}
|
||||
|
||||
let agg;
|
||||
|
@ -181,5 +174,8 @@ export function getVisualizeUrl(
|
|||
},
|
||||
};
|
||||
|
||||
return `#/visualize/create?${stringify(linkUrlParams)}`;
|
||||
return {
|
||||
app: 'visualize',
|
||||
path: `#/create?${stringify(linkUrlParams)}`,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,10 @@ export interface FieldDetails {
|
|||
exists: number;
|
||||
total: boolean;
|
||||
buckets: Bucket[];
|
||||
visualizeUrl: string;
|
||||
visualizeUrl: {
|
||||
app: string;
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Bucket {
|
||||
|
|
|
@ -71,6 +71,7 @@ interface SearchEmbeddableConfig {
|
|||
$compile: ng.ICompileService;
|
||||
savedSearch: SavedSearch;
|
||||
editUrl: string;
|
||||
editPath: string;
|
||||
indexPatterns?: IndexPattern[];
|
||||
editable: boolean;
|
||||
filterManager: FilterManager;
|
||||
|
@ -102,6 +103,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
$compile,
|
||||
savedSearch,
|
||||
editUrl,
|
||||
editPath,
|
||||
indexPatterns,
|
||||
editable,
|
||||
filterManager,
|
||||
|
@ -112,7 +114,14 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
) {
|
||||
super(
|
||||
initialInput,
|
||||
{ defaultTitle: savedSearch.title, editUrl, indexPatterns, editable },
|
||||
{
|
||||
defaultTitle: savedSearch.title,
|
||||
editUrl,
|
||||
editPath,
|
||||
editApp: 'discover',
|
||||
indexPatterns,
|
||||
editable,
|
||||
},
|
||||
parent
|
||||
);
|
||||
|
||||
|
@ -338,6 +347,9 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
this.prevFilters = this.input.filters;
|
||||
this.prevQuery = this.input.query;
|
||||
this.prevTimeRange = this.input.timeRange;
|
||||
} else if (this.searchScope) {
|
||||
// trigger a digest cycle to make sure non-fetch relevant changes are propagated
|
||||
this.searchScope.$applyAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ export class SearchEmbeddableFactory
|
|||
const filterManager = getServices().filterManager;
|
||||
|
||||
const url = await getServices().getSavedSearchUrlById(savedObjectId);
|
||||
const editUrl = getServices().addBasePath(`/app/kibana${url}`);
|
||||
const editUrl = getServices().addBasePath(`/app/discover${url}`);
|
||||
try {
|
||||
const savedObject = await getServices().getSavedSearchById(savedObjectId);
|
||||
const indexPattern = savedObject.searchSource.getField('index');
|
||||
|
@ -98,6 +98,7 @@ export class SearchEmbeddableFactory
|
|||
$rootScope,
|
||||
$compile,
|
||||
editUrl,
|
||||
editPath: url,
|
||||
filterManager,
|
||||
editable: getServices().capabilities.discover.save as boolean,
|
||||
indexPatterns: indexPattern ? [indexPattern] : [],
|
||||
|
|
|
@ -25,7 +25,7 @@ export function getRootBreadcrumbs() {
|
|||
text: i18n.translate('discover.rootBreadcrumb', {
|
||||
defaultMessage: 'Discover',
|
||||
}),
|
||||
href: '#/discover',
|
||||
href: '#/',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// inner angular imports
|
||||
// these are necessary to bootstrap the local angular.
|
||||
// They can stay even after NP cutover
|
||||
import './application/index.scss';
|
||||
import angular from 'angular';
|
||||
// required for `ngSanitize` angular module
|
||||
import 'angular-sanitize';
|
||||
|
@ -59,6 +60,7 @@ import {
|
|||
import { createDiscoverSidebarDirective } from './application/components/sidebar';
|
||||
import { createHitsCounterDirective } from '././application/components/hits_counter';
|
||||
import { DiscoverStartPlugins } from './plugin';
|
||||
import { getScopedHistory } from './kibana_services';
|
||||
|
||||
/**
|
||||
* returns the main inner angular module, it contains all the parts of Angular Discover
|
||||
|
@ -72,7 +74,7 @@ export function getInnerAngularModule(
|
|||
) {
|
||||
initAngularBootstrap();
|
||||
const module = initializeInnerAngularModule(name, core, deps.navigation, deps.data);
|
||||
configureAppAngularModule(module, { core, env: context.env }, true);
|
||||
configureAppAngularModule(module, { core, env: context.env }, true, getScopedHistory);
|
||||
return module;
|
||||
}
|
||||
|
||||
|
@ -86,7 +88,6 @@ export function getInnerAngularModuleEmbeddable(
|
|||
context: PluginInitializerContext
|
||||
) {
|
||||
const module = initializeInnerAngularModule(name, core, deps.navigation, deps.data, true);
|
||||
configureAppAngularModule(module, { core, env: context.env }, true);
|
||||
return module;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import { createHashHistory } from 'history';
|
||||
import { ScopedHistory } from 'kibana/public';
|
||||
import { DiscoverServices } from './build_services';
|
||||
import { createGetterSetter } from '../../kibana_utils/public';
|
||||
import { search } from '../../data/public';
|
||||
|
@ -57,12 +58,15 @@ export const [getUrlTracker, setUrlTracker] = createGetterSetter<{
|
|||
export const [getDocViewsRegistry, setDocViewsRegistry] = createGetterSetter<DocViewsRegistry>(
|
||||
'DocViewsRegistry'
|
||||
);
|
||||
|
||||
/**
|
||||
* Makes sure discover and context are using one instance of history
|
||||
*/
|
||||
export const getHistory = _.once(() => createHashHistory());
|
||||
|
||||
export const [getScopedHistory, setScopedHistory] = createGetterSetter<ScopedHistory>(
|
||||
'scopedHistory'
|
||||
);
|
||||
|
||||
export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search;
|
||||
export { unhashUrl, redirectWhenMissing } from '../../kibana_utils/public';
|
||||
export { formatMsg, formatStack, subscribeWithScope } from '../../kibana_legacy/public';
|
||||
|
|
|
@ -24,6 +24,7 @@ import { filter, map } from 'rxjs/operators';
|
|||
|
||||
import {
|
||||
AppMountParameters,
|
||||
AppUpdater,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
|
@ -35,26 +36,27 @@ import { ChartsPluginStart } from 'src/plugins/charts/public';
|
|||
import { NavigationPublicPluginStart as NavigationStart } from 'src/plugins/navigation/public';
|
||||
import { SharePluginStart } from 'src/plugins/share/public';
|
||||
import { VisualizationsStart, VisualizationsSetup } from 'src/plugins/visualizations/public';
|
||||
import { KibanaLegacySetup, AngularRenderedAppUpdater } from 'src/plugins/kibana_legacy/public';
|
||||
import { KibanaLegacySetup } from 'src/plugins/kibana_legacy/public';
|
||||
import { HomePublicPluginSetup } from 'src/plugins/home/public';
|
||||
import { Start as InspectorPublicPluginStart } from 'src/plugins/inspector/public';
|
||||
import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../data/public';
|
||||
import { SavedObjectLoader } from '../../saved_objects/public';
|
||||
import { createKbnUrlTracker } from '../../kibana_utils/public';
|
||||
import { DEFAULT_APP_CATEGORIES } from '../../../core/public';
|
||||
|
||||
import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types';
|
||||
import { DocViewsRegistry } from './application/doc_views/doc_views_registry';
|
||||
import { DocViewTable } from './application/components/table/table';
|
||||
import { JsonCodeBlock } from './application/components/json_code_block/json_code_block';
|
||||
import {
|
||||
getHistory,
|
||||
setDocViewsRegistry,
|
||||
setUrlTracker,
|
||||
setAngularModule,
|
||||
setServices,
|
||||
setScopedHistory,
|
||||
getScopedHistory,
|
||||
} from './kibana_services';
|
||||
import { createSavedSearchesLoader } from './saved_searches';
|
||||
import { getInnerAngularModuleEmbeddable, getInnerAngularModule } from './get_inner_angular';
|
||||
import { registerFeature } from './register_feature';
|
||||
import { buildServices } from './build_services';
|
||||
|
||||
|
@ -114,7 +116,7 @@ export class DiscoverPlugin
|
|||
implements Plugin<DiscoverSetup, DiscoverStart, DiscoverSetupPlugins, DiscoverStartPlugins> {
|
||||
constructor(private readonly initializerContext: PluginInitializerContext) {}
|
||||
|
||||
private appStateUpdater = new BehaviorSubject<AngularRenderedAppUpdater>(() => ({}));
|
||||
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
|
||||
private docViewsRegistry: DocViewsRegistry | null = null;
|
||||
private embeddableInjector: auto.IInjectorService | null = null;
|
||||
private stopUrlTracking: (() => void) | undefined = undefined;
|
||||
|
@ -155,9 +157,9 @@ export class DiscoverPlugin
|
|||
// we pass getter here instead of plain `history`,
|
||||
// so history is lazily created (when app is mounted)
|
||||
// this prevents redundant `#` when not in discover app
|
||||
getHistory,
|
||||
baseUrl: core.http.basePath.prepend('/app/kibana'),
|
||||
defaultSubUrl: '#/discover',
|
||||
getHistory: getScopedHistory,
|
||||
baseUrl: core.http.basePath.prepend('/app/discover'),
|
||||
defaultSubUrl: '#/',
|
||||
storageKey: `lastUrl:${core.http.basePath.get()}:discover`,
|
||||
navLinkUpdater$: this.appStateUpdater,
|
||||
toastNotifications: core.notifications.toasts,
|
||||
|
@ -182,13 +184,14 @@ export class DiscoverPlugin
|
|||
};
|
||||
|
||||
this.docViewsRegistry.setAngularInjectorGetter(this.getEmbeddableInjector);
|
||||
plugins.kibanaLegacy.registerLegacyApp({
|
||||
core.application.register({
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
updater$: this.appStateUpdater.asObservable(),
|
||||
navLinkId: 'kibana:discover',
|
||||
order: -1004,
|
||||
euiIconType: 'discoverApp',
|
||||
defaultPath: '#/',
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
mount: async (params: AppMountParameters) => {
|
||||
if (!this.initializeServices) {
|
||||
throw Error('Discover plugin method initializeServices is undefined');
|
||||
|
@ -196,6 +199,7 @@ export class DiscoverPlugin
|
|||
if (!this.initializeInnerAngular) {
|
||||
throw Error('Discover plugin method initializeInnerAngular is undefined');
|
||||
}
|
||||
setScopedHistory(params.history);
|
||||
appMounted();
|
||||
const {
|
||||
plugins: { data: dataStart },
|
||||
|
@ -205,6 +209,7 @@ export class DiscoverPlugin
|
|||
// make sure the index pattern list is up to date
|
||||
await dataStart.indexPatterns.clearCache();
|
||||
const { renderApp } = await import('./application/application');
|
||||
params.element.classList.add('dscAppWrapper');
|
||||
const unmount = await renderApp(innerAngularName, params.element);
|
||||
return () => {
|
||||
unmount();
|
||||
|
@ -213,6 +218,8 @@ export class DiscoverPlugin
|
|||
},
|
||||
});
|
||||
|
||||
plugins.kibanaLegacy.forwardApp('discover', 'discover');
|
||||
|
||||
if (plugins.home) {
|
||||
registerFeature(plugins.home);
|
||||
}
|
||||
|
@ -236,6 +243,7 @@ export class DiscoverPlugin
|
|||
return;
|
||||
}
|
||||
// this is used by application mount and tests
|
||||
const { getInnerAngularModule } = await import('./get_inner_angular');
|
||||
const module = getInnerAngularModule(
|
||||
innerAngularName,
|
||||
core,
|
||||
|
@ -305,6 +313,7 @@ export class DiscoverPlugin
|
|||
throw Error('Discover plugin getEmbeddableInjector: initializeServices is undefined');
|
||||
}
|
||||
const { core, plugins } = await this.initializeServices();
|
||||
const { getInnerAngularModuleEmbeddable } = await import('./get_inner_angular');
|
||||
getInnerAngularModuleEmbeddable(
|
||||
embeddableAngularName,
|
||||
core,
|
||||
|
|
|
@ -29,7 +29,7 @@ export function registerFeature(home: HomePublicPluginSetup) {
|
|||
defaultMessage: 'Interactively explore your data by querying and filtering raw documents.',
|
||||
}),
|
||||
icon: 'discoverApp',
|
||||
path: '/app/kibana#/discover',
|
||||
path: '/app/discover#/',
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA,
|
||||
});
|
||||
|
|
|
@ -66,7 +66,7 @@ export function createSavedSearchClass(services: SavedObjectKibanaServices) {
|
|||
});
|
||||
this.showInRecentlyAccessed = true;
|
||||
this.id = id;
|
||||
this.getFullPath = () => `/app/kibana#/discover/${String(id)}`;
|
||||
this.getFullPath = () => `/app/discover#/${String(id)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ export function createSavedSearchesLoader(services: SavedObjectKibanaServices) {
|
|||
nouns: 'saved searches',
|
||||
};
|
||||
|
||||
savedSearchLoader.urlFor = (id: string) => `#/discover/${encodeURIComponent(id)}`;
|
||||
savedSearchLoader.urlFor = (id: string) => `#/${encodeURIComponent(id)}`;
|
||||
|
||||
return savedSearchLoader;
|
||||
}
|
||||
|
|
|
@ -94,8 +94,11 @@ export class EditPanelAction implements Action<ActionContext> {
|
|||
|
||||
public getAppTarget({ embeddable }: ActionContext): { app: string; path: string } | undefined {
|
||||
const app = embeddable ? embeddable.getOutput().editApp : undefined;
|
||||
const path = embeddable ? embeddable.getOutput().editPath : undefined;
|
||||
let path = embeddable ? embeddable.getOutput().editPath : undefined;
|
||||
if (app && path) {
|
||||
if (this.currentAppId) {
|
||||
path += `?${EMBEDDABLE_ORIGINATING_APP_PARAM}=${this.currentAppId}`;
|
||||
}
|
||||
return { app, path };
|
||||
}
|
||||
}
|
||||
|
@ -104,11 +107,6 @@ export class EditPanelAction implements Action<ActionContext> {
|
|||
let editUrl = embeddable ? embeddable.getOutput().editUrl : undefined;
|
||||
if (editUrl && this.currentAppId) {
|
||||
editUrl += `?${EMBEDDABLE_ORIGINATING_APP_PARAM}=${this.currentAppId}`;
|
||||
|
||||
// TODO: Remove this after https://github.com/elastic/kibana/pull/63443
|
||||
if (this.currentAppId === 'kibana') {
|
||||
editUrl += `:${window.location.hash.split(/[\/\?]/)[1]}`;
|
||||
}
|
||||
}
|
||||
return editUrl ? editUrl : '';
|
||||
}
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ScopedHistory } from 'kibana/public';
|
||||
// @ts-ignore
|
||||
import { HomeApp } from './components/home_app';
|
||||
import { getServices } from './kibana_services';
|
||||
|
||||
export const renderApp = async (element: HTMLElement) => {
|
||||
import './index.scss';
|
||||
|
||||
export const renderApp = async (element: HTMLElement, history: ScopedHistory) => {
|
||||
const homeTitle = i18n.translate('home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
|
||||
const { featureCatalogue, chrome } = getServices();
|
||||
|
||||
|
@ -35,7 +38,14 @@ export const renderApp = async (element: HTMLElement) => {
|
|||
|
||||
render(<HomeApp directories={directories} />, element);
|
||||
|
||||
// dispatch synthetic hash change event to update hash history objects
|
||||
// this is necessary because hash updates triggered by using popState won't trigger this event naturally.
|
||||
const unlisten = history.listen(() => {
|
||||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
});
|
||||
|
||||
return () => {
|
||||
unmountComponentAtNode(element);
|
||||
unlisten();
|
||||
};
|
||||
};
|
||||
|
|
|
@ -73,7 +73,7 @@ exports[`apmUiEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addAmpButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial/apm"
|
||||
href="#/tutorial/apm"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add APM"
|
||||
|
@ -105,7 +105,7 @@ exports[`apmUiEnabled 1`] = `
|
|||
aria-describedby="aria-describedby.addLogDataButtonLabel"
|
||||
className="homAddData__button"
|
||||
data-test-subj="logsData"
|
||||
href="#/home/tutorial_directory/logging"
|
||||
href="#/tutorial_directory/logging"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add log data"
|
||||
|
@ -136,7 +136,7 @@ exports[`apmUiEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addMetricsButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/metrics"
|
||||
href="#/tutorial_directory/metrics"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add metric data"
|
||||
|
@ -202,7 +202,7 @@ exports[`apmUiEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addSiemButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/siem"
|
||||
href="#/tutorial_directory/siem"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add events"
|
||||
|
@ -241,7 +241,7 @@ exports[`apmUiEnabled 1`] = `
|
|||
/>
|
||||
</strong>
|
||||
<EuiLink
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="#/tutorial_directory/sampleData"
|
||||
style={
|
||||
Object {
|
||||
"display": "block",
|
||||
|
@ -371,7 +371,7 @@ exports[`isNewKibanaInstance 1`] = `
|
|||
aria-describedby="aria-describedby.addLogDataButtonLabel"
|
||||
className="homAddData__button"
|
||||
data-test-subj="logsData"
|
||||
href="#/home/tutorial_directory/logging"
|
||||
href="#/tutorial_directory/logging"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add log data"
|
||||
|
@ -402,7 +402,7 @@ exports[`isNewKibanaInstance 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addMetricsButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/metrics"
|
||||
href="#/tutorial_directory/metrics"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add metric data"
|
||||
|
@ -468,7 +468,7 @@ exports[`isNewKibanaInstance 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addSiemButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/siem"
|
||||
href="#/tutorial_directory/siem"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add events"
|
||||
|
@ -507,7 +507,7 @@ exports[`isNewKibanaInstance 1`] = `
|
|||
/>
|
||||
</strong>
|
||||
<EuiLink
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="#/tutorial_directory/sampleData"
|
||||
style={
|
||||
Object {
|
||||
"display": "block",
|
||||
|
@ -636,7 +636,7 @@ exports[`mlEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addAmpButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial/apm"
|
||||
href="#/tutorial/apm"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add APM"
|
||||
|
@ -668,7 +668,7 @@ exports[`mlEnabled 1`] = `
|
|||
aria-describedby="aria-describedby.addLogDataButtonLabel"
|
||||
className="homAddData__button"
|
||||
data-test-subj="logsData"
|
||||
href="#/home/tutorial_directory/logging"
|
||||
href="#/tutorial_directory/logging"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add log data"
|
||||
|
@ -699,7 +699,7 @@ exports[`mlEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addMetricsButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/metrics"
|
||||
href="#/tutorial_directory/metrics"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add metric data"
|
||||
|
@ -765,7 +765,7 @@ exports[`mlEnabled 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addSiemButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/siem"
|
||||
href="#/tutorial_directory/siem"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add events"
|
||||
|
@ -804,7 +804,7 @@ exports[`mlEnabled 1`] = `
|
|||
/>
|
||||
</strong>
|
||||
<EuiLink
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="#/tutorial_directory/sampleData"
|
||||
style={
|
||||
Object {
|
||||
"display": "block",
|
||||
|
@ -970,7 +970,7 @@ exports[`render 1`] = `
|
|||
aria-describedby="aria-describedby.addLogDataButtonLabel"
|
||||
className="homAddData__button"
|
||||
data-test-subj="logsData"
|
||||
href="#/home/tutorial_directory/logging"
|
||||
href="#/tutorial_directory/logging"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add log data"
|
||||
|
@ -1001,7 +1001,7 @@ exports[`render 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addMetricsButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/metrics"
|
||||
href="#/tutorial_directory/metrics"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add metric data"
|
||||
|
@ -1067,7 +1067,7 @@ exports[`render 1`] = `
|
|||
<EuiButton
|
||||
aria-describedby="aria-describedby.addSiemButtonLabel"
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/siem"
|
||||
href="#/tutorial_directory/siem"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add events"
|
||||
|
@ -1106,7 +1106,7 @@ exports[`render 1`] = `
|
|||
/>
|
||||
</strong>
|
||||
<EuiLink
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="#/tutorial_directory/sampleData"
|
||||
style={
|
||||
Object {
|
||||
"display": "block",
|
||||
|
|
|
@ -101,7 +101,7 @@ exports[`home directories should not render directory entry when showOnHomePage
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -194,6 +194,7 @@ exports[`home directories should render ADMIN directory entry in "Manage" panel
|
|||
description="Manage the index patterns that help retrieve your data from Elasticsearch."
|
||||
iconType="indexPatternApp"
|
||||
isBeta={false}
|
||||
onClick={[Function]}
|
||||
title="Index Patterns"
|
||||
url="base_path/index_management_landing_page"
|
||||
/>
|
||||
|
@ -229,7 +230,7 @@ exports[`home directories should render ADMIN directory entry in "Manage" panel
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -299,6 +300,7 @@ exports[`home directories should render DATA directory entry in "Explore Data" p
|
|||
description="Display and share a collection of visualizations and saved searches."
|
||||
iconType="dashboardApp"
|
||||
isBeta={false}
|
||||
onClick={[Function]}
|
||||
title="Dashboard"
|
||||
url="base_path/dashboard_landing_page"
|
||||
/>
|
||||
|
@ -357,7 +359,7 @@ exports[`home directories should render DATA directory entry in "Explore Data" p
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -472,7 +474,7 @@ exports[`home isNewKibanaInstance should safely handle execeptions 1`] = `
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -587,7 +589,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when t
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -702,7 +704,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -817,7 +819,7 @@ exports[`home should render home component 1`] = `
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -932,7 +934,7 @@ exports[`home welcome should show the normal home page if loading fails 1`] = `
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -1047,7 +1049,7 @@ exports[`home welcome should show the normal home page if welcome screen is disa
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
@ -1169,7 +1171,7 @@ exports[`home welcome stores skip welcome setting if skipped 1`] = `
|
|||
/>
|
||||
<EuiButton
|
||||
data-test-subj="allPlugins"
|
||||
href="#/home/feature_directory"
|
||||
href="#/feature_directory"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
|
|
@ -30,12 +30,13 @@ exports[`should render popover when appLinks is not empty 1`] = `
|
|||
"id": 0,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "root/app/kibana#/dashboard/722b74f0-b882-11e8-a6d9-e546fe2bba5f",
|
||||
"href": "root/app/dashboards#/view/722b74f0-b882-11e8-a6d9-e546fe2bba5f",
|
||||
"icon": <EuiIcon
|
||||
size="m"
|
||||
type="dashboardApp"
|
||||
/>,
|
||||
"name": "Dashboard",
|
||||
"onClick": [Function],
|
||||
},
|
||||
Object {
|
||||
"href": "rootapp/myAppPath",
|
||||
|
@ -44,6 +45,7 @@ exports[`should render popover when appLinks is not empty 1`] = `
|
|||
type="logoKibana"
|
||||
/>,
|
||||
"name": "myAppLabel",
|
||||
"onClick": [Function],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -57,7 +59,7 @@ exports[`should render simple button when appLinks is empty 1`] = `
|
|||
<EuiButton
|
||||
aria-label="View Sample eCommerce orders"
|
||||
data-test-subj="launchSampleDataSetecommerce"
|
||||
href="root/app/kibana#/dashboard/722b74f0-b882-11e8-a6d9-e546fe2bba5f"
|
||||
onClick={[Function]}
|
||||
>
|
||||
View data
|
||||
</EuiButton>
|
||||
|
|
|
@ -101,7 +101,7 @@ const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
|
|||
footer={
|
||||
<EuiButton
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial/apm"
|
||||
href="#/tutorial/apm"
|
||||
aria-describedby={apmData.ariaDescribedby}
|
||||
>
|
||||
<FormattedMessage id="home.addData.apm.addApmButtonLabel" defaultMessage="Add APM" />
|
||||
|
@ -159,7 +159,7 @@ const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
|
|||
<EuiButton
|
||||
className="homAddData__button"
|
||||
data-test-subj="logsData"
|
||||
href="#/home/tutorial_directory/logging"
|
||||
href="#/tutorial_directory/logging"
|
||||
aria-describedby={loggingData.ariaDescribedby}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -183,7 +183,7 @@ const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
|
|||
footer={
|
||||
<EuiButton
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/metrics"
|
||||
href="#/tutorial_directory/metrics"
|
||||
aria-describedby={metricsData.ariaDescribedby}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -220,7 +220,7 @@ const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
|
|||
footer={
|
||||
<EuiButton
|
||||
className="homAddData__button"
|
||||
href="#/home/tutorial_directory/siem"
|
||||
href="#/tutorial_directory/siem"
|
||||
aria-describedby={siemData.ariaDescribedby}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -256,7 +256,7 @@ const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
|
|||
</strong>
|
||||
<EuiLink
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
href="#/tutorial_directory/sampleData"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="home.addData.sampleDataLink"
|
||||
|
|
|
@ -17,13 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// make sure all dev tools are loaded and registered.
|
||||
import 'uiExports/devTools';
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
if (npStart.plugins.devTools.getSortedDevTools().length === 0) {
|
||||
npStart.core.chrome.navLinks.update('kibana:dev_tools', {
|
||||
hidden: true,
|
||||
});
|
||||
}
|
||||
export const createAppNavigationHandler = (targetUrl: string) => (event: MouseEvent) => {
|
||||
if (event.altKey || event.metaKey || event.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (targetUrl.startsWith('/app/')) {
|
||||
const [, appId, path] = /\/app\/(.*?)((\/|\?|#|$).*)/.exec(targetUrl) || [];
|
||||
if (!appId) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
getServices().application.navigateToApp(appId, { path });
|
||||
}
|
||||
};
|
|
@ -35,6 +35,7 @@ import { FeatureCatalogueCategory } from '../../services';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { createAppNavigationHandler } from './app_navigation_handler';
|
||||
|
||||
const ALL_TAB_ID = 'all';
|
||||
const OTHERS_TAB_ID = 'others';
|
||||
|
@ -114,6 +115,7 @@ export class FeatureDirectory extends React.Component {
|
|||
return (
|
||||
<EuiFlexItem key={directory.id}>
|
||||
<Synopsis
|
||||
onClick={createAppNavigationHandler(directory.path)}
|
||||
description={directory.description}
|
||||
iconType={directory.icon}
|
||||
title={directory.title}
|
||||
|
|
|
@ -41,6 +41,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { Welcome } from './welcome';
|
||||
import { getServices } from '../kibana_services';
|
||||
import { FeatureCatalogueCategory } from '../../services';
|
||||
import { createAppNavigationHandler } from './app_navigation_handler';
|
||||
|
||||
const KEY_ENABLE_WELCOME = 'home:welcome:show';
|
||||
|
||||
|
@ -125,6 +126,7 @@ export class Home extends Component {
|
|||
return (
|
||||
<EuiFlexItem className="homHome__synopsisItem" key={directory.id}>
|
||||
<Synopsis
|
||||
onClick={createAppNavigationHandler(directory.path)}
|
||||
description={directory.description}
|
||||
iconType={directory.icon}
|
||||
title={directory.title}
|
||||
|
@ -203,7 +205,7 @@ export class Home extends Component {
|
|||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiButton data-test-subj="allPlugins" href="#/home/feature_directory">
|
||||
<EuiButton data-test-subj="allPlugins" href="#/feature_directory">
|
||||
<FormattedMessage
|
||||
id="home.directories.notFound.viewFullButtonLabel"
|
||||
defaultMessage="View full directory of Kibana plugins"
|
||||
|
|
|
@ -24,13 +24,22 @@ import { Home } from './home';
|
|||
import { FeatureDirectory } from './feature_directory';
|
||||
import { TutorialDirectory } from './tutorial_directory';
|
||||
import { Tutorial } from './tutorial/tutorial';
|
||||
import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
|
||||
import { HashRouter as Router, Switch, Route } from 'react-router-dom';
|
||||
import { getTutorial } from '../load_tutorials';
|
||||
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
|
||||
import { getServices } from '../kibana_services';
|
||||
import { useMount } from 'react-use';
|
||||
|
||||
const RedirectToDefaultApp = () => {
|
||||
useMount(() => {
|
||||
const { kibanaLegacy } = getServices();
|
||||
kibanaLegacy.navigateToDefaultApp();
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
export function HomeApp({ directories }) {
|
||||
const {
|
||||
config,
|
||||
savedObjectsClient,
|
||||
getBasePath,
|
||||
addBasePath,
|
||||
|
@ -42,8 +51,6 @@ export function HomeApp({ directories }) {
|
|||
const mlEnabled = environment.ml;
|
||||
const apmUiEnabled = environment.apmUi;
|
||||
|
||||
const defaultAppId = config.defaultAppId || 'discover';
|
||||
|
||||
const renderTutorialDirectory = props => {
|
||||
return (
|
||||
<TutorialDirectory
|
||||
|
@ -71,12 +78,12 @@ export function HomeApp({ directories }) {
|
|||
<I18nProvider>
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route path="/home/tutorial/:id" render={renderTutorial} />
|
||||
<Route path="/home/tutorial_directory/:tab?" render={renderTutorialDirectory} />
|
||||
<Route exact path="/home/feature_directory">
|
||||
<Route path="/tutorial/:id" render={renderTutorial} />
|
||||
<Route path="/tutorial_directory/:tab?" render={renderTutorialDirectory} />
|
||||
<Route exact path="/feature_directory">
|
||||
<FeatureDirectory addBasePath={addBasePath} directories={directories} />
|
||||
</Route>
|
||||
<Route exact path="/home">
|
||||
<Route exact path="/">
|
||||
<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={directories}
|
||||
|
@ -88,9 +95,7 @@ export function HomeApp({ directories }) {
|
|||
telemetry={telemetry}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/home">
|
||||
<Redirect to={`/${defaultAppId}`} />
|
||||
</Route>
|
||||
<Route path="*" exact={true} component={RedirectToDefaultApp} />
|
||||
</Switch>
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
|
|
|
@ -23,6 +23,7 @@ import { EuiButton, EuiContextMenu, EuiIcon, EuiPopover } from '@elastic/eui';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getServices } from '../kibana_services';
|
||||
import { createAppNavigationHandler } from './app_navigation_handler';
|
||||
|
||||
export class SampleDataViewDataButton extends React.Component {
|
||||
addBasePath = getServices().addBasePath;
|
||||
|
@ -56,14 +57,13 @@ export class SampleDataViewDataButton extends React.Component {
|
|||
},
|
||||
}
|
||||
);
|
||||
const dashboardPath = this.addBasePath(
|
||||
`/app/kibana#/dashboard/${this.props.overviewDashboard}`
|
||||
);
|
||||
const dashboardPath = `/app/dashboards#/view/${this.props.overviewDashboard}`;
|
||||
const prefixedDashboardPath = this.addBasePath(dashboardPath);
|
||||
|
||||
if (this.props.appLinks.length === 0) {
|
||||
return (
|
||||
<EuiButton
|
||||
href={dashboardPath}
|
||||
onClick={createAppNavigationHandler(dashboardPath)}
|
||||
data-test-subj={`launchSampleDataSet${this.props.id}`}
|
||||
aria-label={viewDataButtonAriaLabel}
|
||||
>
|
||||
|
@ -77,6 +77,7 @@ export class SampleDataViewDataButton extends React.Component {
|
|||
name: label,
|
||||
icon: <EuiIcon type={icon} size="m" />,
|
||||
href: this.addBasePath(path),
|
||||
onClick: createAppNavigationHandler(path),
|
||||
};
|
||||
});
|
||||
const panels = [
|
||||
|
@ -88,7 +89,8 @@ export class SampleDataViewDataButton extends React.Component {
|
|||
defaultMessage: 'Dashboard',
|
||||
}),
|
||||
icon: <EuiIcon type="dashboardApp" size="m" />,
|
||||
href: dashboardPath,
|
||||
href: prefixedDashboardPath,
|
||||
onClick: createAppNavigationHandler(dashboardPath),
|
||||
},
|
||||
...additionalItems,
|
||||
],
|
||||
|
|
|
@ -101,11 +101,11 @@ class TutorialUi extends React.Component {
|
|||
getServices().chrome.setBreadcrumbs([
|
||||
{
|
||||
text: homeTitle,
|
||||
href: '#/home',
|
||||
href: '#/',
|
||||
},
|
||||
{
|
||||
text: addDataTitle,
|
||||
href: '#/home/tutorial_directory',
|
||||
href: '#/tutorial_directory',
|
||||
},
|
||||
{
|
||||
text: tutorial ? tutorial.name : this.props.tutorialId,
|
||||
|
@ -325,7 +325,7 @@ class TutorialUi extends React.Component {
|
|||
});
|
||||
if (overviewDashboard) {
|
||||
label = overviewDashboard.linkLabel;
|
||||
url = this.props.addBasePath(`/app/kibana#/dashboard/${overviewDashboard.id}`);
|
||||
url = this.props.addBasePath(`/app/dashboards#/view/${overviewDashboard.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ class TutorialDirectoryUi extends React.Component {
|
|||
getServices().chrome.setBreadcrumbs([
|
||||
{
|
||||
text: homeTitle,
|
||||
href: '#/home',
|
||||
href: '#/',
|
||||
},
|
||||
{ text: addDataTitle },
|
||||
]);
|
||||
|
@ -138,7 +138,7 @@ class TutorialDirectoryUi extends React.Component {
|
|||
icon: icon,
|
||||
name: tutorialConfig.name,
|
||||
description: tutorialConfig.shortDescription,
|
||||
url: this.props.addBasePath(`#/home/tutorial/${tutorialConfig.id}`),
|
||||
url: this.props.addBasePath(`#/tutorial/${tutorialConfig.id}`),
|
||||
elasticCloud: tutorialConfig.elasticCloud,
|
||||
// Beta label is skipped on the tutorial overview page for now. Too many beta labels.
|
||||
//isBeta: tutorialConfig.isBeta,
|
||||
|
@ -155,7 +155,7 @@ class TutorialDirectoryUi extends React.Component {
|
|||
id: 'home.tutorial.card.sampleDataDescription',
|
||||
defaultMessage: 'Get started exploring Kibana with these "one click" data sets.',
|
||||
}),
|
||||
url: this.props.addBasePath('#/home/tutorial_directory/sampleData'),
|
||||
url: this.props.addBasePath('#/tutorial_directory/sampleData'),
|
||||
elasticCloud: true,
|
||||
onClick: this.onSelectedTabChanged.bind(null, SAMPLE_DATA_TAB_ID),
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue