mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
51 Commits
code-cover
...
imagery-ti
Author | SHA1 | Date | |
---|---|---|---|
2d8afa1456 | |||
f4ef82ef74 | |||
f43121a38a | |||
9124f4f566 | |||
9f7d788c86 | |||
d2374920ff | |||
a6b9ba184c | |||
c00ab72d04 | |||
98fb507f01 | |||
5258227d87 | |||
f43ba8f8f4 | |||
d9baa94970 | |||
afeb89a51a | |||
07992f0b2a | |||
a5c4508578 | |||
a4fab3ce8a | |||
97d80f57cc | |||
0ff9821091 | |||
353bdb5ca5 | |||
28a93fb262 | |||
8882e5f3b3 | |||
9cfabe0054 | |||
7975cf89ef | |||
a9c0e5a139 | |||
92a7ac18a2 | |||
240bc9e713 | |||
d09013ba28 | |||
d99d414c84 | |||
2638302dab | |||
8241ed8bb8 | |||
23dffe33a9 | |||
92e08f19bd | |||
c644e5266a | |||
7fa93c18f3 | |||
5b6e61d95a | |||
474b1ed2bf | |||
0d0de1ed64 | |||
85ab5cb319 | |||
299005982f | |||
8d3b277ef4 | |||
8eae707833 | |||
f62b39054a | |||
7515ce504e | |||
0b5ca621ec | |||
0e0644cd1f | |||
6089ae3531 | |||
876eb59787 | |||
17be0d7132 | |||
ace880dd41 | |||
dc3781c8e5 | |||
b76b4e4098 |
@ -96,6 +96,6 @@ module.exports = (config) => {
|
||||
logLevel: 'warn'
|
||||
},
|
||||
singleRun: true,
|
||||
browserNoActivityTimeout: 90000
|
||||
browserNoActivityTimeout: 400000
|
||||
});
|
||||
}
|
||||
|
@ -31,13 +31,13 @@
|
||||
</mct-form>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<a class='c-button c-button--major'
|
||||
<button class='c-button c-button--major'
|
||||
ng-class="{ disabled: !createForm.$valid }"
|
||||
ng-click="ngModel.confirm()">
|
||||
OK
|
||||
</a>
|
||||
<a class='c-button '
|
||||
</button>
|
||||
<button class='c-button '
|
||||
ng-click="ngModel.cancel()">
|
||||
Cancel
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -31,13 +31,13 @@
|
||||
</mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<a ng-repeat="option in ngModel.dialog.options"
|
||||
<button ng-repeat="option in ngModel.dialog.options"
|
||||
href=''
|
||||
class="s-button lg"
|
||||
title="{{option.description}}"
|
||||
ng-click="ngModel.confirm(option.key)"
|
||||
ng-class="{ major: $first, subtle: !$first }">
|
||||
{{option.name}}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</mct-container>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<div class="c-overlay__outer">
|
||||
<button ng-click="ngModel.cancel()"
|
||||
ng-if="ngModel.cancel"
|
||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"></button>
|
||||
class="c-click-icon c-overlay__close-button icon-x"></button>
|
||||
<div class="c-overlay__contents" ng-transclude></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,9 +29,9 @@
|
||||
type="text" tabindex="10000"
|
||||
ng-model="ngModel.input"
|
||||
ng-keyup="controller.search()"/>
|
||||
<a class="c-search__clear-input clear-icon icon-x-in-circle"
|
||||
<button class="c-search__clear-input clear-icon icon-x-in-circle"
|
||||
ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}"
|
||||
ng-click="ngModel.input = ''; controller.search()"></a>
|
||||
ng-click="ngModel.input = ''; controller.search()"></button>
|
||||
<!-- To prevent double triggering of clicks on click away, render
|
||||
non-clickable version of the button when menu active-->
|
||||
<a ng-if="!toggle.isActive()" class="menu-icon context-available"
|
||||
@ -45,16 +45,16 @@
|
||||
</mct-include>
|
||||
</div>
|
||||
|
||||
<a class="c-button c-search__btn-cancel"
|
||||
<button class="c-button c-search__btn-cancel"
|
||||
ng-show="!(ngModel.input === '' || ngModel.input === undefined)"
|
||||
ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
|
||||
Cancel</a>
|
||||
Cancel</button>
|
||||
</div>
|
||||
|
||||
<div class="active-filter-display flex-elem holder"
|
||||
ng-class="{invisible: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}">
|
||||
<a class="clear-filters icon-x-in-circle s-icon-button"
|
||||
ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }}
|
||||
<button class="clear-filters icon-x-in-circle s-icon-button"
|
||||
ng-click="ngModel.checkAll = true; menuController.checkAll()"></button>Filtered by: {{ ngModel.filtersString }}
|
||||
</div>
|
||||
|
||||
<div class="flex-elem holder results-msg" ng-model="ngModel" ng-show="!loading && ngModel.search">
|
||||
@ -72,7 +72,7 @@
|
||||
ng-model="ngModel"
|
||||
class="l-flex-row flex-elem grows">
|
||||
</mct-representation>
|
||||
<a class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a>
|
||||
<button class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,7 +47,7 @@ define([
|
||||
this.eventEmitter = new EventEmitter();
|
||||
this.providers = {};
|
||||
this.rootRegistry = new RootRegistry();
|
||||
this.rootProvider = new RootObjectProvider(this.rootRegistry);
|
||||
this.rootProvider = new RootObjectProvider.default(this.rootRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,28 +20,37 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
], function (
|
||||
) {
|
||||
|
||||
function RootObjectProvider(rootRegistry) {
|
||||
this.rootRegistry = rootRegistry;
|
||||
class RootObjectProvider {
|
||||
constructor(rootRegistry) {
|
||||
if(!RootObjectProvider.instance) {
|
||||
this.rootRegistry = rootRegistry;
|
||||
this.rootObject = {
|
||||
identifier: {
|
||||
key: "ROOT",
|
||||
namespace: ""
|
||||
},
|
||||
name: 'The root object',
|
||||
type: 'root',
|
||||
composition: []
|
||||
};
|
||||
RootObjectProvider.instance = this;
|
||||
}
|
||||
return RootObjectProvider.instance;
|
||||
}
|
||||
|
||||
RootObjectProvider.prototype.get = function () {
|
||||
return this.rootRegistry.getRoots()
|
||||
.then(function (roots) {
|
||||
return {
|
||||
identifier: {
|
||||
key: "ROOT",
|
||||
namespace: ""
|
||||
},
|
||||
name: 'The root object',
|
||||
type: 'root',
|
||||
composition: roots
|
||||
};
|
||||
});
|
||||
};
|
||||
updateName(name) {
|
||||
this.rootObject.name = name
|
||||
}
|
||||
|
||||
return RootObjectProvider;
|
||||
});
|
||||
async get() {
|
||||
let roots = await this.rootRegistry.getRoots();
|
||||
this.rootObject.composition = roots;
|
||||
return this.rootObject;
|
||||
}
|
||||
}
|
||||
|
||||
const instance = function (rootRegistry) {
|
||||
return new RootObjectProvider(rootRegistry);
|
||||
}
|
||||
|
||||
export default instance;
|
||||
|
@ -31,7 +31,7 @@ define([
|
||||
beforeEach(function () {
|
||||
rootRegistry = jasmine.createSpyObj('rootRegistry', ['getRoots']);
|
||||
rootRegistry.getRoots.and.returnValue(Promise.resolve(['some root']));
|
||||
rootObjectProvider = new RootObjectProvider(rootRegistry);
|
||||
rootObjectProvider = new RootObjectProvider.default(rootRegistry);
|
||||
});
|
||||
|
||||
it('supports fetching root', function () {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="c-overlay__outer">
|
||||
<button
|
||||
v-if="dismissable"
|
||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"
|
||||
class="c-click-icon c-overlay__close-button icon-x"
|
||||
@click="destroy"
|
||||
></button>
|
||||
<div
|
||||
|
@ -29,13 +29,12 @@
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
$p: $interiorMargin;
|
||||
border-radius: 100% !important;
|
||||
$p: $interiorMargin + 2px;
|
||||
color: $overlayColorFg;
|
||||
display: inline-block;
|
||||
font-size: 1.25em;
|
||||
font-size: 1.5em;
|
||||
position: absolute;
|
||||
top: $p; right: $p;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
&__contents {
|
||||
@ -43,7 +42,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__top-bar {
|
||||
@ -87,6 +86,10 @@
|
||||
.c-click-icon {
|
||||
filter: $overlayBrightnessAdjust;
|
||||
}
|
||||
|
||||
.c-object-label__name {
|
||||
filter: $objectLabelNameFilter;
|
||||
}
|
||||
}
|
||||
|
||||
body.desktop {
|
||||
@ -100,7 +103,6 @@ body.desktop {
|
||||
}
|
||||
|
||||
// Overlay types, styling for desktop. Appended to .l-overlay-wrapper element.
|
||||
.l-overlay-large,
|
||||
.l-overlay-small,
|
||||
.l-overlay-fit {
|
||||
.c-overlay__outer {
|
||||
@ -118,8 +120,28 @@ body.desktop {
|
||||
|
||||
.l-overlay-large {
|
||||
// Default
|
||||
.c-overlay__outer {
|
||||
@include overlaySizing($overlayOuterMarginLg);
|
||||
$pad: $interiorMarginLg;
|
||||
$tbPad: floor($pad * 0.8);
|
||||
$lrPad: $pad;
|
||||
.c-overlay {
|
||||
&__blocker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__outer {
|
||||
@include overlaySizing($overlayOuterMarginFullscreen);
|
||||
padding: $tbPad $lrPad;
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
//top: $interiorMargin;
|
||||
//right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
.l-browse-bar {
|
||||
margin-right: 50px; // Don't cover close button
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,4 +161,4 @@ body.desktop {
|
||||
min-width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
|
||||
if (validatedData) {
|
||||
if (this.isStalenessCheck()) {
|
||||
if (this.stalenessSubscription[validatedData.id]) {
|
||||
if (this.stalenessSubscription && this.stalenessSubscription[validatedData.id]) {
|
||||
this.stalenessSubscription[validatedData.id].update(validatedData);
|
||||
}
|
||||
this.telemetryDataCache[validatedData.id] = false;
|
||||
|
@ -142,12 +142,14 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
let telemetryObject = this.telemetryObject;
|
||||
|
||||
return this.openmct.telemetry.request(
|
||||
this.telemetryObject,
|
||||
options
|
||||
).then(results => {
|
||||
const latestDatum = results.length ? results[results.length - 1] : {};
|
||||
const normalizedDatum = this.createNormalizedDatum(latestDatum, this.telemetryObject);
|
||||
const normalizedDatum = this.createNormalizedDatum(latestDatum, telemetryObject);
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
|
@ -21,12 +21,14 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import TelemetryCriterion from "./TelemetryCriterion";
|
||||
import { getMockTelemetry } from "utils/testing";
|
||||
|
||||
let openmct = {},
|
||||
mockListener,
|
||||
testCriterionDefinition,
|
||||
testTelemetryObject,
|
||||
telemetryCriterion;
|
||||
telemetryCriterion,
|
||||
mockTelemetry = getMockTelemetry();
|
||||
|
||||
describe("The telemetry criterion", function () {
|
||||
|
||||
@ -60,7 +62,7 @@ describe("The telemetry criterion", function () {
|
||||
};
|
||||
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
|
||||
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter"]);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter", "request"]);
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||
@ -109,4 +111,30 @@ describe("The telemetry criterion", function () {
|
||||
});
|
||||
expect(telemetryCriterion.result).toBeTrue();
|
||||
});
|
||||
|
||||
describe('the LAD request', () => {
|
||||
beforeEach(async () => {
|
||||
let telemetryRequestResolve;
|
||||
let telemetryRequestPromise = new Promise((resolve) => {
|
||||
telemetryRequestResolve = resolve;
|
||||
});
|
||||
openmct.telemetry.request.and.callFake(() => {
|
||||
setTimeout(() => {
|
||||
telemetryRequestResolve(mockTelemetry);
|
||||
}, 100);
|
||||
return telemetryRequestPromise;
|
||||
});
|
||||
});
|
||||
|
||||
it("returns results for slow LAD requests", async function () {
|
||||
const criteriaRequest = telemetryCriterion.requestLAD();
|
||||
telemetryCriterion.destroy();
|
||||
expect(telemetryCriterion.telemetryObject).toBeUndefined();
|
||||
setTimeout(() => {
|
||||
criteriaRequest.then((result) => {
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
29
src/plugins/defaultRootName/plugin.js
Normal file
29
src/plugins/defaultRootName/plugin.js
Normal file
@ -0,0 +1,29 @@
|
||||
/*****************************************************************************
|
||||
* 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 RootObjectProvider from '../../api/objects/RootObjectProvider.js';
|
||||
|
||||
export default function (name) {
|
||||
return function (openmct) {
|
||||
let rootObjectProvider = new RootObjectProvider();
|
||||
rootObjectProvider.updateName(name);
|
||||
};
|
||||
}
|
99
src/plugins/defaultRootName/pluginSpec.js
Normal file
99
src/plugins/defaultRootName/pluginSpec.js
Normal file
@ -0,0 +1,99 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, 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 {
|
||||
createOpenMct,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
xdescribe("the plugin", () => {
|
||||
let openmct,
|
||||
compositionAPI,
|
||||
newFolderAction,
|
||||
mockObjectPath,
|
||||
mockDialogService,
|
||||
mockComposition,
|
||||
mockPromise,
|
||||
newFolderName = 'New Folder';
|
||||
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct();
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless();
|
||||
|
||||
newFolderAction = openmct.contextMenu._allActions.filter(action => {
|
||||
return action.key === 'newFolder';
|
||||
})[0];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
it('installs the new folder action', () => {
|
||||
expect(newFolderAction).toBeDefined();
|
||||
});
|
||||
|
||||
describe('when invoked', () => {
|
||||
|
||||
beforeEach((done) => {
|
||||
compositionAPI = openmct.composition;
|
||||
mockObjectPath = [{
|
||||
name: 'mock folder',
|
||||
type: 'folder',
|
||||
identifier: {
|
||||
key: 'mock-folder',
|
||||
namespace: ''
|
||||
}
|
||||
}];
|
||||
mockPromise = {
|
||||
then: (callback) => {
|
||||
callback({name: newFolderName});
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
mockDialogService = jasmine.createSpyObj('dialogService', ['getUserInput']);
|
||||
mockComposition = jasmine.createSpyObj('composition', ['add']);
|
||||
|
||||
mockDialogService.getUserInput.and.returnValue(mockPromise);
|
||||
|
||||
spyOn(openmct.$injector, 'get').and.returnValue(mockDialogService);
|
||||
spyOn(compositionAPI, 'get').and.returnValue(mockComposition);
|
||||
spyOn(openmct.objects, 'mutate');
|
||||
|
||||
newFolderAction.invoke(mockObjectPath);
|
||||
});
|
||||
|
||||
it('gets user input for folder name', () => {
|
||||
expect(mockDialogService.getUserInput).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates a new folder object', () => {
|
||||
expect(openmct.objects.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds new folder object to parent composition', () => {
|
||||
expect(mockComposition.add).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
@ -25,14 +25,14 @@
|
||||
class="l-layout__frame c-frame"
|
||||
:class="{
|
||||
'no-frame': !item.hasFrame,
|
||||
'u-inspectable': inspectable
|
||||
'u-inspectable': inspectable,
|
||||
'is-in-small-container': size.width < 600 || size.height < 600
|
||||
}"
|
||||
:style="style"
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
<div
|
||||
class="c-frame-edit__move"
|
||||
class="c-frame__move-bar"
|
||||
@mousedown="isEditing ? startMove([1,1], [0,0], $event) : null"
|
||||
></div>
|
||||
</div>
|
||||
@ -61,6 +61,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
size() {
|
||||
let {width, height} = this.item;
|
||||
return {
|
||||
width: (this.gridSize[0] * width),
|
||||
height: (this.gridSize[1] * height)
|
||||
};
|
||||
},
|
||||
style() {
|
||||
let {x, y, width, height} = this.item;
|
||||
return {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="l-layout__frame c-frame no-frame"
|
||||
class="l-layout__frame c-frame no-frame c-line-view"
|
||||
:class="[styleClass]"
|
||||
:style="style"
|
||||
>
|
||||
@ -31,14 +31,20 @@
|
||||
height="100%"
|
||||
>
|
||||
<line
|
||||
class="c-line-view__hover-indicator"
|
||||
v-bind="linePosition"
|
||||
vector-effect="non-scaling-stroke"
|
||||
/>
|
||||
<line
|
||||
class="c-line-view__line"
|
||||
v-bind="linePosition"
|
||||
:stroke="stroke"
|
||||
stroke-width="2"
|
||||
vector-effect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div
|
||||
class="c-frame-edit__move"
|
||||
class="c-frame__move-bar"
|
||||
@mousedown="startDrag($event)"
|
||||
></div>
|
||||
<div
|
||||
@ -49,7 +55,8 @@
|
||||
class="c-frame-edit__handle"
|
||||
:class="startHandleClass"
|
||||
@mousedown="startDrag($event, 'start')"
|
||||
></div>
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="c-frame-edit__handle"
|
||||
:class="endHandleClass"
|
||||
@ -68,14 +75,18 @@ const START_HANDLE_QUADRANTS = {
|
||||
1: 'c-frame-edit__handle--sw',
|
||||
2: 'c-frame-edit__handle--se',
|
||||
3: 'c-frame-edit__handle--ne',
|
||||
4: 'c-frame-edit__handle--nw'
|
||||
4: 'c-frame-edit__handle--nw',
|
||||
5: 'c-frame-edit__handle--nw',
|
||||
6: 'c-frame-edit__handle--ne'
|
||||
};
|
||||
|
||||
const END_HANDLE_QUADRANTS = {
|
||||
1: 'c-frame-edit__handle--ne',
|
||||
2: 'c-frame-edit__handle--nw',
|
||||
3: 'c-frame-edit__handle--sw',
|
||||
4: 'c-frame-edit__handle--se'
|
||||
4: 'c-frame-edit__handle--se',
|
||||
5: 'c-frame-edit__handle--sw',
|
||||
6: 'c-frame-edit__handle--nw'
|
||||
};
|
||||
|
||||
export default {
|
||||
@ -158,6 +169,12 @@ export default {
|
||||
},
|
||||
vectorQuadrant() {
|
||||
let {x, y, x2, y2} = this.position;
|
||||
if (x2 === x) {
|
||||
return 5; // Vertical line
|
||||
}
|
||||
if (y2 === y) {
|
||||
return 6; // Horizontal line
|
||||
}
|
||||
if (x2 > x) {
|
||||
if (y2 < y) {
|
||||
return 1;
|
||||
@ -170,21 +187,27 @@ export default {
|
||||
return 3;
|
||||
},
|
||||
linePosition() {
|
||||
return this.vectorQuadrant % 2 !== 0
|
||||
// odd vectorQuadrant slopes up
|
||||
? {
|
||||
x1: '0%',
|
||||
y1: '100%',
|
||||
x2: '100%',
|
||||
y2: '0%'
|
||||
}
|
||||
// even vectorQuadrant slopes down
|
||||
: {
|
||||
x1: '0%',
|
||||
y1: '0%',
|
||||
x2: '100%',
|
||||
y2: '100%'
|
||||
};
|
||||
let pos = {};
|
||||
switch(this.vectorQuadrant) {
|
||||
case 1:
|
||||
case 3:
|
||||
// slopes up
|
||||
pos = {x1: '0%', y1: '100%', x2: '100%', y2: '0%'};
|
||||
break;
|
||||
case 5:
|
||||
// vertical
|
||||
pos = {x1: '0%', y1: '0%', x2: '0%', y2: '100%'};
|
||||
break;
|
||||
case 6:
|
||||
// horizontal
|
||||
pos = {x1: '0%', y1: '0%', x2: '100%', y2: '0%'};
|
||||
break;
|
||||
default:
|
||||
// slopes down
|
||||
pos = {x1: '0%', y1: '0%', x2: '100%', y2: '100%'};
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -209,8 +232,7 @@ export default {
|
||||
layoutItem: this.item,
|
||||
index: this.index
|
||||
};
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context, this.initSelect);
|
||||
this.removeSelectable = this.openmct.selection.selectable(this.$el, this.context, this.initSelect);
|
||||
},
|
||||
destroyed() {
|
||||
if (this.removeSelectable) {
|
||||
@ -224,12 +246,17 @@ export default {
|
||||
document.body.addEventListener('mousemove', this.continueDrag);
|
||||
document.body.addEventListener('mouseup', this.endDrag);
|
||||
this.startPosition = [event.pageX, event.pageY];
|
||||
this.dragPosition = {
|
||||
x: this.item.x,
|
||||
y: this.item.y,
|
||||
x2: this.item.x2,
|
||||
y2: this.item.y2
|
||||
};
|
||||
let {x, y, x2, y2} = this.item;
|
||||
this.dragPosition = {x, y, x2, y2};
|
||||
if (x === x2 || y === y2) {
|
||||
if (y > y2 || x < x2) {
|
||||
if (this.dragging === 'start') {
|
||||
this.dragging = 'end';
|
||||
} else if (this.dragging === 'end') {
|
||||
this.dragging = 'start';
|
||||
}
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
},
|
||||
continueDrag(event) {
|
||||
@ -263,7 +290,7 @@ export default {
|
||||
},
|
||||
calculateDragPosition(pxDeltaX, pxDeltaY) {
|
||||
let gridDeltaX = Math.round(pxDeltaX / this.gridSize[0]);
|
||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[1]);
|
||||
let {x, y, x2, y2} = this.item;
|
||||
let dragPosition = {x, y, x2, y2};
|
||||
|
||||
|
60
src/plugins/displayLayout/components/box-and-line-views.scss
Normal file
60
src/plugins/displayLayout/components/box-and-line-views.scss
Normal file
@ -0,0 +1,60 @@
|
||||
.c-box-view {
|
||||
border-width: $drawingObjBorderW !important;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.c-frame & {
|
||||
@include abs();
|
||||
}
|
||||
}
|
||||
|
||||
.c-line-view {
|
||||
&.c-frame {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.c-frame-edit {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.c-handle-info {
|
||||
background: rgba(#999, 0.2);
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
top: 5px; left: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
svg {
|
||||
// Prevent clipping when line is horizontal and vertical
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
// Must use !important to counteract setting in normalize.min.css
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&__line {
|
||||
stroke-linecap: round;
|
||||
stroke-width: $drawingObjBorderW;
|
||||
}
|
||||
|
||||
&__hover-indicator {
|
||||
display: none;
|
||||
opacity: 0.5;
|
||||
stroke: $editFrameColorHov;
|
||||
stroke-width: $drawingObjBorderW + 4;
|
||||
}
|
||||
|
||||
.is-editing & {
|
||||
// Needed to allow line to be moved
|
||||
$w: 4px;
|
||||
min-width: $w;
|
||||
min-height: $w;
|
||||
|
||||
&:hover {
|
||||
[class*='__hover-indicator'] {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
.c-box-view {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.c-frame & {
|
||||
@include abs();
|
||||
}
|
||||
}
|
@ -7,9 +7,13 @@
|
||||
> *:first-child {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&.is-in-small-container {
|
||||
//background: rgba(blue, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -29,7 +33,7 @@
|
||||
border: $editFrameSelectedBorder;
|
||||
box-shadow: $editFrameSelectedShdw;
|
||||
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
@ -37,7 +41,7 @@
|
||||
|
||||
/******************* DEFAULT STYLES FOR -EDIT__MOVE */
|
||||
// All object types
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
@include abs();
|
||||
display: block;
|
||||
}
|
||||
@ -52,7 +56,7 @@
|
||||
transition-delay: $moveBarOutDelay;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -61,14 +65,14 @@
|
||||
.l-layout {
|
||||
/******************* 0 - 1 ITEM SELECTED */
|
||||
&:not(.is-multi-selected) {
|
||||
> .l-layout__frame[s-selected] {
|
||||
> .l-layout__frame {
|
||||
> .c-so-view.has-complex-content {
|
||||
> .c-so-view__local-controls {
|
||||
transition: transform $transOutTime ease-in-out;
|
||||
transition-delay: $moveBarOutDelay;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
transition: $transOut;
|
||||
transition-delay: $moveBarOutDelay;
|
||||
@include userSelectNone();
|
||||
@ -89,7 +93,7 @@
|
||||
$lrOffset: 25%;
|
||||
@include grippy($editFrameMovebarColorFg);
|
||||
content: '';
|
||||
display: block;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: $tbOffset;
|
||||
right: $lrOffset;
|
||||
@ -111,7 +115,7 @@
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
transition: $transIn;
|
||||
transition-delay: 0s;
|
||||
height: $editFrameMovebarH;
|
||||
@ -119,12 +123,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
> .l-layout__frame[s-selected] {
|
||||
> .c-so-view.has-complex-content {
|
||||
+ .c-frame__move-bar:before {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************* > 1 ITEMS SELECTED */
|
||||
&.is-multi-selected {
|
||||
.l-layout__frame[s-selected] {
|
||||
> .c-so-view.has-complex-content + .c-frame-edit__move {
|
||||
> .c-so-view.has-complex-content + .c-frame__move-bar {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
background: $colorListItemBgHov;
|
||||
filter: $filterHov;
|
||||
transition: $transIn;
|
||||
}
|
||||
|
@ -31,11 +31,11 @@
|
||||
<div class="c-imagery__control-bar">
|
||||
<div class="c-imagery__timestamp">{{ getTime() }}</div>
|
||||
<div class="h-local-controls flex-elem">
|
||||
<a
|
||||
<button
|
||||
class="c-button icon-pause pause-play"
|
||||
:class="{'is-paused': paused()}"
|
||||
@click="paused(!paused())"
|
||||
></a>
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -228,7 +228,7 @@ export default {
|
||||
subscribe() {
|
||||
this.unsubscribe = this.openmct.telemetry
|
||||
.subscribe(this.domainObject, (datum) => {
|
||||
let parsedTimestamp = this.timeFormat.parse(datum[this.timeKey]),
|
||||
let parsedTimestamp = this.timeFormat.parse(datum),
|
||||
bounds = this.openmct.time.bounds();
|
||||
|
||||
if(parsedTimestamp >= bounds.start && parsedTimestamp <= bounds.end) {
|
||||
|
@ -42,6 +42,7 @@
|
||||
height: 135px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: $interiorMarginSm;
|
||||
|
||||
&.is-paused {
|
||||
background: rgba($colorPausedBg, 0.4);
|
||||
@ -99,7 +100,7 @@
|
||||
.c-imagery {
|
||||
.h-local-controls--overlay-content {
|
||||
position: absolute;
|
||||
right: $interiorMargin; top: $interiorMargin;
|
||||
left: $interiorMargin; top: $interiorMargin;
|
||||
z-index: 2;
|
||||
background: $colorLocalControlOvrBg;
|
||||
border-radius: $basicCr;
|
||||
|
@ -21,8 +21,11 @@
|
||||
-->
|
||||
<div class="gl-plot plot-legend-{{legend.get('position')}} {{legend.get('expanded')? 'plot-legend-expanded' : 'plot-legend-collapsed'}}">
|
||||
<div class="c-plot-legend gl-plot-legend"
|
||||
ng-class="{ 'hover-on-plot': !!highlights.length }"
|
||||
ng-show="legend.get('position') !== 'hidden'">
|
||||
ng-class="{
|
||||
'hover-on-plot': !!highlights.length,
|
||||
'is-legend-hidden': legend.get('hideLegendWhenSmall')
|
||||
}"
|
||||
>
|
||||
<div class="c-plot-legend__view-control gl-plot-legend__view-control c-disclosure-triangle is-enabled"
|
||||
ng-class="{ 'c-disclosure-triangle--expanded': legend.get('expanded') }"
|
||||
ng-click="legend.set('expanded', !legend.get('expanded'));">
|
||||
@ -36,11 +39,13 @@
|
||||
ng-class="{'is-cursor-locked': !!lockHighlightPoint }">
|
||||
<div class="c-state-indicator__alert-cursor-lock icon-cursor-lock" title="Cursor is point locked. Click anywhere in the plot to unlock."></div>
|
||||
<div class="plot-legend-item"
|
||||
ng-class="{'is-missing': series.domainObject.status === 'missing'}"
|
||||
ng-class="{
|
||||
'is-missing': series.domainObject.status === 'missing'
|
||||
}"
|
||||
ng-repeat="series in series track by $index"
|
||||
>
|
||||
<div class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch "
|
||||
<span class="plot-series-color-swatch"
|
||||
ng-style="{ 'background-color': series.get('color').asHexString() }">
|
||||
</span>
|
||||
<span class="is-missing__indicator" title="This item is missing"></span>
|
||||
@ -86,7 +91,9 @@
|
||||
</thead>
|
||||
<tr ng-repeat="series in series"
|
||||
class="plot-legend-item"
|
||||
ng-class="{'is-missing': series.domainObject.status === 'missing'}"
|
||||
ng-class="{
|
||||
'is-missing': series.domainObject.status === 'missing'
|
||||
}"
|
||||
>
|
||||
<td class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch"
|
||||
@ -128,7 +135,7 @@
|
||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||
<div class="gl-plot-axis-area gl-plot-y has-local-controls"
|
||||
ng-style="{
|
||||
width: (tickWidth + 30) + 'px'
|
||||
width: (tickWidth + 20) + 'px'
|
||||
}">
|
||||
|
||||
<div class="gl-plot-label gl-plot-y-label"
|
||||
@ -146,7 +153,6 @@
|
||||
</option>
|
||||
</select>
|
||||
|
||||
|
||||
<mct-ticks axis="yAxis">
|
||||
<div ng-repeat="tick in ticks track by tick.value"
|
||||
class="gl-plot-tick gl-plot-y-tick-label"
|
||||
@ -159,17 +165,15 @@
|
||||
</div>
|
||||
<div class="gl-plot-wrapper-display-area-and-x-axis"
|
||||
ng-style="{
|
||||
left: (tickWidth + 30) + 'px'
|
||||
}">
|
||||
<div class="l-state-indicators">
|
||||
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."></span>
|
||||
<span class="l-state-indicators__alert-cursor-lock icon-cursor-lock"
|
||||
title="Telemetry point selection is locked. Click anywhere in the plot to unlock."
|
||||
ng-if="lockHighlightPoint"></span>
|
||||
</div>
|
||||
left: (tickWidth + 20) + 'px'
|
||||
}">
|
||||
|
||||
<div class="gl-plot-display-area has-local-controls has-cursor-guides">
|
||||
<div class="l-state-indicators">
|
||||
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."></span>
|
||||
</div>
|
||||
|
||||
<mct-ticks axis="xAxis">
|
||||
<div class="gl-plot-hash hash-v"
|
||||
ng-repeat="tick in ticks track by tick.value"
|
||||
|
@ -114,6 +114,11 @@
|
||||
title="The position of the legend relative to the plot display area.">Position</div>
|
||||
<div class="grid-cell value capitalize">{{ config.legend.get('position') }}</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Hide the legend when the plot is small">Hide when plot small</div>
|
||||
<div class="grid-cell value">{{ config.legend.get('hideLegendWhenSmall') ? "Yes" : "No" }}</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Show the legend expanded by default">Expand by Default</div>
|
||||
|
@ -174,7 +174,6 @@
|
||||
title="The position of the legend relative to the plot display area.">Position</div>
|
||||
<div class="grid-cell value">
|
||||
<select ng-model="form.position">
|
||||
<option value="hidden">Hidden</option>
|
||||
<option value="top">Top</option>
|
||||
<option value="right">Right</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
@ -182,6 +181,11 @@
|
||||
</select>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Hide the legend when the plot is small">Hide when plot small</div>
|
||||
<div class="grid-cell value"><input type="checkbox" ng-model="form.hideLegendWhenSmall"/></div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Show the legend expanded by default">Expand by default</div>
|
||||
|
@ -48,6 +48,7 @@ define([
|
||||
return {
|
||||
position: 'top',
|
||||
expandByDefault: false,
|
||||
hideLegendWhenSmall: false,
|
||||
valueToShowWhenCollapsed: 'nearestValue',
|
||||
showTimestampWhenExpanded: true,
|
||||
showValueWhenExpanded: true,
|
||||
|
@ -32,6 +32,11 @@ define([
|
||||
modelProp: 'position',
|
||||
objectPath: 'configuration.legend.position'
|
||||
},
|
||||
{
|
||||
modelProp: 'hideLegendWhenSmall',
|
||||
coerce: Boolean,
|
||||
objectPath: 'configuration.legend.hideLegendWhenSmall'
|
||||
},
|
||||
{
|
||||
modelProp: 'expandByDefault',
|
||||
coerce: Boolean,
|
||||
|
@ -54,7 +54,8 @@ define([
|
||||
'./themes/snow',
|
||||
'./URLTimeSettingsSynchronizer/plugin',
|
||||
'./notificationIndicator/plugin',
|
||||
'./newFolderAction/plugin'
|
||||
'./newFolderAction/plugin',
|
||||
'./defaultRootName/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@ -89,7 +90,8 @@ define([
|
||||
Snow,
|
||||
URLTimeSettingsSynchronizer,
|
||||
NotificationIndicator,
|
||||
NewFolderAction
|
||||
NewFolderAction,
|
||||
DefaultRootName
|
||||
) {
|
||||
var bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
@ -201,6 +203,7 @@ define([
|
||||
plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default;
|
||||
plugins.NotificationIndicator = NotificationIndicator.default;
|
||||
plugins.NewFolderAction = NewFolderAction.default;
|
||||
plugins.DefaultRootName = DefaultRootName.default;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
@ -17,6 +17,19 @@
|
||||
margin-right: $interiorMarginSm;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&__label {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__close-btn {
|
||||
flex: 0 0 auto;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__object-holder {
|
||||
|
@ -19,7 +19,7 @@
|
||||
>
|
||||
Drag objects here to add them to this view.
|
||||
</div>
|
||||
<button
|
||||
<div
|
||||
v-for="(tab,index) in tabsList"
|
||||
:key="index"
|
||||
class="c-tab c-tabs-view__tab"
|
||||
@ -28,19 +28,12 @@
|
||||
}"
|
||||
@click="showTab(tab, index)"
|
||||
>
|
||||
<div class="c-object-label"
|
||||
:class="{'is-missing': tab.domainObject.status === 'missing'}"
|
||||
>
|
||||
<div class="c-object-label__type-icon"
|
||||
:class="tab.type.definition.cssClass"
|
||||
>
|
||||
<span class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></span>
|
||||
</div>
|
||||
<span class="c-button__label c-object-label__name">{{ tab.domainObject.name }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<span class="c-button__label c-tabs-view__tab__label">{{ tab.domainObject.name }}</span>
|
||||
<button v-if="isEditing"
|
||||
class="icon-x c-click-icon c-tabs-view__tab__close-btn"
|
||||
@click="showRemoveDialog(index)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="(tab, index) in tabsList"
|
||||
@ -59,6 +52,7 @@
|
||||
|
||||
<script>
|
||||
import ObjectView from '../../../ui/components/ObjectView.vue';
|
||||
import RemoveAction from '../../remove/RemoveAction.js';
|
||||
import {
|
||||
getSearchParam,
|
||||
setSearchParam,
|
||||
@ -123,6 +117,7 @@ export default {
|
||||
|
||||
this.unsubscribe = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject);
|
||||
|
||||
this.RemoveAction = new RemoveAction(this.openmct);
|
||||
document.addEventListener('dragstart', this.dragstart);
|
||||
document.addEventListener('dragend', this.dragend);
|
||||
},
|
||||
@ -153,6 +148,38 @@ export default {
|
||||
|
||||
this.currentTab = tab;
|
||||
},
|
||||
showRemoveDialog(index) {
|
||||
if(!this.tabsList[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let activeTab = this.tabsList[index];
|
||||
let childDomainObject = activeTab.domainObject
|
||||
|
||||
let prompt = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: `This action will remove this tab from the Tabs Layout. Do you want to continue?`,
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
emphasis: 'true',
|
||||
callback: () => {
|
||||
this.removeFromComposition(childDomainObject);
|
||||
prompt.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: () => {
|
||||
prompt.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
removeFromComposition(childDomainObject) {
|
||||
this.composition.remove(childDomainObject);
|
||||
},
|
||||
addItem(domainObject) {
|
||||
let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
|
||||
tabItem = {
|
||||
|
@ -74,6 +74,10 @@ define([], function () {
|
||||
return this.cellLimitClasses;
|
||||
}
|
||||
|
||||
getContextualDomainObject(openmct, objectKeyString) {
|
||||
return openmct.objects.get(objectKeyString);
|
||||
}
|
||||
|
||||
getContextMenuActions() {
|
||||
return [];
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ export default {
|
||||
showContextMenu: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.openmct.objects.get(this.row.objectKeyString).then((domainObject) => {
|
||||
this.row.getContextualDomainObject(this.openmct, this.row.objectKeyString).then(domainObject => {
|
||||
let contextualObjectPath = this.objectPath.slice();
|
||||
contextualObjectPath.unshift(domainObject);
|
||||
|
||||
|
@ -54,6 +54,16 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__filter {
|
||||
.c-table__search {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.is-in-small-container & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__headers__label {
|
||||
@ -86,6 +96,10 @@
|
||||
height: 0; // Fixes Chrome 73 overflow bug
|
||||
overflow-x: auto;
|
||||
overflow-y: scroll;
|
||||
|
||||
.is-editing & {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* TABLES */
|
||||
@ -138,7 +152,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* EDITING */
|
||||
/******************************* SPECIFIC CASE WRAPPERS */
|
||||
.is-editing {
|
||||
.c-telemetry-table__headers__labels {
|
||||
th[draggable],
|
||||
@ -158,8 +172,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.paused {
|
||||
border: 1px solid #ff9900;
|
||||
.is-paused {
|
||||
.c-table__body-w {
|
||||
border: 1px solid rgba($colorPausedBg, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* LEGACY */
|
||||
|
@ -20,13 +20,16 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<div class="c-table-wrapper">
|
||||
<div class="c-table-wrapper"
|
||||
:class="{ 'is-paused': paused }"
|
||||
>
|
||||
<!-- main contolbar start-->
|
||||
<div v-if="!marking.useAlternateControlBar"
|
||||
class="c-table-control-bar c-control-bar"
|
||||
>
|
||||
<button
|
||||
v-if="allowExport"
|
||||
v-show="!markedRows.length"
|
||||
class="c-button icon-download labeled"
|
||||
title="Export this view's data"
|
||||
@click="exportAllDataAsCSV()"
|
||||
@ -125,7 +128,7 @@
|
||||
class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
|
||||
:class="{
|
||||
'loading': loading,
|
||||
'paused' : paused
|
||||
'is-paused' : paused
|
||||
}"
|
||||
>
|
||||
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}">
|
||||
|
@ -3,8 +3,8 @@
|
||||
}
|
||||
|
||||
@keyframes rotation-centered {
|
||||
0% { transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { transform: translate(-50%, -50%) rotate(360deg); }
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes clock-hands {
|
||||
|
@ -80,10 +80,14 @@ $uiColor: #0093ff; // Resize bars, splitter bars, etc.
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #ccc;
|
||||
$colorAHov: #fff;
|
||||
$filterHov: brightness(1.3); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 10%);
|
||||
$filterHov: brightness(1.3) contrast(1.5); // Tree, location items
|
||||
$colorSelectedBg: rgba($colorKey, 0.3);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 20%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.7;
|
||||
$objectLabelNameFilter: brightness(1.3);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
@ -94,7 +98,7 @@ $sideBarHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$sideBarHeaderFg: rgba($colorBodyFg, 0.7);
|
||||
|
||||
// Status colors, mainly used for messaging and item ancillary symbols
|
||||
$colorStatusFg: #999;
|
||||
$colorStatusFg: #888;
|
||||
$colorStatusDefault: #ccc;
|
||||
$colorStatusInfo: #60ba7b;
|
||||
$colorStatusInfoFilter: invert(58%) sepia(44%) saturate(405%) hue-rotate(85deg) brightness(102%) contrast(92%);
|
||||
@ -205,9 +209,9 @@ $colorBtnMajorBg: $colorKey;
|
||||
$colorBtnMajorBgHov: $colorKeyHov;
|
||||
$colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
|
||||
$colorBtnCautionBg: #f16f6f;
|
||||
$colorBtnCautionBg: $colorStatusAlert;
|
||||
$colorBtnCautionBgHov: #f1504e;
|
||||
$colorBtnCautionFg: $colorBtnFg;
|
||||
$colorBtnCautionFg: $colorBtnBg;
|
||||
$colorBtnActiveBg: $colorOk;
|
||||
$colorBtnActiveFg: $colorOkFg;
|
||||
$colorBtnSelectedBg: $colorSelectedBg;
|
||||
@ -335,7 +339,7 @@ $shdwItemText: none;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: $colorBodyBg;
|
||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.15);
|
||||
$colorTabHeaderFg: $colorBodyFg;
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
|
||||
@ -353,17 +357,18 @@ $stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
|
||||
$legendTableHeadBg: rgba($colorBodyFg, 0.15);
|
||||
$legendTableHeadBg: $colorTabHeaderBg;
|
||||
|
||||
// Tree
|
||||
$colorTreeBg: transparent;
|
||||
$colorItemTreeHoverBg: rgba(white, 0.07);
|
||||
$colorItemTreeHoverFg: pullForward($colorBodyFg, 20%);
|
||||
$colorItemTreeHoverBg: rgba(#fff, 0.03);
|
||||
$colorItemTreeHoverFg: #fff;
|
||||
$colorItemTreeIcon: $colorKey; // Used
|
||||
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
||||
$colorItemTreeFg: $colorBodyFg;
|
||||
$colorItemTreeSelectedBg: $colorSelectedBg;
|
||||
$colorItemTreeSelectedFg: $colorItemTreeHoverFg;
|
||||
$filterItemTreeSelected: $filterHov;
|
||||
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
|
||||
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
|
||||
$colorItemTreeEditingFg: $editUIColor;
|
||||
@ -398,7 +403,7 @@ $splitterBtnColorBg: $colorBtnBg;
|
||||
$splitterBtnColorFg: #999;
|
||||
$splitterBtnLabelColorFg: #666;
|
||||
$splitterCollapsedBtnColorBg: #222;
|
||||
$splitterCollapsedBtnColorFg: #666;
|
||||
$splitterCollapsedBtnColorFg: #555;
|
||||
$splitterCollapsedBtnColorBgHov: $colorKey;
|
||||
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
|
||||
|
||||
|
@ -80,14 +80,18 @@ $colorKeyHov: #26d8ff;
|
||||
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
|
||||
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
|
||||
$colorKeySelectedBg: $colorKey;
|
||||
$uiColor: #00b2ff; // Resize bars, splitter bars, etc.
|
||||
$uiColor: #0093ff; // Resize bars, splitter bars, etc.
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #ccc;
|
||||
$colorAHov: #fff;
|
||||
$filterHov: brightness(1.3); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 10%);
|
||||
$filterHov: brightness(1.3) contrast(1.5); // Tree, location items
|
||||
$colorSelectedBg: rgba($colorKey, 0.3);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 20%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.7;
|
||||
$objectLabelNameFilter: brightness(1.3);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
@ -209,9 +213,9 @@ $colorBtnMajorBg: $colorKey;
|
||||
$colorBtnMajorBgHov: $colorKeyHov;
|
||||
$colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
|
||||
$colorBtnCautionBg: #f16f6f;
|
||||
$colorBtnCautionBg: $colorStatusAlert;
|
||||
$colorBtnCautionBgHov: #f1504e;
|
||||
$colorBtnCautionFg: $colorBtnFg;
|
||||
$colorBtnCautionFg: $colorBtnBg;
|
||||
$colorBtnActiveBg: $colorOk;
|
||||
$colorBtnActiveFg: $colorOkFg;
|
||||
$colorBtnSelectedBg: $colorSelectedBg;
|
||||
@ -339,7 +343,7 @@ $shdwItemText: none;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: $colorBodyBg;
|
||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.15);
|
||||
$colorTabHeaderFg: $colorBodyFg;
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
|
||||
@ -361,13 +365,14 @@ $legendTableHeadBg: rgba($colorBodyFg, 0.15);
|
||||
|
||||
// Tree
|
||||
$colorTreeBg: transparent;
|
||||
$colorItemTreeHoverBg: rgba(white, 0.07);
|
||||
$colorItemTreeHoverFg: pullForward($colorBodyFg, 20%);
|
||||
$colorItemTreeHoverBg: rgba(#fff, 0.03);
|
||||
$colorItemTreeHoverFg: #fff;
|
||||
$colorItemTreeIcon: $colorKey; // Used
|
||||
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
||||
$colorItemTreeFg: $colorBodyFg;
|
||||
$colorItemTreeSelectedBg: $colorSelectedBg;
|
||||
$colorItemTreeSelectedFg: $colorItemTreeHoverFg;
|
||||
$filterItemTreeSelected: $filterHov;
|
||||
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
|
||||
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
|
||||
$colorItemTreeEditingFg: $editUIColor;
|
||||
@ -402,7 +407,7 @@ $splitterBtnColorBg: $colorBtnBg;
|
||||
$splitterBtnColorFg: #999;
|
||||
$splitterBtnLabelColorFg: #666;
|
||||
$splitterCollapsedBtnColorBg: #222;
|
||||
$splitterCollapsedBtnColorFg: #666;
|
||||
$splitterCollapsedBtnColorFg: #555;
|
||||
$splitterCollapsedBtnColorBgHov: $colorKey;
|
||||
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
|
||||
|
||||
|
@ -78,19 +78,23 @@ $colorKeyFilterHov: invert(69%) sepia(87%) saturate(3243%) hue-rotate(151deg) br
|
||||
$colorKeySelectedBg: $colorKey;
|
||||
$uiColor: #289fec; // Resize bars, splitter bars, etc.
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #999;
|
||||
$colorA: $colorBodyFg;
|
||||
$colorAHov: $colorKey;
|
||||
$filterHov: brightness(1.3); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 40%);
|
||||
$filterHov: brightness(0.8) contrast(2); // Tree, location items
|
||||
$colorSelectedBg: rgba($colorKey, 0.2);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 10%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.5;
|
||||
$objectLabelNameFilter: brightness(0.5);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
$drawerBg: darken($colorBodyBg, 5%);
|
||||
$drawerFg: darken($colorBodyFg, 5%);
|
||||
$sideBarBg: $drawerBg;
|
||||
$sideBarHeaderBg: rgba(black, 0.25);
|
||||
$sideBarHeaderBg: rgba(black, 0.1);
|
||||
$sideBarHeaderFg: rgba($colorBodyFg, 0.7);
|
||||
|
||||
// Status colors, mainly used for messaging and item ancillary symbols
|
||||
@ -224,7 +228,7 @@ $colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
|
||||
$btnStdH: 24px;
|
||||
$colorCursorGuide: rgba(black, 0.6);
|
||||
$shdwCursorGuide: rgba(white, 0.4) 0 0 2px;
|
||||
$colorLocalControlOvrBg: rgba($colorBodyFg, 0.8);
|
||||
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
|
||||
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
|
||||
$colorSelectFg: $colorBtnFg;
|
||||
$colorSelectArw: lighten($colorBtnBg, 20%);
|
||||
@ -364,7 +368,8 @@ $colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
||||
$colorItemTreeFg: $colorBodyFg;
|
||||
$colorItemTreeSelectedBg: $colorSelectedBg;
|
||||
$colorItemTreeSelectedFg: $colorItemTreeHoverFg;
|
||||
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
|
||||
$filterItemTreeSelected: contrast(1.4);
|
||||
$colorItemTreeSelectedIcon: $colorItemTreeIcon;
|
||||
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
|
||||
$colorItemTreeEditingFg: $editUIColor;
|
||||
$colorItemTreeEditingIcon: $editUIColor;
|
||||
|
@ -40,11 +40,11 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
$menuLineH: 1.5rem;
|
||||
$treeItemIndent: 16px;
|
||||
$treeTypeIconW: 18px;
|
||||
$overlayOuterMarginLg: 5%;
|
||||
$overlayOuterMarginFullscreen: 0%;
|
||||
$overlayOuterMarginDialog: 20%;
|
||||
$overlayInnerMargin: 25px;
|
||||
$mainViewPad: 2px;
|
||||
$mainViewPad: 0px;
|
||||
$treeNavArrowD: 20px;
|
||||
/*************** Items */
|
||||
$itemPadLR: 5px;
|
||||
$gridItemDesk: 175px;
|
||||
@ -57,7 +57,7 @@ $tabularTdPadTB: 2px;
|
||||
$plotYBarW: 60px;
|
||||
$plotYLabelMinH: 20px;
|
||||
$plotYLabelW: 10px;
|
||||
$plotXBarH: 35px;
|
||||
$plotXBarH: 32px;
|
||||
$plotLegendH: 20px;
|
||||
$plotLegendWidthCollapsed: 20%;
|
||||
$plotLegendWidthExpanded: 50%;
|
||||
@ -82,14 +82,16 @@ $formLabelMinW: 120px;
|
||||
$formLabelW: 30%;
|
||||
/*************** Wait Spinner */
|
||||
$waitSpinnerD: 32px;
|
||||
$waitSpinnerTreeD: 20px;
|
||||
$waitSpinnerBorderW: 5px;
|
||||
$waitSpinnerTreeD: 20px;
|
||||
$waitSpinnerTreeBorderW: 3px;
|
||||
/*************** Messages */
|
||||
$messageIconD: 80px;
|
||||
$messageListIconD: 32px;
|
||||
/*************** Tables */
|
||||
$tableResizeColHitareaD: 6px;
|
||||
/*************** Misc */
|
||||
$drawingObjBorderW: 3px;
|
||||
|
||||
/************************** MOBILE */
|
||||
$mobileMenuIconD: 24px; // Used
|
||||
|
@ -57,11 +57,6 @@ button {
|
||||
line-height: 90%;
|
||||
padding: 3px 10px;
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
}
|
||||
|
||||
@include desktop() {
|
||||
font-size: 6px;
|
||||
}
|
||||
@ -102,7 +97,8 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.c-click-link {
|
||||
.c-click-link,
|
||||
.c-icon-link {
|
||||
// A clickable element, typically inline, with an icon and label
|
||||
@include cControl();
|
||||
cursor: pointer;
|
||||
@ -117,8 +113,15 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.c-icon-link {
|
||||
&:before {
|
||||
// Icon
|
||||
//color: $colorBtnMajorBg;
|
||||
}
|
||||
}
|
||||
|
||||
.c-icon-button {
|
||||
.c-icon-button__label {
|
||||
&__label {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,9 @@ a {
|
||||
color: $colorA;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: $colorAHov;
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,10 +207,6 @@ body.desktop .has-local-controls {
|
||||
&:hover {
|
||||
box-shadow: $browseSelectableShdwHov;
|
||||
}
|
||||
|
||||
&[s-selected] {
|
||||
border: $browseSelectedBorder;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************** EDITING */
|
||||
@ -284,19 +281,23 @@ body.desktop .has-local-controls {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: $spinnerL + $d/2 + $interiorMargin;
|
||||
background: $colorLoadingBg;
|
||||
margin-left: $treeNavArrowD + $interiorMargin;
|
||||
min-height: 5px + $d;
|
||||
|
||||
.c-tree__item__label {
|
||||
font-style: italic;
|
||||
margin-left: $interiorMargin;
|
||||
opacity: 0.6;
|
||||
}
|
||||
&:before {
|
||||
left: auto;
|
||||
top: auto;
|
||||
transform: translate(0);
|
||||
height: $d;
|
||||
width: $d;
|
||||
border-width: 4px;
|
||||
left: $spinnerL;
|
||||
border-width: 3px;
|
||||
//left: $spinnerL;
|
||||
position: relative;
|
||||
}
|
||||
&:after {
|
||||
display: none;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -29,16 +29,19 @@ mct-plot {
|
||||
.gl-plot.child-frame {
|
||||
&:hover {
|
||||
background: rgba($editUIColorBg, 0.1);
|
||||
box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px;
|
||||
box-shadow: inset rgba($editUIColorBg, 0.3) 0 0 0 1px;
|
||||
}
|
||||
|
||||
&[s-selected] {
|
||||
border: 1px solid $editUIColorFg !important;
|
||||
color: $editUIColorFg !important;
|
||||
box-shadow: $editFrameSelectedShdw;
|
||||
background: rgba($editUIColorBg, 0.2);
|
||||
box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.plot-wrapper-axis-and-display-area {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.c-plot,
|
||||
@ -67,20 +70,14 @@ mct-plot {
|
||||
}
|
||||
|
||||
.c-plot {
|
||||
//$p: $mainViewPad;
|
||||
@include abs($mainViewPad);
|
||||
//position: absolute;
|
||||
//top: $p; right: $p; bottom: $p; left: $p;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
.l-control-bar {
|
||||
.c-control-bar {
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
|
||||
.l-view-section {
|
||||
@ -114,6 +111,12 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-in-small-container & {
|
||||
.c-control-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot {
|
||||
@ -205,7 +208,6 @@ mct-plot {
|
||||
&.gl-plot-y-label {
|
||||
display: block;
|
||||
left: 0; top: 0; right: auto; bottom: 0;
|
||||
padding-left: 5px;
|
||||
text-orientation: mixed;
|
||||
writing-mode: vertical-lr;
|
||||
&:before {
|
||||
@ -271,7 +273,7 @@ mct-plot {
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: $m;
|
||||
right: $m;
|
||||
left: $m;
|
||||
z-index: 9;
|
||||
|
||||
&__reset {
|
||||
@ -284,15 +286,18 @@ mct-plot {
|
||||
top: $m;
|
||||
right: $m;
|
||||
}
|
||||
|
||||
.c-button {
|
||||
box-shadow: $colorLocalControlOvrBg 0 0 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.l-state-indicators {
|
||||
color: $colorPausedBg;
|
||||
position: absolute;
|
||||
display: block;
|
||||
font-size: 1.5em;
|
||||
pointer-events: none;
|
||||
top: $interiorMarginSm;
|
||||
cursor: help;
|
||||
font-size: 1.2em;
|
||||
bottom: $interiorMarginSm;
|
||||
left: $interiorMarginSm;
|
||||
z-index: 2;
|
||||
|
||||
@ -351,11 +356,11 @@ mct-plot {
|
||||
|
||||
.gl-plot-tick {
|
||||
&.gl-plot-x-tick-label {
|
||||
top: $interiorMargin;
|
||||
top: $interiorMarginSm;
|
||||
}
|
||||
&.gl-plot-y-tick-label {
|
||||
right: $interiorMargin;
|
||||
left: $interiorMargin;
|
||||
right: $interiorMarginSm;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,8 +457,22 @@ mct-plot {
|
||||
@include propertiesHeader();
|
||||
margin-bottom: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.is-in-small-container & {
|
||||
&.is-legend-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-plot--stacked {
|
||||
.is-legend-hidden {
|
||||
// Always show the legend in a stacked plot
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.gl-plot-legend {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@ -525,10 +544,19 @@ mct-plot {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.gl-plot {
|
||||
.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
|
||||
.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
|
||||
.plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; }
|
||||
.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
|
||||
|
||||
.gl-plot,
|
||||
.c-plot {
|
||||
&.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
|
||||
&.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
|
||||
|
||||
&.plot-legend-collapsed .icon-cursor-lock::before { padding-right: 5px; }
|
||||
&.plot-legend-expanded .icon-cursor-lock::before { padding-right: 5px; }
|
||||
|
||||
&.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
|
||||
&.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
|
||||
&.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
|
||||
@ -540,7 +568,6 @@ mct-plot {
|
||||
|
||||
.plot-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
|
||||
.plot-series-swatch-and-name,
|
||||
@ -569,8 +596,10 @@ mct-plot {
|
||||
|
||||
/***************** TOP OR BOTTOM */
|
||||
&.plot-legend-top,
|
||||
&.plot-legend-bottom {
|
||||
&.plot-legend-bottom,
|
||||
&.plot-legend-hidden {
|
||||
// General styles when legend is on the top or bottom
|
||||
// -hidden included for legacy plots
|
||||
flex-direction: column;
|
||||
|
||||
&.plot-legend-collapsed {
|
||||
@ -592,6 +621,7 @@ mct-plot {
|
||||
&.plot-legend-left,
|
||||
&.plot-legend-right {
|
||||
// General styles when legend is on left or right
|
||||
|
||||
.gl-plot-legend {
|
||||
max-height: inherit;
|
||||
}
|
||||
@ -622,6 +652,7 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
.plot-legend-item {
|
||||
margin-bottom: $interiorMarginSm;
|
||||
margin-left: 0;
|
||||
flex-wrap: nowrap;
|
||||
.plot-series-swatch-and-name {
|
||||
@ -649,6 +680,31 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
|
||||
/***************** STACKED PLOT LEGEND OVERRIDES */
|
||||
.c-plot--stacked {
|
||||
// Always show the legend on top, ignore any position setting
|
||||
.c-plot,
|
||||
.gl-plot {
|
||||
flex-direction: column !important;
|
||||
|
||||
.c-plot-legend,
|
||||
.gl-plot-legend {
|
||||
margin: 0;
|
||||
margin-bottom: $interiorMargin;
|
||||
order: 1 !important;
|
||||
width: 100% !important;
|
||||
|
||||
.plot-wrapper-collapsed-legend {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
}
|
||||
.plot-wrapper-axis-and-display-area {
|
||||
order: 2 !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************** CURSOR GUIDES */
|
||||
[class*='c-cursor-guide'] {
|
||||
box-shadow: $shdwCursorGuide;
|
||||
|
@ -443,28 +443,18 @@
|
||||
}
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
filter: $filterHov;
|
||||
}
|
||||
|
||||
&[class*="--major"],
|
||||
&[class*='is-active']{
|
||||
background: $colorBtnMajorBg;
|
||||
color: $colorBtnMajorFg;
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnMajorBgHov;
|
||||
color: $colorBtnMajorFgHov;
|
||||
}
|
||||
}
|
||||
|
||||
&[class*='--caution'] {
|
||||
background: $colorBtnCautionBg;
|
||||
color: $colorBtnCautionFg;
|
||||
|
||||
&:hover {
|
||||
background: $colorBtnCautionBgHov;
|
||||
}
|
||||
background: $colorBtnCautionBg !important;
|
||||
color: $colorBtnCautionFg !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,14 +90,28 @@ div.c-table {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
.is-in-small-container & {
|
||||
&:not(.is-paused) {
|
||||
.c-table-control-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.c-table-control-bar {
|
||||
.c-click-icon,
|
||||
.c-button {
|
||||
&__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-table-control-bar {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
//margin-bottom: $interiorMarginSm; // This approach to allow margin to go away when control bar is hidden
|
||||
padding: $interiorMarginSm 0;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
|
@ -3,7 +3,7 @@
|
||||
@import "../plugins/condition/components/conditionals.scss";
|
||||
@import "../plugins/conditionWidget/components/condition-widget.scss";
|
||||
@import "../plugins/condition/components/inspector/conditional-styles.scss";
|
||||
@import "../plugins/displayLayout/components/box-view.scss";
|
||||
@import "../plugins/displayLayout/components/box-and-line-views";
|
||||
@import "../plugins/displayLayout/components/display-layout.scss";
|
||||
@import "../plugins/displayLayout/components/edit-marquee.scss";
|
||||
@import "../plugins/displayLayout/components/image-view.scss";
|
||||
|
@ -142,8 +142,11 @@ export default {
|
||||
getOverlayElement(childElement) {
|
||||
const fragment = new DocumentFragment();
|
||||
const header = this.getPreviewHeader();
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.classList.add('l-preview-window__object-view');
|
||||
wrapper.append(childElement);
|
||||
fragment.append(header);
|
||||
fragment.append(childElement);
|
||||
fragment.append(wrapper);
|
||||
|
||||
return fragment;
|
||||
},
|
||||
|
@ -142,7 +142,7 @@ export default {
|
||||
}
|
||||
|
||||
this.viewContainer = document.createElement('div');
|
||||
this.viewContainer.classList.add('u-angular-object-view-wrapper');
|
||||
this.viewContainer.classList.add('l-angular-ov-wrapper');
|
||||
this.$el.append(this.viewContainer);
|
||||
let provider = this.getViewProvider();
|
||||
if (!provider) {
|
||||
|
@ -10,25 +10,21 @@
|
||||
&__header {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
font-size: 1.05em;
|
||||
align-items: center;
|
||||
margin-bottom: $interiorMargin;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
padding: 1px 2px;
|
||||
|
||||
&__icon {
|
||||
flex: 0 0 auto;
|
||||
margin-right: $interiorMarginSm;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@include headerFont(1em);
|
||||
@include ellipsize();
|
||||
flex: 0 1 auto;
|
||||
.c-object-label {
|
||||
&__name {
|
||||
filter: $objectLabelNameFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.c-so-view--no-frame) {
|
||||
border: $browseFrameBorder;
|
||||
padding: $interiorMargin;
|
||||
padding: 0 $interiorMarginSm;
|
||||
|
||||
.is-editing & {
|
||||
background: rgba($colorBodyBg, 0.8);
|
||||
@ -40,10 +36,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .c-so-view__local-controls {
|
||||
top: $interiorMarginSm; right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
@include isMissing($absPos: true);
|
||||
|
||||
@ -55,9 +47,19 @@
|
||||
}
|
||||
|
||||
&__local-controls {
|
||||
// View Large button
|
||||
box-shadow: $colorLocalControlOvrBg 0 0 0 2px;
|
||||
position: absolute;
|
||||
top: $interiorMargin; right: $interiorMargin;
|
||||
z-index: 2;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.c-click-icon,
|
||||
.c-button {
|
||||
// Shrink buttons a bit when they appear in a frame
|
||||
border-radius: $smallCr !important;
|
||||
font-size: 0.9em;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
|
||||
&__view-large {
|
||||
@ -68,7 +70,6 @@
|
||||
> .c-so-view__view-large { display: block; }
|
||||
}
|
||||
|
||||
/*************************** OBJECT VIEW */
|
||||
&__object-view {
|
||||
flex: 1 1 auto;
|
||||
height: 0; // Chrome 73 overflow bug fix
|
||||
@ -79,15 +80,10 @@
|
||||
@include abs();
|
||||
}
|
||||
}
|
||||
|
||||
.c-click-icon,
|
||||
.c-button {
|
||||
// Shrink buttons a bit when they appear in a frame
|
||||
font-size: 0.9em;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.u-angular-object-view-wrapper {
|
||||
display: contents;
|
||||
.l-angular-ov-wrapper {
|
||||
// This element is the recipient for object styling; cannot be display: contents
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.1em;
|
||||
opacity: $objectLabelTypeIconOpacity;
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<span
|
||||
class="c-disclosure-triangle"
|
||||
:class="{
|
||||
'c-disclosure-triangle--expanded' : value,
|
||||
'is-enabled' : enabled
|
||||
}"
|
||||
:class="[
|
||||
controlClass,
|
||||
{ 'c-disclosure-triangle--expanded' : value },
|
||||
{'is-enabled' : enabled }
|
||||
]"
|
||||
@click="handleClick"
|
||||
></span>
|
||||
</template>
|
||||
@ -25,6 +25,10 @@ export default {
|
||||
propagate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
controlClass: {
|
||||
type: String,
|
||||
default: 'c-disclosure-triangle'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="c-inspector__header">
|
||||
<div v-if="!multiSelect"
|
||||
class="c-inspector__selected-w c-object-label"
|
||||
class="c-inspector__selected c-object-label"
|
||||
:class="{'is-missing': domainObject.status === 'missing' }"
|
||||
>
|
||||
<div class="c-object-label__type-icon"
|
||||
@ -11,17 +11,20 @@
|
||||
title="This item is missing"
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<span v-if="!singleSelectNonObject"
|
||||
class="c-inspector__selected c-object-label__name"
|
||||
>{{ item.name }}</span>
|
||||
<span v-if="singleSelectNonObject"
|
||||
class="c-inspector__selected c-object-label__name c-inspector__selected--non-domain-object"
|
||||
>Layout Object</span>
|
||||
|
||||
<div v-if="singleSelectNonObject"
|
||||
class="c-inspector__selected c-inspector__selected--non-domain-object c-object-label"
|
||||
>
|
||||
<span class="c-object-label__type-icon"
|
||||
:class="typeCssClass"
|
||||
></span>
|
||||
<span class="c-object-label__name">Layout Object</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="multiSelect"
|
||||
class="c-inspector__multiple-selected-w"
|
||||
class="c-inspector__multiple-selected"
|
||||
>
|
||||
{{ itemsSelected }} items selected
|
||||
</div>
|
||||
|
@ -8,13 +8,13 @@
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
&__selected-w,
|
||||
&__multiple-selected-w {
|
||||
&__selected,
|
||||
&__multiple-selected {
|
||||
@include headerFont(1.1em);
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
&__multiple-selected-w {
|
||||
&__multiple-selected {
|
||||
$p: $interiorMarginLg;
|
||||
background: rgba($colorWarningLo, 0.3);
|
||||
border-radius: $basicCr;
|
||||
@ -25,10 +25,11 @@
|
||||
}
|
||||
|
||||
&__selected {
|
||||
@include ellipsize();
|
||||
flex: 1 1 auto;
|
||||
.c-object-label__name {
|
||||
filter: $objectLabelNameFilter;
|
||||
}
|
||||
|
||||
&--non-domain-object {
|
||||
&--non-domain-object .c-object-label__name {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
<div class="l-browse-bar__start">
|
||||
<button
|
||||
v-if="hasParent"
|
||||
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-pointer-left"
|
||||
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-arrow-nav-to-parent"
|
||||
title="Navigate up to parent"
|
||||
@click="goToParent"
|
||||
></button>
|
||||
<div
|
||||
@ -55,7 +56,7 @@
|
||||
:title="lockedOrUnlocked"
|
||||
class="c-button"
|
||||
:class="{
|
||||
'icon-lock': domainObject.locked,
|
||||
'icon-lock c-button--caution': domainObject.locked,
|
||||
'icon-unlocked': !domainObject.locked
|
||||
}"
|
||||
@click="toggleLock(!domainObject.locked)"
|
||||
|
@ -15,7 +15,9 @@
|
||||
<CreateButton class="l-shell__create-button" />
|
||||
<indicators class="l-shell__head-section l-shell__indicators" />
|
||||
<button
|
||||
class="l-shell__head__collapse-button c-button"
|
||||
class="l-shell__head__collapse-button c-icon-button"
|
||||
:class="headExpanded ? 'l-shell__head__collapse-button--collapse' : 'l-shell__head__collapse-button--expand'"
|
||||
:title="`Click to ${headExpanded ? 'collapse' : 'expand'} items`"
|
||||
@click="toggleShellHead"
|
||||
></button>
|
||||
<notification-banner />
|
||||
@ -47,12 +49,23 @@
|
||||
label="Browse"
|
||||
collapsable
|
||||
>
|
||||
<mct-tree class="l-shell__tree" />
|
||||
<button
|
||||
slot="controls"
|
||||
class="c-icon-button l-shell__sync-tree-button icon-target"
|
||||
title="Show selected item in tree"
|
||||
@click="handleSyncTreeNavigation"
|
||||
>
|
||||
</button>
|
||||
<mct-tree
|
||||
:sync-tree-navigation="triggerSync"
|
||||
class="l-shell__tree"
|
||||
/>
|
||||
</pane>
|
||||
<pane class="l-shell__pane-main">
|
||||
<browse-bar
|
||||
ref="browseBar"
|
||||
class="l-shell__main-view-browse-bar"
|
||||
@sync-tree-navigation="handleSyncTreeNavigation"
|
||||
/>
|
||||
<toolbar
|
||||
v-if="toolbar"
|
||||
@ -154,7 +167,8 @@ export default {
|
||||
conductorComponent: undefined,
|
||||
isEditing: false,
|
||||
hasToolbar: false,
|
||||
headExpanded
|
||||
headExpanded,
|
||||
triggerSync: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -204,6 +218,9 @@ export default {
|
||||
}
|
||||
|
||||
this.hasToolbar = structure.length > 0;
|
||||
},
|
||||
handleSyncTreeNavigation() {
|
||||
this.triggerSync = !this.triggerSync;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
||||
color: $colorKey !important;
|
||||
position: absolute;
|
||||
right: -18px;
|
||||
top: 0;
|
||||
top: $interiorMarginSm;
|
||||
transform: translateX(100%);
|
||||
width: $mobileMenuIconD;
|
||||
z-index: 2;
|
||||
@ -100,6 +100,11 @@
|
||||
&__pane-tree {
|
||||
background: linear-gradient(90deg, transparent 70%, rgba(black, 0.2) 99%, rgba(black, 0.3));
|
||||
|
||||
[class*="expand-button"],
|
||||
[class*="sync-tree-button"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
[class*="collapse-button"] {
|
||||
right: -8px;
|
||||
@ -153,7 +158,7 @@
|
||||
}
|
||||
|
||||
&__head {
|
||||
align-items: stretch;
|
||||
align-items: center;
|
||||
background: $colorHeadBg;
|
||||
justify-content: space-between;
|
||||
padding: $interiorMargin $interiorMargin + 2;
|
||||
@ -162,14 +167,21 @@
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
|
||||
[class*='__head__collapse-button'] {
|
||||
align-self: start;
|
||||
.l-shell__head__collapse-button {
|
||||
color: $colorBtnMajorBg;
|
||||
flex: 0 0 auto;
|
||||
margin-top: 6px;
|
||||
font-size: 0.9em;
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-size: 1.1em;
|
||||
&--collapse {
|
||||
&:before {
|
||||
content: $glyph-icon-items-collapse;
|
||||
}
|
||||
}
|
||||
|
||||
&--expand {
|
||||
&:before {
|
||||
content: $glyph-icon-items-expand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,12 +196,6 @@
|
||||
.c-indicator__label {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
[class*='__head__collapse-button'] {
|
||||
&:before {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,6 +310,10 @@
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&__start,
|
||||
&__end,
|
||||
&__actions {
|
||||
@ -313,6 +323,13 @@
|
||||
|
||||
&__actions,
|
||||
&__end {
|
||||
.c-button {
|
||||
&[class*='icon-']:before {
|
||||
min-width: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
@ -320,8 +337,12 @@
|
||||
|
||||
&__start {
|
||||
flex: 1 1 auto;
|
||||
margin-right: $interiorMargin;
|
||||
//margin-right: $interiorMargin;
|
||||
min-width: 0; // Forces interior to compress when pushed on
|
||||
|
||||
[class*='button'] {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__end {
|
||||
@ -330,15 +351,15 @@
|
||||
|
||||
&__nav-to-parent-button,
|
||||
&__disclosure-button {
|
||||
flex: 0 0 auto;
|
||||
//flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__nav-to-parent-button {
|
||||
// This is an icon-button
|
||||
$p: $interiorMargin;
|
||||
margin-right: $interiorMargin;
|
||||
padding-left: $p;
|
||||
padding-right: $p;
|
||||
//$p: $interiorMargin;
|
||||
//margin-right: $interiorMargin;
|
||||
//padding-left: $p;
|
||||
//padding-right: $p;
|
||||
|
||||
.is-editing & {
|
||||
display: none;
|
||||
@ -350,8 +371,13 @@
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.c-object-label__name {
|
||||
filter: $objectLabelNameFilter;
|
||||
}
|
||||
|
||||
&__object-name--w {
|
||||
@include headerFont(1.4em);
|
||||
@include headerFont(1.5em);
|
||||
margin-left: $interiorMarginLg;
|
||||
min-width: 0;
|
||||
|
||||
.is-missing__indicator {
|
||||
|
@ -12,10 +12,6 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__no-results {
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
@ -26,6 +22,33 @@
|
||||
height: 0; // Chrome 73 overflow bug fix
|
||||
padding-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.c-tree {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
transition: all;
|
||||
|
||||
.scrollable-children {
|
||||
.c-tree__item-h {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__item--empty {
|
||||
// Styling for empty tree items
|
||||
// Indent should allow for c-nav view-control width and icon spacing
|
||||
font-style: italic;
|
||||
padding: $interiorMarginSm * 2 1px;
|
||||
opacity: 0.7;
|
||||
pointer-events: none;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: $treeNavArrowD + $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-tree,
|
||||
@ -43,7 +66,6 @@
|
||||
}
|
||||
|
||||
&__item {
|
||||
$aPad: $interiorMarginSm;
|
||||
border-radius: $controlCr;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -82,22 +104,9 @@
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&.is-navigated-object,
|
||||
&.is-selected {
|
||||
.c-tree__item__type-icon:before {
|
||||
color: $colorItemTreeIconHover;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-being-edited {
|
||||
background: $colorItemTreeEditingBg;
|
||||
.c-tree__item__type-icon:before {
|
||||
color: $colorItemTreeEditingIcon;
|
||||
}
|
||||
|
||||
.c-tree__item__name {
|
||||
color: $colorItemTreeEditingFg;
|
||||
font-style: italic;
|
||||
@include desktop {
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,10 +115,6 @@
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__name {
|
||||
color: $colorItemTreeFg;
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
@ -125,6 +130,62 @@
|
||||
width: ceil($mobileTreeItemH * 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-navigated-object,
|
||||
&.is-selected {
|
||||
background: $colorItemTreeSelectedBg;
|
||||
|
||||
[class*="__label"],
|
||||
[class*="__name"] {
|
||||
color: $colorItemTreeSelectedFg;
|
||||
}
|
||||
|
||||
[class*="__type-icon"]:before {
|
||||
color: $colorItemTreeSelectedIcon;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-navigated-object {
|
||||
[class*="__label"],
|
||||
[class*="__name"] {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__item__label {
|
||||
@include desktop {
|
||||
&:hover {
|
||||
filter: $filterHov;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-editing .is-navigated-object {
|
||||
a[class*="__item__label"] {
|
||||
opacity: 0.4;
|
||||
|
||||
[class*="__name"] {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-tree {
|
||||
&__item {
|
||||
body.mobile & {
|
||||
@include button($bg: $colorMobilePaneLeftTreeItemBg, $fg: $colorMobilePaneLeftTreeItemFg);
|
||||
height: $mobileTreeItemH;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
[class*="view-control"] {
|
||||
width: ceil($mobileTreeItemH * 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-tree {
|
||||
margin-left: $treeItemIndent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,6 +202,51 @@
|
||||
}
|
||||
}
|
||||
|
||||
.c-nav {
|
||||
$dimension: $treeNavArrowD;
|
||||
|
||||
&__up, &__down {
|
||||
flex: 0 0 auto;
|
||||
height: $dimension;
|
||||
width: $dimension;
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&.is-enabled {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&:before {
|
||||
// Nav arrow
|
||||
$dimension: 9px;
|
||||
$width: 3px;
|
||||
border: solid $colorItemTreeVC;
|
||||
border-width: 0 $width $width 0;
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%; top: 50%;
|
||||
height: $dimension;
|
||||
width: $dimension;
|
||||
}
|
||||
|
||||
@include desktop {
|
||||
&:hover:before {
|
||||
border-color: $colorItemTreeHoverFg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__up:before {
|
||||
transform: translate(-30%, -50%) rotate(135deg);
|
||||
}
|
||||
|
||||
&__down:before {
|
||||
transform: translate(-70%, -50%) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.c-selector {
|
||||
.c-tree-and-search__tree.c-tree {
|
||||
border: 1px solid $colorInteriorBorder;
|
||||
@ -148,3 +254,32 @@
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
.slide-left,
|
||||
.slide-right {
|
||||
animation-duration: 500ms;
|
||||
animation-iteration-count: 1;
|
||||
transition: all;
|
||||
transition-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
.slide-left {
|
||||
animation-name: animSlideLeft;
|
||||
}
|
||||
|
||||
.slide-right {
|
||||
animation-name: animSlideRight;
|
||||
}
|
||||
|
||||
@keyframes animSlideLeft {
|
||||
0% {opactiy: 0; transform: translateX(100%);}
|
||||
10% {opacity: 1;}
|
||||
100% {transform: translateX(0);}
|
||||
}
|
||||
|
||||
@keyframes animSlideRight {
|
||||
0% {opactiy: 0; transform: translateX(-100%);}
|
||||
10% {opacity: 1;}
|
||||
100% {transform: translateX(0);}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="c-tree-and-search">
|
||||
<div
|
||||
class="c-tree-and-search"
|
||||
>
|
||||
|
||||
<div class="c-tree-and-search__search">
|
||||
<search
|
||||
ref="shell-search"
|
||||
@ -10,15 +13,8 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- loading -->
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="c-tree-and-search__loading loading"
|
||||
></div>
|
||||
<!-- end loading -->
|
||||
|
||||
<div
|
||||
v-if="(allTreeItems.length === 0) || (searchValue && filteredTreeItems.length === 0)"
|
||||
v-if="(searchValue && allTreeItems.length === 0 && !isLoading) || (searchValue && searchResultItems.length === 0)"
|
||||
class="c-tree-and-search__no-results"
|
||||
>
|
||||
No results found
|
||||
@ -26,30 +22,72 @@
|
||||
|
||||
<!-- main tree -->
|
||||
<ul
|
||||
v-if="!isLoading"
|
||||
v-show="!searchValue"
|
||||
ref="mainTree"
|
||||
class="c-tree-and-search__tree c-tree"
|
||||
>
|
||||
<tree-item
|
||||
v-for="treeItem in allTreeItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem"
|
||||
/>
|
||||
<!-- ancestors -->
|
||||
<div v-if="!activeSearch">
|
||||
<tree-item
|
||||
v-for="(ancestor, index) in ancestors"
|
||||
:key="ancestor.id"
|
||||
:node="ancestor"
|
||||
:show-up="index < ancestors.length - 1"
|
||||
:show-down="false"
|
||||
:left-offset="index * 10 + 'px'"
|
||||
:emit-height="getChildHeight"
|
||||
@emittedHeight="setChildHeight"
|
||||
@resetTree="handleReset"
|
||||
/>
|
||||
<!-- loading -->
|
||||
<li
|
||||
v-if="isLoading"
|
||||
class="c-tree__item c-tree-and-search__loading loading"
|
||||
>
|
||||
<span class="c-tree__item__label">Loading...</span>
|
||||
</li>
|
||||
<!-- end loading -->
|
||||
</div>
|
||||
<!-- currently viewed children -->
|
||||
<transition
|
||||
@enter="childrenIn"
|
||||
>
|
||||
<li
|
||||
v-if="!isLoading"
|
||||
:class="childrenSlideClass"
|
||||
:style="childrenListStyles()"
|
||||
>
|
||||
<ul
|
||||
ref="scrollable"
|
||||
class="scrollable-children"
|
||||
:style="scrollableStyles()"
|
||||
@scroll="scrollItems"
|
||||
>
|
||||
<div :style="{ height: childrenHeight + 'px'}">
|
||||
<tree-item
|
||||
v-for="(treeItem, index) in visibleItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem"
|
||||
:left-offset="itemLeftOffset"
|
||||
:item-offset="itemOffset"
|
||||
:item-index="index"
|
||||
:item-height="itemHeight"
|
||||
:virtual-scroll="!noScroll"
|
||||
:show-down="activeSearch ? false : true"
|
||||
@expanded="handleExpanded"
|
||||
/>
|
||||
<li
|
||||
v-if="visibleItems.length === 0"
|
||||
:style="emptyStyles()"
|
||||
class="c-tree__item c-tree__item--empty"
|
||||
>
|
||||
No items
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</li>
|
||||
</transition>
|
||||
</ul>
|
||||
<!-- end main tree -->
|
||||
|
||||
<!-- search tree -->
|
||||
<ul
|
||||
v-if="searchValue"
|
||||
class="c-tree-and-search__tree c-tree"
|
||||
>
|
||||
<tree-item
|
||||
v-for="treeItem in filteredTreeItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem"
|
||||
/>
|
||||
</ul>
|
||||
<!-- end search tree -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -57,6 +95,14 @@
|
||||
import treeItem from './tree-item.vue'
|
||||
import search from '../components/search.vue';
|
||||
|
||||
const LOCAL_STORAGE_KEY__TREE_EXPANDED = 'mct-tree-expanded';
|
||||
const ROOT_PATH = '/browse/';
|
||||
const ITEM_BUFFER = 5;
|
||||
const RECHECK_DELAY = 100;
|
||||
const RESIZE_FIRE_DELAY_MS = 500;
|
||||
let windowResizeId = undefined;
|
||||
let windowResizing = false;
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
name: 'MctTree',
|
||||
@ -64,70 +110,481 @@ export default {
|
||||
search,
|
||||
treeItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchValue: '',
|
||||
allTreeItems: [],
|
||||
filteredTreeItems: [],
|
||||
isLoading: false
|
||||
props: {
|
||||
syncTreeNavigation: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
data() {
|
||||
let isMobile = this.openmct.$injector.get('agentService');
|
||||
return {
|
||||
isLoading: false,
|
||||
searchValue: '',
|
||||
allTreeItems: [],
|
||||
searchResultItems: [],
|
||||
visibleItems: [],
|
||||
ancestors: [],
|
||||
childrenSlideClass: 'slide-left',
|
||||
availableContainerHeight: 0,
|
||||
noScroll: true,
|
||||
updatingView: false,
|
||||
itemHeight: 28,
|
||||
itemOffset: 0,
|
||||
childrenHeight: 0,
|
||||
scrollable: undefined,
|
||||
pageThreshold: 50,
|
||||
activeSearch: false,
|
||||
getChildHeight: false,
|
||||
settingChildrenHeight: false,
|
||||
isMobile: isMobile.mobileName,
|
||||
multipleRootChildren: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentNavigatedPath() {
|
||||
let ancestorsCopy = [...this.ancestors];
|
||||
if (this.multipleRootChildren) {
|
||||
ancestorsCopy.shift(); // remove root
|
||||
}
|
||||
return ancestorsCopy
|
||||
.map((ancestor) => ancestor.id)
|
||||
.join('/');
|
||||
},
|
||||
currentObjectPath() {
|
||||
let ancestorsCopy = [...this.ancestors];
|
||||
return ancestorsCopy
|
||||
.reverse()
|
||||
.map((ancestor) => ancestor.object);
|
||||
},
|
||||
focusedItems() {
|
||||
return this.activeSearch ? this.searchResultItems : this.allTreeItems;
|
||||
},
|
||||
itemLeftOffset() {
|
||||
return this.activeSearch ? '0px' : this.ancestors.length * 10 + 'px';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
syncTreeNavigation() {
|
||||
const AND_SAVE_PATH = true;
|
||||
let currentLocationPath = this.openmct.router.currentLocation.path;
|
||||
let hasParent = this.currentlyViewedObjectParentPath() || (this.multipleRootChildren && !this.currentlyViewedObjectParentPath());
|
||||
let jumpAndScroll = currentLocationPath &&
|
||||
hasParent &&
|
||||
!this.currentPathIsActivePath();
|
||||
let justScroll = this.currentPathIsActivePath() && !this.noScroll;
|
||||
|
||||
if (this.searchValue) {
|
||||
this.searchValue = '';
|
||||
}
|
||||
|
||||
if (jumpAndScroll) {
|
||||
this.scrollTo = this.currentlyViewedObjectId();
|
||||
this.allTreeItems = [];
|
||||
this.jumpPath = this.currentlyViewedObjectParentPath();
|
||||
if (this.multipleRootChildren) {
|
||||
if(!this.jumpPath) {
|
||||
this.jumpPath = 'ROOT';
|
||||
this.ancestors = [];
|
||||
} else {
|
||||
this.ancestors = [this.ancestors[0]]
|
||||
}
|
||||
} else {
|
||||
this.ancestors = [];
|
||||
}
|
||||
this.jumpToPath(AND_SAVE_PATH);
|
||||
} else if (justScroll) {
|
||||
this.scrollTo = this.currentlyViewedObjectId();
|
||||
this.autoScroll();
|
||||
}
|
||||
},
|
||||
searchValue() {
|
||||
if (this.searchValue !== '' && !this.activeSearch) {
|
||||
this.searchActivated();
|
||||
} else if (this.searchValue === '') {
|
||||
this.searchDeactivated();
|
||||
}
|
||||
},
|
||||
searchResultItems() {
|
||||
this.setContainerHeight();
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let savedPath = this.getSavedNavigatedPath();
|
||||
this.searchService = this.openmct.$injector.get('searchService');
|
||||
this.getAllChildren();
|
||||
window.addEventListener('resize', this.handleWindowResize);
|
||||
|
||||
let root = await this.openmct.objects.get('ROOT');
|
||||
let rootNode = this.buildTreeItem(root);
|
||||
// if more than one root item, set multipleRootChildren to true and add root to ancestors
|
||||
if (root.composition && root.composition.length > 1) {
|
||||
this.ancestors.push(rootNode);
|
||||
this.multipleRootChildren = true;
|
||||
} else if (!savedPath) {
|
||||
// needed if saved path is not set, need to set it to the only root child
|
||||
savedPath = root.composition[0].key;
|
||||
}
|
||||
|
||||
if (savedPath) {
|
||||
let scrollIfApplicable = () => {
|
||||
if (this.currentPathIsActivePath()) {
|
||||
this.scrollTo = this.currentlyViewedObjectId();
|
||||
}
|
||||
};
|
||||
this.jumpPath = savedPath;
|
||||
this.afterJump = scrollIfApplicable;
|
||||
}
|
||||
|
||||
this.getAllChildren(rootNode);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.handleWindowResize);
|
||||
},
|
||||
methods: {
|
||||
getAllChildren() {
|
||||
this.isLoading = true;
|
||||
this.openmct.objects.get('ROOT')
|
||||
.then(root => {
|
||||
return this.openmct.composition.get(root).load()
|
||||
})
|
||||
.then(children => {
|
||||
this.isLoading = false;
|
||||
this.allTreeItems = children.map(c => {
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
objectPath: [c],
|
||||
navigateToParent: '/browse'
|
||||
};
|
||||
});
|
||||
});
|
||||
updatevisibleItems() {
|
||||
if (this.updatingView) {
|
||||
return;
|
||||
}
|
||||
this.updatingView = true;
|
||||
requestAnimationFrame(()=> {
|
||||
let start = 0;
|
||||
let end = this.pageThreshold;
|
||||
let allItemsCount = this.focusedItems.length;
|
||||
|
||||
if (allItemsCount < this.pageThreshold) {
|
||||
end = allItemsCount;
|
||||
} else {
|
||||
let firstVisible = this.calculateFirstVisibleItem();
|
||||
let lastVisible = this.calculateLastVisibleItem();
|
||||
let totalVisible = lastVisible - firstVisible;
|
||||
let numberOffscreen = this.pageThreshold - totalVisible;
|
||||
|
||||
start = firstVisible - Math.floor(numberOffscreen / 2);
|
||||
end = lastVisible + Math.ceil(numberOffscreen / 2);
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
end = Math.min(this.pageThreshold, allItemsCount);
|
||||
} else if (end >= allItemsCount) {
|
||||
end = allItemsCount;
|
||||
start = end - this.pageThreshold + 1;
|
||||
}
|
||||
}
|
||||
this.itemOffset = start;
|
||||
this.visibleItems = this.focusedItems.slice(start, end);
|
||||
|
||||
this.updatingView = false;
|
||||
});
|
||||
},
|
||||
getFilteredChildren() {
|
||||
this.searchService.query(this.searchValue).then(children => {
|
||||
this.filteredTreeItems = children.hits.map(child => {
|
||||
async setContainerHeight() {
|
||||
await this.$nextTick();
|
||||
let mainTree = this.$refs.mainTree;
|
||||
let mainTreeHeight = mainTree.clientHeight;
|
||||
|
||||
let context = child.object.getCapability('context'),
|
||||
object = child.object.useCapability('adapter'),
|
||||
objectPath = [],
|
||||
navigateToParent;
|
||||
if (mainTreeHeight !== 0) {
|
||||
this.calculateChildHeight(() => {
|
||||
let ancestorsHeight = this.calculateAncestorHeight();
|
||||
let allChildrenHeight = this.calculateChildrenHeight();
|
||||
|
||||
if (context) {
|
||||
objectPath = context.getPath().slice(1)
|
||||
.map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse();
|
||||
navigateToParent = '/browse/' + objectPath.slice(1)
|
||||
.map((parent) => this.openmct.objects.makeKeyString(parent.identifier))
|
||||
.join('/');
|
||||
if (this.activeSearch) {
|
||||
ancestorsHeight = 0;
|
||||
}
|
||||
this.availableContainerHeight = mainTreeHeight - ancestorsHeight;
|
||||
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(object.identifier),
|
||||
object,
|
||||
objectPath,
|
||||
navigateToParent
|
||||
if (allChildrenHeight > this.availableContainerHeight) {
|
||||
this.setPageThreshold();
|
||||
this.noScroll = false;
|
||||
} else {
|
||||
this.noScroll = true;
|
||||
}
|
||||
this.updatevisibleItems();
|
||||
});
|
||||
} else {
|
||||
window.setTimeout(this.setContainerHeight, RECHECK_DELAY);
|
||||
}
|
||||
},
|
||||
calculateFirstVisibleItem() {
|
||||
let scrollTop = this.$refs.scrollable.scrollTop;
|
||||
return Math.floor(scrollTop / this.itemHeight);
|
||||
},
|
||||
calculateLastVisibleItem() {
|
||||
let scrollBottom = this.$refs.scrollable.scrollTop + this.$refs.scrollable.offsetHeight;
|
||||
return Math.ceil(scrollBottom / this.itemHeight);
|
||||
},
|
||||
calculateChildrenHeight() {
|
||||
let mainTreeTopMargin = this.getElementStyleValue(this.$refs.mainTree, 'marginTop');
|
||||
let childrenCount = this.focusedItems.length;
|
||||
return (this.itemHeight * childrenCount) - mainTreeTopMargin; // 5px margin
|
||||
},
|
||||
setChildrenHeight() {
|
||||
this.childrenHeight = this.calculateChildrenHeight();
|
||||
},
|
||||
calculateAncestorHeight() {
|
||||
let ancestorCount = this.ancestors.length;
|
||||
return this.itemHeight * ancestorCount;
|
||||
},
|
||||
calculateChildHeight(callback) {
|
||||
if (callback) {
|
||||
this.afterChildHeight = callback;
|
||||
}
|
||||
if (!this.activeSearch) {
|
||||
this.getChildHeight = true;
|
||||
} else if (this.afterChildHeight) {
|
||||
// keep the height from before
|
||||
this.afterChildHeight();
|
||||
delete this.afterChildHeight;
|
||||
}
|
||||
},
|
||||
async setChildHeight(item) {
|
||||
if (!this.getChildHeight || this.settingChildrenHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.settingChildrenHeight = true;
|
||||
if (this.isMobile) {
|
||||
item = item.children[0];
|
||||
}
|
||||
await this.$nextTick();
|
||||
let topMargin = this.getElementStyleValue(item, 'marginTop');
|
||||
let bottomMargin = this.getElementStyleValue(item, 'marginBottom');
|
||||
let totalVerticalMargin = topMargin + bottomMargin;
|
||||
|
||||
this.itemHeight = item.clientHeight + totalVerticalMargin;
|
||||
this.setChildrenHeight();
|
||||
if (this.afterChildHeight) {
|
||||
this.afterChildHeight();
|
||||
delete this.afterChildHeight;
|
||||
}
|
||||
this.getChildHeight = false;
|
||||
this.settingChildrenHeight = false;
|
||||
},
|
||||
setPageThreshold() {
|
||||
let threshold = Math.ceil(this.availableContainerHeight / this.itemHeight) + ITEM_BUFFER;
|
||||
// all items haven't loaded yet (nextTick not working for this)
|
||||
if (threshold === ITEM_BUFFER) {
|
||||
window.setTimeout(this.setPageThreshold, RECHECK_DELAY);
|
||||
} else {
|
||||
this.pageThreshold = threshold;
|
||||
}
|
||||
},
|
||||
handleWindowResize() {
|
||||
if (!windowResizing) {
|
||||
windowResizing = true;
|
||||
window.clearTimeout(windowResizeId);
|
||||
windowResizeId = window.setTimeout(() => {
|
||||
this.setContainerHeight();
|
||||
windowResizing = false;
|
||||
}, RESIZE_FIRE_DELAY_MS);
|
||||
}
|
||||
},
|
||||
async getAllChildren(node) {
|
||||
this.isLoading = true;
|
||||
if (this.composition) {
|
||||
this.composition.off('add', this.addChild);
|
||||
this.composition.off('remove', this.removeChild);
|
||||
delete this.composition;
|
||||
}
|
||||
this.allTreeItems = [];
|
||||
this.composition = this.openmct.composition.get(node.object);
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
await this.composition.load();
|
||||
this.finishLoading();
|
||||
},
|
||||
buildTreeItem(domainObject) {
|
||||
let navToParent = ROOT_PATH + this.currentNavigatedPath;
|
||||
if (navToParent === ROOT_PATH) {
|
||||
navToParent = navToParent.slice(0, -1);
|
||||
}
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(domainObject.identifier),
|
||||
object: domainObject,
|
||||
objectPath: [domainObject].concat(this.currentObjectPath),
|
||||
navigateToParent: navToParent
|
||||
};
|
||||
},
|
||||
addChild(child) {
|
||||
let item = this.buildTreeItem(child);
|
||||
this.allTreeItems.push(item);
|
||||
if (!this.isLoading) {
|
||||
this.setContainerHeight();
|
||||
}
|
||||
},
|
||||
removeChild(identifier) {
|
||||
let removeId = this.openmct.objects.makeKeyString(identifier);
|
||||
this.allTreeItems = this.allTreeItems
|
||||
.filter(c => c.id !== removeId);
|
||||
this.setContainerHeight();
|
||||
},
|
||||
async finishLoading() {
|
||||
if (this.jumpPath) {
|
||||
this.jumpToPath();
|
||||
}
|
||||
this.autoScroll();
|
||||
this.isLoading = false;
|
||||
},
|
||||
async jumpToPath(saveExpandedPath = false) {
|
||||
let nodes = this.jumpPath.split('/');
|
||||
for(let i = 0; i < nodes.length; i++) {
|
||||
let currentNode = await this.openmct.objects.get(nodes[i]);
|
||||
let newParent = this.buildTreeItem(currentNode);
|
||||
this.ancestors.push(newParent);
|
||||
|
||||
if (i === nodes.length - 1) {
|
||||
this.jumpPath = '';
|
||||
this.getAllChildren(newParent);
|
||||
if (this.afterJump) {
|
||||
await this.$nextTick()
|
||||
this.afterJump();
|
||||
delete this.afterJump;
|
||||
}
|
||||
if (saveExpandedPath) {
|
||||
this.setCurrentNavigatedPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async autoScroll() {
|
||||
if (!this.scrollTo) {
|
||||
return;
|
||||
}
|
||||
if (this.$refs.scrollable) {
|
||||
let indexOfScroll = this.indexOfItemById(this.scrollTo);
|
||||
let scrollTopAmount = indexOfScroll * this.itemHeight;
|
||||
|
||||
await this.$nextTick();
|
||||
this.$refs.scrollable.scrollTop = scrollTopAmount;
|
||||
// race condition check
|
||||
if(scrollTopAmount > 0 && this.$refs.scrollable.scrollTop === 0) {
|
||||
window.setTimeout(this.autoScroll, RECHECK_DELAY);
|
||||
return;
|
||||
}
|
||||
this.scrollTo = undefined;
|
||||
} else {
|
||||
window.setTimeout(this.autoScroll, RECHECK_DELAY);
|
||||
}
|
||||
},
|
||||
indexOfItemById(id) {
|
||||
for(let i = 0; i < this.allTreeItems.length; i++) {
|
||||
if (this.allTreeItems[i].id === id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
},
|
||||
async getSearchResults() {
|
||||
let results = await this.searchService.query(this.searchValue);
|
||||
this.searchResultItems = results.hits.map(result => {
|
||||
|
||||
let context = result.object.getCapability('context');
|
||||
let object = result.object.useCapability('adapter');
|
||||
let objectPath = [];
|
||||
let navigateToParent;
|
||||
|
||||
if (context) {
|
||||
objectPath = context.getPath().slice(1)
|
||||
.map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse();
|
||||
navigateToParent = objectPath.slice(1)
|
||||
.map((parent) => this.openmct.objects.makeKeyString(parent.identifier));
|
||||
navigateToParent = ROOT_PATH + navigateToParent.reverse().join('/');
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(object.identifier),
|
||||
object,
|
||||
objectPath,
|
||||
navigateToParent
|
||||
}
|
||||
});
|
||||
},
|
||||
searchTree(value) {
|
||||
this.searchValue = value;
|
||||
|
||||
if (this.searchValue !== '') {
|
||||
this.getFilteredChildren();
|
||||
this.getSearchResults();
|
||||
}
|
||||
},
|
||||
searchActivated() {
|
||||
this.activeSearch = true;
|
||||
this.$refs.scrollable.scrollTop = 0;
|
||||
},
|
||||
searchDeactivated() {
|
||||
this.activeSearch = false;
|
||||
this.$refs.scrollable.scrollTop = 0;
|
||||
this.setContainerHeight();
|
||||
},
|
||||
handleReset(node) {
|
||||
this.childrenSlideClass = 'slide-right';
|
||||
this.ancestors.splice(this.ancestors.indexOf(node) + 1);
|
||||
this.getAllChildren(node);
|
||||
this.setCurrentNavigatedPath();
|
||||
},
|
||||
handleExpanded(node) {
|
||||
if (this.activeSearch) {
|
||||
return;
|
||||
}
|
||||
this.childrenSlideClass = 'slide-left';
|
||||
let newParent = this.buildTreeItem(node);
|
||||
this.ancestors.push(newParent);
|
||||
this.getAllChildren(newParent);
|
||||
this.setCurrentNavigatedPath();
|
||||
},
|
||||
getSavedNavigatedPath() {
|
||||
return JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED));
|
||||
},
|
||||
setCurrentNavigatedPath() {
|
||||
if (!this.searchValue) {
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY__TREE_EXPANDED, JSON.stringify(this.currentNavigatedPath));
|
||||
}
|
||||
},
|
||||
currentPathIsActivePath() {
|
||||
return this.getSavedNavigatedPath() === this.currentlyViewedObjectParentPath();
|
||||
},
|
||||
currentlyViewedObjectId() {
|
||||
let currentPath = this.openmct.router.currentLocation.path;
|
||||
if (currentPath) {
|
||||
currentPath = currentPath.split(ROOT_PATH)[1];
|
||||
return currentPath.split('/').pop();
|
||||
}
|
||||
},
|
||||
currentlyViewedObjectParentPath() {
|
||||
let currentPath = this.openmct.router.currentLocation.path;
|
||||
if (currentPath) {
|
||||
currentPath = currentPath.split(ROOT_PATH)[1];
|
||||
currentPath = currentPath.split('/');
|
||||
currentPath.pop();
|
||||
return currentPath.join('/');
|
||||
}
|
||||
},
|
||||
scrollItems(event) {
|
||||
if (!windowResizing) {
|
||||
this.updatevisibleItems();
|
||||
}
|
||||
},
|
||||
childrenListStyles() {
|
||||
return { position: 'relative' };
|
||||
},
|
||||
scrollableStyles() {
|
||||
return {
|
||||
height: this.availableContainerHeight + 'px',
|
||||
overflow: this.noScroll ? 'hidden' : 'scroll'
|
||||
}
|
||||
},
|
||||
emptyStyles() {
|
||||
let offset = ((this.ancestors.length + 1) * 10);
|
||||
return {
|
||||
paddingLeft: offset + 'px'
|
||||
};
|
||||
},
|
||||
childrenIn(el, done) {
|
||||
// still needing this timeout for some reason
|
||||
window.setTimeout(this.setContainerHeight, RECHECK_DELAY);
|
||||
done();
|
||||
},
|
||||
getElementStyleValue(el, style) {
|
||||
let styleString = window.getComputedStyle(el)[style];
|
||||
let index = styleString.indexOf('px');
|
||||
return Number(styleString.slice(0, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,10 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@include desktop() { margin-bottom: $interiorMargin; }
|
||||
|
||||
[class*="button"] {
|
||||
color: $colorBtnMajorBg;
|
||||
}
|
||||
}
|
||||
|
||||
&--reacts {
|
||||
@ -128,12 +132,23 @@
|
||||
@include userSelectNone();
|
||||
color: $splitterBtnLabelColorFg;
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
text-transform: uppercase;
|
||||
transform-origin: top left;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
[class*="expand-button"] {
|
||||
display: none; // Hidden by default
|
||||
background: $splitterCollapsedBtnColorBg;
|
||||
color: $splitterCollapsedBtnColorFg;
|
||||
font-size: 0.9em;
|
||||
|
||||
&:hover {
|
||||
background: $splitterCollapsedBtnColorBgHov;
|
||||
color: inherit;
|
||||
transition: $transIn;
|
||||
}
|
||||
}
|
||||
|
||||
&--resizing {
|
||||
// User is dragging the handle and resizing a pane
|
||||
@include userSelectNone();
|
||||
@ -160,23 +175,12 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.l-pane__header {
|
||||
&:hover {
|
||||
color: $splitterCollapsedBtnColorFgHov;
|
||||
.l-pane__label {
|
||||
color: inherit;
|
||||
}
|
||||
.l-pane__collapse-button {
|
||||
background: $splitterCollapsedBtnColorBgHov;
|
||||
color: inherit;
|
||||
transition: $transIn;
|
||||
}
|
||||
}
|
||||
[class*="collapse-button"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.l-pane__collapse-button {
|
||||
background: $splitterCollapsedBtnColorBg;
|
||||
color: $splitterCollapsedBtnColorFg;
|
||||
[class*="expand-button"] {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,36 +202,26 @@
|
||||
|
||||
.l-pane__collapse-button {
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-right-equilateral;
|
||||
content: $glyph-icon-line-horz;
|
||||
}
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
/************************ COLLAPSED HORIZONTAL SPLITTER, EITHER DIRECTION */
|
||||
[class*="__header"] {
|
||||
@include abs();
|
||||
margin: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
[class*="label"] {
|
||||
position: absolute;
|
||||
transform: translate($interiorMarginLg + 1, 18px) rotate(90deg);
|
||||
left: 3px;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.l-pane__collapse-button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0; // Only have to do this once, because of scaleX(-1) below.
|
||||
[class*="expand-button"] {
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
height: auto; width: 100%;
|
||||
padding: 0;
|
||||
padding: $interiorMargin 2px;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
[class*="label"] {
|
||||
text-orientation: mixed;
|
||||
text-transform: uppercase;
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,10 +237,9 @@
|
||||
transform: translateX(floor($splitterHandleD / -2)); // Center over the pane edge
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
.l-pane__collapse-button {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
[class*="expand-button"] {
|
||||
border-top-left-radius: $controlCr;
|
||||
border-bottom-left-radius: $controlCr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,10 +254,9 @@
|
||||
transform: translateX(floor($splitterHandleD / 2));
|
||||
}
|
||||
|
||||
&:not([class*="--collapsed"]) {
|
||||
.l-pane__collapse-button {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
[class*="expand-button"] {
|
||||
border-top-right-radius: $controlCr;
|
||||
border-bottom-right-radius: $controlCr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,19 @@
|
||||
<span v-if="label"
|
||||
class="l-pane__label"
|
||||
>{{ label }}</span>
|
||||
<slot name="controls"></slot>
|
||||
<button
|
||||
v-if="collapsable"
|
||||
class="l-pane__collapse-button c-button"
|
||||
class="l-pane__collapse-button c-icon-button"
|
||||
@click="toggleCollapse"
|
||||
></button>
|
||||
</div>
|
||||
<button
|
||||
class="l-pane__expand-button"
|
||||
@click="toggleCollapse"
|
||||
>
|
||||
<span class="l-pane__expand-button__label">{{ label }}</span>
|
||||
</button>
|
||||
<div class="l-pane__contents">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
@ -1,38 +1,39 @@
|
||||
<template>
|
||||
<li class="c-tree__item-h">
|
||||
<li
|
||||
ref="me"
|
||||
:style="{
|
||||
'top': virtualScroll ? itemTop : 'auto',
|
||||
'position': virtualScroll ? 'absolute' : 'relative'
|
||||
}"
|
||||
class="c-tree__item-h"
|
||||
>
|
||||
<div
|
||||
class="c-tree__item"
|
||||
:class="{ 'is-alias': isAlias, 'is-navigated-object': navigated }"
|
||||
:class="{
|
||||
'is-alias': isAlias,
|
||||
'is-navigated-object': navigated
|
||||
}"
|
||||
>
|
||||
<view-control
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:enabled="hasChildren"
|
||||
:control-class="'c-nav__up'"
|
||||
:enabled="showUp"
|
||||
@input="resetTreeHere"
|
||||
/>
|
||||
<object-label
|
||||
:domain-object="node.object"
|
||||
:object-path="node.objectPath"
|
||||
:navigate-to-path="navigateToPath"
|
||||
:style="{ paddingLeft: leftOffset }"
|
||||
/>
|
||||
<view-control
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:control-class="'c-nav__down'"
|
||||
:enabled="hasComposition && showDown"
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
v-if="expanded"
|
||||
class="c-tree"
|
||||
>
|
||||
<li
|
||||
v-if="isLoading && !loaded"
|
||||
class="c-tree__item-h"
|
||||
>
|
||||
<div class="c-tree__item loading">
|
||||
<span class="c-tree__item__label">Loading...</span>
|
||||
</div>
|
||||
</li>
|
||||
<tree-item
|
||||
v-for="child in children"
|
||||
:key="child.id"
|
||||
:node="child"
|
||||
/>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@ -40,8 +41,6 @@
|
||||
import viewControl from '../components/viewControl.vue';
|
||||
import ObjectLabel from '../components/ObjectLabel.vue';
|
||||
|
||||
const LOCAL_STORAGE_KEY__TREE_EXPANDED = 'mct-tree-expanded';
|
||||
|
||||
export default {
|
||||
name: 'TreeItem',
|
||||
inject: ['openmct'],
|
||||
@ -53,16 +52,48 @@ export default {
|
||||
node: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
leftOffset: {
|
||||
type: String,
|
||||
default: '0px'
|
||||
},
|
||||
showUp: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showDown: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
itemIndex: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
itemOffset: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
virtualScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
emitHeight: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
this.navigateToPath = this.buildPathString(this.node.navigateToParent);
|
||||
return {
|
||||
hasChildren: false,
|
||||
isLoading: false,
|
||||
loaded: false,
|
||||
hasComposition: false,
|
||||
navigated: this.navigateToPath === this.openmct.router.currentLocation.path,
|
||||
children: [],
|
||||
expanded: false
|
||||
}
|
||||
},
|
||||
@ -74,30 +105,23 @@ export default {
|
||||
}
|
||||
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
return parentKeyString !== this.node.object.location;
|
||||
},
|
||||
itemTop() {
|
||||
return (this.itemOffset + this.itemIndex) * this.itemHeight + 'px';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
expanded() {
|
||||
if (!this.hasChildren) {
|
||||
return;
|
||||
}
|
||||
if (!this.loaded && !this.isLoading) {
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
this.composition.load().then(this.finishLoading);
|
||||
this.isLoading = true;
|
||||
}
|
||||
this.setLocalStorageExpanded(this.navigateToPath);
|
||||
this.$emit('expanded', this.domainObject);
|
||||
},
|
||||
emitHeight() {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('emittedHeight', this.$refs.me);
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// TODO: should update on mutation.
|
||||
// TODO: click navigation should not fubar hash quite so much.
|
||||
// TODO: should highlight if navigated to.
|
||||
// TODO: should have context menu.
|
||||
// TODO: should support drag/drop composition
|
||||
// TODO: set isAlias per tree-item
|
||||
let objectComposition = this.openmct.composition.get(this.node.object);
|
||||
|
||||
this.domainObject = this.node.object;
|
||||
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
|
||||
@ -105,49 +129,19 @@ export default {
|
||||
});
|
||||
|
||||
this.$once('hook:destroyed', removeListener);
|
||||
if (this.openmct.composition.get(this.node.object)) {
|
||||
this.hasChildren = true;
|
||||
if (objectComposition) {
|
||||
this.hasComposition = true;
|
||||
}
|
||||
|
||||
this.openmct.router.on('change:path', this.highlightIfNavigated);
|
||||
|
||||
this.getLocalStorageExpanded();
|
||||
},
|
||||
beforeDestroy() {
|
||||
/****
|
||||
* calling this.setLocalStorageExpanded explicitly here because for whatever reason,
|
||||
* the watcher on this.expanded is not triggering this.setLocalStorageExpanded(),
|
||||
* even though Vue documentation states, "At this stage the instance is still fully functional."
|
||||
*****/
|
||||
this.expanded = false;
|
||||
this.setLocalStorageExpanded();
|
||||
if(this.emitHeight) {
|
||||
this.$emit('emittedHeight', this.$refs.me);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.router.off('change:path', this.highlightIfNavigated);
|
||||
if (this.composition) {
|
||||
this.composition.off('add', this.addChild);
|
||||
this.composition.off('remove', this.removeChild);
|
||||
delete this.composition;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addChild(child) {
|
||||
this.children.push({
|
||||
id: this.openmct.objects.makeKeyString(child.identifier),
|
||||
object: child,
|
||||
objectPath: [child].concat(this.node.objectPath),
|
||||
navigateToParent: this.navigateToPath
|
||||
});
|
||||
},
|
||||
removeChild(identifier) {
|
||||
let removeId = this.openmct.objects.makeKeyString(identifier);
|
||||
this.children = this.children
|
||||
.filter(c => c.id !== removeId);
|
||||
},
|
||||
finishLoading() {
|
||||
this.isLoading = false;
|
||||
this.loaded = true;
|
||||
},
|
||||
buildPathString(parentPath) {
|
||||
return [parentPath, this.openmct.objects.makeKeyString(this.node.object.identifier)].join('/');
|
||||
},
|
||||
@ -158,35 +152,8 @@ export default {
|
||||
this.navigated = false;
|
||||
}
|
||||
},
|
||||
getLocalStorageExpanded() {
|
||||
let expandedPaths = localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED);
|
||||
|
||||
if (expandedPaths) {
|
||||
expandedPaths = JSON.parse(expandedPaths);
|
||||
this.expanded = expandedPaths.includes(this.navigateToPath);
|
||||
}
|
||||
},
|
||||
// expanded nodes/paths are stored in local storage as an array
|
||||
setLocalStorageExpanded() {
|
||||
let expandedPaths = localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED);
|
||||
expandedPaths = expandedPaths ? JSON.parse(expandedPaths) : [];
|
||||
|
||||
if (this.expanded) {
|
||||
if (!expandedPaths.includes(this.navigateToPath)) {
|
||||
expandedPaths.push(this.navigateToPath);
|
||||
}
|
||||
} else {
|
||||
// remove this node path and all children paths from stored expanded paths
|
||||
expandedPaths = expandedPaths.filter(path => !path.startsWith(this.navigateToPath));
|
||||
}
|
||||
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY__TREE_EXPANDED, JSON.stringify(expandedPaths));
|
||||
},
|
||||
removeLocalStorageExpanded() {
|
||||
let expandedPaths = localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED);
|
||||
expandedPaths = expandedPaths ? JSON.parse(expandedPaths) : [];
|
||||
expandedPaths = expandedPaths.filter(path => !path.startsWith(this.navigateToPath));
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY__TREE_EXPANDED, JSON.stringify(expandedPaths));
|
||||
resetTreeHere() {
|
||||
this.$emit('resetTree', this.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ export default {
|
||||
|
||||
this.viewKey = view.key;
|
||||
this.viewContainer = document.createElement('div');
|
||||
this.viewContainer.classList.add('u-angular-object-view-wrapper');
|
||||
this.viewContainer.classList.add('l-angular-ov-wrapper');
|
||||
this.$refs.objectView.append(this.viewContainer);
|
||||
|
||||
this.view = this.currentView.view(this.domainObject, this.objectPath);
|
||||
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<div class="l-browse-bar">
|
||||
<div class="c-preview-header l-browse-bar">
|
||||
<div class="l-browse-bar__start">
|
||||
<div
|
||||
class="l-browse-bar__object-name--w"
|
||||
:class="type.cssClass"
|
||||
class="l-browse-bar__object-name--w c-object-label"
|
||||
>
|
||||
<span class="l-browse-bar__object-name">
|
||||
<div class="c-object-label__type-icon"
|
||||
:class="type.cssClass"
|
||||
></div>
|
||||
<span class="l-browse-bar__object-name c-object-label__name">
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
<context-menu-drop-down :object-path="objectPath" />
|
||||
|
@ -13,11 +13,9 @@
|
||||
}
|
||||
|
||||
&__object-view {
|
||||
background: $colorBodyBg;
|
||||
border: 1px solid $colorInteriorBorder;
|
||||
flex: 1 1 auto;
|
||||
height: 0; // Chrome 73
|
||||
overflow: auto;
|
||||
padding: $interiorMargin;
|
||||
|
||||
> div:not([class]) {
|
||||
// Target an immediate child div without a class and make it display: contents
|
||||
|
@ -14,6 +14,9 @@ const gitRevision = require('child_process')
|
||||
const gitBranch = require('child_process')
|
||||
.execSync('git rev-parse --abbrev-ref HEAD')
|
||||
.toString().trim();
|
||||
const vueFile = devMode ?
|
||||
path.join(__dirname, "node_modules/vue/dist/vue.js") :
|
||||
path.join(__dirname, "node_modules/vue/dist/vue.min.js");
|
||||
|
||||
const webpackConfig = {
|
||||
mode: devMode ? 'development' : 'production',
|
||||
@ -37,7 +40,7 @@ const webpackConfig = {
|
||||
"csv": "comma-separated-values",
|
||||
"EventEmitter": "eventemitter3",
|
||||
"bourbon": "bourbon.scss",
|
||||
"vue": path.join(__dirname, "node_modules/vue/dist/vue.js"),
|
||||
"vue": vueFile,
|
||||
"d3-scale": path.join(__dirname, "node_modules/d3-scale/build/d3-scale.min.js"),
|
||||
"printj": path.join(__dirname, "node_modules/printj/dist/printj.min.js"),
|
||||
"styles": path.join(__dirname, "src/styles"),
|
||||
|
Reference in New Issue
Block a user