From 362e565a090c9c3185b1f55ca50911bf4b47b82f Mon Sep 17 00:00:00 2001 From: Deep Tailor Date: Thu, 11 Jul 2019 16:40:26 -0700 Subject: [PATCH] Global and Local Clear (#2418) * first proto of global clear, working on tables * global clear works on plots * styling * Status bar migration to top of layout, WIP - Refine and remove legacy styles for Indicators; - Significant cleanup in Indicator markup; - Remove unnecessary wrapper component StatusBar.vue; - Move collapse-button styles to a more general location in _controls .scss; - New hasMenu mixin to allow easier application of disclosure control styling; * Status bar migration to top of layout, WIP - Refine styles and markup for Indicators; - Better separation of styles for clickable and non-clickable Indicators; * Status bar migration to top of layout, WIP - Added tracking style to indicator-template; - Moved click action to button in label of globalClearIndicator; - Removed unnecessary markup in Indicators.vue; - Commented out __head collapse button for now in Layout.vue; * Status Bar Migration WIP - Significant progress styling Indicators and their hover bubbles; - Pull back from clickable Indicators to hover approach; - Better theme-based constants for Indicator menu-related colors; * Status Bar Migration WIP - Significant refactor of label element naming in multiple indicator markup files; - Refactor label-related CSS; - Better class naming: no-collapse > no-minify; - Refactor example *-launch files to use buttons instead of tags; - Significant progress on expanding shell head and button styling; * Status Bar Migration WIP - Cleanups, sanding on Indicator CSS; - Added local storage retention for head expanded state; - Adjust dark theme colors for $colorWarningHi for better legibility; - Other minor tweaks and fixes; * Status Bar Migration WIP - Suppress background in Indicators; - Restore Snow as default theme; * add a local clear action, rename plugin * objectViews extends eventemitter, table view provider provides an onClearData function that is called from ObjectView when clear event is emitted. TODO - support plots * add support for plots via legacy view provider * add test for clearDataAction * remove focus from test file * install the following plugins by default: Import Export Folder View Tabs View Flexible Layout LAD Table Go To Original Action * update test to include plugin level tests * remove focus from unit test --- example/notifications/res/dialog-launch.html | 10 +- .../res/notification-launch.html | 10 +- index.html | 7 +- .../res/templates/angular-indicator.html | 4 +- .../res/notification-indicator.html | 10 +- .../clock/src/indicators/ClockIndicator.js | 2 +- .../persistence/couch/src/CouchIndicator.js | 2 +- .../elastic/src/ElasticIndicator.js | 2 +- .../local/src/LocalStorageIndicator.js | 2 +- src/MCT.js | 9 ++ src/adapter/views/LegacyViewProvider.js | 3 + src/api/indicators/SimpleIndicator.js | 2 +- .../indicators/res/indicator-template.html | 4 +- .../overlays/components/DialogComponent.vue | 2 +- src/plugins/clearData/clearDataAction.js | 39 +++++ .../components/globalClearIndicator.vue | 18 +++ src/plugins/clearData/plugin.js | 54 +++++++ .../clearData/test/clearDataActionSpec.js | 62 ++++++++ .../plot/src/configuration/PlotSeries.js | 13 ++ .../plot/src/telemetry/PlotController.js | 10 ++ src/plugins/plugins.js | 7 +- src/plugins/telemetryTable/TelemetryTable.js | 2 + .../TelemetryTableViewProvider.js | 3 + src/styles-new/_constants-espresso.scss | 12 +- src/styles-new/_constants-maelstrom.scss | 12 +- src/styles-new/_constants-snow.scss | 8 +- src/styles-new/_controls.scss | 25 ++-- src/styles-new/_legacy.scss | 120 ---------------- src/styles-new/_mixins.scss | 37 +++-- src/styles-new/_status.scss | 4 +- src/ui/components/ObjectView.vue | 20 +++ src/ui/layout/Layout.vue | 108 +++++++++++--- src/ui/layout/pane.vue | 15 -- src/ui/layout/status-bar/Indicators.vue | 136 +++++++++++++++++- .../layout/status-bar/NotificationBanner.vue | 9 +- src/ui/layout/status-bar/StatusBar.vue | 42 ------ src/ui/registries/ViewRegistry.js | 5 +- 37 files changed, 550 insertions(+), 280 deletions(-) create mode 100644 src/plugins/clearData/clearDataAction.js create mode 100644 src/plugins/clearData/components/globalClearIndicator.vue create mode 100644 src/plugins/clearData/plugin.js create mode 100644 src/plugins/clearData/test/clearDataActionSpec.js delete mode 100644 src/ui/layout/status-bar/StatusBar.vue diff --git a/example/notifications/res/dialog-launch.html b/example/notifications/res/dialog-launch.html index 92372f2970..f6b33d7b7c 100644 --- a/example/notifications/res/dialog-launch.html +++ b/example/notifications/res/dialog-launch.html @@ -1,9 +1,9 @@ -
- Known - Unknown - Error - Info +
+ + + +
diff --git a/example/notifications/res/notification-launch.html b/example/notifications/res/notification-launch.html index 25d48ef529..11c66566e8 100644 --- a/example/notifications/res/notification-launch.html +++ b/example/notifications/res/notification-launch.html @@ -1,9 +1,9 @@ -
- Success - Error - Alert - Progress +
+ + + +
diff --git a/index.html b/index.html index 4d775353bb..d6eb192f89 100644 --- a/index.html +++ b/index.html @@ -50,7 +50,6 @@ openmct.install(openmct.plugins.Generator()); openmct.install(openmct.plugins.ExampleImagery()); openmct.install(openmct.plugins.UTCTimeSystem()); - openmct.install(openmct.plugins.ImportExport()); openmct.install(openmct.plugins.AutoflowView({ type: "telemetry.panel" })); @@ -80,13 +79,9 @@ })); openmct.install(openmct.plugins.SummaryWidget()); openmct.install(openmct.plugins.Notebook()); - openmct.install(openmct.plugins.FolderView()); - openmct.install(openmct.plugins.Tabs()); - openmct.install(openmct.plugins.FlexibleLayout()); - openmct.install(openmct.plugins.LADTable()); openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay'])); openmct.install(openmct.plugins.ObjectMigration()); - openmct.install(openmct.plugins.GoToOriginalAction()); + openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'])); openmct.start(); diff --git a/platform/commonUI/general/res/templates/angular-indicator.html b/platform/commonUI/general/res/templates/angular-indicator.html index e1f4a74521..8c796d99f9 100644 --- a/platform/commonUI/general/res/templates/angular-indicator.html +++ b/platform/commonUI/general/res/templates/angular-indicator.html @@ -20,8 +20,8 @@ at runtime from the About dialog for additional information. --> -
- {{ngModel.getText()}} + {{ngModel.getText()}}
diff --git a/platform/commonUI/notification/res/notification-indicator.html b/platform/commonUI/notification/res/notification-indicator.html index 20bc3eb0f4..75ec9be553 100644 --- a/platform/commonUI/notification/res/notification-indicator.html +++ b/platform/commonUI/notification/res/notification-indicator.html @@ -1,8 +1,8 @@ -
- - - {{notifications.length}} Notifications - {{notifications.length}} + + + {{notifications.length}}
diff --git a/platform/features/clock/src/indicators/ClockIndicator.js b/platform/features/clock/src/indicators/ClockIndicator.js index be9a296ce6..79520bd337 100644 --- a/platform/features/clock/src/indicators/ClockIndicator.js +++ b/platform/features/clock/src/indicators/ClockIndicator.js @@ -49,7 +49,7 @@ define( }; ClockIndicator.prototype.getCssClass = function () { - return "t-indicator-clock icon-clock no-collapse float-right"; + return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable"; }; ClockIndicator.prototype.getText = function () { diff --git a/platform/persistence/couch/src/CouchIndicator.js b/platform/persistence/couch/src/CouchIndicator.js index 250d3a9878..f2f5d739b9 100644 --- a/platform/persistence/couch/src/CouchIndicator.js +++ b/platform/persistence/couch/src/CouchIndicator.js @@ -100,7 +100,7 @@ define( } CouchIndicator.prototype.getCssClass = function () { - return "icon-database " + this.state.statusClass; + return "c-indicator--clickable icon-database " + this.state.statusClass; }; CouchIndicator.prototype.getGlyphClass = function () { diff --git a/platform/persistence/elastic/src/ElasticIndicator.js b/platform/persistence/elastic/src/ElasticIndicator.js index 2ec920eee3..ae46883930 100644 --- a/platform/persistence/elastic/src/ElasticIndicator.js +++ b/platform/persistence/elastic/src/ElasticIndicator.js @@ -84,7 +84,7 @@ define( } ElasticIndicator.prototype.getCssClass = function () { - return "icon-database"; + return "c-indicator--clickable icon-database"; }; ElasticIndicator.prototype.getGlyphClass = function () { return this.state.glyphClass; diff --git a/platform/persistence/local/src/LocalStorageIndicator.js b/platform/persistence/local/src/LocalStorageIndicator.js index 02468e2805..da291762af 100644 --- a/platform/persistence/local/src/LocalStorageIndicator.js +++ b/platform/persistence/local/src/LocalStorageIndicator.js @@ -41,7 +41,7 @@ define( } LocalStorageIndicator.prototype.getCssClass = function () { - return "icon-database s-status-caution"; + return "c-indicator--clickable icon-database s-status-caution"; }; LocalStorageIndicator.prototype.getGlyphClass = function () { return 'caution'; diff --git a/src/MCT.js b/src/MCT.js index cdf93e46e4..eb0574e7ad 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -246,12 +246,21 @@ define([ this.branding = BrandingAPI.default; this.legacyRegistry = defaultRegistry; + + // Plugin's that are installed by default + this.install(this.plugins.Plot()); this.install(this.plugins.TelemetryTable()); this.install(PreviewPlugin.default()); this.install(LegacyIndicatorsPlugin()); this.install(LicensesPlugin.default()); this.install(RemoveActionPlugin.default()); + this.install(this.plugins.ImportExport()); + this.install(this.plugins.FolderView()); + this.install(this.plugins.Tabs()); + this.install(this.plugins.FlexibleLayout()); + this.install(this.plugins.LADTable()); + this.install(this.plugins.GoToOriginalAction()); if (typeof BUILD_CONSTANTS !== 'undefined') { this.install(buildInfoPlugin(BUILD_CONSTANTS)); diff --git a/src/adapter/views/LegacyViewProvider.js b/src/adapter/views/LegacyViewProvider.js index 78727c8c04..96ca51235d 100644 --- a/src/adapter/views/LegacyViewProvider.js +++ b/src/adapter/views/LegacyViewProvider.js @@ -108,6 +108,9 @@ define([ link(); } }, + onClearData() { + scope.$broadcast('clearData'); + }, destroy: function () { element.off(); element.remove(); diff --git a/src/api/indicators/SimpleIndicator.js b/src/api/indicators/SimpleIndicator.js index 742c5da620..37ba1a6739 100644 --- a/src/api/indicators/SimpleIndicator.js +++ b/src/api/indicators/SimpleIndicator.js @@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'], this.openmct = openmct; this.element = $(indicatorTemplate)[0]; - this.textElement = this.element.querySelector('.indicator-text'); + this.textElement = this.element.querySelector('.js-indicator-text'); //Set defaults this.text('New Indicator'); diff --git a/src/api/indicators/res/indicator-template.html b/src/api/indicators/res/indicator-template.html index 348a176a4e..fc0fb5dd9f 100644 --- a/src/api/indicators/res/indicator-template.html +++ b/src/api/indicators/res/indicator-template.html @@ -1,3 +1,3 @@ -
- +
+
diff --git a/src/api/overlays/components/DialogComponent.vue b/src/api/overlays/components/DialogComponent.vue index 4ae1a77fda..eb75005f21 100644 --- a/src/api/overlays/components/DialogComponent.vue +++ b/src/api/overlays/components/DialogComponent.vue @@ -93,7 +93,7 @@ &.message-severity-error:before { @include legacyMessage(); content: $glyph-icon-alert-triangle; - color: $colorWarningLo; + color: $colorWarningHi; } // Messages in a list diff --git a/src/plugins/clearData/clearDataAction.js b/src/plugins/clearData/clearDataAction.js new file mode 100644 index 0000000000..89a400c7f7 --- /dev/null +++ b/src/plugins/clearData/clearDataAction.js @@ -0,0 +1,39 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export default class ClearDataAction { + constructor(openmct, appliesToObjects) { + this.name = 'Clear Data'; + this.description = 'Clears current data for object, unsubscribes and resubscribes to data'; + + this._openmct = openmct; + this._appliesToObjects = appliesToObjects; + } + invoke(objectPath) { + this._openmct.objectViews.emit('clearData', objectPath[0]); + } + appliesTo(objectPath) { + let contextualDomainObject = objectPath[0]; + + return this._appliesToObjects.filter(type => contextualDomainObject.type === type).length; + } +} diff --git a/src/plugins/clearData/components/globalClearIndicator.vue b/src/plugins/clearData/components/globalClearIndicator.vue new file mode 100644 index 0000000000..323f7933cb --- /dev/null +++ b/src/plugins/clearData/components/globalClearIndicator.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/plugins/clearData/plugin.js b/src/plugins/clearData/plugin.js new file mode 100644 index 0000000000..d4a6689cdc --- /dev/null +++ b/src/plugins/clearData/plugin.js @@ -0,0 +1,54 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2019, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([ + './components/globalClearIndicator.vue', + './clearDataAction', + 'vue' +], function ( + GlobaClearIndicator, + ClearDataAction, + Vue +) { + return function plugin(appliesToObjects) { + appliesToObjects = appliesToObjects || []; + + return function install(openmct) { + let component = new Vue ({ + provide: { + openmct + }, + components: { + GlobalClearIndicator: GlobaClearIndicator.default + }, + template: '' + }), + indicator = { + element: component.$mount().$el + }; + + openmct.indicators.add(indicator); + + openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects)); + }; + }; +}); diff --git a/src/plugins/clearData/test/clearDataActionSpec.js b/src/plugins/clearData/test/clearDataActionSpec.js new file mode 100644 index 0000000000..553aa28e43 --- /dev/null +++ b/src/plugins/clearData/test/clearDataActionSpec.js @@ -0,0 +1,62 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import ClearDataActionPlugin from '../plugin.js'; +import ClearDataAction from '../clearDataAction.js'; + +describe('When the Clear Data Plugin is installed,', function () { + var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']), + mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']), + mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']), + openmct = { + objectViews: mockObjectViews, + indicators: mockIndicatorProvider, + contextMenu: mockContextMenuProvider, + install: function (plugin) { + plugin(this); + } + }, + mockObjectPath = [ + {name: 'mockObject1'}, + {name: 'mockObject2'} + ]; + + it('Global Clear Indicator is installed', function () { + openmct.install(ClearDataActionPlugin([])); + + expect(mockIndicatorProvider.add).toHaveBeenCalled(); + }); + + it('Clear Data context menu action is installed', function () { + openmct.install(ClearDataActionPlugin([])); + + expect(mockContextMenuProvider.registerAction).toHaveBeenCalled(); + }); + + it('clear data action emits a clearData event when invoked', function () { + let action = new ClearDataAction(openmct); + + action.invoke(mockObjectPath); + + expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]); + }); +}); diff --git a/src/plugins/plot/src/configuration/PlotSeries.js b/src/plugins/plot/src/configuration/PlotSeries.js index 0fe8132d05..9430d2a18e 100644 --- a/src/plugins/plot/src/configuration/PlotSeries.js +++ b/src/plugins/plot/src/configuration/PlotSeries.js @@ -377,6 +377,19 @@ define([ delete this.unsubscribe; } this.fetch(); + }, + + /** + * Clears the plot series, unsubscribes and resubscribes + * @public + */ + refresh: function () { + this.reset(); + if (this.unsubscribe) { + this.unsubscribe(); + delete this.unsubscribe; + } + this.fetch(); } }); diff --git a/src/plugins/plot/src/telemetry/PlotController.js b/src/plugins/plot/src/telemetry/PlotController.js index cd8e5fa1fd..eabd9aa2fe 100644 --- a/src/plugins/plot/src/telemetry/PlotController.js +++ b/src/plugins/plot/src/telemetry/PlotController.js @@ -63,8 +63,11 @@ define([ $scope.pending = 0; + this.clearData = this.clearData.bind(this); + this.listenTo($scope, 'user:viewport:change:end', this.onUserViewportChangeEnd, this); this.listenTo($scope, '$destroy', this.destroy, this); + this.listenTo($scope, 'clearData', this.clearData); this.config = this.getConfig(this.$scope.domainObject); this.listenTo(this.config.series, 'add', this.addSeries, this); @@ -74,6 +77,7 @@ define([ this.followTimeConductor(); this.newStyleDomainObject = $scope.domainObject.useCapability('adapter'); + this.keyString = this.openmct.objects.makeKeyString(this.newStyleDomainObject.identifier); this.filterObserver = this.openmct.objects.observe( this.newStyleDomainObject, @@ -263,6 +267,12 @@ define([ }); }; + PlotController.prototype.clearData = function () { + this.config.series.forEach(function (series) { + series.refresh(); + }); + }; + /** * Export view as JPG. */ diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index d9dca226b5..288c57f045 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -43,7 +43,8 @@ define([ './LADTable/plugin', './filters/plugin', './objectMigration/plugin', - './goToOriginalAction/plugin' + './goToOriginalAction/plugin', + './clearData/plugin' ], function ( _, UTCTimeSystem, @@ -67,7 +68,8 @@ define([ LADTable, Filters, ObjectMigration, - GoToOriginalAction + GoToOriginalAction, + ClearData ) { var bundleMap = { LocalStorage: 'platform/persistence/local', @@ -166,6 +168,7 @@ define([ plugins.Filters = Filters; plugins.ObjectMigration = ObjectMigration.default; plugins.GoToOriginalAction = GoToOriginalAction.default; + plugins.ClearData = ClearData; return plugins; }); diff --git a/src/plugins/telemetryTable/TelemetryTable.js b/src/plugins/telemetryTable/TelemetryTable.js index 9418f94f4a..cbeebe2f12 100644 --- a/src/plugins/telemetryTable/TelemetryTable.js +++ b/src/plugins/telemetryTable/TelemetryTable.js @@ -49,6 +49,7 @@ define([ this.telemetryObjects = []; this.outstandingRequests = 0; this.configuration = new TelemetryTableConfiguration(domainObject, openmct); + this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.addTelemetryObject = this.addTelemetryObject.bind(this); this.removeTelemetryObject = this.removeTelemetryObject.bind(this); @@ -260,6 +261,7 @@ define([ Object.keys(this.subscriptions).forEach(this.unsubscribe, this); this.openmct.time.off('bounds', this.refreshData); this.openmct.time.off('timeSystem', this.refreshData); + if (this.filterObserver) { this.filterObserver(); } diff --git a/src/plugins/telemetryTable/TelemetryTableViewProvider.js b/src/plugins/telemetryTable/TelemetryTableViewProvider.js index 76be4be39a..b5b3238932 100644 --- a/src/plugins/telemetryTable/TelemetryTableViewProvider.js +++ b/src/plugins/telemetryTable/TelemetryTableViewProvider.js @@ -73,6 +73,9 @@ define([ onEditModeChange(isEditing) { component.isEditing = isEditing; }, + onClearData() { + table.refreshData(); + }, destroy: function (element) { component.$destroy(); component = undefined; diff --git a/src/styles-new/_constants-espresso.scss b/src/styles-new/_constants-espresso.scss index 666a705111..058ed6db85 100644 --- a/src/styles-new/_constants-espresso.scss +++ b/src/styles-new/_constants-espresso.scss @@ -70,9 +70,6 @@ $colorBodyFgEm: #fff; $colorGenBg: #222; $colorHeadBg: #262626; $colorHeadFg: $colorBodyFg; -$colorStatusBarBg: $colorHeadBg; -$colorStatusBarFg: $colorBodyFg; -$colorStatusBarFgHov: #aaa; $colorKey: #0099cc; $colorKeyFg: #fff; $colorKeyHov: #26d8ff; @@ -105,8 +102,8 @@ $colorStatusPartialBg: #3f5e8b; $colorStatusCompleteBg: #457638; $colorAlert: #ff3c00; $colorAlertFg: #fff; -$colorWarningHi: #990000; -$colorWarningHiFg: #FF9594; +$colorWarningHi: #ff0000; +$colorWarningHiFg: #ffdad0; $colorWarningLo: #ff9900; $colorWarningLoFg: #523400; $colorDiagnostic: #a4b442; @@ -281,6 +278,11 @@ $colorIndicatorAvailable: $colorKey; $colorIndicatorDisabled: #555555; $colorIndicatorOn: $colorOk; $colorIndicatorOff: #777777; +$colorIndicatorBgHov: rgba($colorHeadFg, 0.1); +$colorIndicatorMenuBg: $colorHeadBg; +$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px; +$colorIndicatorMenuFg: $colorHeadFg; +$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%); // Staleness $colorTelemFresh: pullForward($colorBodyFg, 20%); diff --git a/src/styles-new/_constants-maelstrom.scss b/src/styles-new/_constants-maelstrom.scss index 5278ca76ef..15a0c968f8 100644 --- a/src/styles-new/_constants-maelstrom.scss +++ b/src/styles-new/_constants-maelstrom.scss @@ -74,9 +74,6 @@ $colorBodyFgEm: #fff; $colorGenBg: #222; $colorHeadBg: #262626; $colorHeadFg: $colorBodyFg; -$colorStatusBarBg: $colorHeadBg; -$colorStatusBarFg: $colorBodyFg; -$colorStatusBarFgHov: #aaa; $colorKey: #0099cc; $colorKeyFg: #fff; $colorKeyHov: #26d8ff; @@ -109,8 +106,8 @@ $colorStatusPartialBg: #3f5e8b; $colorStatusCompleteBg: #457638; $colorAlert: #ff3c00; $colorAlertFg: #fff; -$colorWarningHi: #990000; -$colorWarningHiFg: #FF9594; +$colorWarningHi: #ff0000; +$colorWarningHiFg: #ffdad0; $colorWarningLo: #ff9900; $colorWarningLoFg: #523400; $colorDiagnostic: #a4b442; @@ -285,6 +282,11 @@ $colorIndicatorAvailable: $colorKey; $colorIndicatorDisabled: #555555; $colorIndicatorOn: $colorOk; $colorIndicatorOff: #777777; +$colorIndicatorBgHov: rgba($colorHeadFg, 0.1); +$colorIndicatorMenuBg: $colorHeadBg; +$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px; +$colorIndicatorMenuFg: $colorHeadFg; +$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%); // Staleness $colorTelemFresh: pullForward($colorBodyFg, 20%); diff --git a/src/styles-new/_constants-snow.scss b/src/styles-new/_constants-snow.scss index 3496c59a27..4dba67fe3c 100644 --- a/src/styles-new/_constants-snow.scss +++ b/src/styles-new/_constants-snow.scss @@ -70,9 +70,6 @@ $colorBodyFgEm: #333; $colorGenBg: #fff; $colorHeadBg: #eee; $colorHeadFg: $colorBodyFg; -$colorStatusBarBg: #000; -$colorStatusBarFg: #999; -$colorStatusBarFgHov: #aaa; $colorKey: #0099cc; $colorKeyFg: #fff; $colorKeyHov: #00c0f6; @@ -281,6 +278,11 @@ $colorIndicatorAvailable: $colorKey; $colorIndicatorDisabled: #444; $colorIndicatorOn: $colorOk; $colorIndicatorOff: #666; +$colorIndicatorBgHov: rgba($colorHeadFg, 0.1); +$colorIndicatorMenuBg: white; +$colorIndicatorMenuBgShdw: rgba(black, 0.6) 0 0 6px; +$colorIndicatorMenuFg: $colorHeadFg; +$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%); // Staleness $colorTelemFresh: pullForward($colorBodyFg, 20%); diff --git a/src/styles-new/_controls.scss b/src/styles-new/_controls.scss index 66fcc8c73a..56ec647fb9 100644 --- a/src/styles-new/_controls.scss +++ b/src/styles-new/_controls.scss @@ -49,6 +49,21 @@ button { } } + &[class*='__collapse-button'] { + box-shadow: none; + background: $splitterBtnColorBg; + color: $splitterBtnColorFg; + border-radius: $smallCr; + font-size: 6px; + line-height: 90%; + padding: 3px 15px; + + @include hover() { + background: $colorBtnBgHov; + color: $colorBtnFgHov; + } + } + &.is-active { background: $colorBtnActiveBg; color: $colorBtnActiveFg; @@ -76,13 +91,7 @@ button { @include cClickIconButton(); &--menu { - &:after { - content: $glyph-icon-arrow-down; - font-family: symbolsfont; - font-size: 0.7em; - margin-left: floor($interiorMarginSm * 0.8); - opacity: 0.5; - } + @include hasMenu(); } } @@ -132,7 +141,7 @@ button { /******************************************************** DISCLOSURE CONTROLS */ /********* Disclosure Button */ -// Provides a downward arrow icon that when clicked displays a context menu +// Provides a downward arrow icon that when clicked displays additional options and/or info. // Always placed AFTER an element .c-disclosure-button { @include cClickIcon(); diff --git a/src/styles-new/_legacy.scss b/src/styles-new/_legacy.scss index a04e6356d1..455a64c013 100644 --- a/src/styles-new/_legacy.scss +++ b/src/styles-new/_legacy.scss @@ -782,126 +782,6 @@ mct-indicators mct-include { display: contents; } -.ls-indicator { - $bg: rgba(white, 0.2) !important; - $hbg: $colorStatusBarBg; - $hshdw: rgba(white, 0.4) 0 0 3px; - $br: $controlCr; - $hoverYOffset: -35px; - background: transparent !important; - border-radius: $br; - display: inline-block; - position: relative; - padding: 1px $interiorMarginSm; // Use padding instead of margin to keep hover chatter to a minimum - text-transform: uppercase; - - &:before { - display: inline-block; - } - - .label { - // Hover bubbles that appear when hovering on an Indicator - display: inline-block; - - a, - button, - s-button, - .c-button { - // Make in label look like buttons - transition: $transIn; - background: transparent; - border: 1px solid rgba($colorStatusBarFg, 0.5); - border-radius: $br; - box-sizing: border-box; - color: inherit; - font-size: inherit; - height: auto; - line-height: normal; - padding: 0 2px; - &:hover { - background: $bg; - color: #fff; - } - } - - [class*='icon-'] { - // If any elements within label include the class 'icon-*' then deal with their :before's - &:before { - font-size: 0.8em; - margin-right: $interiorMarginSm; - } - } - } - - &.no-collapse { - display: flex; - flex-flow: row nowrap; - align-items: center; - - > *, - &:before { - flex: 1 1 auto; - } - - &:before { - margin-right: $interiorMarginSm; - } - } - - &:not(.no-collapse) { - &:before { - margin-right: 0 !important; - } - - .label { - transition: all 250ms ease-in 100ms; - background: $hbg; - border-radius: $br; - font-size: .6rem; - left: 0; - bottom: 140%; - opacity: 0; - padding: $interiorMarginSm $interiorMargin; - position: absolute; - transform-origin: 10px 100%; - transform: scale(0.0); - white-space: nowrap; - z-index: 50; - - &:before { - // Infobubble-style arrow element - content: ''; - display: block; - position: absolute; - top: 100%; - @include triangle('down', $size: 4px, $ratio: 1, $color: $hbg); - } - } - - @include hover() { - background: $bg; - - .label { - opacity: 1; - transform: scale(1.0); - transition: all 100ms ease-out 0s; - } - } - } - - &.float-right { - float: right; - } -} - -/* Mobile */ -// Hide the clock indicator when we're phone portrait -body.phone.portrait { - .ls-indicator.t-indicator-clock { - display: none; - } -} - /************************************************* DATETIME UI */ @mixin complexFieldHolder($myW) { width: $myW + $interiorMargin; diff --git a/src/styles-new/_mixins.scss b/src/styles-new/_mixins.scss index 2212ef1802..9ab5a83e95 100644 --- a/src/styles-new/_mixins.scss +++ b/src/styles-new/_mixins.scss @@ -420,20 +420,9 @@ } } -@mixin cClickIconButton() { - // A clickable element that just includes the icon - // Background is displayed on hover - // Padding is included to facilitate a bigger hit area - // Make the icon bigger relative to its container +@mixin cClickIconButtonLayout() { $pLR: 4px; $pTB: 4px; - - @include cControl(); - background: none; - box-shadow: none; - cursor: pointer; - transition: $transOut; - border-radius: $controlCr; padding: $pTB $pLR; &:before, @@ -442,6 +431,20 @@ // Needed for c-togglebutton. font-size: 1.25em; } +} + +@mixin cClickIconButton() { + // A clickable element that just includes the icon + // Background is displayed on hover + // Padding is included to facilitate a bigger hit area + // Make the icon bigger relative to its container + @include cControl(); + @include cClickIconButtonLayout(); + background: none; + box-shadow: none; + cursor: pointer; + transition: $transOut; + border-radius: $controlCr; @include hover() { transition: $transIn; @@ -478,6 +481,16 @@ } } +@mixin hasMenu() { + &:after { + content: $glyph-icon-arrow-down; + font-family: symbolsfont; + font-size: 0.7em; + margin-left: floor($interiorMarginSm * 0.8); + opacity: 0.5; + } +} + @mixin cSelect($bg, $fg, $arwClr, $shdw) { $svgArwClr: str-slice(inspect($arwClr), 2, str-length(inspect($arwClr))); // Remove initial # in color value background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{$svgArwClr}' d='M5 5l5-5H0z'/%3e%3c/svg%3e"), $bg; diff --git a/src/styles-new/_status.scss b/src/styles-new/_status.scss index 3532434fa7..df1bb7995c 100644 --- a/src/styles-new/_status.scss +++ b/src/styles-new/_status.scss @@ -61,7 +61,7 @@ } @mixin indicatorStatusColors($c) { - &:before, .count { + &:before, .c-indicator__count { color: $c; } } @@ -127,7 +127,7 @@ tr { .s-status-icon-ok:before { content: $glyph-icon-check; } /*************************************************** INDICATOR COLORING */ -.ls-indicator { +.c-indicator { &.s-status-info { @include indicatorStatusColors($colorInfo); } diff --git a/src/ui/components/ObjectView.vue b/src/ui/components/ObjectView.vue index ebe07fbb64..3ef8bce506 100644 --- a/src/ui/components/ObjectView.vue +++ b/src/ui/components/ObjectView.vue @@ -61,6 +61,8 @@ export default { if (this.composition) { this.composition._destroy(); } + + this.openmct.objectViews.off('clearData', this.clearData); }, invokeEditModeHandler(editMode) { this.currentView.onEditModeChange(editMode); @@ -112,6 +114,8 @@ export default { this.removeSelectable = openmct.selection.selectable( this.$el, this.getSelectionContext(), true); } + + this.openmct.objectViews.on('clearData', this.clearData); }, show(object, viewKey, immediatelySelect) { if (this.unlisten) { @@ -187,6 +191,22 @@ export default { getComposableDomainObject(event) { let serializedDomainObject = event.dataTransfer.getData('openmct/composable-domain-object'); return JSON.parse(serializedDomainObject); + }, + clearData(domainObject) { + if (domainObject) { + let clearKeyString = this.openmct.objects.makeKeyString(domainObject.identifier), + currentObjectKeyString = this.openmct.objects.makeKeyString(this.currentObject.identifier); + + if (clearKeyString === currentObjectKeyString) { + if (this.currentView.onClearData) { + this.currentView.onClearData(); + } + } + } else { + if (this.currentView.onClearData) { + this.currentView.onClearData(); + } + } } } } diff --git a/src/ui/layout/Layout.vue b/src/ui/layout/Layout.vue index 7ee170e124..7f5afb4242 100644 --- a/src/ui/layout/Layout.vue +++ b/src/ui/layout/Layout.vue @@ -2,9 +2,15 @@
-
+
-
+ + + +
+
@@ -44,9 +52,6 @@ -
- -
@@ -61,12 +66,6 @@ flex-flow: column nowrap; overflow: hidden; - &__status { - background: $colorStatusBarBg; - color: $colorStatusBarFg; - padding: $interiorMarginSm; - } - &__pane-tree { width: 40%; @@ -160,14 +159,52 @@ } &__head { - align-items: center; + align-items: stretch; background: $colorHeadBg; justify-content: space-between; - padding: $interiorMargin; + padding: $interiorMargin $interiorMargin + 2; > [class*="__"] + [class*="__"] { margin-left: $interiorMargin; } + + [class*='__head__collapse-button'] { + align-self: start; + $p: 6px; + padding-left: $p !important; + padding-right: $p !important; + + &:before { + content: $glyph-icon-arrow-down; + font-size: 1.1em; + } + } + + &-section { + // Subdivides elements across the head + display: flex; + flex: 0 1 auto; + padding: 0 $interiorMargin; + } + + &--expanded { + .c-indicator__label { + transition: none !important; + } + + [class*='__head__collapse-button'] { + &:before { + transform: rotate(180deg); + } + } + } + } + + &__controls { + $brdr: 1px solid $colorInteriorBorder; + border-right: $brdr; + border-left: $brdr; + align-items: start; } &__create-button, @@ -175,11 +212,17 @@ flex: 0 0 auto; } - &__controls { - flex: 1 1 100%; - display: flex; - justify-content: flex-end; - margin-right: 2.5%; + &__create-button { margin-right: $interiorMarginLg; } + + &__indicators { + //@include test(); + flex: 1 1 auto; + flex-wrap: wrap; + [class*='indicator-clock'] { order: 90; } + + .c-indicator .label { + font-size: 0.9em; + } } /******************************* MAIN AREA */ @@ -266,9 +309,10 @@ import multipane from './multipane.vue'; import pane from './pane.vue'; import BrowseBar from './BrowseBar.vue'; - import StatusBar from './status-bar/StatusBar.vue'; import Toolbar from '../toolbar/Toolbar.vue'; import AppLogo from './AppLogo.vue'; + import Indicators from './status-bar/Indicators.vue'; + import NotificationBanner from './status-bar/NotificationBanner.vue'; var enterFullScreen = () => { var docElm = document.documentElement; @@ -309,9 +353,10 @@ multipane, pane, BrowseBar, - StatusBar, Toolbar, - AppLogo + AppLogo, + Indicators, + NotificationBanner }, mounted() { this.openmct.editor.on('isEditing', (isEditing)=>{ @@ -321,11 +366,18 @@ this.openmct.selection.on('change', this.toggleHasToolbar); }, data: function () { + let storedHeadProps = window.localStorage.getItem('openmct-shell-head'); + let headExpanded = true; + if (storedHeadProps) { + headExpanded = JSON.parse(storedHeadProps).expanded; + } + return { fullScreen: false, conductorComponent: undefined, isEditing: false, - hasToolbar: false + hasToolbar: false, + headExpanded } }, computed: { @@ -334,6 +386,18 @@ } }, methods: { + toggleShellHead() { + this.headExpanded = !this.headExpanded; + + window.localStorage.setItem( + 'openmct-shell-head', + JSON.stringify( + { + expanded: this.headExpanded + } + ) + ); + }, fullScreenToggle() { if (this.fullScreen) { this.fullScreen = false; diff --git a/src/ui/layout/pane.vue b/src/ui/layout/pane.vue index d17b6feb7b..8b9c8aa5be 100644 --- a/src/ui/layout/pane.vue +++ b/src/ui/layout/pane.vue @@ -148,21 +148,6 @@ font-size: floor(12px * .9); } - &__collapse-button { - box-shadow: none; - background: $splitterBtnColorBg; - color: $splitterBtnColorFg; - border-radius: $smallCr; - font-size: 6px; - line-height: 90%; - padding: 3px 15px; - - @include hover() { - background: $colorBtnBgHov; - color: $colorBtnFgHov; - } - } - &__label { // Name of the pane @include ellipsize(); diff --git a/src/ui/layout/status-bar/Indicators.vue b/src/ui/layout/status-bar/Indicators.vue index bdffcbfb16..040f2366a6 100644 --- a/src/ui/layout/status-bar/Indicators.vue +++ b/src/ui/layout/status-bar/Indicators.vue @@ -17,10 +17,137 @@ at runtime from the About dialog for additional information. --> diff --git a/src/ui/registries/ViewRegistry.js b/src/ui/registries/ViewRegistry.js index 3967e55360..85dddb683c 100644 --- a/src/ui/registries/ViewRegistry.js +++ b/src/ui/registries/ViewRegistry.js @@ -21,7 +21,7 @@ *****************************************************************************/ /*global console */ -define([], function () { +define(['EventEmitter'], function (EventEmitter) { const DEFAULT_VIEW_PRIORITY = 100; /** @@ -31,9 +31,12 @@ define([], function () { * @memberof module:openmct */ function ViewRegistry() { + EventEmitter.apply(this); this.providers = {}; } + ViewRegistry.prototype = Object.create(EventEmitter.prototype); + /** * @private for platform-internal use