Merge branch 'develop' into continuousintegration

This commit is contained in:
walisonjose 2018-06-06 09:33:11 -03:00
commit 16c53fb411
13 changed files with 337 additions and 94 deletions

View File

@ -10,26 +10,26 @@
<b-field
class="columns"
grouped>
<b-field class="column is-one-fifth">
<b-field class="column">
<b-select
@input="addToAdvancedSearchQuery">
@input.native="addToAdvancedSearchQuery($event)">
<option
v-for="(metadata, key) in metadataList"
v-for="metadata in metadataList"
v-if="metadata.enabled"
:value="metadata.id"
:key="key"
:key="metadata.id"
>{{ metadata.name }}</option>
</b-select>
</b-field>
<b-field class="column is-two-thirds">
<b-input
@input="addToAdvancedSearchQuery"/>
@input.native="addValueToAdvancedSearchQuery($event)"/>
</b-field>
<b-field class="column is-one-fifth">
<b-field class="column">
<b-select
@input="addToAdvancedSearchQuery">
@input.native="addToAdvancedSearchQuery($event)">
<option
v-for="(opt, key) in compare"
:value="key"
@ -52,7 +52,7 @@
<a
@click="addSearchMetadata"
class="is-info is-small">
Adicionar mais um campo de busca</a>
{{ $i18n.get('add_more_one_search_field') }}</a>
</div>
</div>
@ -61,16 +61,15 @@
<p class="control">
<button
@click="clearSearch"
class="button is-outlined">Limpar busca</button>
class="button is-outlined">{{ $i18n.get('clear_search') }}</button>
</p>
<p class="control">
<button
@click="searchAdvanced"
class="button is-secondary">Buscar</button>
class="button is-secondary">{{ $i18n.get('search') }}</button>
</p>
</div>
</div>
<pre>{{ metadataIds }} {{ toCompare }}</pre>
</div>
</div>
</template>
@ -80,6 +79,7 @@
name: "AdvancedSearch",
props: {
metadataList: Array,
isRepositoryLevel: false,
},
data(){
return {
@ -95,11 +95,14 @@
clearSearch(){
this.totalSearchMetadata = 1;
},
addValueToAdvancedSearchQuery: _.debounce(($event) => {
console.log($event);
}, 900),
searchAdvanced(){
},
addToAdvancedSearchQuery(optionValue){
console.log(optionValue);
addToAdvancedSearchQuery($event){
console.log($event);
},
}
}
@ -113,11 +116,20 @@
padding-top: 47px;
padding-right: $page-side-padding;
padding-left: $page-side-padding;
padding-top: 47px;
padding-bottom: 47px;
.column {
padding: 0 0.3rem 0.3rem !important;
}
.control {
.select{
width: 100% !important;
select{
width: 100% !important;
}
}
}
}
</style>

View File

@ -35,7 +35,93 @@
</div>
<div class="table-wrapper">
<table class="tainacan-table">
<!-- CARDS VIEW MODE -->
<div
class="tainacan-cards-container"
v-if="viewMode == 'cards'">
<div class="columns is-multiline is-gapless no-gutters">
<div
:key="index"
v-for="(item, index) of items"
class="column is-12-tablet is-half-desktop is-half-widescreen is-one-third-fullhd">
<div
:class="{ 'selected-card': selectedItems[index] }"
class="tainacan-card">
<!-- Checkbox -->
<div
:class="{ 'is-selecting': isSelectingItems }"
class="card-checkbox">
<b-checkbox
size="is-small"
v-model="selectedItems[index]"/>
</div>
<!-- Title -->
<p
v-for="(column, index) in tableFields"
:key="index"
v-if="column.display && column.field_type_object != undefined && (column.field_type_object.related_mapped_prop == 'title')"
class="metadata-title">
<a
v-html="item.metadata != undefined ? renderMetadata(item.metadata, column) : ''"
@click="goToItemPage(item)"/>
</p>
<!-- Actions -->
<div
v-if="item.current_user_can_edit"
class="actions-area"
:label="$i18n.get('label_actions')">
<a
id="button-edit"
:aria-label="$i18n.getFrom('items','edit_item')"
@click.prevent.stop="goToItemEditPage(item.id)">
<b-icon
type="is-secondary"
icon="pencil"/>
</a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneItem(item.id)">
<b-icon
type="is-secondary"
:icon="!isOnTrash ? 'delete' : 'delete-forever'"/>
</a>
</div>
<!-- Remaining metadata -->
<div class="media">
<a
v-if="item.thumbnail != undefined"
@click="goToItemPage(item)">
<img :src="item['thumbnail'].thumb">
</a>
<div class="list-metadata media-body">
<span
v-for="(column, index) in tableFields"
:key="index"
v-if="column.display && column.slug != 'thumbnail' && column.field_type_object != undefined && (column.field_type_object.related_mapped_prop != 'title')">
<h3 class="metadata-label">{{ column.name }}</h3>
<p
v-html="item.metadata != undefined ? renderMetadata(item.metadata, column) : ''"
class="metadata-value"/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- TABLE VIEW MODE -->
<table
v-if="viewMode == 'table'"
class="tainacan-table">
<thead>
<tr>
<!-- Checking list -->
@ -84,8 +170,6 @@
v-for="(column, index) in tableFields"
v-if="column.display"
:label="column.name"
:aria-label="(column.field != 'row_thumbnail' && column.field != 'row_creation' && column.field != 'row_author')
? column.name + '' + (item.metadata ? item.metadata[column.slug].value_as_string : '') : ''"
class="column-default-width"
:class="{
'thumbnail-cell': column.field == 'row_thumbnail',
@ -182,7 +266,8 @@ export default {
tableFields: Array,
items: Array,
isLoading: false,
isOnTrash: false
isOnTrash: false,
viewMode: 'table'
},
mounted() {
this.selectedItems = [];
@ -311,6 +396,7 @@ export default {
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
@import "../../scss/_view-mode-cards.scss";
.selection-control {

View File

@ -20,7 +20,7 @@
<div class="control has-icons-right is-small is-clearfix">
<input
autocomplete="on"
:placeholder="$i18n.get('instruction_search')"
:placeholder="$i18n.get('instruction_search_on_repository')"
class="input is-small"
type="search"
v-model="searchTerm">
@ -28,7 +28,7 @@
<i class="mdi mdi-magnify" />
</span>
</div>
<a @click.prevent="openAdvancedSearchComponent">{{ $i18n.get('advanced_search') }}</a>
<a @click="toItemsPage">{{ $i18n.get('advanced_search') }}</a>
</span>
<a
class="level-item"
@ -51,8 +51,13 @@ export default {
}
},
methods: {
openAdvancedSearchComponent(){
this.$set(this.$route.meta, 'openAdvancedSearch', !this.$route.meta.openAdvancedSearch);
toItemsPage(){
this.$router.push({
path: '/items',
query: {
openAdvancedSearch: true
}
});
}
},
props: {

View File

@ -50,7 +50,7 @@ const routes = [
]
},
{ path: '/items', name: 'ItemsPage', component: ItemsPage, meta: {title: i18nGet('title_items_page'), icon: 'file-multiple', openAdvancedSearch: false} },
{ path: '/items', name: 'ItemsPage', component: ItemsPage, meta: {title: i18nGet('title_items_page'), icon: 'file-multiple'} },
{ path: '/items/new', name: 'ItemCreationForm', component: ItemEditionForm, meta: {title: i18nGet('title_create_item'), icon: 'file-multiple'} },
{ path: '/filters', name: 'FiltersPage', component: FiltersPage, meta: {title: i18nGet('title_repository_filters_page'), icon: 'filter'} },

View File

@ -4,7 +4,8 @@
<!-- SEARCH AND FILTERS --------------------- -->
<!-- Filter menu compress button -->
<button
<button
v-if="!openAdvancedSearch"
id="filter-menu-compress-button"
:class="{'filter-menu-compress-button-top-repo': isRepositoryLevel}"
:style="{ top: isHeaderShrinked ? '125px' : '152px'}"
@ -12,40 +13,33 @@
<b-icon :icon="isFiltersMenuCompressed ? 'menu-right' : 'menu-left'" />
</button>
<!-- Side bar with search and filters -->
<aside
v-show="!isFiltersMenuCompressed"
<aside
v-show="!isFiltersMenuCompressed && !openAdvancedSearch"
class="filters-menu"
:class="{ 'tainacan-form': isOnTheme }">
<b-loading
:is-full-page="false"
:active.sync="isLoadingFilters"/>
<b-field>
<div class="control is-small is-clearfix">
<div class="search-area">
<div class="control has-icons-right is-small is-clearfix">
<input
class="input is-small"
:placeholder="$i18n.get('instruction_search')"
type="search"
autocomplete="on"
:value="searchQuery"
@input="futureSearchQuery = $event.target.value"
@keyup.enter="updateSearch()">
class="input is-small"
:placeholder="$i18n.get('instruction_search')"
type="search"
autocomplete="on"
:value="searchQuery"
@input="futureSearchQuery = $event.target.value"
@keyup.enter="updateSearch()">
<span
@click="updateSearch()"
class="icon is-right">
<i class="mdi mdi-magnify" />
</span>
</div>
<p class="control">
<button
id="collection-search-button"
type="submit"
class="button"
@click="updateSearch()">
<b-icon
icon="magnify"
size="is-small"/>
</button>
</p>
</b-field>
</div>
<a
@click.prevent="openAdvancedSearchComponent"
@click="openAdvancedSearch = !openAdvancedSearch"
class="is-size-7 is-secondary is-pulled-right">{{ $i18n.get('advanced_search') }}</a>
<h3 class="has-text-weight-semibold">{{ $i18n.get('filters') }}</h3>
@ -105,7 +99,9 @@
:active.sync="isLoadingItems"/>
<!-- SEARCH CONTROL ------------------------- -->
<div class="search-control">
<div
v-if="!openAdvancedSearch"
class="search-control">
<b-loading
:is-full-page="false"
:active.sync="isLoadingFields"/>
@ -215,7 +211,7 @@
v-if="isOnTheme"
class="search-control-item">
<b-field>
<b-dropdown
<b-dropdown
@change="onChangeViewMode($event)"
:mobile-modal="false"
position="is-bottom-left"
@ -239,20 +235,55 @@
</b-dropdown>
</b-field>
</div>
<div
v-if="!isOnTheme"
class="search-control-item">
<b-field>
<b-dropdown
v-model="adminViewMode"
:mobile-modal="false"
position="is-bottom-left"
:aria-label="$i18n.get('label_view_mode')">
<button
class="button is-white"
slot="trigger">
<span>
<b-icon
:icon="(adminViewMode == 'table' || adminViewMode == undefined) ?
'table' : (adminViewMode == 'cards' ?
'view-list' : 'view-grid')"/>
</span>
<b-icon icon="menu-down" />
</button>
<b-dropdown-item :value="'table'">
<b-icon icon="table"/>
{{ $i18n.get('label_table') }}
</b-dropdown-item>
<b-dropdown-item :value="'cards'">
<b-icon icon="view-list"/>
{{ $i18n.get('label_cards') }}
</b-dropdown-item>
<b-dropdown-item :value="'grid'">
<b-icon icon="view-grid"/>
{{ $i18n.get('label_grid') }}
</b-dropdown-item>
</b-dropdown>
</b-field>
</div>
</div>
<!-- ADVANCED SEARCH -->
<advanced-search
v-if="openAdvancedSearch"
:is-repository-level="isRepositoryLevel"
:metadata-list="fields" />
<!-- --------------- -->
<!-- STATUS TABS, only on Admin -------- -->
<div
v-if="!isOnTheme"
v-if="!isOnTheme && !openAdvancedSearch"
class="tabs">
<ul>
<li
@ -279,7 +310,8 @@
:table-fields="tableFields"
:items="items"
:is-loading="isLoadingItems"
:is-on-trash="status == 'trash'"/>
:is-on-trash="status == 'trash'"
:view-mode="adminViewMode"/>
<!-- Theme View Modes -->
<div
@ -356,7 +388,9 @@
futureSearchQuery: '',
isHeaderShrinked: false,
localTableFields: [],
registeredViewModes: tainacan_plugin.registered_view_modes
registeredViewModes: tainacan_plugin.registered_view_modes,
adminViewMode: 'table',
openAdvancedSearch: false,
}
},
props: {
@ -365,9 +399,6 @@
enabledViewModes: Object // Used only on theme
},
computed: {
openAdvancedSearch(){
return this.$route.meta.openAdvancedSearch;
},
items() {
return this.getItems();
},
@ -435,9 +466,6 @@
'getViewMode',
'getTotalItems'
]),
openAdvancedSearchComponent(){
this.$set(this.$route.meta, 'openAdvancedSearch', !this.$route.meta.openAdvancedSearch);
},
updateSearch() {
this.$eventBusSearch.setSearchQuery(this.futureSearchQuery);
},
@ -465,11 +493,15 @@
}
}
}
let thumbnailField = this.localTableFields.find(field => field.slug == 'thumbnail');
let creationDateField = this.localTableFields.find(field => field.slug == 'creation_date');
let authorNameField = this.localTableFields.find(field => field.slug == 'author_name');
this.$eventBusSearch.addFetchOnly({
'0': 'thumbnail',
'0': thumbnailField.display ? 'thumbnail' : null,
'meta': fetchOnlyFieldIds,
'1': 'creation_date',
'2': 'author_name'
'1': creationDateField.display ? 'creation_date' : null,
'2': authorNameField.display ? 'author_name': null
});
this.$refs.displayedFieldsDropdown.toggle();
},
@ -487,8 +519,8 @@
.catch(() => this.isLoadingFilters = false);
this.isLoadingFields = true;
this.tableFields = [];
// Processing is done inside a local variable
let fields = [];
this.fetchFields({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
@ -496,7 +528,7 @@
})
.then(() => {
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_thumbnail'),
field: 'row_thumbnail',
field_type: undefined,
@ -517,7 +549,7 @@
else if (field.display == 'yes')
display = true;
this.tableFields.push(
fields.push(
{
name: field.name,
field: field.description,
@ -533,7 +565,7 @@
}
}
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_creation_date'),
field: 'row_creation',
field_type: undefined,
@ -541,7 +573,7 @@
id: undefined,
display: true
});
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_created_by'),
field: 'row_author',
field_type: undefined,
@ -565,7 +597,7 @@
'2': 'author_name'
});
this.isLoadingFields = false;
this.tableFields = fields;
})
.catch(() => {
this.isLoadingFields = false;
@ -592,13 +624,16 @@
/* This condition is to prevent a incorrect fetch by filter or fields when we come from items
* at collection level to items page at repository level
*/
if(this.collectionId === to.params.collectionId) {
if (this.collectionId === to.params.collectionId) {
this.prepareFieldsAndFilters();
}
});
this.$eventBusSearch.setViewMode(this.defaultViewMode);
if(this.$route.query.openAdvancedSearch) {
this.openAdvancedSearch = this.$route.query.openAdvancedSearch;
}
},
mounted() {
@ -645,12 +680,26 @@
margin-top: 48px;
}
#collection-search-button {
border-radius: 0 !important;
padding: 0 8px !important;
border-color: $tainacan-input-background;
&:focus, &:active {
border-color: none !important;
.search-area {
display: flex;
align-items: center;
margin-right: 36px;
.control {
input {
height: 27px;
font-size: 11px;
color: $gray-light;
width: 148px;
}
.icon {
pointer-events: all;
cursor: pointer;
color: $tertiary;
height: 27px;
font-size: 18px;
}
margin-bottom: 5px;
}
}

View File

@ -26,6 +26,7 @@
.b-checkbox { width: 100% };
&:hover { background-color: $primary-lighter; }
.is-small { color: gray; }
&.is-active { background-color: white; }
}
}
}

View File

@ -172,14 +172,13 @@
width: 80px;
.actions-container {
visibility: hidden;
display: flex;
position: relative;
padding: 0;
height: 100%;
width: 80px;
z-index: 9;
background-color: transparent;
background-color: white;
float: right;
}
@ -206,7 +205,6 @@
}
.actions-cell {
.actions-container {
visibility: visible;
background: $tainacan-input-background !important;
}

View File

@ -0,0 +1,81 @@
.tainacan-cards-container {
min-height: 200px;
padding: 0;
.selected-card {
background-color: $primary-lighter;
}
.tainacan-card {
padding: 16px 44px 24px 44px;
.card-checkbox {
position: absolute;
margin-left: -28px;
margin-top: -2px;
}
.actions-area {
position: relative;
float: right;
top: -37px;
right: -30px;
width: 60px;
display: flex;
justify-content: space-between;
visibility: hidden;
opacity: 0;
transition: visibility 0.2s, opacity 0.2s;
}
&:hover .actions-area {
visibility: visible;
opacity: 1.0;
}
img {
width: 130px;
height: auto;
border-radius: 2px;
margin-right: 1.5rem;
}
.metadata-title {
flex-shrink: 0;
font-size: 0.875rem;
margin-bottom: 0.875rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.media {
.media-body {
flex: 1;
font-size: 0.6875rem;
color: gray;
overflow: hidden;
.metadata-label {
font-size: 0.75rem;
line-height: 1.0;
margin-bottom: 0.2rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
font-weight: 500;
color: $gray-light;
}
.metadata-value {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin-bottom: 1rem;
}
}
}
}
}

View File

@ -42,6 +42,8 @@ return [
'add_items_external_source' => __( 'Add items from an external source', 'tainacan' ),
'split' => __( 'Split', 'tainacan' ),
'unified' => __( 'Unified', 'tainacan' ),
'add_more_one_search_field' => __( 'Add more one search field', 'tainacan' ),
'clear_search' => __( 'Clear search', 'tainacan' ),
// Wordpress Status
'publish' => __( 'Publish', 'tainacan' ),
@ -199,6 +201,9 @@ return [
'label_view_modes_available' => __( 'View modes available on theme', 'tainacan' ),
'label_warning' => __( 'Warning', 'tainacan' ),
'label_error' => __( 'Erro', 'tainacan' ),
'label_grid' => __( 'Grid', 'tainacan' ),
'label_table' => __( 'Table', 'tainacan' ),
'label_cards' => __( 'Cards', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
@ -220,6 +225,7 @@ return [
'instruction_insert_url' => __( 'Insert URL', 'tainacan' ),
'instruction_write_text' => __( 'Write Text', 'tainacan' ),
'instruction_search' => __( 'Search', 'tainacan' ),
'instruction_search_on_repository' => __( 'Search on repository', 'tainacan' ),
// Info. Other feedback to user.
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),

View File

@ -96,12 +96,6 @@ export default {
line-height: 20px !important;
font-size: 14px !important;
}
#collection-search-button {
border: 1px solid $secondary !important;
height: 32px !important;
background-color: $secondary;
color: white;
}
.input, .textarea {
font-size: 14px;
border: none;

View File

@ -122,9 +122,9 @@ export default {
loadItems(to) {
// Forces fetch_only to be filled before any search happens
if (this.$store.getters['search/getFetchOnly'] == undefined)
if (this.$store.getters['search/getFetchOnly'] == undefined) {
this.$emit( 'hasToPrepareFieldsAndFilters', to);
else {
} else {
this.$emit( 'isLoadingItems', true);
this.$store.dispatch('collection/fetchItems',
{ 'collectionId': this.collectionId,

View File

@ -14,11 +14,11 @@ export const fetchItems = ({ rootGetters, dispatch, commit }, { collectionId, is
hasFiltered = true;
// Garanttees at least empty fetch_only are passed in case none is found
if (qs.stringify(postQueries.fetch_only) == '')
postQueries.fetch_only = {};
if (qs.stringify(postQueries.fetch_only['meta']) == '')
postQueries.fetch_only['meta'] = [0];
if (qs.stringify(postQueries.fetch_only) == '')
dispatch('search/add_fetchonly', {} , { root: true });
if (qs.stringify(postQueries.fetch_only['meta']) == '')
dispatch('search/add_fetchonly_meta', 0 , { root: true });
// Differentiates between repository level and collection level queries
let endpoint = '/collection/'+collectionId+'/items?'

View File

@ -195,6 +195,11 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$_SESSION['tainacan_importer'][$id]->set_file( $file_name );
if(!isset( $_SESSION['tainacan_importer'][$id]->tmp_file )){
#TODO: Remove dependence of web server (see fetch_from_remote)
$this->markTestSkipped('This test need a apache installation available.');
}
// file isset on importer
$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
@ -254,6 +259,12 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$csv_importer = new Importer\CSV();
$id = $csv_importer->get_id();
$_SESSION['tainacan_importer'][$id]->fetch_from_remote( 'http://localhost/wordpress-test/wp-json' );
if(!isset( $_SESSION['tainacan_importer'][$id]->tmp_file )){
#TODO: Remove dependence of web server (see fetch_from_remote)
$this->markTestSkipped('This test need a apache installation available.');
}
$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
}
}