mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Add landing page with table to Visualize app.
- Update Visualize wizard UI. - kbnTopNav directive supports no-menu-extensions attribute for excluding extensions, so you can hide the menu items entirely.
This commit is contained in:
parent
5778951aa4
commit
5a5eecbfc6
9 changed files with 310 additions and 61 deletions
|
@ -33,7 +33,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Allow searching if there is no linked Saved Searc. -->
|
||||
<!-- Allow searching if there is no linked Saved Search. -->
|
||||
<form
|
||||
ng-if="vis.type.requiresSearch && !$state.linked"
|
||||
name="queryInput"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'plugins/kibana/visualize/styles/main.less';
|
||||
import 'plugins/kibana/visualize/editor/editor';
|
||||
import 'plugins/kibana/visualize/landing/landing';
|
||||
import 'plugins/kibana/visualize/wizard/wizard';
|
||||
import 'plugins/kibana/visualize/editor/add_bucket_agg';
|
||||
import 'plugins/kibana/visualize/editor/agg';
|
||||
|
@ -24,7 +25,7 @@ uiRoutes
|
|||
requireDefaultIndex: true
|
||||
})
|
||||
.when('/visualize', {
|
||||
redirectTo: '/visualize/step/1'
|
||||
redirectTo: '/visualize/landing'
|
||||
});
|
||||
|
||||
// preloading
|
||||
|
|
11
src/core_plugins/kibana/public/visualize/landing/landing.js
Normal file
11
src/core_plugins/kibana/public/visualize/landing/landing.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import routes from 'ui/routes';
|
||||
import modules from 'ui/modules';
|
||||
import visualizeLandingTemplate from './visualize_landing.html';
|
||||
import { VisualizeLandingController } from './visualize_landing';
|
||||
|
||||
routes
|
||||
.when('/visualize/landing', {
|
||||
template: visualizeLandingTemplate,
|
||||
controller: VisualizeLandingController,
|
||||
controllerAs: 'landingController',
|
||||
});
|
|
@ -0,0 +1,147 @@
|
|||
<!-- Local nav. -->
|
||||
<kbn-top-nav name="visualize" no-menu-extensions>
|
||||
<!-- Transcluded elements. -->
|
||||
<div data-transclude-slots>
|
||||
<!-- Title. -->
|
||||
<div
|
||||
data-transclude-slot="topLeftCorner"
|
||||
class="kuiLocalTitle"
|
||||
>
|
||||
Visualize
|
||||
</div>
|
||||
</div>
|
||||
</kbn-top-nav>
|
||||
|
||||
<div class="kuiViewContent kuiViewContent--constrainedWidth">
|
||||
<!-- ControlledTable -->
|
||||
<div class="kuiViewContentItem kuiControlledTable kuiVerticalRhythm">
|
||||
<!-- ToolBar -->
|
||||
<div class="kuiToolBar">
|
||||
<div class="kuiToolBarSearch">
|
||||
<div class="kuiToolBarSearchBox">
|
||||
<div class="kuiToolBarSearchBox__icon kuiIcon fa-search"></div>
|
||||
<input
|
||||
class="kuiToolBarSearchBox__input"
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
aria-label="Filter"
|
||||
ng-model="landingController.filter"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiToolBarSection">
|
||||
<!-- Bulk delete button -->
|
||||
<button
|
||||
class="kuiButton kuiButton--danger kuiButton--iconText"
|
||||
confirm-click="landingController.deleteSelectedItems()"
|
||||
confirmation="Are you sure you want to delete the selected visualizations? This action is irreversible!"
|
||||
aria-label="Delete selected objects"
|
||||
ng-hide="landingController.getSelectedItemsCount() === 0"
|
||||
>
|
||||
<span aria-hidden="true" class="kuiButton__icon kuiIcon fa-trash"></span>
|
||||
Delete
|
||||
</button>
|
||||
|
||||
<!-- Create visualization button -->
|
||||
<a
|
||||
class="kuiButton kuiButton--primary kuiButton--iconText"
|
||||
href="#/visualize/step/1"
|
||||
aria-label="Create new visualization"
|
||||
ng-hide="landingController.getSelectedItemsCount() > 0"
|
||||
>
|
||||
<span aria-hidden="true" class="kuiButton__icon kuiIcon fa-plus"></span>
|
||||
Create visualization
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="kuiToolBarSection">
|
||||
<!-- We need an empty section for the buttons to be positioned consistently. -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NoResults -->
|
||||
<div class="kuiPanel kuiPanel--centered" ng-if="!landingController.items.length">
|
||||
<div class="kuiNoResults">
|
||||
No visualizations matched your search.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<table class="kuiTable" ng-if="landingController.items.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kuiTableHeaderCell kuiTableHeaderCell--checkBox">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="kuiCheckBox"
|
||||
ng-checked="landingController.areAllItemsChecked()"
|
||||
ng-click="landingController.toggleAll()"
|
||||
>
|
||||
</th>
|
||||
<th class="kuiTableHeaderCell">
|
||||
Visualization
|
||||
</th>
|
||||
<th class="kuiTableHeaderCell">
|
||||
Type
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr
|
||||
ng-repeat="item in landingController.items track by item.id | orderBy:'title'"
|
||||
class="kuiTableRow"
|
||||
>
|
||||
<td class="kuiTableRowCell kuiTableRowCell--checkBox">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="kuiCheckBox"
|
||||
ng-click="landingController.toggleItem(item)"
|
||||
ng-checked="landingController.isItemChecked(item)"
|
||||
>
|
||||
</td>
|
||||
|
||||
<td class="kuiTableRowCell">
|
||||
<div class="kuiTableRowCell__liner">
|
||||
<a class="kuiLink" ng-href="{{ item.url }}">
|
||||
{{ item.title }}
|
||||
</a>
|
||||
|
||||
<button
|
||||
class="kuiMicroButton kuiTableRowHoverReveal"
|
||||
ng-click="landingController.edit(item)"
|
||||
aria-label="Edit"
|
||||
tooltip="Edit object"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="kuiIcon fa-code"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="kuiTableRowCell">
|
||||
<div class="kuiTableRowCell__liner">
|
||||
{{ item.type.title }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- ToolBarFooter -->
|
||||
<div class="kuiToolBarFooter">
|
||||
<div class="kuiToolBarFooterSection">
|
||||
<div class="kuiToolBarText" ng-hide="landingController.getSelectedItemsCount() === 0">
|
||||
{{ landingController.getSelectedItemsCount() }} selected
|
||||
</div>
|
||||
</div>
|
||||
<div class="kuiToolBarFooterSection">
|
||||
<!-- We need an empty section for the buttons to be positioned consistently. -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,83 @@
|
|||
import SavedObjectRegistryProvider from 'ui/saved_objects/saved_object_registry';
|
||||
|
||||
export function VisualizeLandingController(
|
||||
$scope,
|
||||
kbnUrl,
|
||||
Notifier,
|
||||
Private
|
||||
) {
|
||||
// TODO: Extract this into an external service.
|
||||
const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName;
|
||||
const visualizationService = services.visualizations;
|
||||
const notify = new Notifier({ location: 'Visualize' });
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
const fetchObjects = () => {
|
||||
visualizationService.find(this.filter)
|
||||
.then(result => {
|
||||
this.items = result.hits;
|
||||
});
|
||||
};
|
||||
|
||||
this.items = [];
|
||||
this.filter = '';
|
||||
|
||||
this.toggleAll = function toggleAll() {
|
||||
if (this.areAllItemsChecked()) {
|
||||
selectedItems = [];
|
||||
} else {
|
||||
selectedItems = this.items.slice(0);
|
||||
}
|
||||
};
|
||||
|
||||
this.toggleItem = function toggleItem(item) {
|
||||
if (this.isItemChecked(item)) {
|
||||
const index = selectedItems.indexOf(item);
|
||||
selectedItems.splice(index, 1);
|
||||
} else {
|
||||
selectedItems.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
this.isItemChecked = function isItemChecked(item) {
|
||||
return selectedItems.indexOf(item) !== -1;
|
||||
};
|
||||
|
||||
this.areAllItemsChecked = function areAllItemsChecked() {
|
||||
return this.getSelectedItemsCount() === this.items.length;
|
||||
};
|
||||
|
||||
this.getSelectedItemsCount = function getSelectedItemsCount() {
|
||||
return selectedItems.length;
|
||||
};
|
||||
|
||||
this.deleteSelectedItems = function deleteSelectedItems() {
|
||||
const selectedIds = selectedItems.map(item => item.id);
|
||||
|
||||
visualizationService.delete(selectedIds)
|
||||
.then(fetchObjects)
|
||||
.then(() => {
|
||||
selectedItems = [];
|
||||
})
|
||||
.catch(error => notify.error(error));
|
||||
};
|
||||
|
||||
this.open = function open(item) {
|
||||
kbnUrl.change(item.url.substr(1));
|
||||
};
|
||||
|
||||
this.edit = function edit(item) {
|
||||
const params = {
|
||||
// TODO: Get this value from somewhere instead of hardcodign it.
|
||||
service: 'savedVisualizations',
|
||||
id: item.id
|
||||
};
|
||||
|
||||
kbnUrl.change('/management/kibana/objects/{{ service }}/{{ id }}', params);
|
||||
};
|
||||
|
||||
$scope.$watch(() => this.filter, () => {
|
||||
fetchObjects();
|
||||
});
|
||||
}
|
|
@ -2,56 +2,48 @@
|
|||
@import (reference) "~ui/styles/bootstrap/list-group";
|
||||
@import (reference) "~ui/styles/list-group-menu";
|
||||
|
||||
/**
|
||||
* 1. Push down the breadcrumbs a bit.
|
||||
*/
|
||||
.vis-wizard {
|
||||
margin: 0;
|
||||
padding: 12px 0 0; // 1
|
||||
.wizard-sub-title {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 8px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.wizard-sub-title {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 8px;
|
||||
padding: 0px 5px;
|
||||
.wizard-type {
|
||||
flex: 1;
|
||||
|
||||
// TODO: When we migrate off Bootstrap, we can eliminate these "mixins".
|
||||
.list-group-item();
|
||||
.list-group-menu .list-group-menu-item();
|
||||
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background-color: @kibanaGray6;
|
||||
}
|
||||
|
||||
.wizard-type-heading {
|
||||
flex: 0 0 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.wizard-type {
|
||||
flex: 1;
|
||||
.wizard-type-heading-icon {
|
||||
flex: 0 0 auto;
|
||||
margin-right: @padding-base-horizontal;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
color: @saved-object-finder-icon-color;
|
||||
}
|
||||
|
||||
// TODO: When we migrate off Bootstrap, we can eliminate these "mixins".
|
||||
.list-group-item();
|
||||
.list-group-menu .list-group-menu-item();
|
||||
.wizard-type-heading-text {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background-color: @kibanaGray6;
|
||||
.wizard-type-description {
|
||||
flex: 1 1 auto;
|
||||
color: @wizard-vis-type-description-color;
|
||||
}
|
||||
|
||||
.wizard-type-heading {
|
||||
flex: 0 0 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.wizard-type-heading-icon {
|
||||
flex: 0 0 auto;
|
||||
margin-right: @padding-base-horizontal;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
color: @saved-object-finder-icon-color;
|
||||
}
|
||||
|
||||
.wizard-type-heading-text {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.wizard-type-description {
|
||||
flex: 1 1 auto;
|
||||
color: @wizard-vis-type-description-color;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-lg) {
|
||||
.wizard {
|
||||
padding: 0;
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
<div class="container-fluid vis-wizard">
|
||||
<div class="visualizeWizardBreadcrumbs">
|
||||
<bread-crumbs></bread-crumbs>
|
||||
<!-- Local nav. -->
|
||||
<kbn-top-nav name="visualize" no-menu-extensions>
|
||||
<!-- Transcluded elements. -->
|
||||
<div data-transclude-slots>
|
||||
<!-- Breadcrumbs. -->
|
||||
<bread-crumbs
|
||||
data-transclude-slot="topLeftCorner"
|
||||
></bread-crumbs>
|
||||
</div>
|
||||
</kbn-top-nav>
|
||||
|
||||
<div class="kuiViewContent kuiViewContent--constrainedWidth">
|
||||
<!-- Header -->
|
||||
<div class="kuiViewContentItem kuiSubHeader">
|
||||
<h1 class="kuiTitle">
|
||||
Select visualization type
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="wizard">
|
||||
<div class="wizard-column">
|
||||
<h3 class="wizard-sub-title">Create New Visualization</h3>
|
||||
<div class="wizard-row">
|
||||
<a
|
||||
class="wizard-type"
|
||||
|
@ -23,13 +37,5 @@
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-column">
|
||||
<h3 class="wizard-sub-title">Or, Open a Saved Visualization</h3>
|
||||
<saved-object-finder
|
||||
title="Saved Visualizations"
|
||||
type="visualizations"
|
||||
class="wizard-row"
|
||||
></saved-object-finder>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
<div class="container-fluid vis-wizard">
|
||||
<div class="visualizeWizardBreadcrumbs">
|
||||
<bread-crumbs></bread-crumbs>
|
||||
<!-- Local nav. -->
|
||||
<kbn-top-nav name="visualize" no-menu-extensions>
|
||||
<!-- Transcluded elements. -->
|
||||
<div data-transclude-slots>
|
||||
<!-- Breadcrumbs. -->
|
||||
<bread-crumbs
|
||||
data-transclude-slot="topLeftCorner"
|
||||
></bread-crumbs>
|
||||
</div>
|
||||
</kbn-top-nav>
|
||||
|
||||
<div class="kuiViewContent kuiViewContent--constrainedWidth">
|
||||
<div class="wizard">
|
||||
<div class="wizard-column wizard-column--small">
|
||||
<h3 class="wizard-sub-title">From a New Search, Select Index</h3>
|
||||
|
|
|
@ -99,9 +99,10 @@ module.directive('kbnTopNav', function (Private) {
|
|||
});
|
||||
});
|
||||
|
||||
const extensions = getNavbarExtensions($attrs.name);
|
||||
|
||||
let controls = _.get($scope, $attrs.config, []);
|
||||
const noMenuExtensions = $attrs.hasOwnProperty('noMenuExtensions');
|
||||
const extensions = noMenuExtensions ? [] : getNavbarExtensions($attrs.name);
|
||||
|
||||
if (controls instanceof KbnTopNavController) {
|
||||
controls.addItems(extensions);
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue