Remove k7design setting (#29565)

Removes support for the k6 navigation style from master. All but the first commit are targeted at a specific section of Kibana. Please take a look at the areas you're familiar with and check it off the list. We'll plan to merge this right before feature freeze.

- [ ] home
- [ ] discover
- [ ] context
- [ ] visualize
- [ ] dashboard
- [ ] devtools 
- [ ] timelion
- [ ] graph
- [x] monitoring 
- [ ] gis 
- [ ] infra 
- [x] ml 
- [ ] security 
- [ ] uptime
- [x] beatscm

@elastic/kibana-app @elastic/kibana-security @elastic/ml-ui @elastic/infrastructure-ui @elastic/kibana-gis @elastic/stack-monitoring @elastic/es-ui
This commit is contained in:
Spencer 2019-02-05 12:57:13 -06:00 committed by GitHub
parent fd8434a823
commit 0aecd79c17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 48 additions and 1995 deletions

View file

@ -1,24 +1,3 @@
<div class="kbnTopNav" ng-if="!k7design">
<div
class="kuiLocalTitle"
role="heading"
aria-level="1"
i18n-id="kbn.context.surroundingDocumentsDescription"
i18n-default-message="Surrounding Documents in {indexPatternId}"
i18n-values="{
indexPatternId: contextApp.state.queryParameters.indexPatternId
}"
></div>
<div class="kuiLocalNavRow kuiLocalNavRow--secondary">
<div class="kuiLocalTabs">
<div class="kuiLocalTab kuiLocalTab-isSelected" >
{{ contextApp.state.queryParameters.anchorType }}#{{ contextApp.state.queryParameters.anchorId }}
</div>
</div>
</div>
</div>
<filter-bar
class-name="'globalFilterGroup__filterBar'"
filters="contextApp.state.queryParameters.filters"

View file

@ -75,8 +75,6 @@ function ContextAppController($scope, config, Private) {
timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();
config.bindToScope($scope, 'k7design');
this.state = createInitialState(
parseInt(config.get('context:step'), 10),
getFirstSortableField(this.indexPattern, config.get('context:tieBreakerFields')),

View file

@ -6,28 +6,6 @@
<kbn-top-nav name="dashboard" config="topNavMenu">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Title. -->
<div data-transclude-slot="topLeftCorner">
<div
class="kuiLocalBreadcrumbs"
data-test-subj="breadcrumbs"
role="heading"
aria-level="1"
ng-if="showPluginBreadcrumbs">
<div class="kuiLocalBreadcrumb">
<a
class="kuiLocalBreadcrumb__link"
href="{{landingPageUrl()}}"
i18n-id="kbn.dashboard.dashboardLinkLabel"
i18n-default-message="Dashboard"
></a>
</div>
<div class="kuiLocalBreadcrumb">
{{ getDashTitle() }}
</div>
</div>
</div>
<!-- Search. -->
<div ng-show="chrome.getVisible()" class="fullWidth" data-transclude-slot="bottomRow">
<search-bar

View file

@ -206,7 +206,6 @@ app.directive('dashboardApp', function ($injector) {
};
updateBreadcrumbs();
dashboardStateManager.registerChangeListener(updateBreadcrumbs);
config.watch('k7design', (val) => $scope.showPluginBreadcrumbs = !val);
$scope.newDashboard = () => { kbnUrl.change(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {}); };
$scope.saveState = () => dashboardStateManager.saveState();

View file

@ -2,12 +2,6 @@
<kbn-top-nav name="devtools" config="kbnDevToolsApp.topNavConfig">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<bread-crumbs
data-transclude-slot="topLeftCorner"
omit-current-page="true"
></bread-crumbs>
<!-- Tabs. -->
<div data-transclude-slot="bottomRow" class="euiTabs" role="tablist">
<a

View file

@ -192,8 +192,6 @@ function discoverController(
return interval.val !== 'custom';
};
config.bindToScope($scope, 'k7design');
// the saved savedSearch
const savedSearch = $route.current.locals.savedSearch;
$scope.$on('$destroy', savedSearch.destroy);

View file

@ -7,7 +7,6 @@
<div data-transclude-slot="topLeftCorner" class="kuiLocalBreadcrumbs">
<h1 tabindex="0" id="kui_local_breadcrumb" class="kuiLocalBreadcrumb" ng-if="opts.savedSearch.id">
<span class="kuiLocalBreadcrumb__emphasis">
<span data-test-subj="discoverCurrentQuery" ng-bind="opts.savedSearch.lastSavedTitle" ng-hide="k7design"></span>
<span
id="reload_saved_search"
aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload saved search'} }}"

View file

@ -59,9 +59,7 @@ uiRoutes
k7Breadcrumbs
});
app.controller('doc', function ($scope, $route, es, config) {
config.bindToScope($scope, 'k7design');
app.controller('doc', function ($scope, $route, es) {
timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();

View file

@ -1,27 +1,4 @@
<div ng-controller="doc" class="app-container">
<div class="kbnTopNav" ng-if="!k7design">
<div
class="kuiLocalTitle"
i18n-id="kbn.doc.singleDocumentTitle"
i18n-default-message="Single Document"
></div>
<div class="kuiLocalNavRow kuiLocalNavRow--secondary">
<div class="kuiLocalTabs">
<div
class="kuiLocalTab kuiLocalTab-isSelected"
ng-bind-template="{{ hit._type }}#{{ hit._id | uriescape }}"
ng-if="!!hit"
></div>
<div
class="kuiLocalTab kuiLocalTab-isSelected"
ng-if="!hit"
i18n-id="kbn.doc.unknownIdTitle"
i18n-default-message="Unknown Id"
></div>
</div>
</div>
</div>
<div class="kuiViewContent">
<!-- no results -->
<div class="kuiViewContentItem" ng-if="status === 'notFound'">

View file

@ -40,7 +40,6 @@ export function HomeApp({
const apmUiEnabled = chrome.getInjected('apmUiEnabled', true);
const mlEnabled = chrome.getInjected('mlEnabled', false);
const savedObjectsClient = chrome.getSavedObjectsClient();
const isK7Design = chrome.getUiSettingsClient().get('k7design', false);
const renderTutorialDirectory = (props) => {
return (
@ -48,7 +47,6 @@ export function HomeApp({
addBasePath={chrome.addBasePath}
openTab={props.match.params.tab}
isCloudEnabled={isCloudEnabled}
isK7Design={isK7Design}
/>
);
};
@ -62,7 +60,6 @@ export function HomeApp({
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={props.match.params.id}
bulkCreate={savedObjectsClient.bulkCreate}
isK7Design={isK7Design}
/>
);
};

View file

@ -8,30 +8,6 @@ exports[`isCloudEnabled is false should not render instruction toggle when ON_PR
<EuiPageBody
restrictWidth={false}
>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"
@ -87,30 +63,6 @@ exports[`isCloudEnabled is false should render ON_PREM instructions with instruc
<EuiPageBody
restrictWidth={false}
>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"
@ -195,62 +147,6 @@ exports[`isCloudEnabled is false should render ON_PREM instructions with instruc
</EuiPage>
`;
exports[`should not render breadcrumbs when K7 1`] = `
<EuiPage
className="homPage"
restrictWidth={false}
>
<EuiPageBody
restrictWidth={false}
>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"
iconType="logoApache"
title="jest test tutorial"
/>
<EuiSpacer
size="l"
/>
<div
className="eui-textCenter"
/>
<EuiSpacer
size="l"
/>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
Object {
"id": "platform id",
"instructions": Array [
Object {
"title": "elasticCloud instructions",
},
],
},
]
}
key="0"
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</EuiPanel>
</div>
</EuiPageBody>
</EuiPage>
`;
exports[`should render ELASTIC_CLOUD instructions when isCloudEnabled is true 1`] = `
<EuiPage
className="homPage"
@ -259,30 +155,6 @@ exports[`should render ELASTIC_CLOUD instructions when isCloudEnabled is true 1`
<EuiPageBody
restrictWidth={false}
>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"

View file

@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import React, { Fragment } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Footer } from './footer';
import { Introduction } from './introduction';
@ -28,7 +28,6 @@ import {
EuiSpacer,
EuiPage,
EuiPanel,
EuiLink,
EuiText,
EuiPageBody,
EuiButtonGroup,
@ -95,21 +94,19 @@ class TutorialUi extends React.Component {
});
}
if(this.props.isK7Design) {
chrome.breadcrumbs.set([
{
text: homeTitle,
href: '#/home'
},
{
text: addDataTitle,
href: '#/home/tutorial_directory'
},
{
text: tutorial ? tutorial.name : this.props.tutorialId
}
]);
}
chrome.breadcrumbs.set([
{
text: homeTitle,
href: '#/home'
},
{
text: addDataTitle,
href: '#/home/tutorial_directory'
},
{
text: tutorial ? tutorial.name : this.props.tutorialId
}
]);
}
getInstructions = () => {
@ -376,28 +373,10 @@ class TutorialUi extends React.Component {
);
}
let breadcrumbs;
if (!this.props.isK7Design) {
breadcrumbs = (
<Fragment>
<div>
<EuiLink href="#/home">{homeTitle}</EuiLink> /{' '}
<EuiLink href="#/home/tutorial_directory">{addDataTitle}</EuiLink> /{' '}
{this.state.tutorial ? this.state.tutorial.name : this.props.tutorialId}
</div>
<EuiSpacer size="s" />
</Fragment>
);
}
return (
<EuiPage className="homPage">
<EuiPageBody>
{breadcrumbs}
{content}
</EuiPageBody>
</EuiPage>
);
@ -411,7 +390,6 @@ TutorialUi.propTypes = {
replaceTemplateStrings: PropTypes.func.isRequired,
tutorialId: PropTypes.string.isRequired,
bulkCreate: PropTypes.func.isRequired,
isK7Design: PropTypes.bool.isRequired,
};
export const Tutorial = injectI18n(TutorialUi);

View file

@ -71,7 +71,6 @@ describe('isCloudEnabled is false', () => {
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => { }}
isK7Design={false}
/>);
await loadTutorialPromise;
@ -96,7 +95,6 @@ describe('isCloudEnabled is false', () => {
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => { }}
isK7Design={false}
/>);
await loadBasicTutorialPromise;
component.update();
@ -111,7 +109,6 @@ describe('isCloudEnabled is false', () => {
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => { }}
isK7Design={false}
/>);
await loadTutorialPromise;
component.update();
@ -130,22 +127,6 @@ test('should render ELASTIC_CLOUD instructions when isCloudEnabled is true', asy
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => { }}
isK7Design={false}
/>);
await loadTutorialPromise;
component.update();
expect(component).toMatchSnapshot(); // eslint-disable-line
});
test('should not render breadcrumbs when K7', async () => {
const component = shallowWithIntl(<Tutorial.WrappedComponent
addBasePath={addBasePath}
isCloudEnabled={true}
getTutorial={getTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => { }}
isK7Design={true}
/>);
await loadTutorialPromise;
component.update();

View file

@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import React, { Fragment } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Synopsis } from './synopsis';
import { SampleDataSetCards } from './sample_data_set_cards';
@ -33,7 +33,6 @@ import {
EuiSpacer,
EuiTitle,
EuiPageBody,
EuiLink,
} from '@elastic/eui';
@ -87,15 +86,13 @@ class TutorialDirectoryUi extends React.Component {
async componentDidMount() {
this._isMounted = true;
if(this.props.isK7Design) {
chrome.breadcrumbs.set([
{
text: homeTitle,
href: '#/home'
},
{ text: addDataTitle }
]);
}
chrome.breadcrumbs.set([
{
text: homeTitle,
href: '#/home'
},
{ text: addDataTitle }
]);
const tutorialConfigs = await getTutorials();
@ -197,24 +194,9 @@ class TutorialDirectoryUi extends React.Component {
}
render() {
let breadcrumbs;
if (!this.props.isK7Design) {
breadcrumbs = (
<Fragment>
<div>
<EuiLink href="#/home">{homeTitle}</EuiLink> / {addDataTitle}
</div>
<EuiSpacer size="s" />
</Fragment>
);
}
return (
<EuiPage className="homPage">
<EuiPageBody>
{breadcrumbs}
<EuiTitle size="l">
<h1>
<FormattedMessage
@ -242,7 +224,6 @@ TutorialDirectoryUi.propTypes = {
addBasePath: PropTypes.func.isRequired,
openTab: PropTypes.string,
isCloudEnabled: PropTypes.bool.isRequired,
isK7Design: PropTypes.bool.isRequired,
};
export const TutorialDirectory = injectI18n(TutorialDirectoryUi);

View file

@ -3,16 +3,6 @@
<kbn-top-nav name="visualize" config="topNavMenu">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<bread-crumbs
data-transclude-slot="topLeftCorner"
class="fullWidth"
page-title="getVisualizationTitle()"
use-links="true"
omit-current-page="true"
omit-pages="['edit']"
></bread-crumbs>
<!-- Search. -->
<div
data-transclude-slot="bottomRow"

View file

@ -340,15 +340,6 @@ function VisEditor(
$state.replace();
$scope.getVisualizationTitle = function getVisualizationTitle() {
return savedVis.lastSavedTitle || i18n('kbn.visualize.topNavMenu.unsavedVisualizationTitle', {
defaultMessage: '{visTitle} (unsaved)',
values: {
visTitle: savedVis.title,
},
});
};
$scope.$watchMulti([
'searchSource.getField("index")',
'vis.type.options.showTimePicker',

View file

@ -1,20 +1,3 @@
<!-- Local nav. -->
<kbn-top-nav name="visualize" ng-if="listingController.showPluginBreadcrumbs">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Title. -->
<div data-transclude-slot="topLeftCorner">
<div
class="kuiLocalTitle"
role="heading"
aria-level="1"
i18n-id="kbn.visualize.listing.topLeftCornerTitle"
i18n-default-message="Visualize"
></div>
</div>
</div>
</kbn-top-nav>
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem"
data-test-subj="visualizeLandingPage"
>

View file

@ -92,5 +92,4 @@ export function VisualizeListingController($injector, createNewVis) {
defaultMessage: 'Visualize',
})
}]);
config.watch('k7design', (val) => this.showPluginBreadcrumbs = !val);
}

View file

@ -1,18 +1,3 @@
<!-- Local nav. -->
<kbn-top-nav name="visualize" ng-if="!k7design">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<bread-crumbs
data-transclude-slot="topLeftCorner"
class="fullWidth"
use-links="true"
omit-current-page="true"
page-title="::'kbn.visualize.newVisWizard.pageTitle' | i18n: { defaultMessage: 'Choose search source' }"
></bread-crumbs>
</div>
</kbn-top-nav>
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem" data-test-subj="visualizeSelectSearch">
<div class="visWizard kuiViewContentItem">
<div class="visWizard__column visWizard__column--small">

View file

@ -61,11 +61,10 @@ routes.when(VisualizeConstants.WIZARD_STEP_2_PAGE_PATH, {
}
});
module.controller('VisualizeWizardStep2', function ($route, $scope, kbnUrl, config) {
module.controller('VisualizeWizardStep2', function ($route, $scope, kbnUrl) {
const type = $route.current.params.type;
const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM];
kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM);
config.bindToScope($scope, 'k7design');
$scope.step2WithSearchUrl = function (hit) {
if (addToDashMode) {

View file

@ -71,16 +71,6 @@ export function getUiSettingDefaults() {
},
}),
},
'k7design': {
name: i18n.translate('kbn.advancedSettings.k7designTitle', {
defaultMessage: 'Use the new K7 UI design',
}),
value: true,
description: i18n.translate('kbn.advancedSettings.k7designText', {
defaultMessage:
'When set, Kibana will use the new K7 design targeted for release in 7.0. At this time, not all features are implemented.',
}),
},
'search:queryLanguage': {
name: i18n.translate('kbn.advancedSettings.searchQueryLanguageTitle', {
defaultMessage: 'Query language',

View file

@ -20,7 +20,6 @@
import 'ui/autoload/modules';
import 'ui/autoload/styles';
import 'ui/i18n';
import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
import { destroyStatusPage, renderStatusPage } from './components/render';
@ -33,8 +32,3 @@ chrome
$scope.$on('$destroy', destroyStatusPage);
});
});
uiModules.get('kibana')
.config(function (appSwitcherEnsureNavigationProvider) {
appSwitcherEnsureNavigationProvider.forceNavigation(true);
});

View file

@ -79,9 +79,6 @@ require('ui/routes')
'search': '/'
}));
}
},
controller($scope, config) {
config.bindToScope($scope, 'k7design');
}
});

View file

@ -5,11 +5,6 @@
<div data-transclude-slots>
<div data-transclude-slot="topLeftCorner">
<span class="kuiLocalTitle">
<span ng-show="opts.savedSheet.id && !k7design">
{{opts.savedSheet.lastSavedTitle}}
&nbsp;
</span>
<span class="timApp__stats" ng-show="stats">
<span
i18n-id="timelion.topNavMenu.statsDescription"

View file

@ -86,7 +86,6 @@ function createBreadcrumbsApi(chrome: { [key: string]: any }) {
* the breadcrumbs if we switch to a Kibana app that does not use breadcrumbs correctly
*/
$setupBreadcrumbsAutoClear: ($rootScope: IRootScopeService, $injector: any) => {
const uiSettings = chrome.getUiSettingsClient();
const $route = $injector.has('$route') ? $injector.get('$route') : {};
$rootScope.$on('$routeChangeStart', () => {
@ -101,7 +100,7 @@ function createBreadcrumbsApi(chrome: { [key: string]: any }) {
}
const k7BreadcrumbsProvider = current.k7Breadcrumbs;
if (!k7BreadcrumbsProvider || !uiSettings.get('k7design')) {
if (!k7BreadcrumbsProvider) {
newPlatformChrome.setBreadcrumbs([]);
return;
}

View file

@ -30,6 +30,7 @@ import '../storage';
import '../directives/kbn_src';
import '../watch_multi';
import './services';
import '../i18n';
import { initAngularApi } from './api/angular';
import appsApi from './api/apps';

View file

@ -1,5 +1,4 @@
@import './kbn_chrome';
@import './loading_indicator';
@import './global_nav/index';
@import './header_global_nav/index';

View file

@ -1,75 +0,0 @@
.kbnGlobalNav {
width: $kbnGlobalNavClosedWidth;
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 0;
background-color: $euiColorPrimary;
overflow: hidden;
z-index: 5;
&.kbnGlobalNav-isOpen {
width: $kbnGlobalNavOpenWidth;
+ .app-wrapper {
left: $kbnGlobalNavOpenWidth;
}
}
.kbnGlobalNav__smallLogoBrand,
.kbnGlobalNav__logoBrand {
height: $kbnGlobalNavLogoHeight;
width: $kbnGlobalNavOpenWidth;
list-style-type: none;
&.kibana {
background-image: url('ui/assets/images/kibana.svg');
background-position: 10px 14px;
background-size: 120px 42px;
background-repeat: no-repeat;
}
}
}
/**
* 1. Push main apps to the top and bottom buttons to the bottom.
* 2. Fill height of global nav, but respect the height of the logo.
* 3. Allow user to scroll to see clipped nav items when the nav is too short.
* 4. Style the scrollbar to look good in Chrome and Safari.
*/
.kbnGlobalNav__links {
@include euiScrollBar; /* 4 */
display: flex; /* 1 */
flex-direction: column; /* 1 */
justify-content: space-between; /* 1 */
height: calc(100% - #{$kbnGlobalNavLogoHeight}); /* 2 */
overflow-x: hidden; /* 3 */
overflow-y: auto; /* 3 */
&::-webkit-scrollbar { /* 4 */
@include size($euiSizeS);
}
&::-webkit-scrollbar-thumb { /* 4 */
background-color: tint($euiColorPrimary, 50%);
}
}
/**
* 1. Prevent the top and bottom links from collapsing when the browser window is too short.
* This problem is specific to Safari.
*/
.kbnGlobalNav__linksSection {
flex: 0 0 auto; /* 1 */
}
.kbnGlobalNav__logoLink {
display: inline-block;
&:hover,
&.active {
background-color: darken($euiColorPrimary, 2%);
}
}

View file

@ -1,2 +0,0 @@
@import './global_nav';
@import './global_nav_link/index';

View file

@ -1,237 +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 sinon from 'sinon';
import ngMock from 'ng_mock';
import expect from 'expect.js';
import { DomLocationProvider } from '../../../../../dom_location';
import { constant, cloneDeep } from 'lodash';
import $ from 'jquery';
import '../../../..';
import '../app_switcher';
describe('appSwitcher directive', function () {
let env;
beforeEach(ngMock.module('kibana'));
function setup(href, links) {
return ngMock.inject(function ($window, $rootScope, $compile, Private) {
const domLocation = Private(DomLocationProvider);
$rootScope.chrome = {
getNavLinks: constant(cloneDeep(links)),
};
env = {
$scope: $rootScope,
$el: $compile($('<app-switcher chrome="chrome">'))($rootScope),
currentHref: href,
location: domLocation
};
Object.defineProperties(domLocation, {
href: {
get: function () { return env.currentHref; },
set: function (val) { return env.currentHref = val; },
},
reload: {
value: sinon.stub()
}
});
env.$scope.$digest();
});
}
describe('when one link is for the active app', function () {
const myLink = {
active: true,
title: 'myLink',
url: 'http://localhost:555/app/myApp',
lastSubUrl: 'http://localhost:555/app/myApp#/lastSubUrl'
};
const notMyLink = {
active: false,
title: 'notMyLink',
url: 'http://localhost:555/app/notMyApp',
lastSubUrl: 'http://localhost:555/app/notMyApp#/lastSubUrl'
};
beforeEach(setup('http://localhost:5555/app/myApp/', [myLink, notMyLink]));
it('links to the inactive apps base url', function () {
const $myLink = env.$el.findTestSubject('appLink').eq(0);
expect($myLink.prop('href')).to.be(myLink.url);
expect($myLink.prop('href')).to.not.be(myLink.lastSubUrl);
});
it('links to the inactive apps last sub url', function () {
const $notMyLink = env.$el.findTestSubject('appLink').eq(1);
expect($notMyLink.prop('href')).to.be(notMyLink.lastSubUrl);
expect($notMyLink.prop('href')).to.not.be(notMyLink.url);
});
});
describe('when none of the links are for the active app', function () {
const myLink = {
active: false,
title: 'myLink',
url: 'http://localhost:555/app/myApp',
lastSubUrl: 'http://localhost:555/app/myApp#/lastSubUrl'
};
const notMyLink = {
active: false,
title: 'notMyLink',
url: 'http://localhost:555/app/notMyApp',
lastSubUrl: 'http://localhost:555/app/notMyApp#/lastSubUrl'
};
beforeEach(setup('http://localhost:5555/app/myApp/', [myLink, notMyLink]));
it('links to the lastSubUrl for each', function () {
const $links = env.$el.findTestSubject('appLink');
const $myLink = $links.eq(0);
const $notMyLink = $links.eq(1);
expect($myLink.prop('href')).to.be(myLink.lastSubUrl);
expect($myLink.prop('href')).to.not.be(myLink.url);
expect($notMyLink.prop('href')).to.be(notMyLink.lastSubUrl);
expect($notMyLink.prop('href')).to.not.be(notMyLink.url);
});
});
describe('clicking a link with matching href but missing hash', function () {
const url = 'http://localhost:555/app/myApp?query=1';
beforeEach(setup(url + '#/lastSubUrl', [
{ url: url }
]));
it('just prevents propagation (no reload)', function () {
const event = new $.Event('click');
expect(env.location.reload.callCount).to.be(0);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(false);
const $link = env.$el.findTestSubject('appLink');
expect($link.prop('href')).to.be(url);
$link.trigger(event);
expect(env.location.reload.callCount).to.be(0);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(true);
});
});
describe('clicking a link that matches entire url', function () {
const url = 'http://localhost:555/app/myApp#/lastSubUrl';
beforeEach(setup(url, [
{ url: url }
]));
it('calls window.location.reload and prevents propagation', function () {
const event = new $.Event('click');
expect(env.location.reload.callCount).to.be(0);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(false);
const $link = env.$el.findTestSubject('appLink');
expect($link.prop('href')).to.be(env.currentHref);
$link.trigger(event);
expect(env.location.reload.callCount).to.be(1);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(true);
});
});
describe('clicking a link with matching href but changed hash', function () {
const rootUrl = 'http://localhost:555/app/myApp?query=1';
const url = rootUrl + '#/lastSubUrl2';
beforeEach(setup(url + '#/lastSubUrl', [
{ url: url }
]));
it('calls window.location.reload and prevents propagation', function () {
const event = new $.Event('click');
expect(env.location.reload.callCount).to.be(0);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(false);
const $link = env.$el.findTestSubject('appLink');
expect($link.prop('href')).to.be(url);
$link.trigger(event);
expect(env.location.reload.callCount).to.be(1);
expect(event.isDefaultPrevented()).to.be(false);
expect(event.isPropagationStopped()).to.be(true);
});
});
describe('clicking a link with matching host', function () {
beforeEach(setup('http://localhost:555/someOtherPath', [
{
active: true,
url: 'http://localhost:555/app/myApp'
}
]));
it('allows click through', function () {
const event = new $.Event('click');
expect(env.location.reload.callCount).to.be(0);
expect(event.isPropagationStopped()).to.be(false);
env.$el.findTestSubject('appLink').trigger(event);
expect(env.location.reload.callCount).to.be(0);
expect(event.isPropagationStopped()).to.be(false);
});
});
describe('clicking a link with matching host and path', function () {
beforeEach(setup('http://localhost:555/app/myApp?someQuery=true', [
{
active: true,
url: 'http://localhost:555/app/myApp?differentQuery=true'
}
]));
it('allows click through', function () {
const event = new $.Event('click');
expect(env.location.reload.callCount).to.be(0);
expect(event.isPropagationStopped()).to.be(false);
env.$el.findTestSubject('appLink').trigger(event);
expect(env.location.reload.callCount).to.be(0);
expect(event.isPropagationStopped()).to.be(false);
});
});
});

View file

@ -1,12 +0,0 @@
<global-nav-link
ng-repeat="link in switcher.links"
ng-if="!link.hidden"
is-active="link.active"
is-disabled="link.disabled"
tooltip-content="switcher.getTooltip(link)"
on-click="switcher.ensureNavigation($event, link)"
url="link.active ? link.url : (link.lastSubUrl || link.url)"
icon="link.icon"
eui-icon-type="link.euiIconType"
label="link.title"
></global-nav-link>

View file

@ -1,93 +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 { DomLocationProvider } from '../../../../dom_location';
import { parse } from 'url';
import { uiModules } from '../../../../modules';
import appSwitcherTemplate from './app_switcher.html';
uiModules
.get('kibana')
.provider('appSwitcherEnsureNavigation', function () {
let forceNavigation = false;
this.forceNavigation = function (val) {
forceNavigation = !!val;
};
this.$get = ['Private', function (Private) {
const domLocation = Private(DomLocationProvider);
return function (event, link) {
if (link.disabled) {
event.preventDefault();
}
if (!forceNavigation || event.isDefaultPrevented() || event.altKey || event.metaKey || event.ctrlKey) {
return;
}
const toParsed = parse(event.delegateTarget.href);
const fromParsed = parse(domLocation.href);
const sameProto = toParsed.protocol === fromParsed.protocol;
const sameHost = toParsed.host === fromParsed.host;
const samePath = toParsed.path === fromParsed.path;
if (sameProto && sameHost && samePath) {
toParsed.hash && domLocation.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();
}
};
}];
})
.directive('appSwitcher', function () {
return {
restrict: 'E',
scope: {
chrome: '=',
},
template: appSwitcherTemplate,
controllerAs: 'switcher',
controller($scope, appSwitcherEnsureNavigation, globalNavState) {
if (!$scope.chrome || !$scope.chrome.getNavLinks) {
throw new TypeError('appSwitcher directive requires the "chrome" config-object');
}
this.links = $scope.chrome.getNavLinks();
// links don't cause full-navigation events in certain scenarios
// so we force them when needed
this.ensureNavigation = appSwitcherEnsureNavigation;
this.getTooltip = link => {
// If the sidebar is open then we don't need to show the title because
// it will already be visible.
if (globalNavState.isOpen()) {
return link.tooltip;
}
return link.tooltip ? link.title + ' - ' + link.tooltip : link.title;
};
}
};
});

View file

@ -1,20 +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 './app_switcher';

View file

@ -1,68 +0,0 @@
<nav
class="kbnGlobalNav"
ng-class="{'kbnGlobalNav-isOpen': isGlobalNavOpen}"
ng-show="isVisible"
data-test-subj="globalNav"
>
<!-- Logo -->
<div class="kbnGlobalNav__logo">
<a
class="kbnGlobalNav__logoLink"
ng-class="{ active: isHomeActive() }"
href="{{ getHref('/app/kibana#/home') }}"
data-test-subj="kibanaLogo"
>
<ul>
<li
ng-if="!logoBrand && !smallLogoBrand"
aria-label="{{ 'common.ui.chrome.globalNav.logoAriaLabel' | i18n: {
defaultMessage: '{appTitle} home',
values: {appTitle}
} }}"
class="kbnGlobalNav__logoBrand kibana"
></li>
<li
ng-if="logoBrand"
ng-style="{ 'background': logoBrand }"
aria-label="{{ 'common.ui.chrome.globalNav.logoAriaLabel' | i18n: {
defaultMessage: '{appTitle} home',
values: {appTitle}
} }}"
class="kbnGlobalNav__logoBrand hidden-sm"
></li>
<li
ng-if="smallLogoBrand"
ng-style="{ 'background': smallLogoBrand }"
aria-label="{{ 'common.ui.chrome.globalNav.logoAriaLabel' | i18n: {
defaultMessage: '{appTitle} home',
values: {appTitle}
} }}"
class="kbnGlobalNav__smallLogoBrand visible-sm hidden-xs"
></li>
</ul>
</a>
</div>
<!-- Links -->
<div class="kbnGlobalNav__links">
<!-- Main apps -->
<div class="kbnGlobalNav__linksSection"><app-switcher chrome="chrome"></app-switcher></div>
<!-- Bottom button -->
<div class="kbnGlobalNav__linksSection">
<div class="chrome-actions" kbn-chrome-append-nav-controls></div>
<!-- Open/close sidebar -->
<global-nav-link
class="{{ globalNavToggleButton.classes }}"
tooltip-content="globalNavToggleButton.tooltipContent"
on-click="toggleGlobalNav($event)"
icon="'plugins/kibana/assets/play-circle.svg'"
eui-icon-type="'sortRight'"
label="globalNavToggleButton.title"
></global-nav-link>
</div>
</div>
</nav>

View file

@ -1,88 +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 './app_switcher';
import './global_nav_link';
import 'ui/i18n';
import globalNavTemplate from './global_nav.html';
import { uiModules } from '../../../modules';
const module = uiModules.get('kibana');
module.directive('globalNav', (globalNavState, chrome, i18n) => {
return {
restrict: 'E',
replace: true,
scope: {
chrome: '=',
isVisible: '=',
logoBrand: '=',
smallLogoBrand: '=',
appTitle: '=',
},
template: globalNavTemplate,
link: scope => {
// App switcher functionality.
function updateGlobalNav() {
const isOpen = globalNavState.isOpen();
scope.isGlobalNavOpen = isOpen;
scope.globalNavToggleButton = {
classes: isOpen ? 'kbnGlobalNavLink--close' : undefined,
title: isOpen
? i18n('common.ui.chrome.globalNav.navToggleButtonCollapseTitle', {
defaultMessage: 'Collapse',
})
: i18n('common.ui.chrome.globalNav.navToggleButtonExpandTitle', {
defaultMessage: 'Expand',
}),
tooltipContent: isOpen
? i18n('common.ui.chrome.globalNav.navToggleButtonCollapseTooltip', {
defaultMessage: 'Collapse side bar',
})
: i18n('common.ui.chrome.globalNav.navToggleButtonExpandTooltip', {
defaultMessage: 'Expand side bar',
}),
};
// Notify visualizations, e.g. the dashboard, that they should re-render.
scope.$root.$broadcast('globalNav:update');
}
updateGlobalNav();
scope.$root.$on('globalNavState:change', () => {
updateGlobalNav();
});
scope.getHref = path => {
return chrome.addBasePath(path);
};
scope.toggleGlobalNav = event => {
event.preventDefault();
globalNavState.setOpen(!globalNavState.isOpen());
};
scope.isHomeActive = () => {
return window.location.hash.indexOf('#/home') === 0;
};
},
};
});

View file

@ -1,209 +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 sinon from 'sinon';
import ngMock from 'ng_mock';
import expect from 'expect.js';
import '../global_nav_link';
describe('globalNavLink directive', () => {
let scope;
let $compile;
beforeEach(ngMock.module('kibana'));
beforeEach(() => {
ngMock.inject(($rootScope, _$compile_) => {
scope = $rootScope.$new();
$compile = _$compile_;
});
});
function create(attrs) {
const template = `
<global-nav-link
is-active="isActive"
is-disabled="isDisabled"
tooltip-content="tooltipContent"
on-click="onClick()"
url="href"
kbn-route="kbnRoute"
icon="icon"
label="title"
/>
`;
const element = $compile(template)(scope);
scope.$apply(() => {
Object.assign(scope, attrs);
});
return element;
}
describe('interface', () => {
describe('isActive attribute', () => {
it(`doesn't apply the active class when false`, () => {
const element = create({
isActive: false,
});
expect(element.hasClass('active')).to.be(false);
});
it('applies the active class when true', () => {
const element = create({
isActive: true,
});
expect(element.hasClass('active')).to.be(true);
});
});
describe('isDisabled attribute', () => {
it(`doesn't apply the kbnGlobalNavLink-isDisabled class when false`, () => {
const element = create({
isDisabled: false,
});
expect(element.hasClass('kbnGlobalNavLink-isDisabled')).to.be(false);
});
it('applies the kbnGlobalNavLink-isDisabled class when true', () => {
const element = create({
isDisabled: true,
});
expect(element.hasClass('kbnGlobalNavLink-isDisabled')).to.be(true);
});
});
describe('tooltipContent attribute', () => {
it('is applied to the tooltip directive', () => {
const attrs = {
tooltipContent: 'hello i am a tooltip',
};
const element = create(attrs);
expect(element.attr('tooltip')).to.be(attrs.tooltipContent);
});
});
describe('onClick attribute', () => {
it('is called when the link is clicked', () => {
const attrs = {
onClick: sinon.spy(),
};
const element = create(attrs);
element.find('[data-test-subj=appLink]').click();
sinon.assert.called(attrs.onClick);
});
});
describe('href attribute', () => {
it('is applied to the link', () => {
const attrs = {
href: 'link to a website',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).to.be(attrs.href);
});
});
describe('kbnRoute attribute', () => {
it(`is applied to the link when href isn't defined`, () => {
const attrs = {
kbnRoute: '#test',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).to.be(attrs.kbnRoute);
});
it(`isn't applied to the link when href is defined`, () => {
const attrs = {
href: 'link to a website',
kbnRoute: '#test',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).not.to.be(attrs.kbnRoute);
});
});
describe('icon attribute', () => {
describe('when present', () => {
it('displays the img element', () => {
const attrs = {
icon: 'icon url',
};
const element = create(attrs);
const img = element.find('img');
expect(img.length).to.be(1);
});
it('hides the placeholder', () => {
const attrs = {
icon: 'icon url',
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
expect(placeholder.length).to.be(0);
});
it(`is set as the img src`, () => {
const attrs = {
icon: 'icon url',
};
const element = create(attrs);
const img = element.find('img');
expect(img.attr('src')).to.contain(encodeURI(attrs.icon));
});
});
describe('when not present', () => {
it('hides the img element', () => {
const attrs = {
icon: undefined,
};
const element = create(attrs);
const img = element.find('img');
expect(img.length).to.be(0);
});
it('displays the placeholder', () => {
const attrs = {
icon: undefined,
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
expect(placeholder.length).to.be(1);
});
it(`uses the title's first letter as the placeholder`, () => {
const attrs = {
icon: undefined,
title: 'Xyz',
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
expect(placeholder.text()).to.contain(attrs.title[0]);
});
});
});
});
});

View file

@ -1,105 +0,0 @@
.kbnGlobalNavLink {
&:hover,
&.active,
&:focus {
box-shadow: none !important;
background-color: darken($euiColorPrimary, 2%);
}
}
.kbnGlobalNavLink {
position: relative;
width: $kbnGlobalNavClosedWidth;
height: $kbnGlobalNavAppIconHeight;
line-height: $euiSizeL;
&.kbnGlobalNavLink-isDisabled {
opacity: 0.5;
.kbnGlobalNavLink__anchor {
cursor: default;
}
}
&.active {
.kbnGlobalNavLink__anchor {
color: $euiColorEmptyShade;
text-decoration: none;
}
}
}
.kbnGlobalNav-isOpen {
.kbnGlobalNavLink {
width: $kbnGlobalNavOpenWidth;
}
}
.kbnGlobalNavLink__anchor {
display: block;
height: 100%;
color: $euiColorEmptyShade;
width: 100%;
line-height: inherit;
}
.kbnGlobalNavLink__icon {
display: inline-block;
width: $kbnGlobalNavClosedWidth;
height: $kbnGlobalNavAppIconHeight;
line-height: $kbnGlobalNavAppIconHeight - 2px;
text-align: center;
}
/**
* This image is used to display the icon.
*/
.kbnGlobalNavLink__iconImage {
height: 18px;
margin-top: $euiSizeS;
}
.kbnGlobalNavLink__euiIcon {
svg {
@include size($euiSize + $euiSizeXS);
}
.euiIcon--app .euiIcon__fillSecondary {
fill: $euiColorGhost;
}
}
/**
* This placeholder text gets shown if there is no specified icon.
*/
.kbnGlobalNavLink__iconPlaceholder {
line-height: $kbnGlobalNavAppIconHeight;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}
.kbnGlobalNavLink__title {
@include euiTextTruncate;
display: none;
width: $kbnGlobalNavOpenWidth - $kbnGlobalNavClosedWidth - 3px;
float: right;
font-size: 0.9em;
text-align: left;
padding-left: 3px;
padding-right: 3px;
line-height: $kbnGlobalNavAppIconHeight;
.kbnGlobalNav-isOpen & {
display: inline-block;
}
}
.kbnGlobalNavLink--close {
/**
* 1. Translation accounts for the icon image being slightly off-center.
*/
.kbnGlobalNavLink__icon {
transform: translateX(1px) scaleX(-1); /* 1 */
}
}

View file

@ -1 +0,0 @@
@import './global_nav_link';

View file

@ -1,38 +0,0 @@
<div
class="kbnGlobalNavLink {{classes}}"
ng-class="{ active: isActive, 'kbnGlobalNavLink-isDisabled': isDisabled }"
tooltip="{{ tooltipContent }}"
tooltip-placement="right"
tooltip-popup-delay="0"
tooltip-append-to-body="1"
>
<a
class="kbnGlobalNavLink__anchor"
href="{{ getHref() }}"
ng-click="onClick({ $event: $event })"
data-test-subj="appLink"
aria-label="{{::label}}"
>
<div class="kbnGlobalNavLink__icon">
<icon ng-if="euiIconType" type="'{{ euiIconType }}'" size="'l'" color="'ghost'" class="kbnGlobalNavLink__euiIcon"></icon>
<img
ng-if="!euiIconType && icon"
class="kbnGlobalNavLink__iconImage"
kbn-src="{{ '/' + icon }}"
aria-hidden="true"
/>
<span
ng-if="!icon"
class="kbnGlobalNavLink__iconPlaceholder"
data-test-subj="appLinkIconPlaceholder"
>
{{ label[0] }}
</span>
</div>
<div class="kbnGlobalNavLink__title">{{ label }}</div>
</a>
</div>

View file

@ -1,54 +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 globalNavLinkTemplate from './global_nav_link.html';
import { uiModules } from '../../../../modules';
const module = uiModules.get('kibana');
module.directive('globalNavLink', chrome => {
return {
restrict: 'E',
replace: true,
scope: {
isActive: '=',
isDisabled: '=',
tooltipContent: '=',
onClick: '&',
url: '=',
kbnRoute: '=',
icon: '=',
euiIconType: '=',
label: '=',
},
template: globalNavLinkTemplate,
link: scope => {
scope.getHref = () => {
if (scope.url) {
return scope.url;
}
if (scope.kbnRoute) {
return chrome.addBasePath(scope.kbnRoute);
}
};
}
};
});

View file

@ -1,20 +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 './global_nav_link';

View file

@ -1,20 +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 './global_nav';

View file

@ -17,8 +17,6 @@
* under the License.
*/
import './global_nav';
import './header_global_nav';
import { kbnChromeProvider } from './kbn_chrome';

View file

@ -1,18 +1,7 @@
<div class="content" chrome-context data-test-subj="kibanaChrome">
<kbn-loading-indicator></kbn-loading-indicator>
<global-nav
ng-if="!k7design"
chrome="chrome"
data-test-subj="globalNav"
is-visible="chrome.getVisible()"
logo-brand="chrome.getBrand('logo')"
small-logo-brand="chrome.getBrand('smallLogo')"
app-title="chrome.getAppTitle()"
></global-nav>
<header-global-nav
ng-if="k7design"
class="header-global-wrapper"
is-visible="chrome.getVisible()"
app-title="chrome.getAppTitle()"

View file

@ -57,9 +57,7 @@ export function kbnChromeProvider(chrome, internals) {
},
controllerAs: 'chrome',
controller($scope, $rootScope, Private, config) {
config.watch('k7design', (val) => $scope.k7design = val);
controller($scope, $rootScope, Private) {
const getUnhashableStates = Private(getUnhashableStatesProvider);
const subUrlRouteFilter = Private(SubUrlRouteFilterProvider);

View file

@ -1,37 +0,0 @@
<div
class="kuiLocalBreadcrumbs"
data-test-subj="breadcrumbs"
role="heading"
aria-level="1"
ng-if="showPluginBreadcrumbs"
>
<div
class="kuiLocalBreadcrumb"
ng-if="useLinks"
ng-repeat="breadcrumb in breadcrumbs"
>
<a
class="kuiLocalBreadcrumb__link"
href="{{ breadcrumb.href }}"
data-test-subj="lnkBreadcrumb{{$index}}"
>
{{ breadcrumb.display }}
</a>
</div>
<div
class="kuiLocalBreadcrumb"
ng-if="!useLinks"
ng-repeat="breadcrumb in breadcrumbs"
>
{{ breadcrumb.display }}
</div>
<div
class="kuiLocalBreadcrumb"
ng-if="pageTitle"
data-test-subj="breadcrumbPageTitle"
>
{{ pageTitle }}
</div>
</div>

View file

@ -1,83 +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 breadCrumbsTemplate from './bread_crumbs.html';
import { uiModules } from '../../modules';
import uiRouter from '../../routes';
const module = uiModules.get('kibana');
module.directive('breadCrumbs', function () {
return {
restrict: 'E',
scope: {
omitCurrentPage: '=',
/**
* Pages to omit from the breadcrumbs. Should be lower-case.
* @type {Array}
*/
omitPages: '=',
/**
* Optional title to append at the end of the breadcrumbs. Note that this can't just be
* 'title', because that will be interpreted by browsers as an actual 'title' HTML attribute.
* @type {String}
*/
pageTitle: '=',
/**
* If true, makes each breadcrumb a clickable link.
* @type {String}
*/
useLinks: '='
},
template: breadCrumbsTemplate,
controller: function ($scope, config) {
config.watch('k7design', (val) => $scope.showPluginBreadcrumbs = !val);
function omitPagesFilter(crumb) {
return (
!$scope.omitPages ||
!$scope.omitPages.includes(crumb.id)
);
}
function omitCurrentPageFilter(crumb) {
return !($scope.omitCurrentPage && crumb.current);
}
$scope.$watchMulti([
'[]omitPages',
'omitCurrentPage'
], function getBreadcrumbs() {
$scope.breadcrumbs = (
uiRouter
.getBreadcrumbs()
.filter(omitPagesFilter)
.filter(omitCurrentPageFilter)
);
const newBreadcrumbs = $scope.breadcrumbs
.map(b => ({ text: b.display, href: b.href }));
if ($scope.pageTitle) {
newBreadcrumbs.push({ text: $scope.pageTitle });
}
});
}
};
});

View file

@ -1,20 +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 './bread_crumbs';

View file

@ -62,8 +62,6 @@ import template from './kbn_top_nav.html';
import { KbnTopNavControllerProvider } from './kbn_top_nav_controller';
import { NavBarExtensionsRegistryProvider } from '../registry/navbar_extensions';
import './bread_crumbs/bread_crumbs';
const module = uiModules.get('kibana');
module.directive('kbnTopNav', function (Private) {

View file

@ -31,13 +31,10 @@ export interface FrameworkAdapter {
visable?: boolean;
order?: number;
}): void;
setUISettings(key: string, value: any): void;
getUISetting(key: 'k7design'): boolean;
}
export const RuntimeFrameworkInfo = t.type({
basePath: t.string,
k7Design: t.boolean,
license: t.type({
type: t.union(LICENSES.map(s => t.literal(s))),
expired: t.boolean,

View file

@ -37,7 +37,6 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
private xpackInfo: FrameworkInfo | null = null;
private adapterService: KibanaAdapterServiceProvider;
private shieldUser: FrameworkUser | null = null;
private settingSubscription: any;
constructor(
private readonly PLUGIN_ID: string,
private readonly management: ManagementAPI,
@ -45,24 +44,9 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
private readonly getBasePath: () => string,
private readonly onKibanaReady: () => Promise<IInjector>,
private readonly XPackInfoProvider: unknown,
private readonly uiSettings: any,
public readonly version: string
) {
this.adapterService = new KibanaAdapterServiceProvider();
this.settingSubscription = uiSettings.getUpdate$().subscribe({
next: ({ key, newValue }: { key: string; newValue: boolean }) => {
if (key === 'k7design' && this.xpackInfo) {
this.xpackInfo.k7Design = newValue;
}
},
});
}
// We dont really want to have this, but it's needed to conditionaly render for k7 due to
// when that data is needed.
public getUISetting(key: 'k7design'): boolean {
return this.uiSettings.get(key);
}
public setUISettings = (key: string, value: any) => {
@ -86,7 +70,6 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
try {
xpackInfoUnpacked = {
basePath: this.getBasePath(),
k7Design: this.uiSettings.get('k7design'),
license: {
type: xpackInfo ? xpackInfo.getLicense().type : 'oss',
expired: xpackInfo ? !xpackInfo.getLicense().isActive : false,
@ -220,7 +203,6 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
if (elem) {
ReactDOM.unmountComponentAtNode(elem);
elem.remove();
this.settingSubscription.unsubscribe();
}
}
});
@ -233,7 +215,6 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
if (elem) {
ReactDOM.unmountComponentAtNode(elem);
elem.remove();
this.settingSubscription.unsubscribe();
}
});
}

View file

@ -53,7 +53,6 @@ export function compose(): FrontendLibs {
chrome.getBasePath,
onKibanaReady,
XPackInfoProvider,
chrome.getUiSettingsClient(),
chrome.getKibanaVersion()
)
);

View file

@ -56,7 +56,6 @@ export function compose(
() => '',
onKibanaReady,
null,
null,
'7.0.0'
)
);

View file

@ -13,8 +13,6 @@ export class FrameworkLib {
public renderUIAtPath = this.adapter.renderUIAtPath.bind(this.adapter);
public registerManagementSection = this.adapter.registerManagementSection.bind(this.adapter);
public registerManagementUI = this.adapter.registerManagementUI.bind(this.adapter);
public setUISettings = this.adapter.setUISettings.bind(this.adapter);
public getUISetting = this.adapter.getUISetting.bind(this.adapter);
constructor(private readonly adapter: FrameworkAdapter) {}

View file

@ -140,9 +140,6 @@ uiRoutes
//======== Controller for basic UI ==================
app.controller('graphuiPlugin', function ($scope, $route, $http, kbnUrl, Private, Promise, confirmModal, kbnBaseUrl, i18n, config) {
config.bindToScope($scope, 'k7design');
function handleSuccess(data) {
return checkLicense(Private, Promise, kbnBaseUrl)
.then(() => data);

View file

@ -3,18 +3,6 @@
<kbn-top-nav name="workspacesTopNav" config="topNavMenu">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Title. -->
<div data-transclude-slot="topLeftCorner">
<div class="kuiLocalTitle" ng-if="!k7design">
<strong ng-if="savedWorkspace.lastSavedTitle">{{ savedWorkspace.lastSavedTitle }}</strong>
<strong
ng-if="!savedWorkspace.lastSavedTitle"
i18n-id="xpack.graph.topNavMenu.defaultNewWorkspaceTitle"
i18n-default-message="New Graph Workspace"
></strong>
</div>
</div>
<div data-transclude-slot="bottomRow" class="gphGraph__flexGroup">
<!-- Select index pattern. -->
<select class="form-control gphIndexSelect" name="mySelect" ng-change="uiSelectIndex()" ng-class="{'gphIndexSelect-unselected':selectedIndex === null}"

View file

@ -1,60 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiBetaBadge, EuiHeaderSection } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import styled from 'styled-components';
interface BetaBadgeHeaderSectionProps {
tooltipContent?: React.ReactNode;
}
export const BetaBadgeHeaderSection: React.SFC<BetaBadgeHeaderSectionProps> = ({
tooltipContent = (
<FormattedMessage
id="xpack.infra.betaBadgeHeaderSection.betaBadgeHeaderSectionDefaultTooltip"
defaultMessage="Please help us improve by reporting issues or bugs in the Kibana repo."
/>
),
}) => (
<VerticallyCenteredHeaderSection side="right">
<EuiBetaBadge
label={
<FormattedMessage id="xpack.infra.betaBadgeHeaderSection.betaLabel" defaultMessage="Beta" />
}
tooltipContent={tooltipContent}
/>
</VerticallyCenteredHeaderSection>
);
export const InfrastructureBetaBadgeHeaderSection = () => (
<BetaBadgeHeaderSection
tooltipContent={
<FormattedMessage
id="xpack.infra.betaBadgeHeaderSection.infrastructureUiIsStillInBetaTooltip"
defaultMessage="The Infrastructure UI is still in beta. Please help us improve by reporting issues or bugs in the Kibana repo."
/>
}
/>
);
export const LogsBetaBadgeHeaderSection = () => (
<BetaBadgeHeaderSection
tooltipContent={
<FormattedMessage
id="xpack.infra.betaBadgeHeaderSection.logsUiIsStillInBetaTooltip"
defaultMessage="The Logs UI is still in beta. Please help us improve by reporting issues or bugs in the Kibana repo."
/>
}
/>
);
const VerticallyCenteredHeaderSection = styled(EuiHeaderSection)`
padding-left: ${props => props.theme.eui.euiSizeS};
padding-right: ${props => props.theme.eui.euiSizeS};
align-items: center;
`;

View file

@ -9,23 +9,15 @@ import React from 'react';
import { Breadcrumb } from 'ui/chrome/api/breadcrumbs';
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
import { ExternalHeader } from './external_header';
import { LegacyHeader } from './legacy_header';
interface HeaderProps {
breadcrumbs?: Breadcrumb[];
appendSections?: React.ReactNode;
}
export const Header = ({ appendSections, breadcrumbs = [] }: HeaderProps) => {
return (
<WithKibanaChrome>
{({ setBreadcrumbs, uiSettings: { k7Design } }) =>
k7Design ? (
<ExternalHeader breadcrumbs={breadcrumbs} setBreadcrumbs={setBreadcrumbs} />
) : (
<LegacyHeader appendSections={appendSections} breadcrumbs={breadcrumbs} />
)
}
</WithKibanaChrome>
);
};
export const Header = ({ breadcrumbs = [] }: HeaderProps) => (
<WithKibanaChrome>
{({ setBreadcrumbs }) => (
<ExternalHeader breadcrumbs={breadcrumbs} setBreadcrumbs={setBreadcrumbs} />
)}
</WithKibanaChrome>
);

View file

@ -1,32 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiHeader, EuiHeaderBreadcrumbs, EuiHeaderSection } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { Breadcrumb } from 'ui/chrome/api/breadcrumbs';
interface LegacyHeaderProps {
breadcrumbs?: Breadcrumb[];
appendSections?: React.ReactNode;
}
export const LegacyHeader: React.SFC<LegacyHeaderProps> = ({
appendSections,
breadcrumbs = [],
}) => (
<HeaderWrapper>
<EuiHeaderSection grow>
<EuiHeaderBreadcrumbs breadcrumbs={breadcrumbs} />
</EuiHeaderSection>
{appendSections}
</HeaderWrapper>
);
const HeaderWrapper = styled(EuiHeader)`
height: 29px;
`;

View file

@ -5,24 +5,11 @@
*/
import React from 'react';
import { Observable, Subscription } from 'rxjs';
import chrome from 'ui/chrome';
import { Breadcrumb } from 'ui/chrome/api/breadcrumbs';
import { RendererFunction } from '../utils/typed_react';
// replace with import from platform core when available
interface UiSettings {
k7Design: boolean;
}
// replace with import from platform core when available
type UiSettings$ = Observable<{
key: string;
oldValue: any;
newValue: any;
}>;
interface WithKibanaChromeProps {
children: RendererFunction<
{
@ -33,48 +20,16 @@ interface WithKibanaChromeProps {
interface WithKibanaChromeState {
basePath: string;
uiSettings: UiSettings;
}
const uiSettingsKeys = ['k7Design'];
export class WithKibanaChrome extends React.Component<
WithKibanaChromeProps,
WithKibanaChromeState
> {
public state: WithKibanaChromeState = {
uiSettings: {
k7Design: chrome.getUiSettingsClient().get('k7design'),
},
basePath: chrome.getBasePath(),
};
private uiSettingsSubscription?: Subscription;
public componentDidMount() {
this.uiSettingsSubscription = (chrome
.getUiSettingsClient()
.getUpdate$() as UiSettings$).subscribe({
next: ({ key, newValue }) => {
if (uiSettingsKeys.includes(key)) {
this.setState(state => ({
...state,
uiSettings: {
...state.uiSettings,
[key]: newValue,
},
}));
}
},
});
}
public componentWillUnmount() {
if (this.uiSettingsSubscription) {
this.uiSettingsSubscription.unsubscribe();
}
}
public render() {
return this.props.children({
...this.state,

View file

@ -15,7 +15,6 @@ import { NoIndices } from '../../components/empty_states/no_indices';
import { Header } from '../../components/header';
import { ColumnarPage } from '../../components/page';
import { InfraHeaderFeedbackLink } from '../../components/header_feedback_link';
import { SourceConfigurationFlyout } from '../../components/source_configuration';
import { WithSourceConfigurationFlyoutState } from '../../components/source_configuration/source_configuration_flyout_state';
import { WithWaffleFilterUrlState } from '../../containers/waffle/with_waffle_filters';
@ -38,9 +37,6 @@ export const HomePage = injectI18n(
return (
<ColumnarPage>
<Header
appendSections={
<InfraHeaderFeedbackLink url="https://discuss.elastic.co/c/infrastructure" />
}
breadcrumbs={[
{
href: '#/',

View file

@ -16,7 +16,6 @@ import { Header } from '../../components/header';
import { LogFlyout } from '../../components/logging/log_flyout';
import { ColumnarPage } from '../../components/page';
import { InfraHeaderFeedbackLink } from '../../components/header_feedback_link';
import { SourceConfigurationFlyout } from '../../components/source_configuration';
import { WithSourceConfigurationFlyoutState } from '../../components/source_configuration/source_configuration_flyout_state';
import { WithLogFilter, WithLogFilterUrlState } from '../../containers/logs/with_log_filter';
@ -43,7 +42,6 @@ export const LogsPage = injectI18n(
return (
<ColumnarPage>
<Header
appendSections={<InfraHeaderFeedbackLink url="https://discuss.elastic.co/c/logs" />}
breadcrumbs={[
{
text: intl.formatMessage({

View file

@ -18,7 +18,6 @@ import React from 'react';
import styled, { withTheme } from 'styled-components';
import { AutoSizer } from '../../components/auto_sizer';
import { InfrastructureBetaBadgeHeaderSection } from '../../components/beta_badge_header_section';
import { Header } from '../../components/header';
import { Metrics } from '../../components/metrics';
import { MetricsSideNav } from '../../components/metrics/side_nav';
@ -113,10 +112,7 @@ export const MetricDetail = withTheme(
];
return (
<ColumnarPage>
<Header
appendSections={<InfrastructureBetaBadgeHeaderSection />}
breadcrumbs={breadcrumbs}
/>
<Header breadcrumbs={breadcrumbs} />
<WithMetricsTimeUrlState />
<DetailPageContent>
<WithMetrics

View file

@ -3,23 +3,6 @@
<div>
<kbn-top-nav name="map" config="topNavMenu">
<div data-transclude-slots>
<!-- Title. -->
<div data-transclude-slot="topLeftCorner">
<div
class="kuiLocalBreadcrumbs"
data-test-subj="breadcrumbs"
role="heading"
aria-level="1"
ng-if="showPluginBreadcrumbs">
<div class="kuiLocalBreadcrumb">
<a class="kuiLocalBreadcrumb__link" href="#">Map</a>
</div>
<div class="kuiLocalBreadcrumb">
{{ getMapTitle() }}
</div>
</div>
</div>
<!-- Search. -->
<div ng-show="chrome.getVisible()" class="fullWidth" data-transclude-slot="bottomRow">
<query-bar

View file

@ -198,16 +198,11 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
}
});
$scope.getMapTitle = function () {
return $scope.map.title;
};
// k7design breadcrumbs
// TODO subscribe to store change and change when store updates title
chrome.breadcrumbs.set([
{ text: 'Maps', href: '#' },
{ text: $scope.getMapTitle() }
{ text: $scope.map.title }
]);
config.watch('k7design', (val) => $scope.showPluginBreadcrumbs = !val);
async function doSave(saveOptions) {
savedMap.syncWithStore(getStore().getState());

View file

@ -1,16 +1,5 @@
<kbn-top-nav name="dashboard" config="topNavMenu">
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<div data-transclude-slot="topLeftCorner">
<div
ng-if="showPluginBreadcrumbs"
class="kuiLocalBreadcrumbs">
<div ng-repeat="crumb in breadcrumbs" class="kuiLocalBreadcrumb">
<a ng-if="crumb.url" kbn-href="{{ crumb.url }}" class="kuiLocalBreadcrumb__link">{{ crumb.label }}</a>
<span ng-if="!crumb.url" class="kuiLocalBreadcrumb__link">{{ crumb.label }}</span>
</div>
</div>
</div>
<div data-transclude-slots>
<!-- Tabs -->
<div data-transclude-slot="bottomRow">
<div ng-if="showTabs" class="kuiLocalTabs" role="tablist">

View file

@ -5,16 +5,13 @@
*/
import $ from 'jquery';
import template from './nav_menu.html';
import uiRouter from 'ui/routes';
import chrome from 'ui/chrome';
import { isFullLicense } from '../../license/check_license';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlNavMenu', function (config, i18n) {
module.directive('mlNavMenu', function () {
return {
restrict: 'E',
transclude: true,
@ -38,109 +35,6 @@ module.directive('mlNavMenu', function (config, i18n) {
};
scope.disableLinks = (isFullLicense() === false);
// TODO - once the k7design flag is disabled, this should all be removed.
const isK7Design = chrome.getUiSettingsClient().get('k7design', false);
if (isK7Design === false) {
// Breadcrumbs
const crumbNames = {
jobs: {
label: i18n('xpack.ml.navMenu.breadcrumbs.jobManagementLabel', { defaultMessage: 'Job Management' }),
url: '#/jobs'
},
new_job: {
label: i18n('xpack.ml.navMenu.breadcrumbs.createNewJobLabel', { defaultMessage: 'Create New Job' }),
url: '#/jobs/new_job'
},
single_metric: {
label: i18n('xpack.ml.navMenu.breadcrumbs.singleMetricJobLabel', { defaultMessage: 'Single Metric Job' }),
url: ''
},
multi_metric: {
label: i18n('xpack.ml.navMenu.breadcrumbs.multiMetricJobLabel', { defaultMessage: 'Multi Metric job' }),
url: ''
},
population: {
label: i18n('xpack.ml.navMenu.breadcrumbs.populationJobLabel', { defaultMessage: 'Population job' }),
url: ''
},
advanced: {
label: i18n('xpack.ml.navMenu.breadcrumbs.advancedJobConfigurationLabel', { defaultMessage: 'Advanced Job Configuration' }),
url: ''
},
datavisualizer: {
label: i18n('xpack.ml.navMenu.breadcrumbs.dataVisualizerLabel', { defaultMessage: 'Data Visualizer' }),
url: ''
},
filedatavisualizer: {
label: i18n('xpack.ml.navMenu.breadcrumbs.fileDataVisualizerLabel', { defaultMessage: 'File Data Visualizer (Experimental)' }),
url: ''
},
explorer: {
label: i18n('xpack.ml.navMenu.breadcrumbs.anomalyExplorerLabel', { defaultMessage: 'Anomaly Explorer' }),
url: '#/explorer'
},
timeseriesexplorer: {
label: i18n('xpack.ml.navMenu.breadcrumbs.singleMetricViewerLabel', { defaultMessage: 'Single Metric Viewer' }),
url: '#/timeseriesexplorer'
},
settings: {
label: i18n('xpack.ml.navMenu.breadcrumbs.settingsLabel', { defaultMessage: 'Settings' }),
url: '#/settings'
},
calendars_list: {
label: i18n('xpack.ml.navMenu.breadcrumbs.calendarManagementLabel', { defaultMessage: 'Calendar Management' }),
url: '#/settings/calendars_list'
},
new_calendar: {
label: i18n('xpack.ml.navMenu.breadcrumbs.newCalendarLabel', { defaultMessage: 'New Calendar' }),
url: '#/settings/calendars_list/new_calendar'
},
edit_calendar: {
label: i18n('xpack.ml.navMenu.breadcrumbs.editCalendarLabel', { defaultMessage: 'Edit Calendar' }),
url: '#/settings/calendars_list/edit_calendar'
},
filter_lists: {
label: i18n('xpack.ml.navMenu.breadcrumbs.filterListsLabel', { defaultMessage: 'Filter Lists' }),
url: '#/settings/filter_lists'
},
new_filter_list: {
label: i18n('xpack.ml.navMenu.breadcrumbs.newFilterListLabel', { defaultMessage: 'New Filter List' }),
url: '#/settings/filter_lists/new'
},
edit_filter_list: {
label: i18n('xpack.ml.navMenu.breadcrumbs.editFilterListLabel', { defaultMessage: 'Edit Filter List' }),
url: '#/settings/filter_lists/edit'
},
};
const breadcrumbs = [{
label: i18n('xpack.ml.navMenu.breadcrumbs.machineLearningLabel', { defaultMessage: 'Machine Learning' }),
url: '#/'
}];
// get crumbs from url
const crumbs = uiRouter.getBreadcrumbs();
if (crumbs.length > 1) {
crumbs.forEach((crumb) => {
breadcrumbs.push(crumbNames[crumb.id]);
});
}
scope.breadcrumbs = breadcrumbs.filter(Boolean);
config.watch('k7design', (val) => scope.showPluginBreadcrumbs = !val);
chrome.breadcrumbs.set(scope.breadcrumbs.map(b => ({ text: b.label, href: b.url })));
// when the page loads, focus on the first breadcrumb
el.ready(() => {
const $crumbs = $('.kuiLocalBreadcrumbs a');
if ($crumbs.length) {
$crumbs[0].focus();
}
});
}
}
};
});

View file

@ -2,32 +2,6 @@
<kbn-top-nav name="{{ monitoringMain.name }}-nav">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<!-- NOTE: The KBN breadCrumbs directive does not work for Monitoring usecase.
Breadcrumbs can't be automatically derived because the directive doesn't
automatically know to show the Clusters breadcrumb. We recreate the
structure and styles manually -->
<div data-transclude-slot="topLeftCorner">
<div
ng-if="showPluginBreadcrumbs"
class="kuiLocalBreadcrumbs">
<div ng-repeat="crumb in monitoringMain.breadcrumbs" class="kuiLocalBreadcrumb">
<a
ng-if="crumb.url"
kbn-href="{{ crumb.url }}"
class="kuiLocalBreadcrumb__link"
data-test-subj="{{ crumb.testSubj }}"
>
{{ crumb.label }}
</a>
<span ng-if="!crumb.url">
{{ crumb.label }}
</span>
</div>
</div>
</div>
<!-- Tabs -->
<div data-transclude-slot="bottomRow">
<div ng-if="monitoringMain.inElasticsearch" class="kuiLocalTabs" role="navigation">

View file

@ -71,7 +71,7 @@ export class MonitoringMainController {
}
const uiModule = uiModules.get('plugins/monitoring/directives', []);
uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, config, $injector) => {
uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, $injector) => {
return {
restrict: 'E',
transclude: true,
@ -80,8 +80,6 @@ uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, config, $inj
controllerAs: 'monitoringMain',
bindToController: true,
link(scope, _element, attributes, controller) {
config.watch('k7design', (val) => scope.showPluginBreadcrumbs = !val);
if (!scope.cluster) {
const $route = $injector.get('$route');
const globalState = $injector.get('globalState');

View file

@ -1,25 +1,12 @@
<kbn-top-nav class="navbar navbar-default navbar-static-top" name="account-nav" ng-if="!k7design">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Title. -->
<div
data-transclude-slot="topLeftCorner"
class="kuiLocalTitle"
>
{{user.full_name || user.username}}
</div>
</div>
</kbn-top-nav>
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem">
<!-- Subheader -->
<div class="kuiBar kuiVerticalRhythm">
<!-- Title -->
<div class="kuiBarSection">
<h1
<h1
class="kuiTitle"
i18n-id="xpack.security.account.accountSettingsTitle"
i18n-default-message="Account Settings"
i18n-default-message="Account Settings"
></h1>
</div>
@ -44,7 +31,7 @@
<label
class="kuiFormLabel"
i18n-id="xpack.security.account.emailLabel"
i18n-default-message="Email"
i18n-default-message="Email"
></label>
<div class="euiText">
<p ng-bind="::accountController.getEmail()" data-test-subj=emailIdField></p>

View file

@ -30,7 +30,6 @@ routes.when('/account', {
controllerAs: 'accountController',
controller($scope, $route, Notifier, config, i18n) {
$scope.user = $route.current.locals.user;
config.bindToScope($scope, 'k7design');
const notifier = new Notifier();

View file

@ -47,15 +47,12 @@ export class UMKibanaFrameworkAdapter implements UMFrameworkAdapter {
// @ts-ignore angular
controller: ($scope, $route, $http, config) => {
const graphQLClient = createGraphQLClient(this.uriPath, this.xsrfHeader);
config.bindToScope($scope, 'k7design');
$scope.$$postDigest(() => {
const elem = document.getElementById('uptimeReactRoot');
let kibanaBreadcrumbs: UMBreadcrumb[] = [];
if ($scope.k7design) {
chrome.breadcrumbs.get$().subscribe((breadcrumbs: UMBreadcrumb[]) => {
kibanaBreadcrumbs = breadcrumbs;
});
}
chrome.breadcrumbs.get$().subscribe((breadcrumbs: UMBreadcrumb[]) => {
kibanaBreadcrumbs = breadcrumbs;
});
const basePath = chrome.getBasePath();
const routerBasename = basePath.endsWith('/')
? `${basePath}/${PLUGIN.ROUTER_BASE_NAME}`
@ -71,7 +68,6 @@ export class UMKibanaFrameworkAdapter implements UMFrameworkAdapter {
ReactDOM.render(
renderComponent({
darkMode,
isUsingK7Design: $scope.k7design,
updateBreadcrumbs: chrome.breadcrumbs.set,
kibanaBreadcrumbs,
routerBasename,

View file

@ -6,7 +6,6 @@
import {
EuiHeader,
EuiHeaderBreadcrumbs,
// @ts-ignore missing typings for EuiHeaderLink
EuiHeaderLink,
// @ts-ignore missing typings for EuiHeaderLinks
@ -62,7 +61,6 @@ export interface UptimeAppProps {
initialDateRangeEnd: string;
initialAutorefreshInterval: number;
initialAutorefreshIsPaused: boolean;
isUsingK7Design: boolean;
kibanaBreadcrumbs: UMBreadcrumb[];
routerBasename: string;
updateBreadcrumbs: UMUpdateBreadcrumbs;
@ -100,20 +98,11 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
initialAutorefreshInterval: autorefreshInterval,
initialDateRangeStart: dateRangeStart,
initialDateRangeEnd: dateRangeEnd,
isUsingK7Design,
kibanaBreadcrumbs,
updateBreadcrumbs,
} = props;
let initialBreadcrumbs: UMBreadcrumb[];
if (isUsingK7Design) {
this.setBreadcrumbs = updateBreadcrumbs;
initialBreadcrumbs = kibanaBreadcrumbs;
} else {
this.setBreadcrumbs = (breadcrumbs: UMBreadcrumb[]) => this.setState({ breadcrumbs });
initialBreadcrumbs = [overviewBreadcrumb];
}
this.setBreadcrumbs = updateBreadcrumbs;
let colors: UptimeAppColors;
if (darkMode) {
@ -133,7 +122,7 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
this.state = {
autorefreshIsPaused,
autorefreshInterval,
breadcrumbs: initialBreadcrumbs,
breadcrumbs: kibanaBreadcrumbs,
colors,
dateRangeStart,
dateRangeEnd,
@ -145,7 +134,7 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
}
public render() {
const { isUsingK7Design, routerBasename, graphQLClient } = this.props;
const { routerBasename, graphQLClient } = this.props;
return (
<I18nContext>
<Router basename={routerBasename}>
@ -172,13 +161,6 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
/>
</EuiHeaderLogo>
</EuiHeaderSectionItem>
{!isUsingK7Design && (
<EuiHeaderSectionItem>
<div style={{ paddingTop: '20px', paddingRight: '8px' }}>
<EuiHeaderBreadcrumbs breadcrumbs={this.state.breadcrumbs} />
</div>
</EuiHeaderSectionItem>
)}
</EuiHeaderSection>
<EuiHeaderSection side="right">
<EuiHeaderSectionItem border="none">