Adds textual filters to metadata and filters list #481

This commit is contained in:
mateuswetah 2021-02-25 11:37:46 -03:00
parent 7153b070c9
commit 9fd2310fc5
6 changed files with 206 additions and 66 deletions

View File

@ -14,8 +14,8 @@
</p>
<p>{{ $i18n.get('info_create_child_metadata') }}</p>
</div>
</section>
<draggable
</section>
<draggable
v-model="childrenMetadata"
:style="{ minHeight: childrenMetadata.length > 0 ? '40px' : '70px' }"
class="active-metadata-area child-metadata-area"
@ -31,18 +31,19 @@
<div
class="active-metadatum-item"
:class="{
'not-sortable-item': metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadatum.parent == 0 || metadatum.collection_id != collectionId,
'not-sortable-item': metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadatum.parent == 0 || metadatum.collection_id != collectionId || metadataNameFilterString != '',
'not-focusable-item': openedMetadatumId == metadatum.id,
'disabled-metadatum': parent.enabled == false,
'inherited-metadatum': (metadatum.collection_id != collectionId && metadatum.parent == 0) || isRepositoryLevel
}"
v-for="(metadatum, index) in childrenMetadata"
:key="metadatum.id">
:key="metadatum.id"
v-show="metadataNameFilterString == '' || metadatum.name.toString().toLowerCase().indexOf(metadataNameFilterString.toString().toLowerCase()) >= 0">
<div
:ref="'metadatum-handler-' + metadatum.id"
class="handle">
<span
:style="{ opacity: !( metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadatum.parent == 0 || metadatum.collection_id != collectionId) ? '1.0' : '0.0' }"
:style="{ opacity: !(metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadatum.parent == 0 || metadatum.collection_id != collectionId || metadataNameFilterString != '') ? '1.0' : '0.0' }"
v-tooltip="{
content: metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder ? $i18n.get('info_not_allowed_change_order_metadata') : $i18n.get('instruction_drag_and_drop_metadatum_sort'),
autoHide: true,
@ -195,7 +196,8 @@
props: {
isRepositoryLevel: Boolean,
parent: Object,
isParentMultiple: Boolean
isParentMultiple: Boolean,
metadataNameFilterString: String
},
data() {
return {

View File

@ -199,12 +199,33 @@ abstract class Metadata_Type {
return isset($options[$key]) ? $options[$key] : '';
}
/**
* Gets print-ready version of the options list in html
*
* Checks if at least one option exists, otherwise return an empty string
*
* @return string An html content with labels and values for the options or an empty string
*/
public function get_options_as_html() {
$options_as_html = '';
$options = $this->get_options();
if ( count($options) > 0 ) {
foreach($options as $option_label => $option_value) {
$options_as_html .= '<div class="field"><div class="label">' . $option_label .'</div>';
$options_as_html .= '<div class="value">' . $option_value . '</div></div>';
}
}
return $options_as_html;
}
/**
* allow i18n from messages
*/
public function get_form_labels(){
return [];
}
/**
* generate the metadata for this metadatum type
*/
@ -226,6 +247,7 @@ abstract class Metadata_Type {
$attributes['primitive_type'] = $this->get_primitive_type();
$attributes['form_component'] = $this->get_form_component();
$attributes['preview_template'] = $this->get_preview_template();
$attributes['options_as_html'] = $this->get_options_as_html();
return $attributes;

View File

@ -4,24 +4,24 @@
v-if="metadatum.description"
class="field">
<div class="label">{{ $i18n.getHelperTitle('metadata', 'description') }}</div>
<div class="content">{{ metadatum.description }}</div>
<div class="value">{{ metadatum.description }}</div>
</div>
<div
v-if="metadatum.semantic_uri"
class="field">
<div class="label">{{ $i18n.getHelperTitle('metadata', 'semantic_uri') }}</div>
<div class="content">{{ metadatum.semantic_uri }}</div>
<div class="value">{{ metadatum.semantic_uri }}</div>
</div>
<div class="field">
<div class="label">{{ $i18n.getHelperTitle('metadata', 'status') }}</div>
<div class="content">
<div class="value">
<template v-if="metadatum.status === 'publish'">{{ $i18n.get('publish_visibility') }}</template>
<template v-if="metadatum.status === 'private'">{{ $i18n.get('private_visibility') }}</template>
</div>
</div>
<div class="field">
<div class="label">{{ $i18n.get('label_display') }}</div>
<div class="content">
<div class="value">
<template v-if="metadatum.display === 'yes'">{{ $i18n.get('label_display_default') }}</template>
<template v-if="metadatum.display === 'no'">{{ $i18n.get('label_not_display') }}</template>
<template v-if="metadatum.display === 'never'">{{ $i18n.get('label_display_never') }}</template>
@ -29,15 +29,11 @@
</div>
<div class="field">
<div class="label">{{ $i18n.get('label_insert_options') }}</div>
<div class="content">{{ insertOptions }}</div>
<div class="value">{{ insertOptions }}</div>
</div>
<template
v-if="metadatum.metadata_type_options">
<div class="field">
<div class="label">{{ $i18n.get('label_options') }}</div>
<div class="content">{{ JSON.stringify(metadatum.metadata_type_options) }}</div>
</div>
</template>
<div
v-if="metadatum.metadata_type_object && metadatum.metadata_type_object.options_as_html"
v-html="metadatum.metadata_type_object.options_as_html" />
</div>
</template>
@ -85,7 +81,7 @@ export default {
.field > .field:not(:last-child) {
margin-bottom: 0em;
}
.field .content {
.field .value {
font-size: 0.9em;
}
}

View File

@ -12,12 +12,31 @@
<div
v-if="(isRepositoryLevel && $userCaps.hasCapability('tnc_rep_edit_filters') || (!isRepositoryLevel && collection && collection.current_user_can_edit_filters))"
:style="{ height: activeFilterList.length <= 0 && !isLoadingFilters ? 'auto' : 'calc(100vh - 6px - ' + columnsTopY + 'px)'}"
:style="{ height: activeFiltersList.length <= 0 && !isLoadingFilters ? 'auto' : 'calc(100vh - 6px - ' + columnsTopY + 'px)'}"
class="columns"
ref="filterEditionPageColumns">
<div class="column">
<div class="tainacan-form sub-header">
<h3 class="has-text-secondary">{{ $i18n.get('filters') }}</h3>
<template v-if="activeFiltersList && activeFiltersList.length > 5 && !isLoadingFilters">
<b-field class="header-item">
<b-input
:placeholder="$i18n.get('instruction_type_search_filter_filter')"
v-model="filterNameFilterString"
icon="magnify"
size="is-small"
icon-right="close-circle"
icon-right-clickable
@icon-right-click="filterNameFilterString = ''" />
</b-field>
</template>
</div>
<section
v-if="activeFilterList.length <= 0 && !isLoadingFilters"
v-if="activeFiltersList.length <= 0 && !isLoadingFilters"
class="field is-grouped-centered section">
<div class="content has-text-gray has-text-centered">
<p>
@ -28,32 +47,34 @@
<p>{{ $i18n.get('info_there_is_no_filter' ) }}</p>
<p>{{ $i18n.get('info_create_filters' ) }}</p>
</div>
</section>
<draggable
</section>
<draggable
class="active-filters-area"
@change="handleChangeOnFilter"
:class="{'filters-area-receive': isDraggingFromAvailable}"
v-model="activeFilterList"
v-model="activeFiltersList"
:group="{ name:'filters', pull: false, put: true }"
:sort="(openedFilterId == '' || openedFilterId == undefined) && !isRepositoryLevel"
:handle="'.handle'"
ghost-class="sortable-ghost"
filter=".not-sortable-item"
:prevent-on-filter="false"
:animation="250">
<div
:animation="250">
<div
class="active-filter-item"
:class="{
'not-sortable-item': (isRepositoryLevel || isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true),
'not-sortable-item': (isRepositoryLevel || isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true || filterNameFilterString != ''),
'not-focusable-item': openedFilterId == filter.id,
'disabled-filter': filter.enabled == false,
'inherited-filter': filter.inherited || isRepositoryLevel
}"
v-for="(filter, index) in activeFilterList"
:key="filter.id">
v-for="(filter, index) in activeFiltersList"
:key="filter.id"
v-show="filterNameFilterString == '' || filter.name.toString().toLowerCase().indexOf(filterNameFilterString.toString().toLowerCase()) >= 0">
<div class="handle">
<span
:style="{ opacity: !(isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true || isRepositoryLevel) ? '1.0' : '0.0' }"
:style="{ opacity: !(isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true || isRepositoryLevel || filterNameFilterString != '') ? '1.0' : '0.0' }"
v-tooltip="{
content: (isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true) ? $i18n.get('info_not_allowed_change_order_filters') : $i18n.get('instruction_drag_and_drop_filter_sort'),
autoHide: true,
@ -386,11 +407,12 @@ export default {
currentFilterTypePreview: undefined,
columnsTopY: 0,
filtersSearchCancel: undefined,
metadataSearchCancel: undefined
metadataSearchCancel: undefined,
filterNameFilterString: ''
}
},
computed: {
activeFilterList: {
activeFiltersList: {
get() {
return this.getFilters();
},
@ -406,9 +428,9 @@ export default {
'$route.query': {
handler(newQuery) {
if (newQuery.edit != undefined) {
let existingFilterIndex = this.activeFilterList.findIndex((filter) => filter.id == newQuery.edit);
let existingFilterIndex = this.activeFiltersList.findIndex((filter) => filter.id == newQuery.edit);
if (existingFilterIndex >= 0)
this.editFilter(this.activeFilterList[existingFilterIndex])
this.editFilter(this.activeFiltersList[existingFilterIndex])
}
},
immediate: true
@ -547,7 +569,7 @@ export default {
this.availableMetadata.splice(metadatumIndex, 1);
// Inserts it at the end of the list
let lastFilterIndex = this.activeFilterList.length;
let lastFilterIndex = this.activeFiltersList.length;
// // Updates store with temporary Filter
// this.addTemporaryFilter(metadatumType);
@ -573,7 +595,7 @@ export default {
this.choosenMetadatum = {};
// Removes element from filters list
this.activeFilterList.splice(this.newFilterIndex, 1);
this.activeFiltersList.splice(this.newFilterIndex, 1);
},
handleChangeOnMetadata($event) {
if ($event.removed) {
@ -582,7 +604,7 @@ export default {
},
updateFiltersOrder() {
let filtersOrder = [];
for (let filter of this.activeFilterList) {
for (let filter of this.activeFiltersList) {
filtersOrder.push({'id': filter.id, 'enabled': filter.enabled});
}
this.isUpdatingFiltersOrder = true;
@ -608,7 +630,7 @@ export default {
}
}
for (let activeFilter of this.activeFilterList) {
for (let activeFilter of this.activeFiltersList) {
for (let i = availableMetadata.length - 1; i >= 0 ; i--) {
if (activeFilter.metadatum != undefined) {
if (activeFilter.metadatum.metadatum_id == availableMetadata[i].id)
@ -621,7 +643,7 @@ export default {
},
onChangeEnable($event, index) {
let filtersOrder = [];
for (let filter of this.activeFilterList) {
for (let filter of this.activeFiltersList) {
filtersOrder.push({'id': filter.id, 'enabled': filter.enabled});
}
filtersOrder[index].enabled = $event;
@ -750,16 +772,16 @@ export default {
// Checks URL as router watcher would not wait for list to load
if (this.$route.query.edit != undefined) {
let existingFilterIndex = this.activeFilterList.findIndex((filter) => filter.id == this.$route.query.edit);
let existingFilterIndex = this.activeFiltersList.findIndex((filter) => filter.id == this.$route.query.edit);
if (existingFilterIndex >= 0)
this.editFilter(this.activeFilterList[existingFilterIndex]);
this.editFilter(this.activeFiltersList[existingFilterIndex]);
}
// Cancels previous Request
if (this.metadataSearchCancel != undefined)
this.metadataSearchCancel.cancel('Metadata search Canceled.');
// Needs to be done after activeFilterList exists to compare and remove chosen metadata.
// Needs to be done after activeFiltersList exists to compare and remove chosen metadata.
this.fetchMetadata({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
@ -842,6 +864,25 @@ export default {
margin-right: 0;
}
}
h3 {
font-weight: 500;
}
}
.sub-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5em;
.header-item {
margin-left: 0.75rem;
margin-bottom: 0px;
}
h3 {
margin-right: auto;
}
}
.loading-spinner {
@ -1016,7 +1057,7 @@ export default {
}
h3 {
margin: 0.2em 0em 1em 0em;
margin: 0.875em 0em 1em 0em;
font-weight: 500;
}

View File

@ -14,12 +14,75 @@
v-model="activeTab">
<b-tab-item :label="$i18n.get('metadata')">
<div
:style="{ height: activeMetadatumList.length <= 0 && !isLoadingMetadata ? 'auto' : 'calc(100vh - 6px - ' + columnsTopY + 'px)'}"
:style="{ height: activeMetadatumList && activeMetadatumList.length <= 0 && !isLoadingMetadata ? 'auto' : 'calc(100vh - 6px - ' + columnsTopY + 'px)'}"
class="columns"
ref="metadataEditionPageColumns">
<b-loading :active.sync="isLoadingMetadatumTypes"/>
<div class="column">
<div class="tainacan-form sub-header">
<h3 class="has-text-secondary">{{ $i18n.get('metadata') }}</h3>
<template v-if="activeMetadatumList && activeMetadatumList.length > 5 && !isLoadingMetadata">
<b-field class="header-item">
<b-dropdown
id="tainacan-switch-compact-metadata-list"
v-model="showCompactMetadataList"
:mobile-modal="true"
position="is-bottom-right"
:aria-label="$i18n.get('label_view_mode')"
aria-role="list"
trap-focus>
<button
class="button is-white"
:aria-label="$i18n.get('label_visualization')"
slot="trigger">
<span class="gray-icon icon">
<i :class="'tainacan-icon tainacan-icon-1-25em tainacan-icon-' + (showCompactMetadataList ? 'menu' : 'viewlist')" />
</span>
<span>{{ showCompactMetadataList ? $i18n.get('label_compact_list') : $i18n.get('label_detailed_list') }}</span>
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown" />
</span>
</button>
<b-dropdown-item
aria-controls="items-list-results"
role="button"
:value="true"
:class="{ 'is-active': showCompactMetadataList }"
aria-role="listitem">
<span class="gray-icon icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-menu" />
</span>
<span>{{ $i18n.get('label_compact_list') }}</span>
</b-dropdown-item>
<b-dropdown-item
aria-controls="items-list-results"
role="button"
:value="false"
:class="{ 'is-active': !showCompactMetadataList }"
aria-role="listitem">
<span class="gray-icon icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-viewlist" />
</span>
<span>{{ $i18n.get('label_detailed_list') }}</span>
</b-dropdown-item>
</b-dropdown>
</b-field>
<b-field class="header-item">
<b-input
:placeholder="$i18n.get('instruction_type_search_metadata_filter')"
v-model="metadataNameFilterString"
icon="magnify"
size="is-small"
icon-right="close-circle"
icon-right-clickable
@icon-right-click="metadataNameFilterString = ''" />
</b-field>
</template>
</div>
<section
v-if="activeMetadatumList.length <= 0 && !isLoadingMetadata"
class="field is-grouped-centered section">
@ -33,23 +96,7 @@
<p>{{ $i18n.get('info_create_metadata' ) }}</p>
</div>
</section>
<div class="tainacan-form sub-header">
<h3 class="label has-text-secondary">{{ $i18n.get('metadata') }}</h3>
<b-field class="header-item">
<b-select
id="tainacan-switch-compact-metadata-list"
size="is-small"
v-model="showCompactMetadataList">
<option :value="true">
{{ $i18n.get('label_compact_list') }}
</option>
<option :value="false">
{{ $i18n.get('label_detailed_list') }}
</option>
</b-select>
</b-field>
</div>
<draggable
v-model="activeMetadatumList"
class="active-metadata-area"
@ -64,12 +111,13 @@
:animation="250">
<div
v-for="(metadatum, index) in activeMetadatumList.filter((meta) => meta != undefined && meta.parent == 0)"
:key="metadatum.id">
:key="metadatum.id"
v-show="metadataNameFilterString == '' || filterByMetadatumName(metadatum)">
<div
class="active-metadatum-item"
:class="{
'is-compact-item': showCompactMetadataList,
'not-sortable-item': isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder,
'not-sortable-item': isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadataNameFilterString != '',
'not-focusable-item': openedMetadatumId == metadatum.id,
'disabled-metadatum': metadatum.enabled == false,
'inherited-metadatum': metadatum.inherited || isRepositoryLevel,
@ -79,7 +127,7 @@
:ref="'metadatum-handler-' + metadatum.id"
class="handle">
<span
:style="{ opacity: !(isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder) ? '1.0' : '0.0' }"
:style="{ opacity: !(isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadataNameFilterString != '') ? '1.0' : '0.0' }"
v-tooltip="{
content: isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder ? $i18n.get('info_not_allowed_change_order_metadata') : $i18n.get('instruction_drag_and_drop_metadatum_sort'),
autoHide: true,
@ -215,6 +263,7 @@
<child-metadata-list
v-if="metadatum.metadata_type_object && metadatum.metadata_type_object.component == 'tainacan-compound'"
:parent.sync="metadatum"
:metadata-name-filter-string="metadataNameFilterString"
:is-parent-multiple="metadatum.multiple == 'yes' || (editForms[metadatum.id] && editForms[metadatum.id].multiple == 'yes')"
:is-repository-level="isRepositoryLevel" />
</div>
@ -320,7 +369,8 @@ export default {
hightlightedMetadatum: '',
editForms: {},
columnsTopY: 0,
showCompactMetadataList: true
showCompactMetadataList: true,
metadataNameFilterString: ''
}
},
computed: {
@ -618,6 +668,21 @@ export default {
<div>` + metadatum.preview_template + `</div>
</div>
</div>`;
},
filterByMetadatumName(metadatum) {
if (metadatum.metadata_type_object &&
metadatum.metadata_type_object.component == 'tainacan-compound' &&
metadatum.metadata_type_options &&
metadatum.metadata_type_options.children_objects &&
metadatum.metadata_type_options.children_objects.length
) {
let childNamesArray = metadatum.metadata_type_options.children_objects.map((children) => children.name);
childNamesArray.push(metadatum.name);
return childNamesArray.some((childName) => childName.toString().toLowerCase().indexOf(this.metadataNameFilterString.toString().toLowerCase()) >= 0);
}
else
return metadatum.name.toString().toLowerCase().indexOf(this.metadataNameFilterString.toString().toLowerCase()) >= 0;
}
}
}
@ -679,6 +744,9 @@ export default {
margin-right: 0;
}
}
h3 {
font-weight: 500;
}
}
.page-title {
@ -692,8 +760,18 @@ export default {
.sub-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5em;
.header-item {
margin-left: 0.75rem;
margin-bottom: 0px;
}
h3 {
margin-right: auto;
}
}
.loading-spinner {
@ -860,8 +938,7 @@ export default {
}
h3 {
margin: 0.2em 0em 1em 0em;
font-weight: 500;
margin: 0.875em 0em 1em 0em;
}
.available-metadatum-item {

View File

@ -553,6 +553,8 @@ return apply_filters( 'tainacan-admin-i18n', [
'instruction_cover_page' => __( 'Search a Page to choose.', 'tainacan' ),
'instruction_type_search_users' => __( 'Search users...', 'tainacan' ),
'instruction_type_search_users_filter' => __( 'Search users to filter...', 'tainacan' ),
'instruction_type_search_metadata_filter' => __( 'Search metadata to filter...', 'tainacan' ),
'instruction_type_search_filter_filter' => __( 'Search filters to filter...', 'tainacan' ),
'instruction_type_search_roles_filter' => __( 'Search roles to filter...', 'tainacan' ),
'instruction_select_a_parent_collection' => __( 'Select a parent collection.', 'tainacan' ),
'instruction_select_collection_thumbnail' => __( 'Select a thumbnail image for collection', 'tainacan' ),