diff --git a/src/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js b/src/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js
new file mode 100644
index 000000000000..4ca96c20a5d9
--- /dev/null
+++ b/src/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js
@@ -0,0 +1,27 @@
+import React from 'react';
+
+import {
+ KuiEmptyTablePrompt,
+ KuiEmptyTablePromptPanel,
+ KuiLinkButton,
+ KuiButtonIcon,
+} from 'ui_framework/components';
+
+export function NoVisualizationsPrompt() {
+ return (
+
+ }
+ >
+ Create a visualization
+
+ }
+ message="Looks like you don't have any visualizations. Let's create some!"
+ />
+
+ );
+}
diff --git a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html
index ebc1c3e71be3..e9733826f88f 100644
--- a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html
+++ b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html
@@ -26,220 +26,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
- |
-
-
-
-
-
-
-
-
-
- {{ item.type.title }}
-
-
- |
-
-
-
-
-
-
-
diff --git a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index acea3a2b3024..b1dc1fe55241 100644
--- a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -1,154 +1,40 @@
import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
import 'ui/pager_control';
import 'ui/pager';
+import { uiModules } from 'ui/modules';
-import { SortableProperties } from 'ui_framework/services';
+import { VisualizeListingTable } from './visualize_listing_table';
+
+const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
+app.directive('visualizeListingTable', function (reactDirective) {
+ return reactDirective(VisualizeListingTable);
+});
export function VisualizeListingController($injector) {
- const $filter = $injector.get('$filter');
- const confirmModal = $injector.get('confirmModal');
const Notifier = $injector.get('Notifier');
- const pagerFactory = $injector.get('pagerFactory');
const Private = $injector.get('Private');
const timefilter = $injector.get('timefilter');
const config = $injector.get('config');
timefilter.enabled = false;
- const limitTo = $filter('limitTo');
// 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 sortableProperties = new SortableProperties([
- {
- name: 'title',
- getValue: item => item.title.toLowerCase(),
- isAscending: true,
- },
- {
- name: 'type',
- getValue: item => item.type.title.toLowerCase(),
- isAscending: true,
- }
- ],
- 'title');
-
- const calculateItemsOnPage = () => {
- this.items = sortableProperties.sortItems(this.items);
- this.pager.setTotalItems(this.items.length);
- this.pageOfItems = limitTo(this.items, this.pager.pageSize, this.pager.startIndex);
- };
-
- const fetchItems = () => {
- this.isFetchingItems = true;
-
- visualizationService.find(this.filter, config.get('savedObjects:listingLimit'))
+ this.fetchItems = (filter) => {
+ return visualizationService.find(filter, config.get('savedObjects:listingLimit'))
.then(result => {
- this.isFetchingItems = false;
- this.items = result.hits;
this.totalItems = result.total;
this.showLimitError = result.total > config.get('savedObjects:listingLimit');
this.listingLimit = config.get('savedObjects:listingLimit');
- calculateItemsOnPage();
+ return result.hits;
});
};
- const deselectAll = () => {
- selectedItems = [];
- };
-
- const selectAll = () => {
- selectedItems = this.pageOfItems.slice(0);
- };
-
- this.isAscending = (name) => sortableProperties.isAscendingByName(name);
- this.getSortedProperty = () => sortableProperties.getSortedProperty();
-
- this.sortOn = function sortOn(propertyName) {
- sortableProperties.sortOn(propertyName);
- deselectAll();
- calculateItemsOnPage();
- };
-
- this.isFetchingItems = false;
- this.items = [];
- this.pageOfItems = [];
- this.filter = '';
-
- this.pager = pagerFactory.create(this.items.length, 20, 1);
-
- this.onFilter = (newFilter) => {
- this.filter = newFilter;
- deselectAll();
- fetchItems();
- };
- fetchItems();
-
- this.toggleAll = function toggleAll() {
- if (this.areAllItemsChecked()) {
- deselectAll();
- } else {
- selectAll();
- }
- };
-
- 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.includes(item);
- };
-
- this.areAllItemsChecked = function areAllItemsChecked() {
- return this.getSelectedItemsCount() === this.pageOfItems.length;
- };
-
- this.getSelectedItemsCount = function getSelectedItemsCount() {
- return selectedItems.length;
- };
-
- this.deleteSelectedItems = function deleteSelectedItems() {
- const doDelete = () => {
- const selectedIds = selectedItems.map(item => item.id);
-
- visualizationService.delete(selectedIds)
- .then(fetchItems)
- .then(() => {
- deselectAll();
- })
- .catch(error => notify.error(error));
- };
-
- confirmModal(
- 'Are you sure you want to delete the selected visualizations? This action is irreversible!',
- {
- confirmButtonText: 'Delete',
- onConfirm: doDelete
- });
- };
-
- this.onPageNext = () => {
- deselectAll();
- this.pager.nextPage();
- calculateItemsOnPage();
- };
-
- this.onPagePrevious = () => {
- deselectAll();
- this.pager.previousPage();
- calculateItemsOnPage();
- };
-
- this.getUrlForItem = function getUrlForItem(item) {
- return `#/visualize/edit/${item.id}`;
+ this.deleteSelectedItems = function deleteSelectedItems(selectedIds) {
+ return visualizationService.delete(selectedIds)
+ .catch(error => notify.error(error));
};
}
diff --git a/src/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js b/src/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
new file mode 100644
index 000000000000..bba3ed4e7295
--- /dev/null
+++ b/src/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
@@ -0,0 +1,261 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import { SortableProperties } from 'ui_framework/services';
+import { Pager } from 'ui/pager';
+import { NoVisualizationsPrompt } from './no_visualizations_prompt';
+
+import {
+ KuiPager,
+ KuiModalOverlay,
+ KuiConfirmModal,
+ KuiListingTableDeleteButton,
+ KuiListingTableCreateButton,
+ KuiListingTable,
+ KuiListingTableNoMatchesPrompt,
+ KuiListingTableLoadingPrompt
+} from 'ui_framework/components';
+
+export class VisualizeListingTable extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ selectedRowIds: [],
+ pageOfItems: [],
+ showDeleteModal: false,
+ filter: '',
+ sortedColumn: '',
+ sortedColumnDirection: '',
+ pageStartNumber: 1,
+ isFetchingItems: false,
+ };
+
+ this.sortableProperties = new SortableProperties(
+ [
+ {
+ name: 'title',
+ getValue: item => item.title.toLowerCase(),
+ isAscending: true,
+ },
+ {
+ name: 'type',
+ getValue: item => item.type.title.toLowerCase(),
+ isAscending: true,
+ }
+ ],
+ 'title'
+ );
+ this.items = [];
+ this.pager = new Pager(this.items.length, 20, 1);
+ }
+
+ calculateItemsOnPage = () => {
+ this.items = this.sortableProperties.sortItems(this.items);
+ this.pager.setTotalItems(this.items.length);
+ const pageOfItems = this.items.slice(this.pager.startIndex, this.pager.startIndex + this.pager.pageSize);
+ this.setState({ pageOfItems, pageStartNumber: this.pager.startItem });
+ };
+
+ deselectAll = () => {
+ this.setState({ selectedRowIds: [] });
+ };
+
+ isAscending = (name) => this.sortableProperties.isAscendingByName(name);
+ getSortedProperty = () => this.sortableProperties.getSortedProperty();
+
+ sortOn = function sortOn(propertyName) {
+ this.sortableProperties.sortOn(propertyName);
+ this.setState({
+ selectedRowIds: [],
+ sortedColumn: this.sortableProperties.getSortedProperty(),
+ sortedColumnDirection: this.sortableProperties.isCurrentSortAscending() ? 'ASC' : 'DESC',
+ });
+ this.calculateItemsOnPage();
+ };
+
+ fetchItems = (filter) => {
+ this.setState({ isFetchingItems: true });
+
+ this.props.fetchItems(filter)
+ .then(items => {
+ this.setState({
+ isFetchingItems: false,
+ selectedRowIds: [],
+ filter,
+ });
+ this.items = items;
+ this.calculateItemsOnPage();
+ });
+ };
+
+ componentDidMount() {
+ this.fetchItems(this.state.filter);
+ }
+
+ onNextPage = () => {
+ this.deselectAll();
+ this.pager.nextPage();
+ this.calculateItemsOnPage();
+ };
+
+ onPreviousPage = () => {
+ this.deselectAll();
+ this.pager.previousPage();
+ this.calculateItemsOnPage();
+ };
+
+ getUrlForItem(item) {
+ return `#/visualize/edit/${item.id}`;
+ }
+
+ renderItemTypeIcon(item) {
+ return item.type.image ?
+
+ {this.state.showDeleteModal && this.renderConfirmDeleteModal()}
+
+
+ );
+ }
+}
+
+VisualizeListingTable.propTypes = {
+ deleteSelectedItems: PropTypes.func,
+ fetchItems: PropTypes.func,
+};
diff --git a/src/ui/public/pager/index.js b/src/ui/public/pager/index.js
index 3f8e47d5d122..9499a273498d 100644
--- a/src/ui/public/pager/index.js
+++ b/src/ui/public/pager/index.js
@@ -1 +1,2 @@
import './pager_factory';
+export { Pager } from './pager';
diff --git a/ui_framework/doc_site/src/views/table/controlled_table.js b/ui_framework/doc_site/src/views/table/controlled_table.js
deleted file mode 100644
index 6ce8563f0590..000000000000
--- a/ui_framework/doc_site/src/views/table/controlled_table.js
+++ /dev/null
@@ -1,186 +0,0 @@
-import React from 'react';
-
-import {
- KuiToolBar,
- KuiToolBarSearchBox,
- KuiToolBarSection,
- KuiButton,
- KuiButtonIcon,
- KuiTable,
- KuiToolBarText,
- KuiControlledTable,
- KuiPager,
- KuiTableRow,
- KuiTableRowCell,
- KuiTableRowCheckBoxCell,
- KuiTableHeaderCell,
- KuiToolBarFooterSection,
- KuiToolBarFooter,
- KuiTableHeaderCheckBoxCell,
- KuiTableBody,
- KuiTableHeader,
-} from '../../../../components';
-
-import {
- LEFT_ALIGNMENT,
- RIGHT_ALIGNMENT
-} from '../../../../services';
-
-export class ControlledTable extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- rowToSelectedStateMap: new Map(),
- };
-
- this.rows = [
- [
-