diff --git a/app/assets/v2/js/grants/index.js b/app/assets/v2/js/grants/index.js
index 5678ed26be4..57f80147e31 100644
--- a/app/assets/v2/js/grants/index.js
+++ b/app/assets/v2/js/grants/index.js
@@ -126,7 +126,29 @@ if (document.getElementById('grants-showcase')) {
editingCollection: false,
createCollectionRedirect: false,
activeTimeout: null,
- scrollTriggered: false
+ selectOptions: [
+ {group: 'Discover', label: null},
+ {label: 'Weighted Shuffle', value: 'weighted_shuffle'},
+ {label: 'Trending', value: '-metadata__upcoming'},
+ {label: 'Undiscovered Gems', value: '-metadata__gem'},
+ {label: 'Recently Updated', value: '-last_update'},
+ {label: 'Newest', value: '-created_on'},
+ {label: 'Oldest', value: 'created_on'},
+ {label: 'A to Z', value: 'title'},
+ {label: 'Z to A', value: '-title'},
+ {group: 'Current Round', label: null},
+ {label: 'Most Relevant', value: ''},
+ {label: 'Highest Amount Raised', value: '-amount_received_in_round'},
+ {label: 'Highest Contributor Count', value: '-positive_round_contributor_count'},
+ {group: 'All-Time', label: null},
+ {label: 'Highest Amount Raised', value: '-amount_received'},
+ {label: 'Highest Contributor Count', value: '-contributor_count'}
+ ],
+ adminOptions: [
+ {group: 'Misc', label: null},
+ {label: 'ADMIN: Risk Score', value: '-weighted_risk_score'},
+ {label: 'ADMIN: Sybil Score', value: '-sybil_score'}
+ ]
},
methods: {
toggleStyle: function(style) {
diff --git a/app/assets/v2/scss/grants/grant.scss b/app/assets/v2/scss/grants/grant.scss
index cfb3a99f069..b5536385eb8 100644
--- a/app/assets/v2/scss/grants/grant.scss
+++ b/app/assets/v2/scss/grants/grant.scss
@@ -688,6 +688,22 @@
.vselect-clean .vs__dropdown-toggle,
.vselect-clean .vs__dropdown-menu {
border: none;
+ border-radius: 10px;
+}
+
+.vselect-clean .vs__dropdown-menu li {
+ padding: 8px;
+ padding-right: 16px;
+ padding-left: 16px;
+}
+
+.vselect-clean .vs__dropdown-menu .vs__dropdown-option--highlight {
+ background: #EFEBFD;
+ color: black;
+}
+
+.vselect-clean hr {
+ margin-top: 0;
}
.rounded-toggle .vs__dropdown-toggle {
diff --git a/app/grants/templates/grants/shared/top-filters.html b/app/grants/templates/grants/shared/top-filters.html
index 12f227b7840..00024d53edb 100644
--- a/app/grants/templates/grants/shared/top-filters.html
+++ b/app/grants/templates/grants/shared/top-filters.html
@@ -16,36 +16,28 @@
|
diff --git a/app/grants/views.py b/app/grants/views.py
index 9329ce41861..252ed0a916b 100644
--- a/app/grants/views.py
+++ b/app/grants/views.py
@@ -769,7 +769,7 @@ def get_grants_by_filters(
_grants = _grants.filter(is_clr_active=True).order_by(f"{sort}")
elif sort.replace('-', '') in [
- 'weighted_shuffle', 'metadata__upcoming', 'metadata__gem', 'created_on', 'amount_received', 'contribution_count', 'contributor_count', 'last_update'
+ 'weighted_shuffle', 'metadata__upcoming', 'metadata__gem', 'created_on', 'amount_received', 'contribution_count', 'contributor_count', 'last_update', 'title'
]:
print(f"Sort is {sort}")
_grants = _grants.order_by(f"{sort}")
diff --git a/cypress/integration/grants/test_grant_explorer.js b/cypress/integration/grants/test_grant_explorer.js
new file mode 100644
index 00000000000..38d4335b9ef
--- /dev/null
+++ b/cypress/integration/grants/test_grant_explorer.js
@@ -0,0 +1,165 @@
+describe('Grants Explorer page', () => {
+ before(() => {
+ cy.setupMetamask();
+ });
+
+ afterEach(() => {
+ cy.logout();
+ });
+
+ after(() => {
+ cy.clearWindows();
+ });
+
+ describe('grants explorer sort menu', () => {
+ it('contains the proper sort options', () => {
+ cy.impersonateUser();
+
+ cy.visit('grants/explorer');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu')
+ .should('contain', 'Discover')
+ .should('contain', 'Weighted Shuffle')
+ .should('contain', 'Trending')
+ .should('contain', 'Undiscovered Gems')
+ .should('contain', 'Recently Updated')
+ .should('contain', 'Newest')
+ .should('contain', 'Oldest')
+ .should('contain', 'A to Z')
+ .should('contain', 'Z to A')
+ .should('contain', 'Current Round')
+ .should('contain', 'Most Relevant')
+ .should('contain', 'Highest Amount Raised')
+ .should('contain', 'Highest Contributor Count')
+ .should('contain', 'All-Time');
+ cy.get('.vs__dropdown-menu').find('#vs3__option-14').should('contain', 'Highest Amount Raised'); // need to be more specific to test two elements with same name
+ cy.get('.vs__dropdown-menu').find('#vs3__option-15').should('contain', 'Highest Contributor Count');
+ });
+
+ it('divides the sort options into category names with disabled labels', () => {
+ cy.impersonateUser();
+
+ cy.visit('grants/explorer');
+
+ cy.get('.vselect-clean').click();
+
+ cy.contains('Discover').parent().should('have.class', 'vs__dropdown-option--disabled');
+ cy.contains('Current Round').parent().should('have.class', 'vs__dropdown-option--disabled');
+ cy.contains('All-Time').parent().should('have.class', 'vs__dropdown-option--disabled');
+ });
+
+ it('does not display admin options when user is not staff', () => {
+ cy.impersonateUser();
+
+ cy.visit('grants/explorer');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu')
+ .should('not.contain', 'Misc')
+ .should('not.contain', 'ADMIN: Risk Score')
+ .should('not.contain', 'ADMIN: Sybil Score');
+ });
+
+ it('displays admin options when user is staff', () => {
+ cy.impersonateStaffUser();
+
+ cy.visit('grants/explorer');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu')
+ .should('contain', 'Misc')
+ .should('contain', 'ADMIN: Risk Score')
+ .should('contain', 'ADMIN: Sybil Score');
+ });
+
+ it('sends the proper sort request to the API', () => {
+ cy.impersonateStaffUser();
+
+ cy.visit('grants/explorer');
+
+ cy.get('.vselect-clean').click();
+
+ // Options in Discover category
+ cy.get('.vs__dropdown-menu').contains('Weighted Shuffle').click();
+ cy.url().should('contain', 'sort_option=weighted_shuffle');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Trending').click();
+ cy.url().should('contain', 'sort_option=-metadata__upcoming');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Undiscovered Gems').click();
+ cy.url().should('contain', 'sort_option=-metadata__gem');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Recently Updated').click();
+ cy.url().should('contain', 'sort_option=-last_update');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Newest').click();
+ cy.url().should('contain', 'sort_option=-created_on');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Oldest').click();
+ cy.url().should('contain', 'sort_option=created_on');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('A to Z').click();
+ cy.url().should('contain', 'sort_option=title');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Z to A').click();
+ cy.url().should('contain', 'sort_option=-title');
+
+ // Options in Current Round category
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Most Relevant').click();
+ cy.url().should('contain', 'sort_option='); // The value of this option is purposely set to empty string (see app/assets/v2/js/grants/index.js)
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Highest Amount Raised').click();
+ cy.url().should('contain', 'sort_option=-amount_received_in_round');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('Highest Contributor Count').click();
+ cy.url().should('contain', 'sort_option=-positive_round_contributor_count');
+
+ // Options in All-Time category
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').find('#vs3__option-14').contains('Highest Amount Raised').click(); // Need to be more specific here because the same options exist above
+ cy.url().should('contain', 'sort_option=-amount_received');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').find('#vs3__option-15').contains('Highest Contributor Count').click();
+ cy.url().should('contain', 'sort_option=-contributor_count');
+
+ // Admin options
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('ADMIN: Risk Score').click();
+ cy.url().should('contain', 'sort_option=-weighted_risk_score');
+
+ cy.get('.vselect-clean').click();
+
+ cy.get('.vs__dropdown-menu').contains('ADMIN: Sybil Score').click();
+ cy.url().should('contain', 'sort_option=-sybil_score');
+ });
+ });
+});
+
\ No newline at end of file
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index e8c67af51ea..c0e785ed3c9 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -50,6 +50,11 @@ Cypress.Commands.add('impersonateUser', () => {
cy.visit('impersonate/4/');
});
+Cypress.Commands.add('impersonateStaffUser', () => {
+ cy.loginRootUser();
+ cy.visit('impersonate/1/');
+});
+
Cypress.Commands.add('logout', () => {
cy.request('logout/?next=/');
});