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

Custom sort #1404

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
242 changes: 192 additions & 50 deletions lib/nav/page-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@
}

.page-list-header {
@include type-list-header();

height: auto;
justify-content: start;
padding: 0;

&:hover {
background-color: transparent;
}

&-site {
flex: 0 0 $site-column;
}
Expand Down Expand Up @@ -111,13 +121,19 @@
}

&-collaborators {
cursor: default;
display: none;
flex: 0 0 $collaborators-column;

@media screen and (min-width: $all-columns-sidebar) {
display: inline;
}
}

& > .ui-button__content {
font-weight: normal;
justify-content: start;
}
}
}

Expand Down Expand Up @@ -152,10 +168,20 @@
</div>
<div class="page-list-headers">
<span v-if="multipleSitesSelected" class="page-list-header page-list-header-site">Site</span>
<span class="page-list-header page-list-header-title">Title</span>
<span class="page-list-header page-list-header-byline">Byline</span>
<span class="page-list-header page-list-header-status">Status</span>
<span class="page-list-header page-list-header-collaborators">Collaborators</span>
<ui-button
v-for="header in headerTitles"
:key="header.key"
buttonType="button"
:class="[`page-list-header page-list-header-${header.key}`]"
disableRipple
:icon="sortBy === header.sortField ? sortIcon : null"
iconPosition="right"
size="small"
type="secondary"
@click="header.key !== 'collaborators' && sortByField(header.sortField)"
>
{{ header.title }}
</ui-button>
</div>
<div class="page-list-readout">
<page-list-item
Expand Down Expand Up @@ -185,7 +211,9 @@
import statusSelector from './status-selector.vue';
import pageListItem from './page-list-item.vue';

const DEFAULT_QUERY_SIZE = 50;
const DEFAULT_QUERY_SIZE = 50,
SORT_DESC = 'desc',
SORT_ASC = 'asc';

/**
* get data for all sites, and format it into something we can use
Expand Down Expand Up @@ -216,16 +244,14 @@
* @param {string} username
* @return {object}
*/
function buildQuery({ siteFilter, queryText, queryUser, offset, statusFilter, isMyPages, username }) { // eslint-disable-line
function buildQuery({ siteFilter, queryText, queryUser, offset, statusFilter, isMyPages, username, sortBy, sortOrder }) { // eslint-disable-line
let query = {
index: 'pages',
body: {
size: DEFAULT_QUERY_SIZE,
from: offset,
sort: {
updateTime: {
order: 'desc'
}
[sortBy]: { order: sortOrder }
},
query: {}
}
Expand Down Expand Up @@ -302,6 +328,15 @@
query.body.query.bool.must.push({
term: { archived: false }
});

// Status sorting is handled differently,
// we have to deal with boolean properties
if (sortBy === 'status') {
query.body.sort = {
published: { order: sortOrder },
scheduled: { order: sortOrder }
};
}
} else if (statusFilter === 'draft') {
query.body.query.bool.must.push({
term: { published: false }
Expand All @@ -328,22 +363,35 @@
query.body.query.bool.must.push({
term: { published: true }
});

// also sort by last published timestamp
query.body.sort = {
publishTime: { order: 'desc' }
};
if (sortBy === 'status') {
query.body.sort = {
publishTime: { order: sortOrder }
};
}
} else if (statusFilter === 'scheduled') {
query.body.query.bool.must.push({
term: { scheduled: true }
});
// also sort by last scheduled time
query.body.sort = {
scheduledTime: { order: 'desc' }
};

// also sort by scheduledlast scheduled time

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// also sort by scheduledlast scheduled time
// also sort by last scheduled time

if (sortBy === 'status') {
query.body.sort = {
scheduledTime: { order: sortOrder }
};
}
} else if (statusFilter === 'archived') {
query.body.query.bool.must.push({
term: { archived: true }
});

// Also, sort by last update time
if (sortBy === 'status') {
query.body.sort = {
updateTime: { order: sortOrder }
};
}
}

return query;
Expand All @@ -359,7 +407,26 @@
sites: getInitialSites.call(this),
pages: [],
selectedStatus: _.get(this.$store, 'state.url.status', 'all'),
isPopoverOpen: false
isPopoverOpen: false,
sortBy: 'title.raw',
sortOrder: SORT_ASC,
headerTitles: [{
title: 'Title',
key: 'title',
sortField: 'title.raw'
}, {
title: 'Byline',
key: 'byline',
sortField: 'authors.raw'
}, {
title: 'Status',
key: 'status',
sortField: 'status'
}, {
title: 'Collaborators',
key: 'collaborators',
sortField: 'users'
}]
};
},
computed: {
Expand Down Expand Up @@ -388,15 +455,34 @@
const user = this.query.match(/user:(\S+)/i);

return user ? user[1] : '';
},
sortIcon() {
return this.sortOrder === SORT_DESC ? 'arrow_downward' : 'arrow_upward';
}
},
methods: {
/**
* Sets the isPopoverOpen prop to true
* when the popover is opened
* @returns {void}
*/
onPopoverOpen() {
this.isPopoverOpen = true;
},
/**
* Sets the isPopoverOpen prop to false
* when the popover is closed
* @returns {void}
*/
onPopoverClose() {
this.isPopoverOpen = false;
},
/**
* Sets the selected site in the state
* and refetches the pages
* @param {String} slug
* @returns {void}
*/
selectSite(slug) {
const site = _.find(this.sites, (s) => s.slug === slug);

Expand All @@ -405,12 +491,23 @@
this.offset = 0;
this.fetchPages();
},
/**
* Sets the selected sites if there are multiple selected
* @param {String[]} allSites
* @returns {void}
*/
selectMultipleSites(allSites) {
this.sites = _.map(this.sites, (site) => {
site.selected = allSites;
return site;
});
},
/**
* Sets the selected site in the state
* and refetches the pages
* @param {String} slug
* @returns {void}
*/
setSingleSite(slug) {
// loop through all sites, making sure that only one is selected
_.each(this.sites, (site) => {
Expand All @@ -425,59 +522,104 @@
this.offset = 0;
this.fetchPages();
},
/**
* Triggers a request to filter the pages with
* a 300 ms delay
* @returns {void}
*/
filterList: _.debounce(function () {
this.$store.commit('FILTER_PAGELIST_SEARCH', this.query);
this.offset = 0;
this.fetchPages();
}, 300),
/**
* Sets the selected status in the state
* and refetches the pages
* @param {String} status
* @returns {void}
*/
selectStatus(status) {
this.selectedStatus = status;

this.$store.commit('FILTER_PAGELIST_STATUS', this.selectedStatus);
this.offset = 0;
this.fetchPages();
},
/**
* Sets the built query in the state
* and refetches the pages
* @param {Object} query
* @returns {void}
*/
setQuery(query) {
this.query = query;
this.offset = 0;
this.fetchPages();
},
/**
* Sets the sort order and sort field in the state
* and refetches the pages
* @param {String} field
* @returns {void}
*/
sortByField(field) {
this.sortOrder = this.sortBy === field ? this.toggleSortOrder(this.sortOrder) : SORT_ASC;
this.sortBy = field;
this.offset = 0;

this.fetchPages();
},
/**
* Toggles the sort order between ascending and descending
* @param {String} order
* @returns {String}
*/
toggleSortOrder(order) {
return order === SORT_DESC ? SORT_ASC : SORT_DESC;
},
/**
* Makes a query to ES to fetch for all pages
* @returns {Promise}
*/
fetchPages() {
const siteFilter = _.map(this.selectedSites, (site) => site.slug),
queryText = this.queryText,
queryUser = this.queryUser,
offset = this.offset,
const {
isMyPages,
offset,
queryText,
queryUser,
selectedSites,
selectedStatus: statusFilter,
sortBy,
sortOrder
} = this,
siteFilter = _.map(selectedSites, (site) => site.slug),
prefix = _.get(this.$store, 'state.site.prefix'),
isMyPages = this.isMyPages,
username = _.get(this.$store, 'state.user.username'),
statusFilter = this.selectedStatus,
query = buildQuery({ siteFilter, queryText, queryUser, offset, statusFilter, isMyPages, username });

return postJSON(prefix + searchRoute, query).then((res) => {
const hits = _.get(res, 'hits.hits') || [],
total = _.get(res, 'hits.total'),
pages = _.map(hits, (hit) => Object.assign({}, hit._source, { uri: hit._id }));

if (offset === 0) {
this.pages = pages;
} else {
this.pages = this.pages.concat(pages);
}

this.offset = offset + pages.length;
this.total = total; // update the total for this particular query
// (it's used to hide the "load more" button)

// set the url hash
if (_.get(this.$store, 'state.ui.currentDrawer')) {
this.$store.dispatch('setHash', { menu: {
tab: isMyPages ? 'my-pages' : 'all-pages',
sites: siteFilter.join(','),
status: statusFilter,
query: this.query
}});
}
});
query = buildQuery({ siteFilter, queryText, queryUser, offset, statusFilter, isMyPages, username, sortBy, sortOrder });

return postJSON(prefix + searchRoute, query)
.then((res) => {
const hits = _.get(res, 'hits.hits') || [],
total = _.get(res, 'hits.total'),
pages = _.map(hits, (hit) => Object.assign({}, hit._source, { uri: hit._id }));

this.pages = offset === 0 ? pages : this.pages.concat(pages);

this.offset = offset + pages.length;
this.total = total; // update the total for this particular query
// (it's used to hide the "load more" button)

// set the url hash
if (_.get(this.$store, 'state.ui.currentDrawer')) {
this.$store.dispatch('setHash', { menu: {
tab: isMyPages ? 'my-pages' : 'all-pages',
sites: siteFilter.join(','),
status: statusFilter,
query: this.query
}});
}
})
.catch((e) => console.error(e));
}
},
mounted() {
Expand Down
Loading