Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add filtering by metadata #7388

Merged
merged 11 commits into from
Jan 28, 2024
23 changes: 22 additions & 1 deletion src/plugins/plan/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/

import _ from 'lodash';
export function getValidatedData(domainObject) {
const sourceMap = domainObject.sourceMap;
const json = getObjectJson(domainObject);
Expand All @@ -45,6 +46,16 @@
groupActivity.end = activity[sourceMap.end];
}

if (Array.isArray(sourceMap.filterMetadata)) {
groupActivity.filterMetadataValues = [];
sourceMap.filterMetadata.forEach((property) => {
const value = _.get(activity, property);
groupActivity.filterMetadataValues.push({

Check warning on line 53 in src/plugins/plan/util.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/plan/util.js#L49-L53

Added lines #L49 - L53 were not covered by tests
value
});
});
}

if (!mappedJson[groupIdKey]) {
mappedJson[groupIdKey] = [];
}
Expand Down Expand Up @@ -92,14 +103,24 @@
orderedGroupNames = groups;
}
}

if (orderedGroupNames === undefined) {
orderedGroupNames = Object.keys(planData);
}

return orderedGroupNames;
}

export function getFilteredValues(activity) {
let values = [];
if (Array.isArray(activity.filterMetadataValues)) {
values = activity.filterMetadataValues;
} else if (activity?.properties) {
values = Object.values(activity.properties);

Check warning on line 118 in src/plugins/plan/util.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/plan/util.js#L114-L118

Added lines #L114 - L118 were not covered by tests
}

return values;

Check warning on line 121 in src/plugins/plan/util.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/plan/util.js#L121

Added line #L121 was not covered by tests
}

export function getContrastingColor(hexColor) {
function cutHex(h, start, end) {
const hStr = h.charAt(0) === '#' ? h.substring(1, 7) : h;
Expand Down
44 changes: 37 additions & 7 deletions src/plugins/timelist/TimelistComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
import ListView from '../../ui/components/List/ListView.vue';
import { getPreciseDuration } from '../../utils/duration.js';
import { getValidatedData, getValidatedGroups } from '../plan/util.js';
import {
getFilteredValues,
getFilterMetadataProperties,
getValidatedData,
getValidatedGroups
} from '../plan/util.js';
import { SORT_ORDER_OPTIONS } from './constants.js';

const SCROLL_TIMEOUT = 10000;
Expand Down Expand Up @@ -208,22 +213,22 @@
this.setViewFromConfig(mutatedObject.configuration);
},
setViewFromConfig(configuration) {
this.filterValue = configuration.filter || '';
this.filterMetadataValue = configuration.filterMetadata || '';

Check warning on line 217 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L217

Added line #L217 was not covered by tests
if (this.isEditing) {
this.filterValue = configuration.filter;
this.hideAll = false;
this.listActivities();
} else {
this.filterValue = configuration.filter;
this.setSort();
this.listActivities();
}
this.listActivities();

Check warning on line 223 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L223

Added line #L223 was not covered by tests
},
updateTimestamp(timestamp) {
//The clock never stops ticking
this.updateTimeStampAndListActivities(timestamp);
},
setFixedTime() {
this.filterValue = this.domainObject.configuration.filter;
this.filterValue = this.domainObject.configuration.filter || '';
this.filterMetadataValue = this.domainObject.configuration.filterMetadata || '';

Check warning on line 231 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L231

Added line #L231 was not covered by tests
this.isFixedTime = !this.timeContext.isRealTime();
if (this.isFixedTime) {
this.hideAll = false;
Expand Down Expand Up @@ -326,7 +331,21 @@
return true;
}

const hasFilterMatch = this.filterByName(activity.name);
let hasNameMatch = false;
let hasMetadataMatch = false;
if (this.filterValue || this.filterMetadataValue) {
if (this.filterValue) {
hasNameMatch = this.filterByName(activity.name);
}
if (this.filterMetadataValue) {
hasMetadataMatch = this.filterByMetadata(activity);
}
} else {
hasNameMatch = true;

Check warning on line 344 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L344

Added line #L344 was not covered by tests
hasMetadataMatch = true;
}

const hasFilterMatch = hasNameMatch || hasMetadataMatch;

Check warning on line 348 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L346-L348

Added lines #L346 - L348 were not covered by tests
if (hasFilterMatch === false || this.hideAll === true) {
return false;
}
Expand Down Expand Up @@ -354,6 +373,17 @@
return regex.test(name.toLowerCase());
});
},
filterByMetadata(activity) {
const filters = this.filterMetadataValue.split(',');

return filters.some((search) => {
const normalized = search.trim().toLowerCase();
const regex = new RegExp(normalized);
const activityValues = getFilteredValues(activity);

Check warning on line 383 in src/plugins/timelist/TimelistComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/TimelistComponent.vue#L383

Added line #L383 was not covered by tests
return regex.test(activityValues.join().toLowerCase());
});
},
// Add activity classes, increase activity counts by type,
// set indices of the first occurrences of current and future activities - used for scrolling
styleActivity(activity, index) {
Expand Down
71 changes: 58 additions & 13 deletions src/plugins/timelist/inspector/FilteringComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,47 @@
<div v-if="canEdit" class="c-inspect-properties__hint span-all">
Filter this view by comma-separated keywords.
</div>
<div class="c-inspect-properties__label" title="Filter by keyword.">Filters</div>
<div v-if="canEdit" class="c-inspect-properties__value" :class="{ 'form-error': hasError }">
<div class="c-inspect-properties__label" aria-label="Activity Names" title="Filter by keyword.">

Check warning on line 27 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L27

Added line #L27 was not covered by tests
Activity Names
</div>
<div
v-if="canEdit"
class="c-inspect-properties__value"

Check warning on line 32 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L29-L32

Added lines #L29 - L32 were not covered by tests
:class="{ 'form-error': hasFilterError }"
>
<textarea
v-model="filterValue"
class="c-input--flex"
type="text"
@keydown.enter.exact.stop="forceBlur($event)"
@keyup="updateForm($event, 'filter')"
@keyup="updateNameFilter($event, 'filter')"

Check warning on line 40 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L40

Added line #L40 was not covered by tests
></textarea>
</div>
<div v-else class="c-inspect-properties__value">
{{ filterValue }}
</div>
</li>
<li class="c-inspect-properties__row">

Check warning on line 47 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L47

Added line #L47 was not covered by tests
<div class="c-inspect-properties__label" aria-label="Meta-data Tags" title="Filter by keyword.">
Meta-data Tags
</div>
<div
v-if="canEdit"
class="c-inspect-properties__value"
:class="{ 'form-error': hasMetadataFilterError }"

Check warning on line 54 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L54

Added line #L54 was not covered by tests
>
<textarea

Check warning on line 56 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L56

Added line #L56 was not covered by tests
v-model="filterMetadataValue"
class="c-input--flex"
type="text"

Check warning on line 59 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L59

Added line #L59 was not covered by tests
@keydown.enter.exact.stop="forceBlur($event)"
@keyup="updateMetadataFilter($event, 'filterMetadata')"

Check warning on line 61 in src/plugins/timelist/inspector/FilteringComponent.vue

View check run for this annotation

Codecov / codecov/patch

src/plugins/timelist/inspector/FilteringComponent.vue#L61

Added line #L61 was not covered by tests
></textarea>
</div>
<div v-else class="c-inspect-properties__value">
{{ filterMetadataValue }}
</div>
</li>
</template>

<script>
Expand All @@ -48,7 +75,9 @@
return {
isEditing: this.openmct.editor.isEditing(),
filterValue: this.domainObject.configuration.filter,
hasError: false
filterMetadataValue: this.domainObject.configuration.filterMetadata,
hasFilterError: false,
hasMetadataFilterError: false
};
},
computed: {
Expand All @@ -65,37 +94,53 @@
methods: {
setEditState(isEditing) {
this.isEditing = isEditing;
if (!this.isEditing && this.hasError) {
if (!this.isEditing && this.hasFilterError && this.hasMetadataFilterError) {
this.filterValue = this.domainObject.configuration.filter;
this.hasError = false;
this.filterMetadataValue = this.domainObject.configuration.filterMetadata;
this.hasFilterError = false;
this.hasMetadataFilterError = false;
}
},
forceBlur(event) {
event.target.blur();
},
updateForm(event, property) {
if (!this.isValid()) {
this.hasError = true;
updateNameFilter(event, property) {
if (!this.isValid(this.filterValue)) {
this.hasFilterError = true;

return;
}

this.hasError = false;
this.hasFilterError = false;

this.$emit('updated', {
property,
value: this.filterValue.replace(/,(\s)*$/, '')
});
},
isValid() {
updateMetadataFilter(event, property) {
if (!this.isValid(this.filterMetadataValue)) {
this.hasMetadataFilterError = true;

return;
}

this.hasMetadataFilterError = false;

this.$emit('updated', {
property,
value: this.filterMetadataValue.replace(/,(\s)*$/, '')
});
},
isValid(value) {
// Test for any word character, any whitespace character or comma
if (this.filterValue === '') {
if (value === '') {
return true;
}

const regex = new RegExp(/^([a-zA-Z0-9_\-\s,])+$/g);

return regex.test(this.filterValue);
return regex.test(value);
}
}
};
Expand Down
12 changes: 3 additions & 9 deletions src/plugins/timelist/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,10 @@ export default function () {
initialize: function (domainObject) {
domainObject.configuration = {
sortOrderIndex: 0,
futureEventsIndex: 1,
futureEventsDurationIndex: 0,
futureEventsDuration: 20,
currentEventsIndex: 1,
currentEventsDurationIndex: 0,
currentEventsDuration: 20,
pastEventsIndex: 1,
pastEventsDurationIndex: 0,
pastEventsDuration: 20,
filter: ''
filter: '',
filterMetadata: '',
isCompact: false
};
domainObject.composition = [];
}
Expand Down
Loading