mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Add TableHeader + TableHeaderColumn react components * Migration of kbnTableHeader to use react component * Disable mocha tests * Add jest tests
This commit is contained in:
parent
f57a2a774e
commit
509531fc64
14 changed files with 763 additions and 361 deletions
|
@ -27,9 +27,6 @@ import $ from 'jquery';
|
|||
import 'plugins/kibana/discover/index';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
|
||||
const SORTABLE_FIELDS = ['bytes', '@timestamp'];
|
||||
const UNSORTABLE_FIELDS = ['request_body'];
|
||||
|
||||
describe('Doc Table', function () {
|
||||
let $parentScope;
|
||||
let $scope;
|
||||
|
@ -119,155 +116,6 @@ describe('Doc Table', function () {
|
|||
});
|
||||
};
|
||||
|
||||
describe('kbnTableHeader', function () {
|
||||
const $elem = angular.element(`
|
||||
<thead
|
||||
kbn-table-header
|
||||
columns="columns"
|
||||
index-pattern="indexPattern"
|
||||
sort-order="sortOrder"
|
||||
on-change-sort-order="onChangeSortOrder"
|
||||
on-move-column="moveColumn"
|
||||
on-remove-column="removeColumn"
|
||||
></thead>
|
||||
`);
|
||||
|
||||
beforeEach(function () {
|
||||
init($elem, {
|
||||
columns: [],
|
||||
sortOrder: [],
|
||||
onChangeSortOrder: sinon.stub(),
|
||||
moveColumn: sinon.spy(),
|
||||
removeColumn: sinon.spy(),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
destroy();
|
||||
});
|
||||
|
||||
describe('adding and removing columns', function () {
|
||||
columnTests('[data-test-subj~="docTableHeaderField"]', $elem);
|
||||
});
|
||||
|
||||
describe('sorting button', function () {
|
||||
beforeEach(function () {
|
||||
$parentScope.columns = ['bytes', '_source'];
|
||||
$elem.scope().$digest();
|
||||
});
|
||||
|
||||
it('should show for sortable columns', function () {
|
||||
expect($elem.find(`[data-test-subj="docTableHeaderFieldSort_bytes"]`).length).to.be(1);
|
||||
});
|
||||
|
||||
it('should not be shown for unsortable columns', function () {
|
||||
expect($elem.find(`[data-test-subj="docTableHeaderFieldSort__source"]`).length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cycleSortOrder function', function () {
|
||||
it('should exist', function () {
|
||||
expect($scope.cycleSortOrder).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should call onChangeSortOrder with ascending order for a sortable field without sort order', function () {
|
||||
$scope.sortOrder = [];
|
||||
$scope.cycleSortOrder(SORTABLE_FIELDS[0]);
|
||||
expect($scope.onChangeSortOrder.callCount).to.be(1);
|
||||
expect($scope.onChangeSortOrder.firstCall.args).to.eql([SORTABLE_FIELDS[0], 'asc']);
|
||||
});
|
||||
|
||||
it('should call onChangeSortOrder with ascending order for a sortable field already sorted by in descending order', function () {
|
||||
$scope.sortOrder = [SORTABLE_FIELDS[0], 'desc'];
|
||||
$scope.cycleSortOrder(SORTABLE_FIELDS[0]);
|
||||
expect($scope.onChangeSortOrder.callCount).to.be(1);
|
||||
expect($scope.onChangeSortOrder.firstCall.args).to.eql([SORTABLE_FIELDS[0], 'asc']);
|
||||
});
|
||||
|
||||
it('should call onChangeSortOrder with ascending order for a sortable field when already sorted by an different field', function () {
|
||||
$scope.sortOrder = [SORTABLE_FIELDS[1], 'asc'];
|
||||
$scope.cycleSortOrder(SORTABLE_FIELDS[0]);
|
||||
expect($scope.onChangeSortOrder.callCount).to.be(1);
|
||||
expect($scope.onChangeSortOrder.firstCall.args).to.eql([SORTABLE_FIELDS[0], 'asc']);
|
||||
});
|
||||
|
||||
it('should call onChangeSortOrder with descending order for a sortable field already sorted by in ascending order', function () {
|
||||
$scope.sortOrder = [SORTABLE_FIELDS[0], 'asc'];
|
||||
$scope.cycleSortOrder(SORTABLE_FIELDS[0]);
|
||||
expect($scope.onChangeSortOrder.callCount).to.be(1);
|
||||
expect($scope.onChangeSortOrder.firstCall.args).to.eql([SORTABLE_FIELDS[0], 'desc']);
|
||||
});
|
||||
|
||||
it('should not call onChangeSortOrder for an unsortable field', function () {
|
||||
$scope.sortOrder = [];
|
||||
$scope.cycleSortOrder(UNSORTABLE_FIELDS[0]);
|
||||
expect($scope.onChangeSortOrder.callCount).to.be(0);
|
||||
});
|
||||
|
||||
it('should not try to call onChangeSortOrder when it is not defined', function () {
|
||||
$scope.onChangeSortOrder = undefined;
|
||||
expect(() => $scope.cycleSortOrder(SORTABLE_FIELDS[0])).to.not.throwException();
|
||||
});
|
||||
});
|
||||
|
||||
describe('headerClass function', function () {
|
||||
it('should exist', function () {
|
||||
expect($scope.headerClass).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should return list including kbnDocTableHeader__sortChange for a sortable field not currently sorted by', function () {
|
||||
expect($scope.headerClass(SORTABLE_FIELDS[0])).to.contain('kbnDocTableHeader__sortChange');
|
||||
});
|
||||
|
||||
it('should return undefined for an unsortable field', function () {
|
||||
expect($scope.headerClass(UNSORTABLE_FIELDS[0])).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should return list including fa-sort-up for a sortable field not currently sorted by', function () {
|
||||
expect($scope.headerClass(SORTABLE_FIELDS[0])).to.contain('fa-sort-up');
|
||||
});
|
||||
|
||||
it('should return list including fa-sort-up for a sortable field currently sorted by in ascending order', function () {
|
||||
$scope.sortOrder = [SORTABLE_FIELDS[0], 'asc'];
|
||||
expect($scope.headerClass(SORTABLE_FIELDS[0])).to.contain('fa-sort-up');
|
||||
});
|
||||
|
||||
it('should return list including fa-sort-down for a sortable field currently sorted by in descending order', function () {
|
||||
$scope.sortOrder = [SORTABLE_FIELDS[0], 'desc'];
|
||||
expect($scope.headerClass(SORTABLE_FIELDS[0])).to.contain('fa-sort-down');
|
||||
});
|
||||
});
|
||||
|
||||
describe('moving columns', function () {
|
||||
beforeEach(function () {
|
||||
$parentScope.columns = ['bytes', 'request_body', '@timestamp', 'point'];
|
||||
$elem.scope().$digest();
|
||||
});
|
||||
|
||||
it('should move columns to the right', function () {
|
||||
$scope.moveColumnRight('bytes');
|
||||
expect($scope.onMoveColumn.callCount).to.be(1);
|
||||
expect($scope.onMoveColumn.firstCall.args).to.eql(['bytes', 1]);
|
||||
});
|
||||
|
||||
it('shouldnt move the last column to the right', function () {
|
||||
$scope.moveColumnRight('point');
|
||||
expect($scope.onMoveColumn.callCount).to.be(0);
|
||||
});
|
||||
|
||||
it('should move columns to the left', function () {
|
||||
$scope.moveColumnLeft('@timestamp');
|
||||
expect($scope.onMoveColumn.callCount).to.be(1);
|
||||
expect($scope.onMoveColumn.firstCall.args).to.eql(['@timestamp', 1]);
|
||||
});
|
||||
|
||||
it('shouldnt move the first column to the left', function () {
|
||||
$scope.moveColumnLeft('bytes');
|
||||
expect($scope.onMoveColumn.callCount).to.be(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('kbnTableRow', function () {
|
||||
const $elem = angular.element(
|
||||
'<tr kbn-table-row="row" ' +
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
.kbnDocTableHeader button {
|
||||
margin-left: $euiSizeXS;
|
||||
}
|
||||
.kbnDocTableHeader__move,
|
||||
.kbnDocTableHeader__sortChange {
|
||||
opacity: 0;
|
||||
|
||||
th:hover &,
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
<tr>
|
||||
<td width="1%"></td>
|
||||
<th
|
||||
ng-if="indexPattern.timeFieldName && !hideTimeColumn"
|
||||
data-test-subj="docTableHeaderField"
|
||||
scope="col"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
i18n-id="kbn.docTable.tableHeader.timeHeaderCellTitle"
|
||||
i18n-default-message="Time"
|
||||
></span>
|
||||
<button
|
||||
id="docTableHeaderFieldSort{{indexPattern.timeFieldName}}"
|
||||
tabindex="0"
|
||||
aria-label="{{ getAriaLabelForColumn(indexPattern.timeFieldName) }}"
|
||||
ng-class="headerClass(indexPattern.timeFieldName)"
|
||||
role="button"
|
||||
ng-click="cycleSortOrder(indexPattern.timeFieldName)"
|
||||
tooltip="{{ ::'kbn.docTable.tableHeader.sortByTimeTooltip' | i18n: {defaultMessage: 'Sort by time'} }}"
|
||||
></button>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
ng-repeat="name in columns"
|
||||
data-test-subj="docTableHeaderField"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-{{name}}"
|
||||
>
|
||||
{{getShortDotsName(name)}}
|
||||
<button
|
||||
data-test-subj="docTableHeaderFieldSort_{{name}}"
|
||||
id="docTableHeaderFieldSort{{name}}"
|
||||
ng-if="isSortableColumn(name)"
|
||||
aria-label="{{ getAriaLabelForColumn(name) }}"
|
||||
ng-class="headerClass(name)"
|
||||
ng-click="cycleSortOrder(name)"
|
||||
tooltip="{{tooltip(name)}}"
|
||||
tooltip-append-to-body="1"
|
||||
></button>
|
||||
</span>
|
||||
<button
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
ng-click="onRemoveColumn(name)"
|
||||
ng-if="canRemoveColumn(name)"
|
||||
tooltip-append-to-body="1"
|
||||
tooltip="{{ ::'kbn.docTable.tableHeader.removeColumnButtonTooltip' | i18n: {defaultMessage: 'Remove column'} }}"
|
||||
aria-label="{{ 'kbn.docTable.tableHeader.removeColumnButtonAriaLabel' | i18n: {
|
||||
defaultMessage: 'Remove {columnName} column',
|
||||
values: {columnName: name}
|
||||
} }}"
|
||||
data-test-subj="docTableRemoveHeader-{{name}}"
|
||||
></button>
|
||||
<button
|
||||
class="fa fa-angle-double-left kbnDocTableHeader__move"
|
||||
ng-click="moveColumnLeft(name)"
|
||||
ng-if="canMoveColumnLeft(name)"
|
||||
tooltip-append-to-body="1"
|
||||
tooltip="{{ ::'kbn.docTable.tableHeader.moveColumnLeftButtonTooltip' | i18n: {defaultMessage: 'Move column to the left'} }}"
|
||||
aria-label="{{ 'kbn.docTable.tableHeader.moveColumnLeftButtonAriaLabel' | i18n: {
|
||||
defaultMessage: 'Move {columnName} column to the left',
|
||||
values: {columnName: name}
|
||||
} }}"
|
||||
></button>
|
||||
<button
|
||||
class="fa fa-angle-double-right kbnDocTableHeader__move"
|
||||
ng-click="moveColumnRight(name)"
|
||||
ng-if="canMoveColumnRight(name)"
|
||||
tooltip-append-to-body="1"
|
||||
tooltip="{{ ::'kbn.docTable.tableHeader.moveColumnRightButtonTooltip' | i18n: {defaultMessage: 'Move column to the right'} }}"
|
||||
aria-label="{{ 'kbn.docTable.tableHeader.moveColumnRightButtonAriaLabel' | i18n: {
|
||||
defaultMessage: 'Move {columnName} column to the right',
|
||||
values: {columnName: name}
|
||||
} }}"
|
||||
></button>
|
||||
</th>
|
||||
</tr>
|
|
@ -16,133 +16,19 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { shortenDottedString } from '../../../../common/utils/shorten_dotted_string';
|
||||
import headerHtml from './table_header.html';
|
||||
import { wrapInI18nContext } from 'ui/i18n';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { TableHeader } from './table_header/table_header';
|
||||
const module = uiModules.get('app/discover');
|
||||
|
||||
|
||||
module.directive('kbnTableHeader', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
columns: '=',
|
||||
sortOrder: '=',
|
||||
indexPattern: '=',
|
||||
onChangeSortOrder: '=?',
|
||||
onRemoveColumn: '=?',
|
||||
onMoveColumn: '=?',
|
||||
},
|
||||
template: headerHtml,
|
||||
controller: function ($scope, config) {
|
||||
$scope.hideTimeColumn = config.get('doc_table:hideTimeColumn');
|
||||
$scope.isShortDots = config.get('shortDots:enable');
|
||||
|
||||
$scope.getShortDotsName = function getShortDotsName(columnName) {
|
||||
return $scope.isShortDots ? shortenDottedString(columnName) : columnName;
|
||||
};
|
||||
|
||||
$scope.isSortableColumn = function isSortableColumn(columnName) {
|
||||
return (
|
||||
!!$scope.indexPattern
|
||||
&& _.isFunction($scope.onChangeSortOrder)
|
||||
&& _.get($scope, ['indexPattern', 'fields', 'byName', columnName, 'sortable'], false)
|
||||
);
|
||||
};
|
||||
|
||||
$scope.tooltip = function (column) {
|
||||
if (!$scope.isSortableColumn(column)) return '';
|
||||
const name = $scope.isShortDots ? shortenDottedString(column) : column;
|
||||
return i18n.translate('kbn.docTable.tableHeader.sortByColumnTooltip', {
|
||||
defaultMessage: 'Sort by {columnName}',
|
||||
values: { columnName: name },
|
||||
});
|
||||
};
|
||||
|
||||
$scope.canMoveColumnLeft = function canMoveColumn(columnName) {
|
||||
return (
|
||||
_.isFunction($scope.onMoveColumn)
|
||||
&& $scope.columns.indexOf(columnName) > 0
|
||||
);
|
||||
};
|
||||
|
||||
$scope.canMoveColumnRight = function canMoveColumn(columnName) {
|
||||
return (
|
||||
_.isFunction($scope.onMoveColumn)
|
||||
&& $scope.columns.indexOf(columnName) < $scope.columns.length - 1
|
||||
);
|
||||
};
|
||||
|
||||
$scope.canRemoveColumn = function canRemoveColumn(columnName) {
|
||||
return (
|
||||
_.isFunction($scope.onRemoveColumn)
|
||||
&& (columnName !== '_source' || $scope.columns.length > 1)
|
||||
);
|
||||
};
|
||||
|
||||
$scope.headerClass = function (column) {
|
||||
if (!$scope.isSortableColumn(column)) return;
|
||||
|
||||
const sortOrder = $scope.sortOrder;
|
||||
const defaultClass = ['fa', 'fa-sort-up', 'kbnDocTableHeader__sortChange'];
|
||||
|
||||
if (!sortOrder || column !== sortOrder[0]) return defaultClass;
|
||||
return ['fa', sortOrder[1] === 'asc' ? 'fa-sort-up' : 'fa-sort-down'];
|
||||
};
|
||||
|
||||
$scope.moveColumnLeft = function moveLeft(columnName) {
|
||||
const newIndex = $scope.columns.indexOf(columnName) - 1;
|
||||
|
||||
if (newIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.onMoveColumn(columnName, newIndex);
|
||||
};
|
||||
|
||||
$scope.moveColumnRight = function moveRight(columnName) {
|
||||
const newIndex = $scope.columns.indexOf(columnName) + 1;
|
||||
|
||||
if (newIndex >= $scope.columns.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.onMoveColumn(columnName, newIndex);
|
||||
};
|
||||
|
||||
$scope.cycleSortOrder = function cycleSortOrder(columnName) {
|
||||
if (!$scope.isSortableColumn(columnName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [currentColumnName, currentDirection = 'asc'] = $scope.sortOrder;
|
||||
const newDirection = (
|
||||
(columnName === currentColumnName && currentDirection === 'asc')
|
||||
? 'desc'
|
||||
: 'asc'
|
||||
);
|
||||
|
||||
$scope.onChangeSortOrder(columnName, newDirection);
|
||||
};
|
||||
|
||||
$scope.getAriaLabelForColumn = function getAriaLabelForColumn(name) {
|
||||
if (!$scope.isSortableColumn(name)) return null;
|
||||
|
||||
const [currentColumnName, currentDirection = 'asc'] = $scope.sortOrder;
|
||||
if(name === currentColumnName && currentDirection === 'asc') {
|
||||
return i18n.translate('kbn.docTable.tableHeader.sortByColumnDescendingAriaLabel', {
|
||||
defaultMessage: 'Sort {columnName} descending',
|
||||
values: { columnName: name },
|
||||
});
|
||||
}
|
||||
return i18n.translate('kbn.docTable.tableHeader.sortByColumnAscendingAriaLabel', {
|
||||
defaultMessage: 'Sort {columnName} ascending',
|
||||
values: { columnName: name },
|
||||
});
|
||||
};
|
||||
module.directive('kbnTableHeader', function (reactDirective, config) {
|
||||
return reactDirective(
|
||||
wrapInI18nContext(TableHeader),
|
||||
undefined,
|
||||
{ restrict: 'A' },
|
||||
{
|
||||
hideTimeColumn: config.get('doc_table:hideTimeColumn'),
|
||||
isShortDots: config.get('shortDots:enable'),
|
||||
}
|
||||
};
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TableHeader with time column renders correctly 1`] = `
|
||||
<tr
|
||||
class="kbnDocTableHeader"
|
||||
data-test-subj="docTableHeader"
|
||||
>
|
||||
<th
|
||||
style="width: 24px;"
|
||||
/>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-time"
|
||||
>
|
||||
Time
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-time-tt"
|
||||
aria-label="Sort time descending"
|
||||
class="fa fa-sort-up"
|
||||
data-test-subj="docTableHeaderFieldSort_time"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-first"
|
||||
>
|
||||
first
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-first-tt"
|
||||
aria-label="Remove first column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-first"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-first-tt"
|
||||
aria-label="Move first column to the right"
|
||||
class="fa fa-angle-double-right kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveRightHeader-first"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-middle"
|
||||
>
|
||||
middle
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Remove middle column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Move middle column to the left"
|
||||
class="fa fa-angle-double-left kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveLeftHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Move middle column to the right"
|
||||
class="fa fa-angle-double-right kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveRightHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-last"
|
||||
>
|
||||
last
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-last-tt"
|
||||
aria-label="Remove last column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-last"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-last-tt"
|
||||
aria-label="Move last column to the left"
|
||||
class="fa fa-angle-double-left kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveLeftHeader-last"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`TableHeader without time column renders correctly 1`] = `
|
||||
<tr
|
||||
class="kbnDocTableHeader"
|
||||
data-test-subj="docTableHeader"
|
||||
>
|
||||
<th
|
||||
style="width: 24px;"
|
||||
/>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-first"
|
||||
>
|
||||
first
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-first-tt"
|
||||
aria-label="Remove first column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-first"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-first-tt"
|
||||
aria-label="Move first column to the right"
|
||||
class="fa fa-angle-double-right kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveRightHeader-first"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-middle"
|
||||
>
|
||||
middle
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Remove middle column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Move middle column to the left"
|
||||
class="fa fa-angle-double-left kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveLeftHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-middle-tt"
|
||||
aria-label="Move middle column to the right"
|
||||
class="fa fa-angle-double-right kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveRightHeader-middle"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
data-test-subj="docTableHeaderField"
|
||||
>
|
||||
<span
|
||||
data-test-subj="docTableHeader-last"
|
||||
>
|
||||
last
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-last-tt"
|
||||
aria-label="Remove last column"
|
||||
class="fa fa-remove kbnDocTableHeader__move"
|
||||
data-test-subj="docTableRemoveHeader-last"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="euiToolTipAnchor"
|
||||
>
|
||||
<button
|
||||
aria-describedby="docTableHeader-last-tt"
|
||||
aria-label="Move last column to the left"
|
||||
class="fa fa-angle-double-left kbnDocTableHeader__move"
|
||||
data-test-subj="docTableMoveLeftHeader-last"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
`;
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 { IndexPatternEnhanced } from 'ui/index_patterns/_index_pattern';
|
||||
// @ts-ignore
|
||||
import { shortenDottedString } from '../../../../../common/utils/shorten_dotted_string';
|
||||
|
||||
export type SortOrder = [string, 'asc' | 'desc'];
|
||||
export interface ColumnProps {
|
||||
name: string;
|
||||
displayName: string;
|
||||
isSortable: boolean;
|
||||
isRemoveable: boolean;
|
||||
colLeftIdx: number;
|
||||
colRightIdx: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns properties necessary to display the time column
|
||||
* If it's an IndexPattern with timefield, the time column is
|
||||
* prepended, not moveable and removeable
|
||||
* @param timeFieldName
|
||||
*/
|
||||
export function getTimeColumn(timeFieldName: string): ColumnProps {
|
||||
return {
|
||||
name: timeFieldName,
|
||||
displayName: 'Time',
|
||||
isSortable: true,
|
||||
isRemoveable: false,
|
||||
colLeftIdx: -1,
|
||||
colRightIdx: -1,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* A given array of column names returns an array of properties
|
||||
* necessary to display the columns. If the given indexPattern
|
||||
* has a timefield, a time column is prepended
|
||||
* @param columns
|
||||
* @param indexPattern
|
||||
* @param hideTimeField
|
||||
* @param isShortDots
|
||||
*/
|
||||
export function getDisplayedColumns(
|
||||
columns: string[],
|
||||
indexPattern: IndexPatternEnhanced,
|
||||
hideTimeField: boolean,
|
||||
isShortDots: boolean
|
||||
) {
|
||||
if (!Array.isArray(columns) || typeof indexPattern !== 'object' || !indexPattern.getFieldByName) {
|
||||
return [];
|
||||
}
|
||||
const columnProps = columns.map((column, idx) => {
|
||||
const field = indexPattern.getFieldByName(column);
|
||||
return {
|
||||
name: column,
|
||||
displayName: isShortDots ? shortenDottedString(column) : column,
|
||||
isSortable: field && field.sortable ? true : false,
|
||||
isRemoveable: column !== '_source' || columns.length > 1,
|
||||
colLeftIdx: idx - 1 < 0 ? -1 : idx - 1,
|
||||
colRightIdx: idx + 1 >= columns.length ? -1 : idx + 1,
|
||||
};
|
||||
});
|
||||
return !hideTimeField && indexPattern.timeFieldName
|
||||
? [getTimeColumn(indexPattern.timeFieldName), ...columnProps]
|
||||
: columnProps;
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { TableHeader } from './table_header';
|
||||
// @ts-ignore
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import { SortOrder } from './helpers';
|
||||
import { IndexPatternEnhanced, StaticIndexPatternField } from 'ui/index_patterns/_index_pattern';
|
||||
|
||||
function getMockIndexPattern() {
|
||||
return {
|
||||
id: 'test',
|
||||
title: 'Test',
|
||||
timeFieldName: 'time',
|
||||
fields: [],
|
||||
isTimeNanosBased: () => false,
|
||||
getFieldByName: name => {
|
||||
if (name === 'test1') {
|
||||
return {
|
||||
name,
|
||||
type: 'string',
|
||||
aggregatable: false,
|
||||
searchable: true,
|
||||
sortable: true,
|
||||
} as StaticIndexPatternField;
|
||||
} else {
|
||||
return {
|
||||
name,
|
||||
type: 'string',
|
||||
aggregatable: false,
|
||||
searchable: true,
|
||||
sortable: false,
|
||||
} as StaticIndexPatternField;
|
||||
}
|
||||
},
|
||||
} as IndexPatternEnhanced;
|
||||
}
|
||||
|
||||
function getMockProps(props = {}) {
|
||||
const defaultProps = {
|
||||
indexPattern: getMockIndexPattern(),
|
||||
hideTimeColumn: false,
|
||||
columns: ['first', 'middle', 'last'],
|
||||
sortOrder: ['time', 'asc'] as SortOrder,
|
||||
isShortDots: true,
|
||||
onRemoveColumn: jest.fn(),
|
||||
onChangeSortOrder: jest.fn(),
|
||||
onMoveColumn: jest.fn(),
|
||||
onPageNext: jest.fn(),
|
||||
onPagePrevious: jest.fn(),
|
||||
};
|
||||
|
||||
return Object.assign({}, defaultProps, props);
|
||||
}
|
||||
|
||||
describe('TableHeader with time column', () => {
|
||||
const props = getMockProps();
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<table>
|
||||
<thead>
|
||||
<TableHeader {...props} />
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
|
||||
test('renders correctly', () => {
|
||||
const docTableHeader = findTestSubject(wrapper, 'docTableHeader');
|
||||
expect(docTableHeader.getDOMNode()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('time column is sortable with button, cycling sort direction', () => {
|
||||
findTestSubject(wrapper, 'docTableHeaderFieldSort_time').simulate('click');
|
||||
expect(props.onChangeSortOrder).toHaveBeenCalledWith('time', 'desc');
|
||||
});
|
||||
|
||||
test('time column is not removeable, no button displayed', () => {
|
||||
const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-time');
|
||||
expect(removeButton.length).toBe(0);
|
||||
});
|
||||
|
||||
test('time column is not moveable, no button displayed', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-time');
|
||||
expect(moveButtonLeft.length).toBe(0);
|
||||
const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-time');
|
||||
expect(moveButtonRight.length).toBe(0);
|
||||
});
|
||||
|
||||
test('first column is removeable', () => {
|
||||
const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first');
|
||||
expect(removeButton.length).toBe(1);
|
||||
removeButton.simulate('click');
|
||||
expect(props.onRemoveColumn).toHaveBeenCalledWith('first');
|
||||
});
|
||||
|
||||
test('first column is not moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first');
|
||||
expect(moveButtonLeft.length).toBe(0);
|
||||
});
|
||||
|
||||
test('first column is moveable to the right', () => {
|
||||
const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first');
|
||||
expect(moveButtonRight.length).toBe(1);
|
||||
moveButtonRight.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1);
|
||||
});
|
||||
|
||||
test('middle column is moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle');
|
||||
expect(moveButtonLeft.length).toBe(1);
|
||||
moveButtonLeft.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0);
|
||||
});
|
||||
|
||||
test('middle column is moveable to the right', () => {
|
||||
const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle');
|
||||
expect(moveButtonRight.length).toBe(1);
|
||||
moveButtonRight.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2);
|
||||
});
|
||||
|
||||
test('last column moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last');
|
||||
expect(moveButtonLeft.length).toBe(1);
|
||||
moveButtonLeft.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TableHeader without time column', () => {
|
||||
const props = getMockProps({ hideTimeColumn: true });
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<table>
|
||||
<thead>
|
||||
<TableHeader {...props} />
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
|
||||
test('renders correctly', () => {
|
||||
const docTableHeader = findTestSubject(wrapper, 'docTableHeader');
|
||||
expect(docTableHeader.getDOMNode()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('first column is removeable', () => {
|
||||
const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first');
|
||||
expect(removeButton.length).toBe(1);
|
||||
removeButton.simulate('click');
|
||||
expect(props.onRemoveColumn).toHaveBeenCalledWith('first');
|
||||
});
|
||||
|
||||
test('first column is not moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first');
|
||||
expect(moveButtonLeft.length).toBe(0);
|
||||
});
|
||||
|
||||
test('first column is moveable to the right', () => {
|
||||
const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first');
|
||||
expect(moveButtonRight.length).toBe(1);
|
||||
moveButtonRight.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1);
|
||||
});
|
||||
|
||||
test('middle column is moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle');
|
||||
expect(moveButtonLeft.length).toBe(1);
|
||||
moveButtonLeft.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0);
|
||||
});
|
||||
|
||||
test('middle column is moveable to the right', () => {
|
||||
const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle');
|
||||
expect(moveButtonRight.length).toBe(1);
|
||||
moveButtonRight.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2);
|
||||
});
|
||||
|
||||
test('last column moveable to the left', () => {
|
||||
const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last');
|
||||
expect(moveButtonLeft.length).toBe(1);
|
||||
moveButtonLeft.simulate('click');
|
||||
expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { IndexPatternEnhanced } from 'ui/index_patterns/_index_pattern';
|
||||
// @ts-ignore
|
||||
import { shortenDottedString } from '../../../../../common/utils/shorten_dotted_string';
|
||||
import { TableHeaderColumn } from './table_header_column';
|
||||
import { SortOrder, getDisplayedColumns } from './helpers';
|
||||
|
||||
interface Props {
|
||||
columns: string[];
|
||||
hideTimeColumn: boolean;
|
||||
indexPattern: IndexPatternEnhanced;
|
||||
isShortDots: boolean;
|
||||
onChangeSortOrder: (name: string, direction: 'asc' | 'desc') => void;
|
||||
onMoveColumn: (name: string, index: number) => void;
|
||||
onRemoveColumn: (name: string) => void;
|
||||
sortOrder: SortOrder;
|
||||
}
|
||||
|
||||
export function TableHeader({
|
||||
columns,
|
||||
hideTimeColumn,
|
||||
indexPattern,
|
||||
isShortDots,
|
||||
onChangeSortOrder,
|
||||
onMoveColumn,
|
||||
onRemoveColumn,
|
||||
sortOrder,
|
||||
}: Props) {
|
||||
const displayedColumns = getDisplayedColumns(columns, indexPattern, hideTimeColumn, isShortDots);
|
||||
const [currColumnName, currDirection = 'asc'] = sortOrder;
|
||||
|
||||
return (
|
||||
<tr data-test-subj="docTableHeader" className="kbnDocTableHeader">
|
||||
<th style={{ width: '24px' }}></th>
|
||||
{displayedColumns.map(col => {
|
||||
return (
|
||||
<TableHeaderColumn
|
||||
key={col.name}
|
||||
{...col}
|
||||
sortDirection={col.name === currColumnName ? currDirection : ''}
|
||||
onMoveColumn={onMoveColumn}
|
||||
onRemoveColumn={onRemoveColumn}
|
||||
onChangeSortOrder={onChangeSortOrder}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { shortenDottedString } from '../../../../../common/utils/shorten_dotted_string';
|
||||
|
||||
interface Props {
|
||||
colLeftIdx: number; // idx of the column to the left, -1 if moving is not possible
|
||||
colRightIdx: number; // idx of the column to the right, -1 if moving is not possible
|
||||
displayName: string;
|
||||
isRemoveable: boolean;
|
||||
isSortable: boolean;
|
||||
name: string;
|
||||
onChangeSortOrder?: (name: string, direction: 'asc' | 'desc') => void;
|
||||
onMoveColumn?: (name: string, idx: number) => void;
|
||||
onRemoveColumn?: (name: string) => void;
|
||||
sortDirection: 'asc' | 'desc' | ''; // asc|desc -> field is sorted in this direction, else ''
|
||||
}
|
||||
|
||||
export function TableHeaderColumn({
|
||||
colLeftIdx,
|
||||
colRightIdx,
|
||||
displayName,
|
||||
isRemoveable,
|
||||
isSortable,
|
||||
name,
|
||||
onChangeSortOrder,
|
||||
onMoveColumn,
|
||||
onRemoveColumn,
|
||||
sortDirection,
|
||||
}: Props) {
|
||||
const btnSortIcon = sortDirection === 'desc' ? 'fa fa-sort-down' : 'fa fa-sort-up';
|
||||
const btnSortClassName =
|
||||
sortDirection !== '' ? btnSortIcon : `kbnDocTableHeader__sortChange ${btnSortIcon}`;
|
||||
|
||||
// action buttons displayed on the right side of the column name
|
||||
const buttons = [
|
||||
// Sort Button
|
||||
{
|
||||
active: isSortable,
|
||||
ariaLabel:
|
||||
sortDirection === 'asc'
|
||||
? i18n.translate('kbn.docTable.tableHeader.sortByColumnDescendingAriaLabel', {
|
||||
defaultMessage: 'Sort {columnName} descending',
|
||||
values: { columnName: name },
|
||||
})
|
||||
: i18n.translate('kbn.docTable.tableHeader.sortByColumnAscendingAriaLabel', {
|
||||
defaultMessage: 'Sort {columnName} ascending',
|
||||
values: { columnName: name },
|
||||
}),
|
||||
className: btnSortClassName,
|
||||
onClick: () => {
|
||||
/**
|
||||
* cycle sorting direction
|
||||
* asc -> desc, desc -> asc, default: asc
|
||||
*/
|
||||
if (typeof onChangeSortOrder === 'function') {
|
||||
const newDirection = sortDirection === 'asc' ? 'desc' : 'asc';
|
||||
onChangeSortOrder(name, newDirection);
|
||||
}
|
||||
},
|
||||
testSubject: `docTableHeaderFieldSort_${name}`,
|
||||
tooltip: i18n.translate('kbn.docTable.tableHeader.sortByColumnTooltip', {
|
||||
defaultMessage: 'Sort by {columnName}',
|
||||
values: { columnName: name },
|
||||
}),
|
||||
},
|
||||
// Remove Button
|
||||
{
|
||||
active: isRemoveable,
|
||||
ariaLabel: i18n.translate('kbn.docTable.tableHeader.removeColumnButtonAriaLabel', {
|
||||
defaultMessage: 'Remove {columnName} column',
|
||||
values: { columnName: name },
|
||||
}),
|
||||
className: 'fa fa-remove kbnDocTableHeader__move',
|
||||
onClick: () => onRemoveColumn && onRemoveColumn(name),
|
||||
testSubject: `docTableRemoveHeader-${name}`,
|
||||
tooltip: i18n.translate('kbn.docTable.tableHeader.removeColumnButtonTooltip', {
|
||||
defaultMessage: 'Remove Column',
|
||||
}),
|
||||
},
|
||||
// Move Left Button
|
||||
{
|
||||
active: colLeftIdx >= 0,
|
||||
ariaLabel: i18n.translate('kbn.docTable.tableHeader.moveColumnLeftButtonAriaLabel', {
|
||||
defaultMessage: 'Move {columnName} column to the left',
|
||||
values: { columnName: name },
|
||||
}),
|
||||
className: 'fa fa-angle-double-left kbnDocTableHeader__move',
|
||||
onClick: () => onMoveColumn && onMoveColumn(name, colLeftIdx),
|
||||
testSubject: `docTableMoveLeftHeader-${name}`,
|
||||
tooltip: i18n.translate('kbn.docTable.tableHeader.moveColumnLeftButtonTooltip', {
|
||||
defaultMessage: 'Move column to the left',
|
||||
}),
|
||||
},
|
||||
// Move Right Button
|
||||
{
|
||||
active: colRightIdx >= 0,
|
||||
ariaLabel: i18n.translate('kbn.docTable.tableHeader.moveColumnRightButtonAriaLabel', {
|
||||
defaultMessage: 'Move {columnName} column to the right',
|
||||
values: { columnName: name },
|
||||
}),
|
||||
className: 'fa fa-angle-double-right kbnDocTableHeader__move',
|
||||
onClick: () => onMoveColumn && onMoveColumn(name, colRightIdx),
|
||||
testSubject: `docTableMoveRightHeader-${name}`,
|
||||
tooltip: i18n.translate('kbn.docTable.tableHeader.moveColumnRightButtonTooltip', {
|
||||
defaultMessage: 'Move column to the right',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<th data-test-subj="docTableHeaderField">
|
||||
<span data-test-subj={`docTableHeader-${name}`}>
|
||||
{displayName}
|
||||
{buttons
|
||||
.filter(button => button.active)
|
||||
.map((button, idx) => (
|
||||
<EuiToolTip
|
||||
id={`docTableHeader-${name}-tt`}
|
||||
content={button.tooltip}
|
||||
key={`button-${idx}`}
|
||||
>
|
||||
<button
|
||||
aria-label={button.ariaLabel}
|
||||
className={button.className}
|
||||
data-test-subj={button.testSubject}
|
||||
onClick={button.onClick}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
))}
|
||||
</span>
|
||||
</th>
|
||||
);
|
||||
}
|
|
@ -34,6 +34,7 @@ export interface IndexPattern {
|
|||
// that currently depend on an interface without methods to succeed
|
||||
export interface IndexPatternEnhanced extends IndexPattern {
|
||||
isTimeNanosBased: () => boolean;
|
||||
getFieldByName: (name: string) => StaticIndexPatternField | undefined;
|
||||
}
|
||||
|
||||
export interface IndexPatternGetProvider {
|
||||
|
@ -45,6 +46,7 @@ export interface StaticIndexPatternField {
|
|||
type: string;
|
||||
aggregatable: boolean;
|
||||
searchable: boolean;
|
||||
sortable?: boolean;
|
||||
}
|
||||
|
||||
export interface StaticIndexPattern {
|
||||
|
|
|
@ -328,6 +328,11 @@ export class IndexPattern {
|
|||
return this.fields.byName[this.timeFieldName];
|
||||
}
|
||||
|
||||
getFieldByName(name) {
|
||||
if (!this.fields || !this.fields.byName) return;
|
||||
return this.fields.byName[name];
|
||||
}
|
||||
|
||||
isWildcard() {
|
||||
return _.includes(this.title, '*');
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ export default function () {
|
|||
this.isTimeBased = () => Boolean(this.timeFieldName);
|
||||
this.getNonScriptedFields = sinon.spy(IndexPattern.prototype.getNonScriptedFields);
|
||||
this.getScriptedFields = sinon.spy(IndexPattern.prototype.getScriptedFields);
|
||||
this.getFieldByName = sinon.spy(IndexPattern.prototype.getFieldByName);
|
||||
this.getSourceFiltering = sinon.stub();
|
||||
this.metaFields = ['_id', '_type', '_source'];
|
||||
this.fieldFormatMap = {};
|
||||
|
|
|
@ -1599,8 +1599,6 @@
|
|||
"kbn.docTable.tableHeader.sortByColumnAscendingAriaLabel": "{columnName} を昇順に並べ替える",
|
||||
"kbn.docTable.tableHeader.sortByColumnDescendingAriaLabel": "{columnName} を降順に並べ替える",
|
||||
"kbn.docTable.tableHeader.sortByColumnTooltip": "{columnName} で並べ替えます",
|
||||
"kbn.docTable.tableHeader.sortByTimeTooltip": "時間で並べ替えます",
|
||||
"kbn.docTable.tableHeader.timeHeaderCellTitle": "時間",
|
||||
"kbn.docTable.tableRow.detailHeading": "拡張ドキュメント",
|
||||
"kbn.docTable.tableRow.filterForValueButtonAriaLabel": "値でフィルタリング",
|
||||
"kbn.docTable.tableRow.filterForValueButtonTooltip": "値でフィルタリング",
|
||||
|
|
|
@ -1600,8 +1600,6 @@
|
|||
"kbn.docTable.tableHeader.sortByColumnAscendingAriaLabel": "升序排序 {columnName}",
|
||||
"kbn.docTable.tableHeader.sortByColumnDescendingAriaLabel": "降序排序 {columnName}",
|
||||
"kbn.docTable.tableHeader.sortByColumnTooltip": "按“{columnName}”排序",
|
||||
"kbn.docTable.tableHeader.sortByTimeTooltip": "按时间排序",
|
||||
"kbn.docTable.tableHeader.timeHeaderCellTitle": "时间",
|
||||
"kbn.docTable.tableRow.detailHeading": "已展开文档",
|
||||
"kbn.docTable.tableRow.filterForValueButtonAriaLabel": "筛留值",
|
||||
"kbn.docTable.tableRow.filterForValueButtonTooltip": "筛留值",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue