Skip to content

Commit cc0a011

Browse files
committed
frontend: change logic of when doc links are shown in search results
The crate version page uses a fallback to handle crates that don't define `documentation` keys in their manifests: if docs.rs has documentation for that crate version, that those docs are used. The search results do not implement the same logic, so crates that don't have `documentation` keys don't get the handy documentation link in the crate row. This copies the logic from the version model into the crate model, using the default crate version as the version to look for on docs.rs. I strongly suspect there is a better way to do this than copying a bunch of code, and would welcome suggestions from those more familiar with Ember. This would eventually fix rust-lang#1484.
1 parent 2baaf0b commit cc0a011

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

Diff for: app/components/crate-row.hbs

+3-3
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@
6161
{{#if @crate.homepage}}
6262
<li><a href="{{@crate.homepage}}">Homepage</a></li>
6363
{{/if}}
64-
{{#if @crate.documentation}}
65-
<li><a href="{{@crate.documentation}}">Documentation</a></li>
64+
{{#if @crate.documentationLink}}
65+
<li><a href="{{@crate.documentationLink}}">Documentation</a></li>
6666
{{/if}}
6767
{{#if @crate.repository}}
6868
<li><a href="{{@crate.repository}}">Repository</a></li>
6969
{{/if}}
7070
</ul>
7171

72-
</div>
72+
</div>

Diff for: app/controllers/search.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import { action } from '@ember/object';
33
import { inject as service } from '@ember/service';
44
import { tracked } from '@glimmer/tracking';
55

6-
import { restartableTask } from 'ember-concurrency';
6+
import { all, restartableTask } from 'ember-concurrency';
77
import { bool, reads } from 'macro-decorators';
88

9+
import { AjaxError } from '../utils/ajax';
910
import { pagination } from '../utils/pagination';
1011
import { CATEGORY_PREFIX, processSearchQuery } from '../utils/search';
1112

@@ -73,6 +74,22 @@ export default class SearchController extends Controller {
7374
? { page, per_page, sort, q: query, all_keywords }
7475
: { page, per_page, sort, ...processSearchQuery(query) };
7576

76-
return await this.store.query('crate', searchOptions);
77+
const crates = await this.store.query('crate', searchOptions);
78+
79+
// Prime the docs for the most recent versions of each crate.
80+
const docTasks = [];
81+
for (const crate of crates) {
82+
docTasks.push(crate.loadDocsStatusTask.perform());
83+
}
84+
try {
85+
await all(docTasks);
86+
} catch (e) {
87+
// report unexpected errors to Sentry and ignore `ajax()` errors
88+
if (!didCancel(error) && !(error instanceof AjaxError)) {
89+
this.sentry.captureException(error);
90+
}
91+
}
92+
93+
return crates;
7794
});
7895
}

Diff for: app/models/crate.js

+42
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import Model, { attr, hasMany } from '@ember-data/model';
22
import { waitForPromise } from '@ember/test-waiters';
33

4+
import { task } from 'ember-concurrency';
45
import { apiAction } from '@mainmatter/ember-api-actions';
56
import { cached } from 'tracked-toolbox';
67

8+
import ajax from '../utils/ajax';
9+
710
export default class Crate extends Model {
811
@attr name;
912
@attr downloads;
@@ -42,6 +45,45 @@ export default class Crate extends Model {
4245
}
4346
}
4447

48+
get documentationLink() {
49+
let crateDocsLink = this.documentation;
50+
51+
// if this is *not* a docs.rs link we'll return it directly
52+
if (crateDocsLink && !crateDocsLink.startsWith('https://docs.rs/')) {
53+
return crateDocsLink;
54+
}
55+
56+
// if we know about a successful docs.rs build, we'll return a link to that
57+
let { docsRsLink } = this;
58+
if (docsRsLink) {
59+
return docsRsLink;
60+
}
61+
62+
// finally, we'll return the specified documentation link, whatever it is
63+
if (crateDocsLink) {
64+
return crateDocsLink;
65+
}
66+
67+
return null;
68+
}
69+
70+
loadDocsStatusTask = task(async () => {
71+
if (!this.documentation) {
72+
return await ajax(`https://docs.rs/crate/${this.name}/=${this.defaultVersion}/status.json`);
73+
}
74+
});
75+
76+
get hasDocsRsLink() {
77+
let docsStatus = this.loadDocsStatusTask.lastSuccessful?.value;
78+
return docsStatus?.doc_status === true;
79+
}
80+
81+
get docsRsLink() {
82+
if (this.hasDocsRsLink) {
83+
return `https://docs.rs/${this.name}`;
84+
}
85+
}
86+
4587
@cached get versionIdsBySemver() {
4688
let versions = this.versions.toArray() ?? [];
4789
return versions.sort(compareVersionBySemver).map(v => v.id);

0 commit comments

Comments
 (0)