Update telemetry table for multisession (#2686)

* update telemetry table to ingest marked row data, add a new alterntate bar with includes row name, selected rows and show selected rows toggle

* Enhancements for alternate toolbar in telem tables

- .c-control-bar adds style enhancements and `__label` element;
- Added `label` prop, markup and styling to ToggleSwitch;
- ToggleSwitch layout enhanced;
- Unit tested in main view and placed in Display Layout;

* made improvements to row marking

* bug fixes for marking

* fix linting issues

* -Make reviewer requested changes
-Clarify prop for marking
-Include alternateControlBar in the marking prop
- - since it only makes sense for making

Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
This commit is contained in:
Deep Tailor 2020-02-27 10:27:58 -08:00 committed by GitHub
parent a0b7999ea2
commit 85902b878e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 184 additions and 53 deletions

View File

@ -47,6 +47,7 @@ define([
this.subscriptions = {}; this.subscriptions = {};
this.tableComposition = undefined; this.tableComposition = undefined;
this.telemetryObjects = []; this.telemetryObjects = [];
this.datumCache = [];
this.outstandingRequests = 0; this.outstandingRequests = 0;
this.configuration = new TelemetryTableConfiguration(domainObject, openmct); this.configuration = new TelemetryTableConfiguration(domainObject, openmct);
this.paused = false; this.paused = false;
@ -155,6 +156,7 @@ define([
processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator) { processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator) {
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator)); let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows); this.boundedRows.add(telemetryRows);
this.emit('historical-rows-processed');
} }
/** /**
@ -227,12 +229,28 @@ define([
return; return;
} }
if (!this.paused) { if (this.paused) {
let realtimeDatum = {
datum,
columnMap,
keyString,
limitEvaluator
};
this.datumCache.push(realtimeDatum);
} else {
this.processRealtimeDatum(datum, columnMap, keyString, limitEvaluator); this.processRealtimeDatum(datum, columnMap, keyString, limitEvaluator);
} }
}, subscribeOptions); }, subscribeOptions);
} }
processDatumCache() {
this.datumCache.forEach(cachedDatum => {
this.processRealtimeDatum(cachedDatum.datum, cachedDatum.columnMap, cachedDatum.keyString, cachedDatum.limitEvaluator);
});
this.datumCache = [];
}
processRealtimeDatum(datum, columnMap, keyString, limitEvaluator) { processRealtimeDatum(datum, columnMap, keyString, limitEvaluator) {
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator)); this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
} }
@ -272,8 +290,8 @@ define([
unpause() { unpause() {
this.paused = false; this.paused = false;
this.processDatumCache();
this.boundedRows.subscribeToBounds(); this.boundedRows.subscribeToBounds();
this.refreshData();
} }
destroy() { destroy() {

View File

@ -68,7 +68,7 @@ define([
table, table,
objectPath objectPath
}, },
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>' template: '<table-component :isEditing="isEditing" :marking="{enable: true}"/>'
}); });
}, },
onEditModeChange(editMode) { onEditModeChange(editMode) {
@ -86,7 +86,7 @@ define([
priority() { priority() {
return 1; return 1;
} }
} };
} }
return TelemetryTableViewProvider; return TelemetryTableViewProvider;
}); });

View File

@ -21,7 +21,10 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="c-table-wrapper"> <div class="c-table-wrapper">
<div class="c-table-control-bar c-control-bar"> <!-- main contolbar start-->
<div v-if="!marking.useAlternateControlBar"
class="c-table-control-bar c-control-bar"
>
<button <button
v-if="allowExport" v-if="allowExport"
class="c-button icon-download labeled" class="c-button icon-download labeled"
@ -48,11 +51,11 @@
<span class="c-button__label">Unmark All Rows</span> <span class="c-button__label">Unmark All Rows</span>
</button> </button>
<div <div
v-if="enableMarking" v-if="marking.enable"
class="c-separator" class="c-separator"
></div> ></div>
<button <button
v-if="enableMarking" v-if="marking.enable"
class="c-button icon-pause pause-play labeled" class="c-button icon-pause pause-play labeled"
:class=" paused ? 'icon-play is-paused' : 'icon-pause'" :class=" paused ? 'icon-play is-paused' : 'icon-pause'"
:title="paused ? 'Continue Data Flow' : 'Pause Data Flow'" :title="paused ? 'Continue Data Flow' : 'Pause Data Flow'"
@ -62,8 +65,37 @@
{{ paused ? 'Play' : 'Pause' }} {{ paused ? 'Play' : 'Pause' }}
</span> </span>
</button> </button>
<slot name="buttons"></slot> <slot name="buttons"></slot>
</div> </div>
<!-- main controlbar end -->
<!-- alternate controlbar start -->
<div v-if="marking.useAlternateControlBar && markedRows.length"
class="c-table-control-bar c-control-bar"
>
<div class="c-control-bar__label">
{{ markedRows.length > 1 ? `${markedRows.length} ${marking.rowNamePlural} selected`: `${markedRows.length} ${marking.rowName} selected` }}
</div>
<toggle-switch
id="show-filtered-rows-toggle"
label="Show selected items only"
:checked="isShowingMarkedRowsOnly"
@change="toggleMarkedRows"
/>
<button
class="c-button icon-x labeled"
title="Deselect All"
@click="unmarkAllRows()"
>
<span class="c-button__label">Deselect All</span>
</button>
<slot name="buttons"></slot>
</div>
<!-- alternate controlbar end -->
<div <div
class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar" class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
@ -205,6 +237,7 @@ import TableColumnHeader from './table-column-header.vue';
import TelemetryFilterIndicator from './TelemetryFilterIndicator.vue'; import TelemetryFilterIndicator from './TelemetryFilterIndicator.vue';
import CSVExporter from '../../../exporters/CSVExporter.js'; import CSVExporter from '../../../exporters/CSVExporter.js';
import _ from 'lodash'; import _ from 'lodash';
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
const VISIBLE_ROW_COUNT = 100; const VISIBLE_ROW_COUNT = 100;
const ROW_HEIGHT = 17; const ROW_HEIGHT = 17;
@ -216,7 +249,8 @@ export default {
TelemetryTableRow, TelemetryTableRow,
TableColumnHeader, TableColumnHeader,
search, search,
TelemetryFilterIndicator TelemetryFilterIndicator,
ToggleSwitch
}, },
inject: ['table', 'openmct', 'objectPath'], inject: ['table', 'openmct', 'objectPath'],
props: { props: {
@ -236,9 +270,16 @@ export default {
'type': Boolean, 'type': Boolean,
'default': true 'default': true
}, },
enableMarking: { marking: {
type: Boolean, type: Object,
default: false default() {
return {
enable: false,
useAlternateControlBar: false,
rowName: '',
rowNamePlural: ""
}
}
} }
}, },
data() { data() {
@ -270,7 +311,8 @@ export default {
scrollW: 0, scrollW: 0,
markCounter: 0, markCounter: 0,
paused: false, paused: false,
markedRows: [] markedRows: [],
isShowingMarkedRowsOnly: false
} }
}, },
computed: { computed: {
@ -317,6 +359,7 @@ export default {
this.table.on('object-removed', this.removeObject); this.table.on('object-removed', this.removeObject);
this.table.on('outstanding-requests', this.outstandingRequests); this.table.on('outstanding-requests', this.outstandingRequests);
this.table.on('refresh', this.clearRowsAndRerender); this.table.on('refresh', this.clearRowsAndRerender);
this.table.on('historical-rows-processed', this.checkForMarkedRows);
this.table.filteredRows.on('add', this.rowsAdded); this.table.filteredRows.on('add', this.rowsAdded);
this.table.filteredRows.on('remove', this.rowsRemoved); this.table.filteredRows.on('remove', this.rowsRemoved);
@ -631,18 +674,19 @@ export default {
}, },
unpause(unpausedByButton) { unpause(unpausedByButton) {
if (unpausedByButton) { if (unpausedByButton) {
this.paused = false; this.undoMarkedRows();
this.table.unpause(); this.table.unpause();
this.markedRows = []; this.paused = false;
this.pausedByButton = false; this.pausedByButton = false;
} else { } else {
if (!this.pausedByButton) { if (!this.pausedByButton) {
this.paused = false; this.undoMarkedRows();
this.table.unpause(); this.table.unpause();
this.markedRows = []; this.paused = false;
} }
} }
this.isShowingMarkedRowsOnly = false;
}, },
togglePauseByButton() { togglePauseByButton() {
if (this.paused) { if (this.paused) {
@ -655,24 +699,23 @@ export default {
this.markedRows.forEach(r => r.marked = false); this.markedRows.forEach(r => r.marked = false);
this.markedRows = []; this.markedRows = [];
}, },
unmarkRow(rowIndex, ctrlKeyModifier) { unmarkRow(rowIndex) {
if (ctrlKeyModifier) { if (this.markedRows.length > 1) {
let row = this.visibleRows[rowIndex], let row = this.visibleRows[rowIndex],
positionInMarkedArray = this.markedRows.indexOf(row); positionInMarkedArray = this.markedRows.indexOf(row);
row.marked = false; row.marked = false;
this.markedRows.splice(positionInMarkedArray, 1); this.markedRows.splice(positionInMarkedArray, 1);
} else if (this.markedRows.length === 1) {
this.unmarkAllRows();
}
if (this.markedRows.length === 0) { if (this.markedRows.length === 0) {
this.unpause(); this.unpause();
}
} else if (this.markedRows.length) {
this.undoMarkedRows();
this.markRow(rowIndex);
} }
}, },
markRow(rowIndex, keyModifier) { markRow(rowIndex, keyModifier) {
if (!this.enableMarking) { if (!this.marking.enable) {
return; return;
} }
@ -691,12 +734,13 @@ export default {
this.markedRows[insertMethod](markedRow); this.markedRows[insertMethod](markedRow);
}, },
unmarkAllRows(skipUnpause) { unmarkAllRows(skipUnpause) {
this.markedRows.forEach(row => row.marked = false); this.undoMarkedRows();
this.markedRows = []; this.isShowingMarkedRowsOnly = false;
this.unpause(); this.unpause();
this.restorePreviousRows();
}, },
markMultipleConcurrentRows(rowIndex) { markMultipleConcurrentRows(rowIndex) {
if (!this.enableMarking) { if (!this.marking.enable) {
return; return;
} }
@ -733,6 +777,34 @@ export default {
} }
} }
} }
},
checkForMarkedRows() {
this.markedRows = this.table.filteredRows.getRows().filter(row => row.marked);
},
showRows(rows) {
this.table.filteredRows.rows = rows;
this.table.filteredRows.emit('filter');
},
toggleMarkedRows(flag) {
if (flag) {
this.isShowingMarkedRowsOnly = true;
this.userScroll = this.scrollable.scrollTop;
this.allRows = this.table.filteredRows.getRows();
this.showRows(this.markedRows);
this.setHeight();
} else {
this.isShowingMarkedRowsOnly = false;
this.restorePreviousRows();
}
},
restorePreviousRows() {
if (this.allRows && this.allRows.length) {
this.showRows(this.allRows);
this.allRows = [];
this.setHeight();
this.scrollable.scrollTop = this.userScroll;
}
} }
} }
} }

View File

@ -28,6 +28,16 @@
height: $controlBarH; height: $controlBarH;
} }
.c-control-bar {
display: flex;
align-items: center;
&__label {
display: inline-block;
white-space: nowrap;
}
}
.l-view-section { .l-view-section {
@include abs(); @include abs();
overflow: auto; overflow: auto;

View File

@ -1,16 +1,25 @@
<template> <template>
<label class="c-toggle-switch"> <div class="c-toggle-switch">
<input <label class="c-toggle-switch__control">
:id="id" <input
type="checkbox" :id="id"
:checked="checked" type="checkbox"
@change="onUserSelect($event)" :checked="checked"
@change="onUserSelect($event)"
>
<span class="c-toggle-switch__slider"></span>
</label>
<div
v-if="label && label.length"
class="c-toggle-switch__label"
> >
<span class="c-toggle-switch__slider"></span> {{ label }}
</label> </div>
</div>
</template> </template>
<script> <script>
export default { export default {
inject: ['openmct'], inject: ['openmct'],
props: { props: {
@ -18,6 +27,11 @@ export default {
type: String, type: String,
required: true required: true
}, },
label: {
type: String,
required: false,
default: ''
},
checked: Boolean checked: Boolean
}, },
methods: { methods: {
@ -26,4 +40,5 @@ export default {
} }
} }
} }
</script> </script>

View File

@ -2,15 +2,40 @@
$d: 12px; $d: 12px;
$m: 2px; $m: 2px;
$br: $d/1.5; $br: $d/1.5;
cursor: pointer; display: inline-flex;
overflow: hidden; align-items: center;
display: inline;
vertical-align: middle; vertical-align: middle;
&__control,
&__label {
flex: 0 0 auto;
}
&__control {
cursor: pointer;
overflow: hidden;
display: block;
}
input {
opacity: 0;
width: 0;
height: 0;
&:checked {
+ .c-toggle-switch__slider {
background: $colorKey; // TODO: make discrete theme constants for these colors
&:before {
transform: translateX(100%);
}
}
}
}
&__slider { &__slider {
// Sits within __switch
background: $colorBtnBg; // TODO: make discrete theme constants for these colors background: $colorBtnBg; // TODO: make discrete theme constants for these colors
border-radius: $br; border-radius: $br;
//box-shadow: inset rgba($colorBtnFg, 0.4) 0 0 0 1px;
display: inline-block; display: inline-block;
height: $d + ($m*2); height: $d + ($m*2);
position: relative; position: relative;
@ -31,18 +56,9 @@
} }
} }
input { &__label {
opacity: 0; margin-left: $interiorMarginSm;
width: 0; margin-right: $interiorMargin;
height: 0; white-space: nowrap;
&:checked {
+ .c-toggle-switch__slider {
background: $colorKey; // TODO: make discrete theme constants for these colors
&:before {
transform: translateX(100%);
}
}
}
} }
} }