Skip to content

Commit de97fbd

Browse files
authored
Merge pull request #10344 from eth3lbert/app-default-version
Include `default_version` by default
2 parents 810c231 + 4d95228 commit de97fbd

File tree

9 files changed

+74
-65
lines changed

9 files changed

+74
-65
lines changed

app/adapters/crate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default class CrateAdapter extends ApplicationAdapter {
4949
function setDefaultInclude(query) {
5050
if (query.include === undefined) {
5151
// This ensures `crate.versions` are always fetched from another request.
52-
query.include = 'keywords,categories,downloads';
52+
query.include = 'keywords,categories,downloads,default_version';
5353
}
5454

5555
return query;

app/adapters/version.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,14 @@ export default class VersionAdapter extends ApplicationAdapter {
66
let num = snapshot.record.num;
77
return `/${this.namespace}/crates/${crateName}/${num}`;
88
}
9+
10+
urlForQueryRecord(query) {
11+
let { name, num } = query ?? {};
12+
let baseUrl = this.buildURL('crate', name);
13+
let url = `${baseUrl}/${num}`;
14+
// The following used to remove them from URL's query string.
15+
delete query.name;
16+
delete query.num;
17+
return url;
18+
}
919
}

app/models/crate.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ export default class Crate extends Model {
6767
return Object.fromEntries(versions.slice().map(v => [v.id, v]));
6868
}
6969

70+
/** @return {Map<string, import("../models/version").default>} */
71+
@cached
72+
get loadedVersionsByNum() {
73+
let versionsRef = this.hasMany('versions');
74+
let values = versionsRef.value();
75+
return new Map(values?.map(ref => [ref.num, ref]));
76+
}
77+
7078
@cached get releaseTrackSet() {
7179
let map = new Map();
7280
let { versionsObj: versions, versionIdsBySemver } = this;

app/routes/crate/dependencies.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ export default class VersionRoute extends Route {
66

77
async model() {
88
let crate = this.modelFor('crate');
9-
let versions = await crate.loadVersionsTask.perform();
10-
119
let { default_version } = crate;
12-
let version = versions.find(version => version.num === default_version) ?? versions.lastObject;
1310

14-
this.router.replaceWith('crate.version-dependencies', crate, version.num);
11+
this.router.replaceWith('crate.version-dependencies', crate, default_version);
1512
}
1613
}

app/routes/crate/version-dependencies.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
1+
import { NotFoundError } from '@ember-data/adapter/error';
12
import Route from '@ember/routing/route';
23
import { inject as service } from '@ember/service';
34

45
export default class VersionRoute extends Route {
6+
@service store;
57
@service router;
68

79
async model(params, transition) {
810
let crate = this.modelFor('crate');
911

10-
let versions;
12+
let requestedVersion = params.version_num;
13+
let version;
1114
try {
12-
versions = await crate.loadVersionsTask.perform();
15+
version =
16+
crate.loadedVersionsByNum.get(requestedVersion) ??
17+
(await this.store.queryRecord('version', {
18+
name: crate.id,
19+
num: requestedVersion,
20+
}));
1321
} catch (error) {
14-
let title = `${crate.name}: Failed to load version data`;
15-
return this.router.replaceWith('catch-all', { transition, error, title, tryAgain: true });
16-
}
17-
18-
let requestedVersion = params.version_num;
19-
let version = versions.find(version => version.num === requestedVersion);
20-
if (!version) {
21-
let title = `${crate.name}: Version ${requestedVersion} not found`;
22-
return this.router.replaceWith('catch-all', { transition, title });
22+
if (error instanceof NotFoundError) {
23+
let title = `${crate.name}: Version ${requestedVersion} not found`;
24+
return this.router.replaceWith('catch-all', { transition, title });
25+
} else {
26+
let title = `${crate.name}: Failed to load version data`;
27+
return this.router.replaceWith('catch-all', { transition, error, title, tryAgain: true });
28+
}
2329
}
2430

2531
try {

app/routes/crate/version.js

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
1+
import { NotFoundError } from '@ember-data/adapter/error';
12
import Route from '@ember/routing/route';
23
import { inject as service } from '@ember/service';
34
import { waitForPromise } from '@ember/test-waiters';
45

56
import { didCancel } from 'ember-concurrency';
6-
import semverSort from 'semver/functions/rsort';
77

88
import { AjaxError } from '../../utils/ajax';
99

1010
export default class VersionRoute extends Route {
1111
@service router;
1212
@service sentry;
13+
@service store;
1314

1415
async model(params, transition) {
1516
let crate = this.modelFor('crate');
1617

17-
let versions;
18+
// TODO: Resolved version without waiting for versions to be resolved
19+
// The main blocker for this right now is that we have a "belongsTo" relationship between
20+
// `version-download` and `version` in sync mode. This requires us to wait for `versions` to
21+
// exist before `version-download` can be created.
1822
try {
19-
versions = await crate.loadVersionsTask.perform();
23+
await crate.loadVersionsTask.perform();
2024
} catch (error) {
2125
let title = `${crate.name}: Failed to load version data`;
2226
return this.router.replaceWith('catch-all', { transition, error, title, tryAgain: true });
2327
}
2428

2529
let version;
2630
let requestedVersion = params.version_num;
27-
if (requestedVersion) {
28-
version = versions.find(version => version.num === requestedVersion);
29-
if (!version) {
30-
let title = `${crate.name}: Version ${requestedVersion} not found`;
31-
return this.router.replaceWith('catch-all', { transition, title });
32-
}
33-
} else {
34-
let { default_version } = crate;
35-
version = versions.find(version => version.num === default_version);
36-
37-
if (!version) {
38-
let versionNums = versions.map(it => it.num);
39-
semverSort(versionNums, { loose: true });
31+
let num = requestedVersion || crate.default_version;
4032

41-
version = versions.find(version => version.num === versionNums[0]);
33+
try {
34+
version =
35+
crate.loadedVersionsByNum.get(num) ??
36+
(await crate.store.queryRecord('version', {
37+
name: crate.id,
38+
num,
39+
}));
40+
} catch (error) {
41+
if (error instanceof NotFoundError) {
42+
let title =
43+
requestedVersion == null
44+
? `${crate.name}: Failed to find default version`
45+
: `${crate.name}: Version ${requestedVersion} not found`;
46+
return this.router.replaceWith('catch-all', { transition, title });
47+
} else {
48+
let title = `${crate.name}: Failed to load version data`;
49+
return this.router.replaceWith('catch-all', { transition, error, title, tryAgain: true });
4250
}
4351
}
4452

e2e/acceptance/crate-dependencies.spec.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,6 @@ test.describe('Acceptance | crate dependencies page', { tag: '@acceptance' }, ()
6262
await expect(page.locator('[data-test-try-again]')).toHaveCount(0);
6363
});
6464

65-
test('shows an error page if versions fail to load', async ({ page, msw, ember }) => {
66-
let crate = msw.db.crate.create({ name: 'foo' });
67-
msw.db.version.create({ crate, num: '2.0.0' });
68-
await msw.worker.use(http.get('/api/v1/crates/:crate_name/versions', () => HttpResponse.json({}, { status: 500 })));
69-
70-
await page.goto('/crates/foo/1.0.0/dependencies');
71-
72-
await expect(page).toHaveURL('/crates/foo/1.0.0/dependencies');
73-
await expect(page.locator('[data-test-404-page]')).toBeVisible();
74-
await expect(page.locator('[data-test-title]')).toHaveText('foo: Failed to load version data');
75-
await expect(page.locator('[data-test-go-back]')).toHaveCount(0);
76-
await expect(page.locator('[data-test-try-again]')).toBeVisible();
77-
});
78-
7965
test('shows error message if loading of dependencies fails', async ({ page, msw }) => {
8066
let crate = msw.db.crate.create({ name: 'foo' });
8167
msw.db.version.create({ crate, num: '1.0.0' });

tests/acceptance/crate-dependencies-test.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,6 @@ module('Acceptance | crate dependencies page', function (hooks) {
7474
assert.dom('[data-test-try-again]').doesNotExist();
7575
});
7676

77-
test('shows an error page if versions fail to load', async function (assert) {
78-
let crate = this.db.crate.create({ name: 'foo' });
79-
this.db.version.create({ crate, num: '2.0.0' });
80-
81-
this.worker.use(http.get('/api/v1/crates/:crate_name/versions', () => HttpResponse.json({}, { status: 500 })));
82-
83-
await visit('/crates/foo/1.0.0/dependencies');
84-
assert.strictEqual(currentURL(), '/crates/foo/1.0.0/dependencies');
85-
assert.dom('[data-test-404-page]').exists();
86-
assert.dom('[data-test-title]').hasText('foo: Failed to load version data');
87-
assert.dom('[data-test-go-back]').doesNotExist();
88-
assert.dom('[data-test-try-again]').exists();
89-
});
90-
9177
test('shows error message if loading of dependencies fails', async function (assert) {
9278
let crate = this.db.crate.create({ name: 'foo' });
9379
this.db.version.create({ crate, num: '1.0.0' });

tests/adapters/crate-test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,26 @@ module('Adapter | crate', function (hooks) {
2929

3030
test('findRecord requests do not include versions by default', async function (assert) {
3131
let _foo = this.db.crate.create({ name: 'foo' });
32-
let version = this.db.version.create({ crate: _foo });
32+
this.db.version.create({ crate: _foo, num: '0.0.1' });
33+
this.db.version.create({ crate: _foo, num: '0.0.2' });
34+
this.db.version.create({ crate: _foo, num: '0.0.3' });
35+
36+
let versions = this.db.version.getAll().reverse();
37+
let default_version = versions.find(it => it.num === '0.0.3');
3338

3439
let store = this.owner.lookup('service:store');
3540

3641
let foo = await store.findRecord('crate', 'foo');
3742
assert.strictEqual(foo?.name, 'foo');
3843

39-
// versions should not be loaded yet
44+
// Only `defaul_version` should be loaded
4045
let versionsRef = foo.hasMany('versions');
41-
assert.deepEqual(versionsRef.ids(), []);
46+
assert.deepEqual(versionsRef.ids(), [`${default_version.id}`]);
4247

4348
await versionsRef.load();
44-
assert.deepEqual(versionsRef.ids(), [`${version.id}`]);
49+
assert.deepEqual(
50+
versionsRef.ids(),
51+
versions.map(it => `${it.id}`),
52+
);
4553
});
4654
});

0 commit comments

Comments
 (0)