diff --git a/app/components/sort-dropdown/option.hbs b/app/components/sort-dropdown/option.hbs
index 5534b3ca32c..c0322393a52 100644
--- a/app/components/sort-dropdown/option.hbs
+++ b/app/components/sort-dropdown/option.hbs
@@ -1,3 +1,3 @@
-<@menu.Item>
+<@menu.Item ...attributes>
{{yield}}
@menu.Item>
\ No newline at end of file
diff --git a/app/controllers/crate/versions.js b/app/controllers/crate/versions.js
new file mode 100644
index 00000000000..5585ddd476f
--- /dev/null
+++ b/app/controllers/crate/versions.js
@@ -0,0 +1,20 @@
+import Controller from '@ember/controller';
+import { tracked } from '@glimmer/tracking';
+
+export default class SearchController extends Controller {
+ queryParams = ['sort'];
+
+ @tracked sort;
+
+ get currentSortBy() {
+ return this.sort === 'semver' ? 'SemVer' : 'Date';
+ }
+
+ get sortedVersions() {
+ let versions = this.model.versions.toArray();
+
+ return this.sort === 'semver'
+ ? versions.sort((a, b) => b.semver.compare(a.semver))
+ : versions.sort((a, b) => b.created_at - a.created_at);
+ }
+}
diff --git a/app/styles/crate/versions.module.css b/app/styles/crate/versions.module.css
index e96bd62faa5..939a9121278 100644
--- a/app/styles/crate/versions.module.css
+++ b/app/styles/crate/versions.module.css
@@ -1,5 +1,8 @@
-.back-link {
- margin-bottom: 20px;
+.results-meta {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
}
.page-description {
diff --git a/app/templates/crate/versions.hbs b/app/templates/crate/versions.hbs
index 2222a9e8c5b..0f11c234c6e 100644
--- a/app/templates/crate/versions.hbs
+++ b/app/templates/crate/versions.hbs
@@ -1,6 +1,18 @@
-⬅ Back to Main Page
+
+
+ ⬅ Back to Main Page
+
+
+
+ Sort by
+
+ Date
+ SemVer
+
+
+
All {{ this.model.versions.length }}
@@ -9,9 +21,9 @@
- {{#each this.model.versions as |version|}}
+ {{#each this.sortedVersions as |version|}}
-
-
+
{{/each}}
diff --git a/tests/acceptance/versions-test.js b/tests/acceptance/versions-test.js
new file mode 100644
index 00000000000..b33a856c48e
--- /dev/null
+++ b/tests/acceptance/versions-test.js
@@ -0,0 +1,28 @@
+import { click, currentURL, findAll, visit } from '@ember/test-helpers';
+import { module, test } from 'qunit';
+
+import { setupApplicationTest } from 'cargo/tests/helpers';
+
+module('Acceptance | crate versions page', function (hooks) {
+ setupApplicationTest(hooks);
+
+ test('show versions sorted by date', async function (assert) {
+ let crate = this.server.create('crate', { name: 'nanomsg' });
+ this.server.create('version', { crate, num: '0.1.0', created_at: '2017-01-01' });
+ this.server.create('version', { crate, num: '0.2.0', created_at: '2018-01-01' });
+ this.server.create('version', { crate, num: '0.3.0', created_at: '2019-01-01' });
+ this.server.create('version', { crate, num: '0.2.1', created_at: '2020-01-01' });
+
+ await visit('/crates/nanomsg/versions');
+ assert.equal(currentURL(), '/crates/nanomsg/versions');
+
+ let versions = findAll('[data-test-version]').map(it => it.dataset.testVersion);
+ assert.deepEqual(versions, ['0.2.1', '0.3.0', '0.2.0', '0.1.0']);
+
+ await click('[data-test-current-order]');
+ await click('[data-test-semver-sort] a');
+
+ versions = findAll('[data-test-version]').map(it => it.dataset.testVersion);
+ assert.deepEqual(versions, ['0.3.0', '0.2.1', '0.2.0', '0.1.0']);
+ });
+});