Flexible inspector properties (#4109)

* inspector properties can be passed in through context
* defaults to the currently hard-coded details (title, type, modified or created)
This commit is contained in:
David Tsay 2021-09-17 16:20:22 -07:00 committed by GitHub
parent b315803180
commit aa5edb0b83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 579 additions and 177 deletions

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<li
draggable="true"

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div class="c-elements-pool">
<Search

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div class="c-inspector">
<object-name />
@ -19,7 +41,9 @@
type="vertical"
>
<pane class="c-inspector__properties">
<properties />
<Properties
v-if="!activity"
/>
<location />
<inspector-views />
</pane>
@ -57,7 +81,7 @@ import multipane from '../layout/multipane.vue';
import pane from '../layout/pane.vue';
import ElementsPool from './ElementsPool.vue';
import Location from './Location.vue';
import Properties from './Properties.vue';
import Properties from './details/Properties.vue';
import ObjectName from './ObjectName.vue';
import InspectorViews from './InspectorViews.vue';
import _ from "lodash";
@ -98,7 +122,8 @@ export default {
key: '__styles',
name: 'Styles'
}],
currentTabbedView: {}
currentTabbedView: {},
activity: undefined
};
},
mounted() {
@ -111,9 +136,12 @@ export default {
methods: {
updateInspectorViews(selection) {
this.refreshComposition(selection);
if (this.openmct.types.get('conditionSet')) {
this.refreshTabs(selection);
}
this.setActivity(selection);
},
refreshComposition(selection) {
if (selection.length > 0 && selection[0].length > 0) {
@ -150,6 +178,12 @@ export default {
},
isCurrent(view) {
return _.isEqual(this.currentTabbedView, view);
},
setActivity(selection) {
this.activity = selection
&& selection.length
&& selection[0].length
&& selection[0][0].activity;
}
}
};

View File

@ -0,0 +1,166 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import {
createOpenMct,
resetApplicationState
} from 'utils/testing';
import Vue from 'vue';
const INSPECTOR_SELECTOR_PREFIX = '.c-inspect-properties__';
describe('the inspector', () => {
let appHolder;
let openmct;
let folderItem;
let selection;
beforeEach((done) => {
folderItem = {
name: 'folder',
type: 'folder',
id: 'mock-folder-key',
identifier: {
namespace: '',
key: 'mock-folder-key'
},
created: 1592851063871
};
selection = [
{
context: {
item: folderItem
}
}
];
appHolder = document.createElement('div');
openmct = createOpenMct();
openmct.on('start', done);
openmct.start(appHolder);
});
afterEach(() => {
return resetApplicationState(openmct);
});
it('displays default details for selection', async () => {
openmct.selection.select(selection);
await Vue.nextTick();
const details = getDetails();
const [
title,
type,
timestamp
] = details;
expect(title.name)
.toEqual('Title');
expect(title.value.toLowerCase())
.toEqual(folderItem.name);
expect(type.name)
.toEqual('Type');
expect(type.value.toLowerCase())
.toEqual(folderItem.type);
expect(timestamp.name)
.toEqual('Created');
expect(new Date(timestamp.value).toString())
.toEqual(new Date(folderItem.created).toString());
});
it('details show modified date', async () => {
const modifiedTimestamp = folderItem.created + 1000;
folderItem.modified = modifiedTimestamp;
openmct.selection.select(selection);
await Vue.nextTick();
const details = getDetails();
const timestamp = details[details.length - 1];
expect(timestamp.name)
.toEqual('Modified');
expect(new Date(timestamp.value).toString())
.toEqual(new Date(folderItem.modified).toString());
});
it('displays custom details if provided through context', async () => {
const NAME_PREFIX = 'Custom Name';
const VALUE_PREFIX = 'Custom Value';
const indexes = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const customDetails = indexes.map(index => {
return {
name: `${NAME_PREFIX} ${index}`,
value: `${VALUE_PREFIX} ${index}`
};
});
selection[0].context.details = customDetails;
openmct.selection.select(selection);
await Vue.nextTick();
const details = getDetails();
expect(details.length)
.toEqual(customDetails.length);
details.forEach((detail, index) => {
expect(detail.name)
.toEqual(customDetails[index].name);
expect(detail.value)
.toEqual(customDetails[index].value);
});
});
function getDetailsElements() {
const inspectorDetailsSection = appHolder
.querySelector(`${INSPECTOR_SELECTOR_PREFIX}section`);
const details = inspectorDetailsSection
.querySelectorAll(`${INSPECTOR_SELECTOR_PREFIX}row`);
return details;
}
function getDetails() {
const detailsElements = getDetailsElements();
const details = Array.from(detailsElements)
.map(element => {
return {
name: getText(element, 'label'),
value: getText(element, 'value')
};
});
return details;
}
function getText(element, selectorSuffix) {
return element.querySelector(`${INSPECTOR_SELECTOR_PREFIX}${selectorSuffix}`)
.textContent.trim();
}
});

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
export const mockTelemetryTableSelection = [
[{
context: {

View File

@ -1,10 +1,29 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div></div>
</template>
<style>
</style>
<script>
export default {
inject: ['openmct'],

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div class="c-inspect-properties c-inspect-properties--location">
<div

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div class="c-inspector__header">
<div v-if="!multiSelect"

View File

@ -1,171 +0,0 @@
<template>
<div v-if="!activity"
class="c-inspector__properties c-inspect-properties"
>
<div class="c-inspect-properties__header">
Details
</div>
<ul
v-if="!multiSelect && !singleSelectNonObject"
class="c-inspect-properties__section"
>
<li class="c-inspect-properties__row">
<div class="c-inspect-properties__label">
Title
</div>
<div class="c-inspect-properties__value">
{{ item.name }}
</div>
</li>
<li class="c-inspect-properties__row">
<div class="c-inspect-properties__label">
Type
</div>
<div class="c-inspect-properties__value">
{{ typeName }}
</div>
</li>
<li
v-if="item.created"
class="c-inspect-properties__row"
>
<div class="c-inspect-properties__label">
Created
</div>
<div class="c-inspect-properties__value">
{{ formatTime(item.created) }}
</div>
</li>
<li
v-if="item.modified"
class="c-inspect-properties__row"
>
<div class="c-inspect-properties__label">
Modified
</div>
<div class="c-inspect-properties__value">
{{ formatTime(item.modified) }}
</div>
</li>
<li
v-for="prop in typeProperties"
:key="prop.name"
class="c-inspect-properties__row"
>
<div class="c-inspect-properties__label">
{{ prop.name }}
</div>
<div class="c-inspect-properties__value">
{{ prop.value }}
</div>
</li>
</ul>
<div
v-if="multiSelect"
class="c-inspect-properties__row--span-all"
>
No properties to display for multiple items
</div>
<div
v-if="singleSelectNonObject"
class="c-inspect-properties__row--span-all"
>
No properties to display for this item
</div>
</div>
</template>
<script>
import Moment from "moment";
export default {
inject: ['openmct'],
data() {
return {
domainObject: {},
activity: undefined,
multiSelect: false
};
},
computed: {
item() {
return this.domainObject || {};
},
type() {
return this.openmct.types.get(this.item.type);
},
typeName() {
if (!this.type) {
return `Unknown: ${this.item.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, key) => {
return object[key];
}, this.item)
};
});
},
singleSelectNonObject() {
return !this.item.identifier && !this.multiSelect;
}
},
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 || selection[0].length === 0) {
this.domainObject = {};
return;
}
if (selection.length > 1) {
this.multiSelect = true;
this.domainObject = {};
return;
} else {
this.multiSelect = false;
this.domainObject = selection[0][0].context.item;
this.activity = selection[0][0].context.activity;
}
},
formatTime(unixTime) {
return Moment.utc(unixTime).format('YYYY-MM-DD[\n]HH:mm:ss') + ' UTC';
}
}
};
</script>

View File

@ -0,0 +1,43 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<li class="c-inspect-properties__row">
<div class="c-inspect-properties__label">
{{ detail.name }}
</div>
<div class="c-inspect-properties__value">
{{ detail.value }}
</div>
</li>
</template>
<script>
export default {
props: {
detail: {
type: Object,
required: true
}
}
};
</script>

View File

@ -0,0 +1,201 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
<template>
<div class="c-inspector__properties c-inspect-properties">
<div class="c-inspect-properties__header">
Details
</div>
<ul
v-if="hasDetails"
class="c-inspect-properties__section"
>
<Component
:is="getComponent(detail)"
v-for="detail in details"
:key="detail.name"
:detail="detail"
/>
</ul>
<div
v-else
class="c-inspect-properties__row--span-all"
>
{{ noDetailsMessage }}
</div>
</div>
</template>
<script>
import Moment from 'moment';
import DetailText from './DetailText.vue';
export default {
components: {
DetailText
},
inject: ['openmct'],
data() {
return {
selection: undefined
};
},
computed: {
details() {
return this.customDetails ? this.customDetails : this.domainObjectDetails;
},
customDetails() {
if (this.context === undefined) {
return;
}
return this.context.details;
},
domainObject() {
if (this.context === undefined) {
return;
}
return this.context.item;
},
type() {
if (this.domainObject === undefined) {
return;
}
return this.openmct.types.get(this.domainObject.type);
},
domainObjectDetails() {
if (this.domainObject === undefined) {
return;
}
const title = this.domainObject.name;
const typeName = this.type ? this.type.definition.name : `Unknown: ${this.domainObject.type}`;
const timestampLabel = this.domainObject.modified ? 'Modified' : 'Created';
const timestamp = this.domainObject.modified ? this.domainObject.modified : this.domainObject.created;
const details = [
{
name: 'Title',
value: title
},
{
name: 'Type',
value: typeName
}
];
if (timestamp !== undefined) {
const formattedTimestamp = Moment.utc(timestamp)
.format('YYYY-MM-DD[\n]HH:mm:ss')
+ ' UTC';
details.push(
{
name: timestampLabel,
value: formattedTimestamp
}
);
}
return [...details, ...this.typeProperties];
},
context() {
if (
!this.selection
|| !this.selection.length
|| !this.selection[0].length
) {
return;
}
return this.selection[0][0].context;
},
hasDetails() {
return Boolean(
this.details
&& this.details.length
&& !this.multiSelection
);
},
multiSelection() {
return this.selection && this.selection.length > 1;
},
noDetailsMessage() {
return this.multiSelection
? 'No properties to display for multiple items'
: 'No properties to display for this item';
},
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, key) => {
return object[key];
}, 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: {
getComponent(detail) {
const component = detail.component ? detail.component : 'text';
return `detail-${component}`;
},
updateSelection(selection) {
this.selection = selection;
}
}
};
</script>