mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 03:00:13 +00:00
Compare commits
10 Commits
vue-table-
...
vue-main-s
Author | SHA1 | Date | |
---|---|---|---|
f8fe37d41f | |||
4f5b9902a6 | |||
e5c2d7b256 | |||
6737c71c45 | |||
ca055ab765 | |||
4ba90ff73e | |||
eaa971cb56 | |||
0301d88033 | |||
e2e0cf17db | |||
01a39f4fb7 |
@ -66,5 +66,4 @@
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
<mct-include key="'conductor'" class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"></mct-include>
|
||||
</div>
|
||||
|
@ -319,6 +319,12 @@ define([
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
key: "elementsPool",
|
||||
template: elementsTemplate
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"type": "decorator",
|
||||
|
@ -55,7 +55,7 @@ define(
|
||||
|
||||
// A view is editable unless explicitly flagged as not
|
||||
(views || []).forEach(function (view) {
|
||||
if (isEditable(view) ||
|
||||
if (view.editable === true ||
|
||||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
|
||||
(view.key === 'table' && type.getKey() === 'table') ||
|
||||
(view.key === 'rt-table' && type.getKey() === 'rttable')
|
||||
@ -64,14 +64,6 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
function isEditable(view) {
|
||||
if (typeof view.editable === Function) {
|
||||
return view.editable(domainObject.useCapability('adapter'));
|
||||
} else {
|
||||
return view.editable === true;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,6 @@ define([
|
||||
'./plugins/plugins',
|
||||
'./adapter/indicators/legacy-indicators-plugin',
|
||||
'./plugins/buildInfo/plugin',
|
||||
'./adapter/vue-adapter/install',
|
||||
'./ui/registries/ViewRegistry',
|
||||
'./ui/registries/InspectorViewRegistry',
|
||||
'./ui/registries/ToolbarRegistry',
|
||||
@ -51,7 +50,6 @@ define([
|
||||
plugins,
|
||||
LegacyIndicatorsPlugin,
|
||||
buildInfoPlugin,
|
||||
installVueAdapter,
|
||||
ViewRegistry,
|
||||
InspectorViewRegistry,
|
||||
ToolbarRegistry,
|
||||
@ -336,8 +334,6 @@ define([
|
||||
});
|
||||
domElement.appendChild(appLayout.$mount().$el);
|
||||
|
||||
console.log('Attaching adapter');
|
||||
installVueAdapter(appLayout, this);
|
||||
|
||||
this.router.start();
|
||||
this.emit('start');
|
||||
|
@ -1,41 +0,0 @@
|
||||
define([
|
||||
|
||||
], function (
|
||||
|
||||
) {
|
||||
|
||||
class InspectorAdapter {
|
||||
constructor(layout, openmct) {
|
||||
console.log('installing inspector adapter');
|
||||
|
||||
this.openmct = openmct;
|
||||
this.layout = layout;
|
||||
this.$injector = openmct.$injector;
|
||||
this.angular = openmct.$angular;
|
||||
|
||||
this.objectService = this.$injector.get('objectService');
|
||||
this.templateLinker = this.$injector.get('templateLinker');
|
||||
this.$timeout = this.$injector.get('$timeout');
|
||||
|
||||
this.templateMap = {};
|
||||
this.$injector.get('templates[]').forEach((t) => {
|
||||
this.templateMap[t.key] = this.templateMap[t.key] || t;
|
||||
});
|
||||
|
||||
var $rootScope = this.$injector.get('$rootScope');
|
||||
this.scope = $rootScope.$new();
|
||||
|
||||
this.templateLinker.link(
|
||||
this.scope,
|
||||
angular.element(layout.$refs.inspector.$refs.properties),
|
||||
this.templateMap["inspectorRegion"]
|
||||
);
|
||||
this.$timeout(function () {
|
||||
//hello!
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return InspectorAdapter;
|
||||
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
define([
|
||||
'./main-adapter',
|
||||
'./tree-adapter',
|
||||
'./inspector-adapter'
|
||||
], function (
|
||||
MainAdapter,
|
||||
TreeAdapter,
|
||||
InspectorAdapter
|
||||
) {
|
||||
|
||||
return function install(layout, openmct) {
|
||||
let main = new MainAdapter(layout, openmct);
|
||||
let tree = new TreeAdapter(layout, openmct);
|
||||
let inspector = new InspectorAdapter(layout, openmct);
|
||||
}
|
||||
});
|
@ -1,153 +0,0 @@
|
||||
define([
|
||||
|
||||
], function (
|
||||
|
||||
) {
|
||||
|
||||
// Find an object in an array of objects.
|
||||
function findObject(domainObjects, id) {
|
||||
var i;
|
||||
for (i = 0; i < domainObjects.length; i += 1) {
|
||||
if (domainObjects[i].getId() === id) {
|
||||
return domainObjects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recursively locate and return an object inside of a container
|
||||
// via a path. If at any point in the recursion it fails to find
|
||||
// the next object, it will return the parent.
|
||||
function findViaComposition(containerObject, path) {
|
||||
var nextId = path.shift();
|
||||
if (!nextId) {
|
||||
return containerObject;
|
||||
}
|
||||
return containerObject.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
var nextObject = findObject(composees, nextId);
|
||||
if (!nextObject) {
|
||||
return containerObject;
|
||||
}
|
||||
if (!nextObject.hasCapability('composition')) {
|
||||
return nextObject;
|
||||
}
|
||||
return findViaComposition(nextObject, path);
|
||||
});
|
||||
}
|
||||
|
||||
function getLastChildIfRoot(object) {
|
||||
if (object.getId() !== 'ROOT') {
|
||||
return object;
|
||||
}
|
||||
return object.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
return composees[composees.length - 1];
|
||||
});
|
||||
}
|
||||
|
||||
function pathForObject(domainObject) {
|
||||
var context = domainObject.getCapability('context'),
|
||||
objectPath = context ? context.getPath() : [],
|
||||
ids = objectPath.map(function (domainObj) {
|
||||
return domainObj.getId();
|
||||
});
|
||||
return "/browse/" + ids.slice(1).join("/");
|
||||
}
|
||||
|
||||
class MainAdapter {
|
||||
constructor(layout, openmct) {
|
||||
this.openmct = openmct;
|
||||
this.layout = layout;
|
||||
this.$injector = openmct.$injector;
|
||||
this.angular = openmct.$angular;
|
||||
|
||||
this.objectService = this.$injector.get('objectService');
|
||||
this.templateLinker = this.$injector.get('templateLinker');
|
||||
this.navigationService = this.$injector.get('navigationService');
|
||||
this.$timeout = this.$injector.get('$timeout');
|
||||
|
||||
this.templateMap = {};
|
||||
this.$injector.get('templates[]').forEach((t) => {
|
||||
this.templateMap[t.key] = this.templateMap[t.key] || t;
|
||||
});
|
||||
|
||||
var $rootScope = this.$injector.get('$rootScope');
|
||||
this.scope = $rootScope.$new();
|
||||
this.scope.representation = {};
|
||||
|
||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results) => {
|
||||
let navigatePath = results[1];
|
||||
if (!navigatePath) {
|
||||
navigatePath = 'mine';
|
||||
}
|
||||
this.navigateToPath(navigatePath);
|
||||
});
|
||||
|
||||
this.navigationService.addListener(o => this.navigateToObject(o));
|
||||
}
|
||||
|
||||
navigateToPath(path) {
|
||||
if (!Array.isArray(path)) {
|
||||
path = path.split('/');
|
||||
}
|
||||
return this.getObject('ROOT')
|
||||
.then(root => {
|
||||
return findViaComposition(root, path);
|
||||
})
|
||||
.then(getLastChildIfRoot)
|
||||
.then(object => {
|
||||
this.setMainViewObject(object);
|
||||
});
|
||||
}
|
||||
|
||||
setMainViewObject(object) {
|
||||
this.scope.domainObject = object;
|
||||
this.scope.navigatedObject = object;
|
||||
this.templateLinker.link(
|
||||
this.scope,
|
||||
angular.element(this.layout.$refs.mainContainer),
|
||||
this.templateMap["browseObject"]
|
||||
);
|
||||
document.title = object.getModel().name;
|
||||
this.scheduleDigest();
|
||||
}
|
||||
|
||||
idsForObject(domainObject) {
|
||||
return this.urlService
|
||||
.urlForLocation("", domainObject)
|
||||
.replace('/', '');
|
||||
}
|
||||
|
||||
navigateToObject(object) {
|
||||
let path = pathForObject(object);
|
||||
let views = object.useCapability('view');
|
||||
let params = this.openmct.router.getParams();
|
||||
let currentViewIsValid = views.some(v => v.key === params['view']);
|
||||
if (!currentViewIsValid) {
|
||||
this.scope.representation = {
|
||||
selected: views[0]
|
||||
}
|
||||
this.openmct.router.update(path, {
|
||||
view: views[0].key
|
||||
});
|
||||
} else {
|
||||
this.openmct.router.setPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
scheduleDigest() {
|
||||
this.$timeout(function () {
|
||||
// digest done!
|
||||
});
|
||||
}
|
||||
|
||||
getObject(id) {
|
||||
return this.objectService.getObjects([id])
|
||||
.then(function (results) {
|
||||
return results[id];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return MainAdapter;
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
define([
|
||||
|
||||
], function (
|
||||
|
||||
) {
|
||||
|
||||
class TreeAdapter {
|
||||
constructor(layout, openmct) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return TreeAdapter;
|
||||
|
||||
});
|
@ -20,18 +20,20 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import CSV from 'comma-separated-values';
|
||||
import {saveAs} from 'file-saver/FileSaver';
|
||||
|
||||
class CSVExporter {
|
||||
export(rows, options) {
|
||||
let headers = (options && options.headers) ||
|
||||
(Object.keys((rows[0] || {})).sort());
|
||||
let filename = (options && options.filename) || "export.csv";
|
||||
let csvText = new CSV(rows, { header: headers }).encode();
|
||||
let blob = new Blob([csvText], { type: "text/csv" });
|
||||
saveAs(blob, filename);
|
||||
define([
|
||||
'csv',
|
||||
'saveAs'
|
||||
], function (CSV, saveAs) {
|
||||
class CSVExporter {
|
||||
export(rows, options) {
|
||||
let headers = (options && options.headers) ||
|
||||
(Object.keys((rows[0] || {})).sort());
|
||||
let filename = (options && options.filename) || "export.csv";
|
||||
let csvText = new CSV(rows, { header: headers }).encode();
|
||||
let blob = new Blob([csvText], { type: "text/csv" });
|
||||
saveAs(blob, filename);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default CSVExporter;
|
||||
return CSVExporter;
|
||||
});
|
@ -1,123 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* 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 _ from 'lodash';
|
||||
import MCT from '../../MCT.js';
|
||||
import ObjectViewsRegistry from '../../ui/registries/ViewRegistry.js';
|
||||
import InspectorViewsRegistry from '../../ui/registries/InspectorViewRegistry.js';
|
||||
import TelemetryTableViewProvider from './TelemetryTableViewProvider.js';
|
||||
import TableConfigurationViewProvider from './TableConfigurationViewProvider.js';
|
||||
|
||||
fdescribe('The TelemetryTable plugin', function() {
|
||||
let openmct;
|
||||
let tableType;
|
||||
let objectViewsSpy;
|
||||
let inspectorViewsSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
objectViewsSpy = spyOn(ObjectViewsRegistry.prototype, 'addProvider');
|
||||
inspectorViewsSpy = spyOn(InspectorViewsRegistry.prototype, 'addProvider');
|
||||
openmct = new MCT();
|
||||
tableType = openmct.types.get('table');
|
||||
});
|
||||
|
||||
describe('defines a telemetry object type', function () {
|
||||
it('that is registered with the type registry.', function () {
|
||||
expect(tableType).toBeDefined();
|
||||
});
|
||||
|
||||
it('that is createable.', function () {
|
||||
expect(tableType.definition.creatable).toBe(true);
|
||||
});
|
||||
|
||||
describe('that initializes new table object.', function () {
|
||||
let tableObject;
|
||||
|
||||
beforeEach(function () {
|
||||
tableObject = {};
|
||||
tableType.definition.initialize(tableObject);
|
||||
});
|
||||
it('with valid default configuration.', function () {
|
||||
expect(tableObject.configuration.hiddenColumns).toBeDefined();
|
||||
});
|
||||
it('to support composition.', function () {
|
||||
expect(tableObject.composition).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('registers the table view provider', function () {
|
||||
expect(objectViewsSpy).toHaveBeenCalledWith(new TelemetryTableViewProvider(openmct));
|
||||
});
|
||||
|
||||
it('registers the table configuration view provider', function () {
|
||||
expect(inspectorViewsSpy).toHaveBeenCalledWith(new TableConfigurationViewProvider(openmct));
|
||||
});
|
||||
|
||||
/*
|
||||
it('defines a view for telemetry objects', function() {
|
||||
let tableObject = createTableObject();
|
||||
let views = openmct.objectViews.get(tableObject);
|
||||
|
||||
expect(findTableView(views)).toBeDefined();
|
||||
});
|
||||
|
||||
it('defines a table view for telemetry objects', function() {
|
||||
let telemetryObject = createTelemetryObject();
|
||||
let views = openmct.objectViews.get(telemetryObject);
|
||||
|
||||
expect(findTableView(views)).toBeDefined();
|
||||
});
|
||||
|
||||
it('defines a configuration view for table objects', function() {
|
||||
let tableObject = createTableObject();
|
||||
let selection = createSelection(tableObject);
|
||||
let views = openmct.inspectorViews.get(selection);
|
||||
|
||||
expect(views).toBeDefined();
|
||||
expect(findTableView(views)).toBeDefined();
|
||||
});
|
||||
function findTableView(views) {
|
||||
return views.find(view => view.key === 'table');
|
||||
}
|
||||
|
||||
function createTableObject() {
|
||||
let tableObject = {};
|
||||
tableType.definition.initialize(tableObject);
|
||||
|
||||
return tableObject;
|
||||
}
|
||||
|
||||
function createTelemetryObject() {
|
||||
return {
|
||||
telemetry: {}
|
||||
};
|
||||
}
|
||||
|
||||
function createSelection(object) {
|
||||
return [{
|
||||
context: {
|
||||
item: object
|
||||
}
|
||||
}];
|
||||
}
|
||||
*/
|
||||
});
|
@ -1,42 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* 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 _ from 'lodash';
|
||||
import MCT from '../../MCT.js';
|
||||
import TelemetryTablePlugin from './plugin.js';
|
||||
|
||||
describe('The TelemetryTable view', function() {
|
||||
let mockTimeSystem;
|
||||
let openmct;
|
||||
let tablePlugin;
|
||||
|
||||
beforeEach(function () {
|
||||
openmct = new MCT();
|
||||
mockTimeSystem = {
|
||||
key: 'utc'
|
||||
};
|
||||
spyOn(openmct.time, 'timeSystem');
|
||||
openmct.time.timeSystem.and.returnValue(mockTimeSystem);
|
||||
});
|
||||
|
||||
//it('allows editing of table objects');
|
||||
//it('does not allow editing of telemetry objects');
|
||||
});
|
@ -30,11 +30,12 @@ define([], function () {
|
||||
this.objectKeyString = objectKeyString;
|
||||
}
|
||||
|
||||
getFormattedDatum(headers) {
|
||||
return Object.keys(headers).reduce((formattedDatum, columnKey) => {
|
||||
formattedDatum[columnKey] = this.getFormattedValue(columnKey);
|
||||
return formattedDatum;
|
||||
}, {});
|
||||
getFormattedDatum() {
|
||||
return Object.values(this.columns)
|
||||
.reduce((formattedDatum, column) => {
|
||||
formattedDatum[column.getKey()] = this.getFormattedValue(column.getKey());
|
||||
return formattedDatum;
|
||||
}, {});
|
||||
}
|
||||
|
||||
getFormattedValue(key) {
|
||||
|
@ -30,7 +30,7 @@ define(function () {
|
||||
initialize(domainObject) {
|
||||
domainObject.composition = [];
|
||||
domainObject.configuration = {
|
||||
hiddenColumns: {}
|
||||
columns: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -35,14 +35,12 @@ define([
|
||||
return {
|
||||
key: 'table',
|
||||
name: 'Telemetry Table',
|
||||
editable: function(domainObject) {
|
||||
return domainObject.type === 'table';
|
||||
},
|
||||
editable: true,
|
||||
canView: function (domainObject) {
|
||||
return domainObject.type === 'table' || domainObject.hasOwnProperty('telemetry');
|
||||
},
|
||||
view: function (domainObject) {
|
||||
let csvExporter = new CSVExporter.default();
|
||||
let csvExporter = new CSVExporter();
|
||||
let table = new TelemetryTable(domainObject, openmct);
|
||||
let component;
|
||||
return {
|
||||
|
@ -1,111 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* 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 _ from 'lodash';
|
||||
import MCT from '../../../MCT.js';
|
||||
import SortedTableRowCollection from './SortedTableRowCollection.js';
|
||||
|
||||
describe('The SortedTableRowCollection', function() {
|
||||
let mockTimeSystem;
|
||||
let openmct;
|
||||
let rows;
|
||||
let mockSortedIndex;
|
||||
|
||||
beforeEach(function () {
|
||||
openmct = new MCT();
|
||||
mockTimeSystem = {
|
||||
key: 'utc'
|
||||
};
|
||||
spyOn(openmct.time, 'timeSystem');
|
||||
openmct.time.timeSystem.and.returnValue(mockTimeSystem);
|
||||
rows = new BoundedTableRowCollection(openmct);
|
||||
});
|
||||
|
||||
describe('Shortcut behavior', function() {
|
||||
let testTelemetry;
|
||||
beforeEach(function() {
|
||||
testTelemetry = [
|
||||
{
|
||||
datum: {utc: 100}
|
||||
}, {
|
||||
datum: {utc: 200}
|
||||
}, {
|
||||
datum: {utc: 300}
|
||||
}, {
|
||||
datum: {utc: 400}
|
||||
}
|
||||
];
|
||||
rows.add(testTelemetry);
|
||||
mockSortedIndex = spyOn(_, 'sortedIndex');
|
||||
mockSortedIndex.and.callThrough();
|
||||
});
|
||||
describe('when sorted ascending', function () {
|
||||
it('Uses lodash sortedIndex to find insertion point when test value is between first and last values', function () {
|
||||
rows.add({
|
||||
datum: {utc: 250}
|
||||
});
|
||||
expect(mockSortedIndex).toHaveBeenCalled();
|
||||
});
|
||||
it('shortcuts insertion point search when test value is greater than last value', function() {
|
||||
rows.add({
|
||||
datum: {utc: 500}
|
||||
});
|
||||
expect(mockSortedIndex).not.toHaveBeenCalled();
|
||||
});
|
||||
it('shortcuts insertion point search when test value is less than or equal to first value', function () {
|
||||
rows.add({
|
||||
datum: {utc: 100}
|
||||
});
|
||||
|
||||
rows.add({
|
||||
datum: {utc: 50}
|
||||
});
|
||||
expect(mockSortedIndex).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('when sorted descending', function () {
|
||||
it('Uses lodash sortedIndex to find insertion point when test value is between first and last values', function () {
|
||||
rows.add({
|
||||
datum: {utc: 250}
|
||||
});
|
||||
expect(mockSortedIndex).toHaveBeenCalled();
|
||||
});
|
||||
it('shortcuts insertion point search when test value is greater than last value', function() {
|
||||
rows.add({
|
||||
datum: {utc: 500}
|
||||
});
|
||||
expect(mockSortedIndex).not.toHaveBeenCalled();
|
||||
});
|
||||
it('shortcuts insertion point search when test value is less than or equal to first value', function () {
|
||||
rows.add({
|
||||
datum: {utc: 100}
|
||||
});
|
||||
|
||||
rows.add({
|
||||
datum: {utc: 50}
|
||||
});
|
||||
expect(mockSortedIndex).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
it('Evicts old telemetry on bounds change');
|
||||
it('Does not drop data that falls ahead of end bounds');
|
||||
});
|
||||
});
|
@ -82,7 +82,8 @@ define(
|
||||
// Going to check for duplicates. Bound the search problem to
|
||||
// items around the given time. Use sortedIndex because it
|
||||
// employs a binary search which is O(log n). Can use binary search
|
||||
// because the array is guaranteed ordered due to sorted insertion.
|
||||
// based on time stamp because the array is guaranteed ordered due
|
||||
// to sorted insertion.
|
||||
let startIx = this.sortedIndex(this.rows, row);
|
||||
let endIx = undefined;
|
||||
|
||||
@ -112,49 +113,26 @@ define(
|
||||
* @private
|
||||
*/
|
||||
sortedIndex(rows, testRow, lodashFunction) {
|
||||
if (this.rows.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sortOptionsKey = this.sortOptions.key;
|
||||
const testRowValue = testRow.datum[sortOptionsKey];
|
||||
const firstValue = this.rows[0].datum[sortOptionsKey];
|
||||
const lastValue = this.rows[this.rows.length - 1].datum[sortOptionsKey];
|
||||
|
||||
lodashFunction = lodashFunction || _.sortedIndex;
|
||||
|
||||
if (this.sortOptions.direction === 'asc') {
|
||||
if (testRowValue > lastValue) {
|
||||
return this.rows.length;
|
||||
} else if (testRowValue === lastValue) {
|
||||
return this.rows.length - 1;
|
||||
} else if (testRowValue <= firstValue) {
|
||||
return 0;
|
||||
} else {
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
return thisRow.datum[sortOptionsKey];
|
||||
});
|
||||
}
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
return thisRow.datum[sortOptionsKey];
|
||||
});
|
||||
} else {
|
||||
if (testRowValue >= firstValue) {
|
||||
return 0;
|
||||
} else if (testRowValue < lastValue) {
|
||||
return this.rows.length;
|
||||
} else if (testRowValue === lastValue) {
|
||||
return this.rows.length - 1;
|
||||
} else {
|
||||
// Use a custom comparison function to support descending sort.
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
const thisRowValue = thisRow.datum[sortOptionsKey];
|
||||
if (testRowValue === thisRowValue) {
|
||||
return EQUAL;
|
||||
} else if (testRowValue < thisRowValue) {
|
||||
return LESS_THAN;
|
||||
} else {
|
||||
return GREATER_THAN;
|
||||
}
|
||||
});
|
||||
}
|
||||
const testRowValue = testRow.datum[this.sortOptions.key];
|
||||
// Use a custom comparison function to support descending sort.
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
const thisRowValue = thisRow.datum[sortOptionsKey];
|
||||
if (testRowValue === thisRowValue) {
|
||||
return EQUAL;
|
||||
} else if (testRowValue < thisRowValue) {
|
||||
return LESS_THAN;
|
||||
} else {
|
||||
return GREATER_THAN;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ export default {
|
||||
data: function () {
|
||||
return {
|
||||
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
|
||||
formattedRow: this.row.getFormattedDatum(this.headers),
|
||||
formattedRow: this.row.getFormattedDatum(),
|
||||
rowLimitClass: this.row.getRowLimitClass(),
|
||||
cellLimitClasses: this.row.getCellLimitClasses()
|
||||
}
|
||||
@ -59,7 +59,7 @@ export default {
|
||||
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
|
||||
},
|
||||
formatRow: function (row) {
|
||||
this.formattedRow = row.getFormattedDatum(this.headers);
|
||||
this.formattedRow = row.getFormattedDatum();
|
||||
this.rowLimitClass = row.getRowLimitClass();
|
||||
this.cellLimitClasses = row.getCellLimitClasses();
|
||||
}
|
||||
|
@ -80,7 +80,8 @@
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
|
||||
> [class*="__"] + [class*="__"] {
|
||||
&__control-bar,
|
||||
&__headers-w {
|
||||
// Don't allow top level elements to grow or shrink
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@ -89,6 +90,7 @@
|
||||
th, td {
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
font-size: 0.7rem; // TEMP LEGACY TODO: refactor this when __main-container font-size is dealt with
|
||||
white-space: nowrap;
|
||||
min-width: $min-w;
|
||||
padding: $tabularTdPadTB $tabularTdPadLR;
|
||||
@ -203,7 +205,7 @@
|
||||
/******************************* WRAPPERS */
|
||||
&__body-w {
|
||||
// Wraps __body table provides scrolling
|
||||
flex: 1 1 100% !important; // TODO: temp override on tabular-holder > * { style which sets this to 0 0 auto
|
||||
flex: 1 1 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@ -233,7 +235,7 @@
|
||||
z-index: -1;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
position: absolute !important; // TODO: fix tabular-holder > * { which sets this to pos: relative
|
||||
position: absolute;
|
||||
|
||||
//Add some padding to allow for decorations such as limits indicator
|
||||
tr {
|
||||
@ -280,6 +282,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
headers: {},
|
||||
headersCount: 0,
|
||||
visibleRows: [],
|
||||
columnWidths: [],
|
||||
sizingRows: {},
|
||||
@ -343,6 +346,7 @@ export default {
|
||||
let headers = this.table.configuration.getVisibleHeaders();
|
||||
|
||||
this.headers = headers;
|
||||
this.headersCount = Object.values(headers).length;
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
},
|
||||
setSizingTableWidth() {
|
||||
@ -450,12 +454,12 @@ export default {
|
||||
}
|
||||
},
|
||||
exportAsCSV() {
|
||||
const headerKeys = Object.keys(this.headers);
|
||||
const justTheData = this.table.filteredRows.getRows()
|
||||
.map(row => row.getFormattedDatum(this.headers));
|
||||
.map(row => row.getFormattedDatum());
|
||||
const headers = Object.keys(this.headers);
|
||||
this.csvExporter.export(justTheData, {
|
||||
filename: this.table.domainObject.name + '.csv',
|
||||
headers: headerKeys
|
||||
headers: headers
|
||||
});
|
||||
},
|
||||
outstandingRequests(loading) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
}
|
||||
|
||||
// Global
|
||||
$fontBaseSize: 12px;
|
||||
$colorBodyBg: #fcfcfc;
|
||||
$colorBodyFg: #666;
|
||||
$colorGenBg: #fff;
|
||||
@ -19,6 +20,7 @@ $colorStatusBarBg: #000;
|
||||
$colorStatusBarFg: #999;
|
||||
$colorStatusBarFgHov: #aaa;
|
||||
$colorKey: #0099cc;
|
||||
$colorKeyFilter: brightness(0.9) sepia(1) hue-rotate(145deg) saturate(6);
|
||||
$colorKeySelectedBg: $colorKey;
|
||||
$colorKeyFg: #fff;
|
||||
$colorKeyHov: #00c0f6;
|
||||
@ -36,7 +38,8 @@ $overlayCr: 11px;
|
||||
$shdwTextSubtle: rgba(black, 0.2) 0 1px 2px;
|
||||
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, $contrastRatioPercent);
|
||||
$btnPad: $interiorMargin, $interiorMargin * 1.25;
|
||||
$colorBtnBg: #aaaaaa;
|
||||
$colorBtnBgHov: pullForward($colorBtnBg, $hoverRatioPercent);
|
||||
$colorBtnFg: #fff;
|
||||
$colorBtnFgHov: $colorBtnFg;
|
||||
@ -68,6 +71,7 @@ $sliderKnobR: 2px;
|
||||
$timeControllerToiLineColor: $colorBodyFg;
|
||||
$timeControllerToiLineColorHov: #0052b5;
|
||||
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
|
||||
$createBtnTextTransform: uppercase;
|
||||
|
||||
// Foundation Colors
|
||||
$colorAlt1: #776ba2;
|
||||
@ -90,17 +94,18 @@ $colorTick: rgba(black, 0.2);
|
||||
$colorSelectableSelectedPrimary: $colorKey;
|
||||
$colorSelectableHov: rgba($colorBodyFg, 0.4);
|
||||
|
||||
// Menu colors
|
||||
// Menus
|
||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
|
||||
$colorMenuFg: pullForward($colorMenuBg, 70%);
|
||||
$colorMenuIc: $colorKey;
|
||||
$colorMenuHovBg: pullForward($colorMenuBg, $hoverRatioPercent);
|
||||
$colorMenuHovFg: $colorMenuFg;
|
||||
$colorMenuHovIc: $colorMenuIc;
|
||||
$colorMenuHovBg: $colorMenuIc; //pullForward($colorMenuBg, $hoverRatioPercent);
|
||||
$colorMenuHovFg: $colorMenuBg;
|
||||
$colorMenuHovIc: $colorMenuBg;
|
||||
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
|
||||
$shdwMenuText: none;
|
||||
$colorCreateMenuLgIcon: $colorKey;
|
||||
$colorCreateMenuText: $colorBodyFg;
|
||||
$menuItemPad: ($interiorMargin, nth($btnPad, 2));
|
||||
|
||||
// Form colors
|
||||
$colorCheck: $colorKey;
|
||||
@ -238,13 +243,14 @@ $scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
|
||||
// Splitter
|
||||
$splitterD: 7px;
|
||||
$splitterHandleD: 2px;
|
||||
$splitterHandleHitMargin: 4px;
|
||||
$splitterGrippyD: ($splitterHandleD - 4, 75px, 50px); // thickness, length, min-length
|
||||
$colorSplitterBaseBg: $colorBodyBg;
|
||||
$colorSplitterBg: pullForward($colorSplitterBaseBg, 20%);
|
||||
$colorSplitterFg: $colorBodyBg;
|
||||
$colorSplitterHover: $colorKey; // pullForward($colorSplitterBg, $hoverRatioPercent * 2);
|
||||
$colorSplitterActive: $colorKey;
|
||||
$splitterBtnD: (16px, 35px);
|
||||
$splitterBtnD: (16px, 35px); // height, width
|
||||
$splitterBtnColorBg: #eee;
|
||||
$splitterBtnColorFg: #999;
|
||||
$splitterBtnColorHoverBg: rgba($colorKey, 1);
|
||||
|
@ -15,8 +15,10 @@ $interiorMarginLg: 10px;
|
||||
$inputTextPTopBtm: 2px;
|
||||
$inputTextPLeftRight: 5px;
|
||||
$inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
$menuLineH: 1.5rem;
|
||||
$treeItemIndent: 16px;
|
||||
$treeTypeIconW: 18px;
|
||||
|
||||
/*************** Items */
|
||||
$itemPadLR: 5px;
|
||||
$ueBrowseGridItemLg: 200px;
|
||||
@ -111,6 +113,7 @@ $glyph-icon-frame-show: '\e1045';
|
||||
$glyph-icon-frame-hide: '\e1046';
|
||||
$glyph-icon-import: '\e1047';
|
||||
$glyph-icon-export: '\e1048';
|
||||
$glyph-icon-minimize: '\e1049'; // 12px only
|
||||
$glyph-icon-activity: '\e1100';
|
||||
$glyph-icon-activity-mode: '\e1101';
|
||||
$glyph-icon-autoflow-tabular: '\e1102';
|
||||
@ -142,4 +145,38 @@ $glyph-icon-timer: '\e1127';
|
||||
$glyph-icon-topic: '\e1128';
|
||||
$glyph-icon-box-with-dashed-lines: '\e1129';
|
||||
$glyph-icon-summary-widget: '\e1130';
|
||||
$glyph-icon-notebook: '\e1131';
|
||||
$glyph-icon-notebook: '\e1131';
|
||||
|
||||
/************************** GLYPHS AS DATA URI */
|
||||
// Only objects have been converted, for use in Create menu and folder views
|
||||
$bg-icon-activity: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M288 32H160l160 160H174.872C152.74 153.742 111.377 128 64 128H0v256h64c47.377 0 88.74-25.742 110.872-64H320L160 480h128l224-224L288 32z'/%3e%3c/svg%3e");
|
||||
$bg-icon-activity-mode: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 0C148.6 0 56.6 66.2 18.6 160H64c28.4 0 54 12.4 71.5 32H256l-96-96h128l160 160-160 160H160l96-96H135.5C118 339.6 92.4 352 64 352H18.6c38 93.8 129.9 160 237.4 160 141.4 0 256-114.6 256-256S397.4 0 256 0z'/%3e%3c/svg%3e");
|
||||
$bg-icon-autoflow-tabular: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M96 0C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h32V0H96zM192 0h128v512H192zM416 0h-32v352h128V96c0-52.8-43.2-96-96-96z'/%3e%3c/svg%3e");
|
||||
$bg-icon-clock: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 0C114.62 0 0 114.62 0 256s114.62 256 256 256 256-114.62 256-256S397.38 0 256 0zm135 345a36 36 0 0 1-31.21 18 35.83 35.83 0 0 1-18-4.83l-110.85-64-.14-.08q-.6-.35-1.19-.73l-.43-.28-.93-.64-.63-.45-.63-.48-.85-.67-.32-.27c-.36-.3-.72-.61-1.07-.92a35.76 35.76 0 0 1-6.52-7.9c-.14-.23-.27-.47-.41-.7s-.29-.49-.43-.74a35.75 35.75 0 0 1-3.58-9.59v-.06c-.1-.46-.19-.92-.27-1.38 0-.14-.05-.28-.08-.42-.06-.35-.11-.71-.15-1.07s-.07-.52-.1-.79-.05-.51-.07-.77l-.09-1.12v-.52-1.39V81a36 36 0 0 1 36-36 36 36 0 0 1 36 36v161.22l92.85 53.61A36 36 0 0 1 391 345z' fill='%2300a14b'/%3e%3c/svg%3e");
|
||||
$bg-icon-database: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 256C114.615 256 0 213.019 0 160v256c0 53.019 114.615 96 256 96s256-42.981 256-96V160c0 53.019-114.615 96-256 96z'/%3e%3cellipse fill='%23666666' cx='256' cy='96' rx='256' ry='96'/%3e%3c/svg%3e");
|
||||
$bg-icon-database-query: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M341.76 409.643C316.369 423.871 287.118 432 256 432c-97.047 0-176-78.953-176-176S158.953 80 256 80s176 78.953 176 176c0 31.118-8.129 60.369-22.357 85.76l95.846 95.846C509.747 430.661 512 423.429 512 416V96c0-53.019-114.615-96-256-96S0 42.981 0 96v320c0 53.019 114.615 96 256 96 63.055 0 120.774-8.554 165.388-22.73l-79.628-79.627z'/%3e%3cpath fill='%23666666' d='M176 256c0 44.112 35.888 80 80 80s80-35.888 80-80-35.888-80-80-80-80 35.888-80 80z'/%3e%3c/svg%3e");
|
||||
$bg-icon-dataset: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 96H288l-54.6-54.6-18.7-18.7C202.2 10.2 177.6 0 160 0H32C14.4 0 0 14.4 0 32v192c0-35.2 28.8-64 64-64h384c35.2 0 64 28.8 64 64v-64c0-35.2-28.8-64-64-64zM448 224H64c-35.2 0-64 28.8-64 64v160c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64zM160 448H96V288h64v160zm128 0h-64V288h64v160zm128 0h-64V288h64v160z'/%3e%3c/svg%3e");
|
||||
$bg-icon-datatable: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 256C114.6 256 0 213 0 160v256c0 53 114.6 96 256 96s256-43 256-96V160c0 53-114.6 96-256 96zm192 31.5v128c-18.3 7.8-39.9 14.4-64 19.7v-128c24.1-5.3 45.7-11.9 64-19.7zm-320 19.7v128c-24.1-5.2-45.7-11.9-64-19.7v-128c18.3 7.8 39.9 14.4 64 19.7zM192 445V317c20.5 2 41.9 3 64 3s43.5-1.1 64-3v128c-20.5 2-41.9 3-64 3s-43.5-1.1-64-3z'/%3e%3cellipse fill='%23666666' cx='256' cy='96' rx='256' ry='96'/%3e%3c/svg%3e");
|
||||
$bg-icon-dictionary: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M416 320c52.8 0 96-43.2 96-96V96c0-52.8-43.2-96-96-96v160l-64-32-64 32V0H96C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96v-96c0 52.8-43.2 96-96 96H96v-96h320z'/%3e%3c/svg%3e");
|
||||
$bg-icon-folder: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 96H288l-54.6-54.6-18.7-18.7C202.2 10.2 177.6 0 160 0H32C14.4 0 0 14.4 0 32v192c0-35.2 28.8-64 64-64h384c35.2 0 64 28.8 64 64v-64c0-35.2-28.8-64-64-64zM448 224H64c-35.2 0-64 28.8-64 64v160c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64z'/%3e%3c/svg%3e");
|
||||
$bg-icon-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 0H64C28.8 0 0 28.8 0 64v384c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V64c0-35.2-28.8-64-64-64zm0 448H64V64h384v384z'/%3e%3cpath fill='%23666666' d='M160 128l-64 64v224h320V256l-64-64-64 64z'/%3e%3c/svg%3e");
|
||||
$bg-icon-layout: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M224 0H96C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h128V0zM416 0H288v288.832h224V96c0-52.8-43.2-96-96-96zM288 512h128c52.8 0 96-43.2 96-96v-64.832H288V512z'/%3e%3c/svg%3e");
|
||||
$bg-icon-object: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='none' d='M256 96L76.8 208 256 320l179.2-112z'/%3e%3cpath fill='%23666666' d='M256 512l256-160V160L255.99 0 0 160v192l256 160zm0-416l179.2 112L256 320 76.8 208 256 96z'/%3e%3c/svg%3e");
|
||||
$bg-icon-object-unknown: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M255-1L-1 159v192l256 160 256-160V159L255-1zm37.7 430.6c-10.6 10.4-23 15.4-38 15.4-15.6 0-28.1-4.9-38.1-14.8-10-10-14.8-22.4-14.8-38.1 0-15.2 5.1-27.6 15.5-38.1s22.6-15.6 37.4-15.6c14.8 0 27.1 5.2 37.8 16 10.7 10.8 15.9 23.2 15.9 38-.1 14.5-5.4 27-15.7 37.2zm26.4-156.3c-11.8 5.9-18.7 11-21.7 16.2-1.8 3.1-3 7.4-3.7 13.4v20.5H213v-22.1c0-20.1 2.2-34.9 6.5-44 4-8.6 11.3-15.1 22.4-20l17.4-7.7c16-7.1 24.1-17.6 24.1-31.4 0-8-3-15.2-8.6-20.9-5.6-5.6-12.8-8.6-20.8-8.6-12 0-27.2 5-31.4 28.7l-1.1 6.1H148l.7-8.1c2-22.3 8.5-41.2 19.4-56.1 9.8-13.5 22.8-24.3 38.5-32.3 15.7-8 32.3-12 49.1-12 30.3 0 55.1 9.7 75.7 29.8 20.6 20 30.6 44 30.6 73.6 0 35.4-14.4 60.7-42.9 74.9z'/%3e%3c/svg%3e");
|
||||
$bg-icon-packet: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='none' d='M256 96L76.8 208 256 320l179.2-112z'/%3e%3cpath fill='%23666666' d='M256 0L0 160v256c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96V160L256 0zm0 96l179.2 112L256 320 76.8 208 256 96z'/%3e%3c/svg%3e");
|
||||
$bg-icon-page: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M352 256c-52.8 0-96-43.2-96-96V0H96C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96V256H352z'/%3e%3cpath fill='%23666666' d='M384 192h128L320 0v128c0 35.2 28.8 64 64 64z'/%3e%3c/svg%3e");
|
||||
$bg-icon-plot-overlay: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M415 0H97C43.65 0 0 43.65 0 97v203.41c7.09 9.32 12.83 14.17 16 15.42 7.14-2.81 27.22-23.77 46.48-73C83.71 188.64 120.64 124 176 124c26.2 0 50.71 14.58 72.85 43.34 18.67 24.25 32.42 54.46 40.67 75.54 19.26 49.19 39.34 70.15 46.48 73 7.14-2.81 27.22-23.77 46.48-73C403.71 188.64 440.64 124 496 124a69.55 69.55 0 0 1 16 1.87V97c0-53.35-43.65-97-97-97z'/%3e%3cpath fill='%23666666' d='M496 196.17c-7.14 2.81-27.22 23.76-46.48 73C428.29 323.36 391.36 388 336 388c-26.2 0-50.71-14.58-72.85-43.34-18.67-24.25-32.42-54.46-40.67-75.54-19.26-49.19-39.34-70.15-46.48-73-7.14 2.81-27.22 23.76-46.48 73C108.29 323.36 71.36 388 16 388a69.56 69.56 0 0 1-16-1.87V415c0 53.35 43.65 97 97 97h318c53.35 0 97-43.65 97-97V211.59c-7.09-9.32-12.83-14.17-16-15.42z'/%3e%3c/svg%3e");
|
||||
$bg-icon-plot-stacked: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M44.8 156c12.49 0 24.48-13.26 42.76-35.09 22.71-27.14 51-60.91 98-60.91 22.32 0 43.31 7.73 62.4 23 14.34 11.45 25.58 25.21 36.46 38.53C303.63 145 314 156 326.4 156H512V97c0-53.35-43.65-97-97-97H97C43.65 0 0 43.65 0 97v59h44.8z'/%3e%3cpath fill='%23666666' d='M264.75 205.2c-14.12-11.32-25.26-25-36-38.14C211 145.32 199.37 132 185.6 132c-12.53 0-24.54 13.27-42.83 35.12-22.7 27.12-51 60.88-98 60.88H0v56h185.6c22 0 42.77 7.67 61.65 22.8 14.12 11.32 25.26 25 36 38.14C301 366.68 312.63 380 326.4 380c12.53 0 24.54-13.27 42.83-35.12 22.7-27.12 51-60.88 98-60.88H512v-56H326.4c-22.03 0-42.77-7.67-61.65-22.8z'/%3e%3cpath fill='%23666666' d='M467.2 356c-12.49 0-24.48 13.26-42.76 35.09-22.71 27.14-51 60.91-98 60.91-22.32 0-43.31-7.73-62.4-23-14.34-11.45-25.58-25.21-36.46-38.53C208.37 367 198 356 185.6 356H0v59c0 53.35 43.65 97 97 97h318c53.35 0 97-43.65 97-97v-59h-44.8z'/%3e%3c/svg%3e");
|
||||
$bg-icon-session: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M317.8 262.2c3.3 2.1 6.6 4.3 9.6 6.8l60.2 48.2c14.8 11.9 41.9 11.9 56.7 0l67.6-54c.1-2.4.1-4.7.1-7.1 0-26.1-3.9-51.2-11.1-74.9L423.5 243c-29.1 23.3-70.1 29.6-105.7 19.2zM124.3 317.1l60.2-48.2c29-23.2 70-29.6 105.6-19.2-3.3-2.1-6.6-4.3-9.6-6.8l-60.2-48.2c-14.8-11.9-41.9-11.9-56.7 0L103.5 243c-20 16-45.7 24-71.5 24-10.8 0-21.5-1.4-31.9-4.2v.8c2.5 1.7 5 3.4 7.3 5.3l60.2 48.2c14.9 11.9 41.9 11.9 56.7 0z'/%3e%3cpath fill='%23666666' d='M60.3 189.1l60.2-48.2c40.1-32.1 102.8-32.1 142.9 0l60.2 48.2c14.8 11.9 41.9 11.9 56.7 0l90.5-72.4C425.2 46.5 346 0 256 0 136.7 0 36.4 81.6 8 192.1c15.4 8.8 38.9 7.8 52.3-3zM344.5 371l-60.2-48.2c-14.8-11.9-41.9-11.9-56.7 0L167.5 371c-20 16-45.7 24-71.5 24-23.9 0-47.7-6.9-67.1-20.7C71.7 456.1 157.3 512 256 512s184.3-55.9 227.1-137.7c-40.2 28.7-99.9 27.6-138.6-3.3z'/%3e%3c/svg%3e");
|
||||
$bg-icon-tabular: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 0H64C28.8 0 0 28.8 0 64v384c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V64c0-35.2-28.8-64-64-64zM320 224H192v-96h128v96zm-128 32h128v96H192v-96zm-32 96H32v-96h128v96zm0-224v96H32v-96h128zM64 480c-8.5 0-16.5-3.3-22.6-9.4S32 456.5 32 448v-64h128v96H64zm128 0v-96h128v96H192zm288-32c0 8.5-3.3 16.5-9.4 22.6S456.5 480 448 480h-96v-96h128v64zm0-96H352v-96h128v96zm0-128H352v-96h128v96z'/%3e%3c/svg%3e");
|
||||
$bg-icon-tabular-lad: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 0H64C28.7.1.1 28.7 0 64v384c.1 35.3 28.7 63.9 64 64h384c35.3-.1 63.9-28.7 64-64V64c-.1-35.3-28.7-63.9-64-64zM32 128h128v96H32v-96zm0 128h128v96H32v-96zm32 224c-17.6-.1-31.9-14.4-32-32v-64h128v96H64zm128 0v-96h128v96H192zm288-32c-.1 17.6-14.4 31.9-32 32h-96v-96h128v64zm0-192v96H192v-96h32v-32h-32v-96h288v96h-32v32h32z'/%3e%3cpath fill='%23666666' d='M391.2 273.7L336 246.1V160c0-8.8-7.2-16-16-16s-16 7.2-16 16v105.9l72.8 36.4c7.9 4 17.5.8 21.5-7.2 4-7.8.8-17.5-7.1-21.4z'/%3e%3c/svg%3e");
|
||||
$bg-icon-tabular-lad-set: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M64 384V96c-35.3.1-63.9 28.7-64 64v288c.1 35.3 28.7 63.9 64 64h288c35.3-.1 63.9-28.7 64-64H128c-35.3-.1-63.9-28.7-64-64z'/%3e%3cpath fill='%23666666' d='M448 0H160c-35.3.1-63.9 28.7-64 64v288c.1 35.3 28.7 63.9 64 64h288c35.3-.1 63.9-28.7 64-64V64c-.1-35.3-28.7-63.9-64-64zM128 96h96v64h-96V96zm0 96h96v96h-96v-96zm32 192c-17.6-.1-31.9-14.4-32-32v-32h96v64h-64zm96 0v-64h96v64h-96zm224-32c-.1 17.6-14.4 31.9-32 32h-64v-64h96v32zm0-64H256V96h224v192z'/%3e%3cpath fill='%23666666' d='M416 240c8.8 0 16-7.2 16-16 0-6.9-4.4-13-10.9-15.2L384 196.5V144c0-8.8-7.2-16-16-16s-16 7.2-16 16v75.5l58.9 19.6c1.7.6 3.4.9 5.1.9z'/%3e%3c/svg%3e");
|
||||
$bg-icon-tabular-realtime: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M0 64v384c0 35.2 28.8 64 64 64h288c35.2 0 64-28.8 64-64V340c-19.8 7.8-41.4 12-64 12-35.4 0-68.4-10.5-96-28.6V352h-96v-96h35.3c-5.2-10.1-9.4-20.8-12.6-32H160v-96h22.7C203.6 54.2 271.6 0 352 0H64C28.8 0 0 28.8 0 64zm288 320h96v64c0 8.5-3.3 16.5-9.4 22.6S360.5 480 352 480h-64v-96zm-160 96H64c-8.5 0-16.5-3.3-22.6-9.4S32 456.5 32 448v-64h96v96zm0-128H32v-96h96v96zm32 32h96v96h-96v-96zm-32-160H32v-96h96v96z'/%3e%3cpath fill='%23666666' d='M192 160c0 88.4 71.6 160 160 160s160-71.6 160-160S440.4 0 352 0 192 71.6 192 160zm49.7 39.8L227 187.5c-1.4-6.4-2.3-12.9-2.7-19.6 15.1-.1 30.1-5 41.9-14.8l39.6-33c7.5-6.2 21.1-6.2 28.6 0l39.6 33c2.8 2.3 5.7 4.3 8.8 6.1-23-11.7-52.7-9.2-72.8 7.5l-39.6 33c-7.6 6.3-21.2 6.3-28.7.1zM352 288c-36.7 0-69.7-15.4-93-40.1 14.2-.6 28.1-5.5 39.2-14.7l39.6-33c7.5-6.2 21.1-6.2 28.6 0l39.6 33c11 9.2 25 14.1 39.2 14.7-23.5 24.7-56.5 40.1-93.2 40.1zm125.9-151.3c1.4 7.5 2.1 15.3 2.1 23.3 0 9.4-1 18.6-3 27.5l-14.7 12.3c-7.5 6.2-21.1 6.2-28.6 0l-39.6-33c-2.8-2.3-5.7-4.3-8.8-6.1 23 11.7 52.7 9.2 72.8-7.5l19.8-16.5zM352 32c46.4 0 87.1 24.7 109.5 61.7l-31.2 26c-7.5 6.2-21.1 6.2-28.6 0l-39.6-33c-23.6-19.7-60.6-19.7-84.3 0l-39.6 33c-2.5 2.1-5.7 3.5-9.1 4.2C244.7 70.8 293.8 32 352 32z'/%3e%3c/svg%3e");
|
||||
$bg-icon-tabular-scrolling: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M32 0C14.4 0 0 14.4 0 32v96h224V0H32zM512 128V32c0-17.6-14.4-32-32-32H288v128h224zM0 192v96c0 17.6 14.4 32 32 32h192V192H0zM480 320c17.6 0 32-14.4 32-32v-96H288v128h192zM256 512L128 384h256z'/%3e%3c/svg%3e");
|
||||
$bg-icon-telemetry: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M16 315.83c7.14-2.81 27.22-23.77 46.48-73C83.71 188.64 120.64 124 176 124c26.2 0 50.71 14.58 72.85 43.34 18.67 24.25 32.42 54.46 40.67 75.54 19.26 49.19 39.34 70.15 46.48 73 7.14-2.81 27.22-23.77 46.48-73 18.7-47.75 49.57-103.57 94.47-116.23A255.87 255.87 0 0 0 256 0C114.62 0 0 114.62 0 256a257.18 257.18 0 0 0 5 50.52c4.77 5.39 8.61 8.37 11 9.31z'/%3e%3cpath fill='%23666666' d='M496 196.17c-7.14 2.81-27.22 23.76-46.48 73C428.29 323.36 391.36 388 336 388c-26.2 0-50.71-14.58-72.85-43.34-18.67-24.25-32.42-54.46-40.67-75.54-19.26-49.19-39.34-70.15-46.48-73-7.14 2.81-27.22 23.76-46.48 73-18.7 47.75-49.57 103.57-94.47 116.23A255.87 255.87 0 0 0 256 512c141.38 0 256-114.62 256-256a257.18 257.18 0 0 0-5-50.52c-4.77-5.39-8.61-8.37-11-9.31z'/%3e%3c/svg%3e");
|
||||
$bg-icon-timeline: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M128 128h192v64H128zM192 224h192v64H192zM160 320h192v64H160z'/%3e%3cpath fill='%23666666' d='M416 0h-64v96h63.8c.1 0 .1.1.2.2v319.7c0 .1-.1.1-.2.2H352v96h64c52.8 0 96-43.2 96-96V96c0-52.8-43.2-96-96-96zM96 415.8V96.2c0-.1.1-.1.2-.2H160V0H96C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h64v-96H96.2c-.1 0-.2-.1-.2-.2z'/%3e%3c/svg%3e");
|
||||
$bg-icon-timer: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M288 73.3V32.01a32 32 0 0 0-32-32h-64a32 32 0 0 0-32 32V73.3C67.48 100.84 0 186.54 0 288.01c0 123.71 100.29 224 224 224s224-100.29 224-224c0-101.48-67.5-187.2-160-214.71zm-54 224.71l-131.88 105.5A167.4 167.4 0 0 1 56 288.01c0-92.64 75.36-168 168-168 3.36 0 6.69.11 10 .31v177.69z'/%3e%3c/svg%3e");
|
||||
$bg-icon-topic: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M227.18 238.32l43.15-43.15a25.18 25.18 0 0 1 35.36 0l43.15 43.15a94.42 94.42 0 0 0 35.18 22.25V174.5l-28.82-28.82a95.11 95.11 0 0 0-134.35 0l-43.15 43.15a25.18 25.18 0 0 1-35.36 0L128 174.5v86.07a95.11 95.11 0 0 0 99.18-22.25z'/%3e%3cpath fill='%23666666' d='M252.82 273.68l-43.15 43.15a25.18 25.18 0 0 1-35.36 0l-43.15-43.15c-1-1-2.1-2-3.18-3v98.68a95.11 95.11 0 0 0 131.18-3l43.15-43.15a25.18 25.18 0 0 1 35.36 0l43.15 43.15c1 1 2.1 2 3.18 3v-98.68a95.11 95.11 0 0 0-131.18 3z'/%3e%3cpath fill='%23666666' d='M416 0h-64v96h63.83l.17.17v319.66l-.17.17H352v96h64c52.8 0 96-43.2 96-96V96c0-52.8-43.2-96-96-96zM160 416H96.17l-.17-.17V96.17l.17-.17H160V0H96C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h64v-96z'/%3e%3c/svg%3e");
|
||||
$bg-icon-box-with-dashed-lines: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M0 192h64v128H0zM64 64.11l.11-.11H160V0H64A64.19 64.19 0 0 0 0 64v96h64V64.11zM64 447.89V352H0v96a64.19 64.19 0 0 0 64 64h96v-64H64.11zM192 0h128v64H192zM448 447.89l-.11.11H352v64h96a64.19 64.19 0 0 0 64-64v-96h-64v95.89zM448 0h-96v64h95.89l.11.11V160h64V64a64.19 64.19 0 0 0-64-64zM448 192h64v128h-64zM192 448h128v64H192zM128 128h256v256H128z'/%3e%3c/svg%3e");
|
||||
$bg-icon-summary-widget: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 0H64C28.8 0 0 28.8 0 64v384c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V64c0-35.2-28.8-64-64-64zm-24.1 305.2l-41.3 71.6-94.8-65.8 9.6 115h-82.7l9.6-115-94.8 65.8-41.3-71.6L192.5 256 88.1 206.8l41.3-71.6 94.8 65.8-9.6-115h82.7l-9.6 115 94.8-65.8 41.3 71.6L319.5 256l104.4 49.2z'/%3e%3c/svg%3e");
|
||||
$bg-icon-notebook: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 55.4c0-39.9-27.7-63.7-61.5-52.7L0 128h448V55.4zM448 160H0v288c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64zm-32 256H224V256h192v160z'/%3e%3c/svg%3e");
|
||||
|
@ -0,0 +1,355 @@
|
||||
/******************************************************** BUTTONS */
|
||||
%c-control {
|
||||
@include userSelectNone();
|
||||
$fs: 1em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: $fs;
|
||||
justify-content: start;
|
||||
cursor: pointer;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
font-family: symbolsfont;
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&:after {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
[class*="__label"] {
|
||||
line-height: $fs; // Remove effect on top and bottom padding
|
||||
font-size: $fs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
%c-button {
|
||||
@extend %c-control;
|
||||
background: $colorBtnBg;
|
||||
border-radius: $controlCr;
|
||||
color: $colorBtnFg;
|
||||
padding: nth($btnPad, 1) nth($btnPad, 2);
|
||||
|
||||
&:hover {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
}
|
||||
|
||||
&[class*="--major"] {
|
||||
background: $colorBtnMajorBg;
|
||||
color: $colorBtnMajorFg;
|
||||
|
||||
&:hover {
|
||||
background: $colorBtnMajorBgHov;
|
||||
color: $colorBtnMajorFgHov;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********* Buttons */
|
||||
// Optionally can include icon in :before
|
||||
.c-button {
|
||||
@extend %c-button;
|
||||
}
|
||||
|
||||
/********* Icon Buttons */
|
||||
.c-icon-button {
|
||||
// A clickable element that just includes the icon, no background
|
||||
// Padding is included to facilitate a bigger hit area
|
||||
// Make the icon bigger relative to its container
|
||||
@extend %c-control;
|
||||
$pLR: 3px;
|
||||
$pTB: 3px;
|
||||
border-radius: $controlCr;
|
||||
color: $colorKey;
|
||||
font-size: $fontBaseSize * 1.2;
|
||||
padding: $pTB $pLR ;
|
||||
|
||||
&:hover {
|
||||
background: rgba($colorKey, 0.2);
|
||||
}
|
||||
|
||||
&:before {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
/********* Button Sets */
|
||||
.c-button-set {
|
||||
// Buttons are smashed together with minimal margin
|
||||
// c-buttons don't have border-radius between buttons, creates a tool-button-strip look
|
||||
// c-icon-buttons get grouped more closely together
|
||||
// When one set is adjacent to another, provides a divider between
|
||||
|
||||
display: inline-flex;
|
||||
|
||||
> * {
|
||||
// Assume buttons are immediate descendants
|
||||
flex: 0 0 auto;
|
||||
|
||||
&[class^="c-button"] {
|
||||
// Only apply the following to buttons that have background, eg. c-button
|
||||
border-radius: 0;
|
||||
|
||||
+ * {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: $controlCr;
|
||||
border-bottom-left-radius: $controlCr;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-top-right-radius: $controlCr;
|
||||
border-bottom-right-radius: $controlCr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ .c-button-set {
|
||||
$m: $interiorMarginSm;
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: $m;
|
||||
border-right: 1px solid $colorInteriorBorder;
|
||||
margin-right: $m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********* Menu Buttons */
|
||||
// Always includes :after dropdown arrow
|
||||
// Optionally can include icon in :before
|
||||
// Default menu position is down and to the right
|
||||
// Apply c-menu-button--menus-up and c-menu-button--menus-left to --w wrapper element to modify menu position
|
||||
.c-menu-button {
|
||||
$m: $interiorMarginSm;
|
||||
@extend %c-button;
|
||||
|
||||
&:before {
|
||||
margin-right: $m;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-family: symbolsfont;
|
||||
margin-left: $m;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&--w {
|
||||
// Wraps c-menu-button, contains button and menu
|
||||
.c-menu {
|
||||
// Default position
|
||||
top: 100%; left: 0;
|
||||
}
|
||||
|
||||
&.c-menu-button--menus-up {
|
||||
.c-menu {
|
||||
top: auto; bottom: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.c-menu-button--menus-left {
|
||||
.c-menu {
|
||||
left: auto; right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** DISCLOSURE CONTROLS */
|
||||
/********* Disclosure Button */
|
||||
// Provides a downward arrow icon that when clicked displays a context menu
|
||||
// Always placed AFTER an element
|
||||
.c-disclosure-button {
|
||||
@extend .c-icon-button;
|
||||
margin-left: $interiorMarginSm;
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
/********* Disclosure Triangle */
|
||||
// Provides an arrow icon that when clicked expands an element to reveal its contents.
|
||||
// Used in tree items. Always placed BEFORE an element.
|
||||
.c-disclosure-triangle {
|
||||
$d: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
width: $d;
|
||||
position: relative;
|
||||
|
||||
&.is-enabled:before {
|
||||
$s: .65;
|
||||
content: $glyph-icon-arrow-right-equilateral;
|
||||
display: block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 1rem * $s;
|
||||
position: absolute;
|
||||
transform-origin: floor(($d / 2) * $s); // This is slightly better than 'center'
|
||||
transition: transform 100ms ease-in-out;
|
||||
}
|
||||
|
||||
&--expanded {
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************** FORM ELEMENTS */
|
||||
/********* Inline inputs */
|
||||
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
|
||||
.c-input-inline {
|
||||
@include input-base();
|
||||
border: 1px solid transparent;
|
||||
display: block !important;
|
||||
min-width: 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
overflow: hidden;
|
||||
transition: all 250ms ease;
|
||||
white-space: nowrap;
|
||||
|
||||
&:not(:focus) {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
padding-left: $inputTextPLeftRight;
|
||||
padding-right: $inputTextPLeftRight;
|
||||
}
|
||||
&:hover {
|
||||
border-color: rgba($colorBodyFg, 0.2);
|
||||
}
|
||||
&:focus {
|
||||
@include nice-input($shdw: rgba(0, 0, 0, 0.6) 0 1px 3px);
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** MENUS */
|
||||
@mixin menuOuter() {
|
||||
border-radius: $basicCr;
|
||||
background: $colorMenuBg;
|
||||
text-shadow: $shdwMenuText;
|
||||
padding: $interiorMarginSm;
|
||||
box-shadow: $shdwMenu;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 70;
|
||||
}
|
||||
|
||||
@mixin menuInner() {
|
||||
color: $colorMenuFg;
|
||||
li {
|
||||
@extend %c-control;
|
||||
color: $colorMenuFg;
|
||||
display: flex;
|
||||
padding: nth($menuItemPad, 1) nth($menuItemPad, 2);
|
||||
transition: $transIn;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
&:before {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
color: $colorMenuIc;
|
||||
font-size: 1em;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-menu {
|
||||
@include menuOuter();
|
||||
@include menuInner();
|
||||
li {
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid pullForward($colorMenuBg, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-super-menu {
|
||||
// Two column layout, menu items on left with detail of hover element on right
|
||||
@include menuOuter();
|
||||
display: flex;
|
||||
padding: $interiorMarginLg;
|
||||
flex-direction: row;
|
||||
|
||||
> [class*="__"] {
|
||||
$m: $interiorMarginLg;
|
||||
flex: 1 1 50%;
|
||||
&:first-child {
|
||||
margin-right: $m;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-left: 1px solid $colorInteriorBorder;
|
||||
padding-left: $m;
|
||||
}
|
||||
}
|
||||
|
||||
&__menu {
|
||||
@include menuInner();
|
||||
overflow: auto;
|
||||
|
||||
ul {
|
||||
margin-right: $interiorMarginSm; // Fend off scrollbar
|
||||
}
|
||||
|
||||
li {
|
||||
border-radius: $controlCr;
|
||||
}
|
||||
}
|
||||
|
||||
&__item-description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
.l-item-description {
|
||||
&__icon,
|
||||
&__description {
|
||||
//flex: 1 1 50%;
|
||||
}
|
||||
|
||||
&__name,
|
||||
&__description {
|
||||
margin-top: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
min-height: 20%;
|
||||
margin: 10% 25%;
|
||||
}
|
||||
|
||||
&__name {
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
&__description {
|
||||
font-size: $fontBaseSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,9 @@
|
||||
}
|
||||
|
||||
/******************************* RESETS */
|
||||
* {
|
||||
*,
|
||||
:before,
|
||||
:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@ -41,6 +43,15 @@ div {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.u-space {
|
||||
// Provides a separator space between elements
|
||||
&--right {
|
||||
+ [class*="__"] {
|
||||
margin-left: $interiorMarginLg !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* BROWSER ELEMENTS */
|
||||
body.desktop {
|
||||
::-webkit-scrollbar {
|
||||
@ -95,8 +106,9 @@ body, html {
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
font-size: $fontBaseSize;
|
||||
font-weight: normal;
|
||||
background-color: $colorBodyBg;
|
||||
color: $colorBodyFg;
|
||||
@ -151,6 +163,12 @@ table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/************************** LEGACY */
|
||||
|
||||
mct-container {
|
||||
|
@ -1,24 +1,3 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
@mixin glyphBefore($unicode, $family: 'symbolsfont') {
|
||||
&:before {
|
||||
content: $unicode;
|
||||
@ -33,16 +12,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
[class*="icon-"].labeled {
|
||||
// Moved from .s-button and generalized
|
||||
&:before {
|
||||
// Fend off label from icon when it's included
|
||||
margin-right: $interiorMarginSm;
|
||||
@mixin glyphBg($glyphUrl) {
|
||||
background-image: $glyphUrl;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
[class*="icon-"] {
|
||||
&:before, &:after
|
||||
{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
}
|
||||
|
||||
/************************** 16 PX CLASSES */
|
||||
|
||||
.icon-alert-rect { @include glyphBefore($glyph-icon-alert-rect); }
|
||||
.icon-alert-triangle { @include glyphBefore($glyph-icon-alert-triangle); }
|
||||
.icon-arrow-down { @include glyphBefore($glyph-icon-arrow-down); }
|
||||
@ -162,3 +146,36 @@
|
||||
.icon-folder-12px { @include glyphBefore($glyph-icon-folder,'symbolsfont-12px'); }
|
||||
.icon-list-view-12px { @include glyphBefore($glyph-icon-list-view,'symbolsfont-12px'); }
|
||||
.icon-grippy-12px { @include glyphBefore($glyph-icon-grippy,'symbolsfont-12px'); }
|
||||
|
||||
/************************** GLYPH BG CLASSES */
|
||||
.bg-icon-activity { @include glyphBg($bg-icon-activity); }
|
||||
.bg-icon-activity-mode { @include glyphBg($bg-icon-activity-mode); }
|
||||
.bg-icon-autoflow-tabular { @include glyphBg($bg-icon-autoflow-tabular); }
|
||||
.bg-icon-clock { @include glyphBg($bg-icon-clock); }
|
||||
.bg-icon-database { @include glyphBg($bg-icon-database); }
|
||||
.bg-icon-database-query { @include glyphBg($bg-icon-database-query); }
|
||||
.bg-icon-dataset { @include glyphBg($bg-icon-dataset); }
|
||||
.bg-icon-datatable { @include glyphBg($bg-icon-datatable); }
|
||||
.bg-icon-dictionary { @include glyphBg($bg-icon-dictionary); }
|
||||
.bg-icon-folder { @include glyphBg($bg-icon-folder); }
|
||||
.bg-icon-image { @include glyphBg($bg-icon-image); }
|
||||
.bg-icon-layout { @include glyphBg($bg-icon-layout); }
|
||||
.bg-icon-object { @include glyphBg($bg-icon-object); }
|
||||
.bg-icon-object-unknown { @include glyphBg($bg-icon-object-unknown); }
|
||||
.bg-icon-packet { @include glyphBg($bg-icon-packet); }
|
||||
.bg-icon-page { @include glyphBg($bg-icon-page); }
|
||||
.bg-icon-plot-overlay { @include glyphBg($bg-icon-plot-overlay); }
|
||||
.bg-icon-plot-stacked { @include glyphBg($bg-icon-plot-stacked); }
|
||||
.bg-icon-session { @include glyphBg($bg-icon-session); }
|
||||
.bg-icon-tabular { @include glyphBg($bg-icon-tabular); }
|
||||
.bg-icon-tabular-lad { @include glyphBg($bg-icon-tabular-lad); }
|
||||
.bg-icon-tabular-lad-set { @include glyphBg($bg-icon-tabular-lad-set); }
|
||||
.bg-icon-tabular-realtime { @include glyphBg($bg-icon-tabular-realtime); }
|
||||
.bg-icon-tabular-scrolling { @include glyphBg($bg-icon-tabular-scrolling); }
|
||||
.bg-icon-telemetry { @include glyphBg($bg-icon-telemetry); }
|
||||
.bg-icon-timeline { @include glyphBg($bg-icon-timeline); }
|
||||
.bg-icon-timer { @include glyphBg($bg-icon-timer); }
|
||||
.bg-icon-topic { @include glyphBg($bg-icon-topic); }
|
||||
.bg-icon-box-with-dashed-lines { @include glyphBg($bg-icon-box-with-dashed-lines); }
|
||||
.bg-icon-summary-widget { @include glyphBg($bg-icon-summary-widget); }
|
||||
.bg-icon-notebook { @include glyphBg($bg-icon-notebook); }
|
||||
|
@ -62,6 +62,36 @@
|
||||
background-size: $d $d;
|
||||
}
|
||||
|
||||
/************************** LAYOUT */
|
||||
@mixin gridTwoColumn() {
|
||||
display: grid;
|
||||
grid-row-gap: 0;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
align-items: start;
|
||||
|
||||
[class*="header"] {
|
||||
border-radius: $smallCr;
|
||||
background-color: $colorInspectorSectionHeaderBg;
|
||||
color: $colorInspectorSectionHeaderFg;
|
||||
margin: 0 0 $interiorMarginSm 0;
|
||||
padding: $interiorMarginSm $interiorMargin;
|
||||
|
||||
&:not(:first-child) {
|
||||
// Allow multiple headers within a component
|
||||
margin-top: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
|
||||
[class*="span-all"],
|
||||
[class*="header"] {
|
||||
@include gridTwoColumnSpanCols();
|
||||
}
|
||||
}
|
||||
|
||||
@mixin gridTwoColumnSpanCols() {
|
||||
grid-column: 1 / 3;
|
||||
}
|
||||
|
||||
/************************** TEXT */
|
||||
@mixin ellipsize() {
|
||||
overflow: hidden;
|
||||
@ -80,13 +110,10 @@
|
||||
}
|
||||
|
||||
/************************** CONTROLS, BUTTONS */
|
||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0px 2px) {
|
||||
@mixin input-base() {
|
||||
appearance: none;
|
||||
background: $bg;
|
||||
border: none;
|
||||
color: $fg;
|
||||
border-radius: $controlCr;
|
||||
box-shadow: inset $shdw;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
@ -99,6 +126,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0px 2px) {
|
||||
@include input-base();
|
||||
background: $bg;
|
||||
color: $fg;
|
||||
box-shadow: inset $shdw;
|
||||
}
|
||||
|
||||
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
|
||||
background: $bg;
|
||||
color: $fg;
|
||||
|
@ -56,7 +56,7 @@
|
||||
//
|
||||
//!********************************* VIEWS *!
|
||||
@import "../styles/fixed-position";
|
||||
@import "../styles/lists/tabular";
|
||||
//@import "../styles/lists/tabular";
|
||||
@import "../styles/plots/plots-main";
|
||||
@import "../styles/plots/legend";
|
||||
@import "../styles/iframe";
|
||||
|
29
src/ui/components/controls/ContextMenu.vue
Normal file
29
src/ui/components/controls/ContextMenu.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="item in contextMenuItems"
|
||||
:class="item.class"
|
||||
:title="item.title">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
contextMenuItems: [
|
||||
{name: 'Open In New Tab', class: 'icon-new-window', title: 'Open in a new browser tab'},
|
||||
{name: 'Preview', class: 'hide-in-t-main-view icon-eye-open', title: 'Preview in large dialog'},
|
||||
{name: 'Edit Properties...', class: 'major icon-pencil', title: 'Edit properties of this object.'},
|
||||
{name: 'Duplicate', class: 'icon-duplicate', title: 'Duplicate object to another location.'},
|
||||
{name: 'Create Link', class: 'icon-link', title: 'Create Link to object in another location.'},
|
||||
{name: 'Export as JSON', class: 'icon-export', title: 'Export as JSON'},
|
||||
{name: 'Import from JSON', class: 'icon-import', title: 'Import from JSON'}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
102
src/ui/components/controls/CreateButton.vue
Normal file
102
src/ui/components/controls/CreateButton.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div class="c-create-button--w">
|
||||
<div class="c-create-button c-menu-button c-button--major icon-plus"
|
||||
@click="toggleCreateMenu">
|
||||
<span class="c-button__label">Create</span>
|
||||
</div>
|
||||
<div class="c-create-menu c-super-menu"
|
||||
v-if="showCreateMenu">
|
||||
<div class="c-super-menu__menu">
|
||||
<ul>
|
||||
<li v-for="item in createMenuItems"
|
||||
:class="item.class"
|
||||
:title="item.title"
|
||||
@mouseover="showItemDescription">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="c-super-menu__item-description">
|
||||
<div class="l-item-description__icon bg-icon-plot-stacked"></div>
|
||||
<div class="l-item-description__name">Name</div>
|
||||
<div class="l-item-description__description">
|
||||
A timer that counts up or down to a datetime.
|
||||
Timers can be started, stopped and reset whenever needed,
|
||||
and support a variety of display formats.
|
||||
Each Timer displays the same value to all users.
|
||||
Timers can be added to Display Layouts.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-create-button,
|
||||
.c-create-menu {
|
||||
&--w {
|
||||
// Wrapper for Create button and menu
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.c-create-button .c-button__label {
|
||||
text-transform: $createBtnTextTransform;
|
||||
}
|
||||
|
||||
.c-create-menu {
|
||||
max-height: 80vh;
|
||||
max-width: 500px;
|
||||
min-height: 250px;
|
||||
z-index: 70;
|
||||
|
||||
[class*="__icon"] {
|
||||
filter: $colorKeyFilter;
|
||||
}
|
||||
|
||||
[class*="__item-description"] {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
showCreateMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleCreateMenu: function () {
|
||||
this.showCreateMenu = !this.showCreateMenu;
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
createMenuItems: [
|
||||
{ name: 'Folder', class: 'icon-folder', title: 'Details will go here' },
|
||||
{ name: 'Display Layout', class: 'icon-layout', title: 'Details will go here' },
|
||||
{ name: 'Fixed Position Display', class: 'icon-box-with-dashed-lines', title: 'Details will go here' },
|
||||
{ name: 'Overlay Plot', class: 'icon-plot-overlay', title: 'Details will go here' },
|
||||
{ name: 'Stacked Plot', class: 'icon-plot-stacked', title: 'Details will go here' },
|
||||
{ name: 'Telemetry Table', class: 'icon-tabular-realtime', title: 'Details will go here' },
|
||||
{ name: 'Clock', class: 'icon-clock', title: 'Details will go here' },
|
||||
{ name: 'Timer', class: 'icon-timer', title: 'Details will go here' },
|
||||
{ name: 'Web Page', class: 'icon-page', title: 'Details will go here' },
|
||||
{ name: 'Event Message Generator', class: 'icon-folder-new', title: 'Details will go here' },
|
||||
{ name: 'Hyperlink', class: 'icon-chain-links', title: 'Details will go here' },
|
||||
{ name: 'Notebook', class: 'icon-notebook', title: 'Details will go here' },
|
||||
{ name: 'State Generator', class: 'icon-telemetry', title: 'Details will go here' },
|
||||
{ name: 'Sine Wave Generator', class: 'icon-telemetry', title: 'Details will go here' },
|
||||
{ name: 'Example Imagery', class: 'icon-image', title: 'Details will go here' },
|
||||
{ name: 'Summary Widget', class: 'icon-summary-widget', title: 'Details will go here' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
121
src/ui/components/controls/MainViewBrowseBar.vue
Normal file
121
src/ui/components/controls/MainViewBrowseBar.vue
Normal file
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div class="l-browse-bar">
|
||||
<div class="l-browse-bar__start">
|
||||
<a class="l-browse-bar__nav-to-parent-button c-icon-button icon-pointer-left"></a>
|
||||
<div class="l-browse-bar__object-name--w icon-folder">
|
||||
<span class="l-browse-bar__object-name c-input-inline" contenteditable>
|
||||
Object Name Lorem ipsum dolor sit amet
|
||||
</span>
|
||||
</div>
|
||||
<div class="l-browse-bar__context-actions c-disclosure-button"></div>
|
||||
</div>
|
||||
|
||||
<div class="l-browse-bar__end">
|
||||
<div class="l-browse-bar__view-switcher c-menu-button--w c-menu-button--menus-left">
|
||||
<div class="c-menu-button icon-thumbs-strip"
|
||||
title="Switch view type"
|
||||
@click="toggleMenu">
|
||||
<span class="c-button__label">Grid</span>
|
||||
</div>
|
||||
<MenuPlaceholder v-if="showMenu"></MenuPlaceholder>
|
||||
</div>
|
||||
<!-- Action buttons -->
|
||||
<div class="l-browse-bar__actions">
|
||||
<div class="l-browse-bar__action c-button icon-eye-open" title="Preview"></div>
|
||||
<div class="l-browse-bar__action c-button icon-notebook" title="New Notebook entry"></div>
|
||||
<div class="l-browse-bar__action c-button c-button--major icon-pencil" title="Edit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MenuPlaceholder from '../controls/ContextMenu.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
showMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
editNameEnabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleMenu: function () {
|
||||
this.showMenu = !this.showMenu;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MenuPlaceholder
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
/******************************* START */
|
||||
|
||||
.l-browse-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
[class*="__"] {
|
||||
// Removes extraneous horizontal white space
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
&__start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 1 auto;
|
||||
font-size: 1.4em;
|
||||
margin-right: $interiorMargin;
|
||||
min-width: 0; // Forces interior to compress when pushed on
|
||||
}
|
||||
|
||||
&__end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
|
||||
[class*="__"] + [class*="__"] {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&__nav-to-parent-button,
|
||||
&__disclosure-button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__nav-to-parent-button {
|
||||
// This is an icon-button
|
||||
$p: $interiorMarginLg;
|
||||
margin-right: $interiorMargin;
|
||||
padding-left: $p;
|
||||
padding-right: $p;
|
||||
}
|
||||
|
||||
&__object-name--w {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
|
||||
&:before {
|
||||
// Icon
|
||||
opacity: 0.5;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__object-name {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -28,7 +28,6 @@
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
$hitMargin: 4px;
|
||||
/**************************** BASE - MOBILE AND DESKTOP */
|
||||
.l-multipane {
|
||||
display: flex;
|
||||
@ -86,6 +85,11 @@
|
||||
transition: opacity 150ms ease;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
> * {
|
||||
min-width: 0 !important;
|
||||
min-height: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +114,6 @@
|
||||
padding: $interiorMargin;
|
||||
pointer-events: inherit;
|
||||
transition: opacity 250ms ease 250ms;
|
||||
overflow: auto;
|
||||
|
||||
.l-pane__contents {
|
||||
// Don't pad all nested __contents
|
||||
@ -149,7 +152,7 @@
|
||||
|
||||
&__collapse-button {
|
||||
$m: 2px;
|
||||
$h: nth($splitterBtnD, 1) - ($m * 2);
|
||||
$h: 12px;
|
||||
color: $splitterBtnColorFg;
|
||||
flex: 0 0 nth($splitterBtnD, 1);
|
||||
font-size: $h * .9;
|
||||
@ -159,27 +162,24 @@
|
||||
|
||||
&:after {
|
||||
// Close icon
|
||||
background: $splitterBtnColorFg;
|
||||
border-radius: 2px;
|
||||
color: $splitterBtnColorBg;
|
||||
content: $glyph-icon-minus;
|
||||
background: $colorBtnBg;
|
||||
border-radius: $smallCr;
|
||||
color: $colorBtnFg;
|
||||
content: $glyph-icon-arrow-right-equilateral;
|
||||
display: block;
|
||||
font-family: symbolsfont;
|
||||
font-size: .8em;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
padding: 0 7px;
|
||||
font-size: 6px;
|
||||
line-height: 90%;
|
||||
padding: 3px 15px;
|
||||
position: absolute;
|
||||
right: $m;
|
||||
top: $m;
|
||||
text-align: right;
|
||||
transition: $transOut;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(black, 0.1);
|
||||
//color: $splitterBtnColorHoverFg;
|
||||
&:after {
|
||||
background: $splitterBtnColorHoverBg;
|
||||
color: $splitterBtnColorHoverFg;
|
||||
@ -192,6 +192,7 @@
|
||||
// Name of the pane
|
||||
@include ellipsize();
|
||||
display: block;
|
||||
padding-right: nth($splitterBtnD, 2) + $interiorMargin; // Force label to ellipsis
|
||||
text-transform: uppercase;
|
||||
transform-origin: top left;
|
||||
flex: 1 0 90%;
|
||||
@ -200,6 +201,10 @@
|
||||
&--resizing {
|
||||
// User is dragging the handle and resizing a pane
|
||||
@include userSelectNone();
|
||||
|
||||
+ .l-pane {
|
||||
@include userSelectNone();
|
||||
}
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
@ -216,10 +221,6 @@
|
||||
background: $splitterBtnColorFg;
|
||||
color: $splitterBtnColorBg;
|
||||
|
||||
&:after {
|
||||
content: $glyph-icon-plus;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $splitterBtnColorHoverBg !important;
|
||||
}
|
||||
@ -241,9 +242,9 @@
|
||||
&:before {
|
||||
// Extended hit area
|
||||
top: 0;
|
||||
right: $hitMargin * -1;
|
||||
right: $splitterHandleHitMargin * -1;
|
||||
bottom: 0;
|
||||
left: $hitMargin * -1;
|
||||
left: $splitterHandleHitMargin * -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,7 +268,6 @@
|
||||
right: auto;
|
||||
transform: translateX(-50%);
|
||||
width: auto;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,6 +278,14 @@
|
||||
left: 0;
|
||||
transform: translateX(floor($splitterHandleD / -2)); // Center over the pane edge
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
> .l-pane__collapse-button {
|
||||
&:after {
|
||||
transform: translateX(-50%) scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Horizontal Splitter After */
|
||||
@ -286,6 +294,12 @@
|
||||
right: 0;
|
||||
transform: translateX(floor($splitterHandleD / 2));
|
||||
}
|
||||
|
||||
&:not([class*="--collapsed"]) {
|
||||
> .l-pane__collapse-button:after {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,25 +313,43 @@
|
||||
&:before {
|
||||
// Extended hit area
|
||||
left: 0;
|
||||
top: $hitMargin * -1;
|
||||
top: $splitterHandleHitMargin * -1;
|
||||
right: 0;
|
||||
bottom: $hitMargin * -1;
|
||||
bottom: $splitterHandleHitMargin * -1;
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Vertical Splitter Before */
|
||||
// Pane collapses downward
|
||||
&[class*="-before"] {
|
||||
> .l-pane__handle {
|
||||
top: 0;
|
||||
transform: translateY(floor($splitterHandleD / -2)); // Center over the pane edge
|
||||
transform: translateY(floor($splitterHandleD / -1));
|
||||
}
|
||||
|
||||
> .l-pane__collapse-button:after {
|
||||
content: $glyph-icon-arrow-down;
|
||||
}
|
||||
|
||||
&.l-pane--collapsed {
|
||||
> .l-pane__collapse-button:after {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Vertical Splitter After */
|
||||
// Pane collapses upward. Not sure we'll ever use this...
|
||||
&[class*="-after"] {
|
||||
> .l-pane__handle {
|
||||
bottom: 0;
|
||||
transform: translateY(floor($splitterHandleD / 2)); // Center over the pane edge
|
||||
transform: translateY(floor($splitterHandleD / 1));
|
||||
}
|
||||
|
||||
&:not(.l-pane--collapsed) > .l-pane__collapse-button {
|
||||
&:after {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
flex: 0 0 auto;
|
||||
opacity: 0.5;
|
||||
overflow: hidden;
|
||||
padding: 2px; // Prevents clipping
|
||||
padding: 2px 0; // Prevents clipping
|
||||
transition: width 250ms ease;
|
||||
width: 1em;
|
||||
}
|
||||
|
@ -1,43 +1,12 @@
|
||||
<template>
|
||||
<span class="c-view-control"
|
||||
<span class="c-disclosure-triangle"
|
||||
:class="{
|
||||
'c-view-control--expanded' : expanded,
|
||||
'c-disclosure-triangle--expanded' : expanded,
|
||||
'is-enabled' : enabled
|
||||
}"
|
||||
@click="toggle"></span>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";;
|
||||
|
||||
.c-view-control {
|
||||
$d: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
width: $d;
|
||||
position: relative;
|
||||
|
||||
&.is-enabled:before {
|
||||
$s: .65;
|
||||
content: $glyph-icon-arrow-right-equilateral;
|
||||
display: block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 1rem * $s;
|
||||
position: absolute;
|
||||
transform-origin: floor(($d / 2) * $s); // This is slightly better than 'center'
|
||||
transition: transform 100ms ease-in-out;
|
||||
}
|
||||
|
||||
&--expanded {
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
|
33
src/ui/components/inspector/Elements.vue
Normal file
33
src/ui/components/inspector/Elements.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
mounted() {
|
||||
let openmct = this.openmct;
|
||||
let $injector = openmct.$injector;
|
||||
let angular = openmct.$angular;
|
||||
|
||||
let templateLinker = $injector.get('templateLinker');
|
||||
|
||||
let templateMap = {};
|
||||
$injector.get('templates[]').forEach((t) => {
|
||||
templateMap[t.key] = templateMap[t.key] || t;
|
||||
});
|
||||
|
||||
let $rootScope = $injector.get('$rootScope');
|
||||
this.$scope = $rootScope.$new();
|
||||
|
||||
templateLinker.link(
|
||||
this.$scope,
|
||||
angular.element(this.$el),
|
||||
templateMap.elementsPool
|
||||
);
|
||||
},
|
||||
destroyed() {
|
||||
this.$scope.$destroy();
|
||||
}
|
||||
}
|
||||
</script>
|
167
src/ui/components/inspector/Inspector.vue
Normal file
167
src/ui/components/inspector/Inspector.vue
Normal file
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<multipane class="c-inspector"
|
||||
type="vertical">
|
||||
<pane class="c-inspector__properties">
|
||||
<properties></properties>
|
||||
<location></location>
|
||||
<inspector-view></inspector-view>
|
||||
</pane>
|
||||
<pane class="c-inspector__elements"
|
||||
handle="before"
|
||||
label="Elements">
|
||||
<elements></elements>
|
||||
</pane>
|
||||
</multipane>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-inspector {
|
||||
min-width: 150px;
|
||||
|
||||
> [class*="__"] {
|
||||
min-height: 50px;
|
||||
|
||||
+ [class*="__"] {
|
||||
// Margin between elements
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
> .l-pane__contents {
|
||||
overflow: auto;
|
||||
|
||||
> * {
|
||||
// Fend off scrollbar
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__elements {
|
||||
// LEGACY TODO: Refactor when markup is updated, fix scrolling
|
||||
// so that only tree holder handles overflow
|
||||
height: 200px;
|
||||
|
||||
.tree-item {
|
||||
.t-object-label {
|
||||
// Elements pool is a flat list, so don't indent items.
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************** LEGACY */
|
||||
// TODO: refactor when markup can be converted
|
||||
.inspector-location {
|
||||
display: inline-block;
|
||||
|
||||
.location-item {
|
||||
$h: 1.2em;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $h;
|
||||
position: relative;
|
||||
padding: 2px 4px;
|
||||
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
height: $h;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
color: $colorItemTreeHoverFg;
|
||||
.icon {
|
||||
color: $colorItemTreeIconHover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.last) .t-object-label .t-title-label:after {
|
||||
color: pushBack($colorInspectorFg, 15%);
|
||||
content: '\e904';
|
||||
display: inline-block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 8px;
|
||||
font-style: normal !important;
|
||||
line-height: inherit;
|
||||
margin-left: $interiorMarginSm;
|
||||
width: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-properties {
|
||||
@include gridTwoColumn();
|
||||
|
||||
+ .c-properties {
|
||||
// Margin between components
|
||||
margin-top: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&__section,
|
||||
&__row {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
&__row + &__row {
|
||||
> [class*="__"] {
|
||||
// Row borders, effected via border-top on child elements of the row
|
||||
border-top: 1px solid $colorInspectorSectionHeaderBg;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
font-size: .85em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
&__label,
|
||||
&__value {
|
||||
padding: 3px $interiorMarginLg 3px 0;
|
||||
}
|
||||
|
||||
&__label {
|
||||
color: $colorInspectorPropName;
|
||||
|
||||
&[title] {
|
||||
// When a cell has a title, assume it's helpful text
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
|
||||
&__value {
|
||||
color: $colorInspectorPropVal;
|
||||
word-break: break-all;
|
||||
&:first-child {
|
||||
// If there is no preceding .label element, make value span columns
|
||||
@include gridTwoColumnSpanCols();
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import multipane from '../controls/multipane.vue';
|
||||
import pane from '../controls/pane.vue';
|
||||
import Elements from './Elements.vue';
|
||||
import Location from './Location.vue';
|
||||
import Properties from './Properties.vue';
|
||||
import InspectorView from './InspectorView.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
multipane,
|
||||
pane,
|
||||
Elements,
|
||||
Properties,
|
||||
Location,
|
||||
InspectorView
|
||||
}
|
||||
}
|
||||
</script>
|
32
src/ui/components/inspector/InspectorView.vue
Normal file
32
src/ui/components/inspector/InspectorView.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="c-properties"></div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection(this.openmct.selection.get());
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
if (this.selectedView && this.selectedView.destroy) {
|
||||
this.selectedView.destroy();
|
||||
}
|
||||
this.$el.innerHTML = '';
|
||||
this.selectedView = this.openmct.inspectorViews.get(selection);
|
||||
if (!this.selectedView) {
|
||||
return;
|
||||
}
|
||||
this.selectedView.show(this.$el);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
42
src/ui/components/inspector/Location.vue
Normal file
42
src/ui/components/inspector/Location.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="c-properties c-properties--location">
|
||||
<div class="c-properties__header" title="The location of this linked object.">Location</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label">This Link</div>
|
||||
<div class="c-properties__value">TODO</div>
|
||||
</li>
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label">Original</div>
|
||||
<div class="c-properties__value">TODO</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
domainObject: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection(this.openmct.selection.get());
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
if (selection.length === 0) {
|
||||
this.domainObject = {};
|
||||
return;
|
||||
}
|
||||
this.domainObject = selection[0].context.item;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
96
src/ui/components/inspector/Properties.vue
Normal file
96
src/ui/components/inspector/Properties.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="c-properties c-properties--properties">
|
||||
<div class="c-properties__header">Properties</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label">Title</div>
|
||||
<div class="c-properties__value">{{ domainObject.name }}</div>
|
||||
</li>
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label">Type</div>
|
||||
<div class="c-properties__value">{{ typeName }}</div>
|
||||
</li>
|
||||
<li class="c-properties__row" v-if="domainObject.created">
|
||||
<div class="c-properties__label">Created</div>
|
||||
<div class="c-properties__value">{{ domainObject.created }}</div>
|
||||
</li>
|
||||
<li class="c-properties__row" v-if="domainObject.modified">
|
||||
<div class="c-properties__label">Modified</div>
|
||||
<div class="c-properties__value">{{ domainObject.modified }}</div>
|
||||
</li>
|
||||
<li class="c-properties__row"
|
||||
v-for="prop in typeProperties"
|
||||
:key="prop.name">
|
||||
<div class="c-properties__label">{{ prop.name }}</div>
|
||||
<div class="c-properties__value">{{ prop.value }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
domainObject: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
type() {
|
||||
return this.openmct.types.get(this.domainObject.type);
|
||||
},
|
||||
typeName() {
|
||||
if (!this.type) {
|
||||
return `Unknown: ${this.domainObject.type}`;
|
||||
}
|
||||
return this.type.definition.name;
|
||||
},
|
||||
typeProperties() {
|
||||
if (!this.type) {
|
||||
return [];
|
||||
}
|
||||
let definition = this.type.definition;
|
||||
if (!definition.form || definition.form.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return definition.form
|
||||
.map((field) => {
|
||||
let path = field.property
|
||||
if (typeof path === 'string') {
|
||||
path = [path];
|
||||
}
|
||||
return {
|
||||
name: field.name,
|
||||
path
|
||||
};
|
||||
})
|
||||
.filter(field => Array.isArray(field.path))
|
||||
.map((field) => {
|
||||
return {
|
||||
name: field.name,
|
||||
value: field.path.reduce((object, field) => {
|
||||
return object[field];
|
||||
}, this.domainObject)
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection(this.openmct.selection.get());
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
if (selection.length === 0) {
|
||||
this.domainObject = {};
|
||||
return;
|
||||
}
|
||||
this.domainObject = selection[0].context.item;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
159
src/ui/components/layout/BrowseObject.vue
Normal file
159
src/ui/components/layout/BrowseObject.vue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
// Find an object in an array of objects.
|
||||
function findObject(domainObjects, id) {
|
||||
var i;
|
||||
for (i = 0; i < domainObjects.length; i += 1) {
|
||||
if (domainObjects[i].getId() === id) {
|
||||
return domainObjects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recursively locate and return an object inside of a container
|
||||
// via a path. If at any point in the recursion it fails to find
|
||||
// the next object, it will return the parent.
|
||||
function findViaComposition(containerObject, path) {
|
||||
var nextId = path.shift();
|
||||
if (!nextId) {
|
||||
return containerObject;
|
||||
}
|
||||
return containerObject.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
var nextObject = findObject(composees, nextId);
|
||||
if (!nextObject) {
|
||||
return containerObject;
|
||||
}
|
||||
if (!nextObject.hasCapability('composition')) {
|
||||
return nextObject;
|
||||
}
|
||||
return findViaComposition(nextObject, path);
|
||||
});
|
||||
}
|
||||
|
||||
function getLastChildIfRoot(object) {
|
||||
if (object.getId() !== 'ROOT') {
|
||||
return object;
|
||||
}
|
||||
return object.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
return composees[composees.length - 1];
|
||||
});
|
||||
}
|
||||
|
||||
function pathForObject(domainObject) {
|
||||
var context = domainObject.getCapability('context'),
|
||||
objectPath = context ? context.getPath() : [],
|
||||
ids = objectPath.map(function (domainObj) {
|
||||
return domainObj.getId();
|
||||
});
|
||||
return "/browse/" + ids.slice(1).join("/");
|
||||
}
|
||||
|
||||
export default {
|
||||
inject: ["openmct"],
|
||||
mounted() {
|
||||
let openmct = this.openmct;
|
||||
let $injector = openmct.$injector;
|
||||
let angular = openmct.$angular;
|
||||
|
||||
this.objectService = $injector.get('objectService');
|
||||
this.templateLinker = $injector.get('templateLinker');
|
||||
this.navigationService = $injector.get('navigationService');
|
||||
this.$timeout = $injector.get('$timeout');
|
||||
|
||||
this.templateMap = {};
|
||||
$injector.get('templates[]').forEach((t) => {
|
||||
this.templateMap[t.key] = this.templateMap[t.key] || t;
|
||||
});
|
||||
|
||||
this.$rootScope = $injector.get('$rootScope');
|
||||
this.$scope = this.$rootScope.$new();
|
||||
this.$scope.representation = {};
|
||||
|
||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results) => {
|
||||
let navigatePath = results[1];
|
||||
if (!navigatePath) {
|
||||
navigatePath = 'mine';
|
||||
}
|
||||
this.navigateToPath(navigatePath);
|
||||
});
|
||||
|
||||
this.navigationService.addListener(o => this.navigateToObject(o));
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
navigateToPath(path) {
|
||||
if (!Array.isArray(path)) {
|
||||
path = path.split('/');
|
||||
}
|
||||
return this.getObject('ROOT')
|
||||
.then(root => {
|
||||
return findViaComposition(root, path);
|
||||
})
|
||||
.then(getLastChildIfRoot)
|
||||
.then(object => {
|
||||
this.setMainViewObject(object);
|
||||
});
|
||||
},
|
||||
|
||||
setMainViewObject(object) {
|
||||
this.$scope.domainObject = object;
|
||||
this.$scope.navigatedObject = object;
|
||||
this.templateLinker.link(
|
||||
this.$scope,
|
||||
this.openmct.$angular.element(this.$el),
|
||||
this.templateMap["browseObject"]
|
||||
);
|
||||
document.title = object.getModel().name;
|
||||
this.scheduleDigest();
|
||||
},
|
||||
|
||||
idsForObject(domainObject) {
|
||||
return this.urlService
|
||||
.urlForLocation("", domainObject)
|
||||
.replace('/', '');
|
||||
},
|
||||
|
||||
navigateToObject(object) {
|
||||
let path = pathForObject(object);
|
||||
let views = object.useCapability('view');
|
||||
let params = this.openmct.router.getParams();
|
||||
let currentViewIsValid = views.some(v => v.key === params['view']);
|
||||
if (!currentViewIsValid) {
|
||||
this.scope.representation = {
|
||||
selected: views[0]
|
||||
}
|
||||
this.openmct.router.update(path, {
|
||||
view: views[0].key
|
||||
});
|
||||
} else {
|
||||
this.openmct.router.setPath(path);
|
||||
}
|
||||
},
|
||||
|
||||
scheduleDigest() {
|
||||
this.$timeout(function () {
|
||||
// digest done!
|
||||
});
|
||||
},
|
||||
|
||||
getObject(id) {
|
||||
return this.objectService.getObjects([id])
|
||||
.then(function (results) {
|
||||
return results[id];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
15
src/ui/components/layout/Conductor.vue
Normal file
15
src/ui/components/layout/Conductor.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<mct-include key="'conductor'" class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"></mct-include>
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
<template>
|
||||
<div class="l-shell">
|
||||
<div class="l-shell__head">
|
||||
[ Create Button ]
|
||||
[ App Logo ]
|
||||
<CreateButton class="l-shell__create-button"></CreateButton>
|
||||
<div class="l-shell__controls">
|
||||
<a class="c-icon-button icon-new-window" title="Open in a new browser tab"></a>
|
||||
<a class="c-icon-button icon-fullscreen-collapse" title="Enable full screen mode"></a>
|
||||
</div>
|
||||
<div class="l-shell__app-logo">[ App Logo ]</div>
|
||||
</div>
|
||||
<multipane class="l-shell__main"
|
||||
type="horizontal">
|
||||
@ -14,17 +18,22 @@
|
||||
<search class="c-search--major" ref="shell-search"></search>
|
||||
</div>
|
||||
<div class="l-shell__tree">
|
||||
<mct-tree :nodes="treeRoots"></mct-tree>
|
||||
<mct-tree></mct-tree>
|
||||
</div>
|
||||
</pane>
|
||||
<pane class="l-shell__pane-main">
|
||||
<div class="l-shell__main-container" ref="mainContainer"></div>
|
||||
<MainViewBrowseBar class="l-shell__main-view-browse-bar"></MainViewBrowseBar>
|
||||
<browse-object class="l-shell__main-container">
|
||||
</browse-object>
|
||||
<mct-template template-key="conductor"
|
||||
class="l-shell__time-conductor">
|
||||
</mct-template>
|
||||
</pane>
|
||||
<pane class="l-shell__pane-inspector l-pane--holds-multipane"
|
||||
handle="before"
|
||||
label="Inspect"
|
||||
collapsable>
|
||||
<MctInspector ref="inspector"></MctInspector>
|
||||
<Inspector ref="inspector"></Inspector>
|
||||
</pane>
|
||||
</multipane>
|
||||
<div class="l-shell__status">
|
||||
@ -72,10 +81,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__head,
|
||||
&__pane-inspector {
|
||||
body.mobile & {
|
||||
display: none;
|
||||
&__pane-main {
|
||||
> .l-pane__contents {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,13 +107,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__head,
|
||||
&__pane-inspector {
|
||||
body.mobile & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__head,
|
||||
&__status {
|
||||
flex: 0 1 auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/******************************* HEAD */
|
||||
&__head {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid $colorInteriorBorder;
|
||||
padding: $interiorMargin;
|
||||
|
||||
> [class*="__"] + [class*="__"] {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__create-button,
|
||||
&__app-logo {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__controls {
|
||||
flex: 1 1 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-right: 2.5%;
|
||||
}
|
||||
|
||||
/********** MAIN AREA */
|
||||
&__main-container {
|
||||
// Wrapper for main views
|
||||
font-size: 16px; // TEMP FOR LEGACY STYLING
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: $interiorMargin; right: $interiorMarginLg; bottom: $interiorMargin; left: $interiorMarginLg;
|
||||
flex: 1 1 100%;
|
||||
font-size: 16px; // TEMP FOR LEGACY STYLING - TODO: REMOVE!
|
||||
}
|
||||
|
||||
&__tree {
|
||||
@ -115,24 +159,12 @@
|
||||
|
||||
&__time-conductor {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
min-height: 50px;
|
||||
padding: $interiorMarginLg;
|
||||
flex: 0 0 auto;
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
body.desktop & {
|
||||
/********** HEAD AND STATUS */
|
||||
&__head,
|
||||
&__status {
|
||||
display: block;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
&__head {
|
||||
border-bottom: 1px solid $colorInteriorBorder;
|
||||
height: 40px;
|
||||
padding: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&__pane-tree,
|
||||
&__pane-inspector {
|
||||
max-width: 30%;
|
||||
@ -150,23 +182,31 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import MctInspector from './MctInspector.vue';
|
||||
import MctMain from './MctMain.vue';
|
||||
import Inspector from '../inspector/Inspector.vue';
|
||||
import MctStatus from './MctStatus.vue';
|
||||
import MctTree from './mct-tree.vue';
|
||||
import BrowseObject from './BrowseObject.vue';
|
||||
import MctTemplate from '../legacy/mct-template.vue';
|
||||
import ContextMenu from '../controls/ContextMenu.vue';
|
||||
import CreateButton from '../controls/CreateButton.vue';
|
||||
import search from '../controls/search.vue';
|
||||
import multipane from '../controls/multipane.vue';
|
||||
import pane from '../controls/pane.vue';
|
||||
import MainViewBrowseBar from '../controls/MainViewBrowseBar.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MctInspector,
|
||||
MctMain,
|
||||
Inspector,
|
||||
MctStatus,
|
||||
MctTree,
|
||||
BrowseObject,
|
||||
'mct-template': MctTemplate,
|
||||
ContextMenu,
|
||||
CreateButton,
|
||||
search,
|
||||
multipane,
|
||||
pane
|
||||
pane,
|
||||
MainViewBrowseBar
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,202 +0,0 @@
|
||||
<template>
|
||||
<multipane class="c-inspector"
|
||||
type="vertical">
|
||||
<pane class="c-inspector__properties">
|
||||
<div ref="properties"></div>
|
||||
</pane>
|
||||
<pane class="l-pane c-inspector__elements"
|
||||
handle="before"
|
||||
label="Elements">
|
||||
<div ref="elements">c-inspector__elements 1</div>
|
||||
</pane>
|
||||
</multipane>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
@mixin grid-two-column() {
|
||||
display: grid;
|
||||
grid-row-gap: 0;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
@mixin grid-two-column-span-cols() {
|
||||
grid-column: 1 / 3;
|
||||
}
|
||||
|
||||
.c-inspector {
|
||||
min-width: 150px;
|
||||
|
||||
> [class*="__"] {
|
||||
min-height: 50px;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
|
||||
> .l-pane__contents > * {
|
||||
// Provide margin against scrollbar
|
||||
// TODO: move this into pane.vue
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&__elements {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.l-inspector-part {
|
||||
display: contents; // Legacy
|
||||
}
|
||||
|
||||
h2 {
|
||||
// Legacy, somewhat
|
||||
@include grid-two-column-span-cols;
|
||||
border-radius: $smallCr;
|
||||
background-color: $colorInspectorSectionHeaderBg;
|
||||
color: $colorInspectorSectionHeaderFg;
|
||||
font-size: .85em;
|
||||
font-weight: normal;
|
||||
margin: $interiorMarginLg 0 $interiorMarginSm 0;
|
||||
padding: $interiorMarginSm $interiorMargin;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-properties {
|
||||
.label {
|
||||
color: $colorInspectorPropName;
|
||||
}
|
||||
.value {
|
||||
color: $colorInspectorPropVal;
|
||||
word-break: break-all;
|
||||
&:first-child {
|
||||
// If there is no preceding .label element, make value span columns
|
||||
@include grid-two-column-span-cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* PROPERTIES GRID */
|
||||
|
||||
.grid-elem {
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
}
|
||||
&.label {
|
||||
background-color: rgba(0,0,128,0.2);
|
||||
}
|
||||
&.value {
|
||||
background-color: rgba(0,128,0,0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// Properties grids
|
||||
.grid-properties, // LEGACY
|
||||
.l-grid-properties {
|
||||
@include grid-two-column;
|
||||
}
|
||||
|
||||
.grid-row {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.grid-span-all {
|
||||
@include grid-two-column-span-cols;
|
||||
}
|
||||
|
||||
.grid-row {
|
||||
.grid-cell {
|
||||
padding: 3px $interiorMarginLg 3px 0;
|
||||
&[title] {
|
||||
// When a cell has a title, assume it's helpful text
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
&.force-border,
|
||||
&:not(:first-of-type) {
|
||||
// Row borders, effected via border-top on child elements of the row
|
||||
.grid-cell {
|
||||
border-top: 1px solid $colorInspectorSectionHeaderBg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************** LEGACY STYLES */
|
||||
.tree {
|
||||
.grid-properties {
|
||||
margin-left: $treeItemIndent + $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.inspector-location {
|
||||
display: inline-block;
|
||||
|
||||
.location-item {
|
||||
$h: 1.2em;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $h;
|
||||
position: relative;
|
||||
padding: 2px 4px;
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
height: $h;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
color: $colorItemTreeHoverFg;
|
||||
.icon {
|
||||
color: $colorItemTreeIconHover;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:not(.last) .t-object-label .t-title-label:after {
|
||||
color: pushBack($colorInspectorFg, 15%);
|
||||
content: '\e904';
|
||||
display: inline-block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 8px;
|
||||
font-style: normal !important;
|
||||
line-height: inherit;
|
||||
margin-left: $interiorMarginSm;
|
||||
width: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// Elements pool
|
||||
.holder-elements {
|
||||
.current-elements {
|
||||
position: relative;
|
||||
.tree-item {
|
||||
.t-object-label {
|
||||
// Elements pool is a flat list, so don't indent items.
|
||||
/*font-size: 0.75rem;*/
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import multipane from '../controls/multipane.vue';
|
||||
import pane from '../controls/pane.vue';
|
||||
export default {
|
||||
components: {
|
||||
multipane,
|
||||
pane
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<mct-representation key='browse-object'></mct-representation>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.MCT_Main {
|
||||
position: absolute;
|
||||
right: 100px;
|
||||
top: 0px;
|
||||
bottom: 20px;
|
||||
left: 100px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -10,9 +10,8 @@
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
// TODO: make sure hit area encompasses all of the tree item; currently is just the text
|
||||
|
||||
.c-tree {
|
||||
@include userSelectNone();
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
@ -70,7 +69,8 @@
|
||||
|
||||
&:before {
|
||||
// Type icon
|
||||
display: inline-block;
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.3em;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
38
src/ui/components/legacy/mct-template.vue
Normal file
38
src/ui/components/legacy/mct-template.vue
Normal file
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
templateKey: String
|
||||
},
|
||||
mounted() {
|
||||
let openmct = this.openmct;
|
||||
let $injector = openmct.$injector;
|
||||
let angular = openmct.$angular;
|
||||
|
||||
let templateLinker = $injector.get('templateLinker');
|
||||
|
||||
let templateMap = {};
|
||||
$injector.get('templates[]').forEach((t) => {
|
||||
templateMap[t.key] = templateMap[t.key] || t;
|
||||
});
|
||||
|
||||
let $rootScope = $injector.get('$rootScope');
|
||||
this.$scope = $rootScope.$new();
|
||||
console.log('mounting', this.templateKey);
|
||||
console.log('template:', templateMap[this.templateKey]);
|
||||
|
||||
templateLinker.link(
|
||||
this.$scope,
|
||||
angular.element(this.$el),
|
||||
templateMap[this.templateKey]
|
||||
);
|
||||
},
|
||||
destroyed() {
|
||||
this.$scope.$destroy();
|
||||
}
|
||||
}
|
||||
</script>
|
Reference in New Issue
Block a user