Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/components/crate-sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
.msrv,
.edition,
.license,
.linecount,
.bytes,
.purl {
display: flex;
Expand All @@ -37,7 +38,8 @@

.date,
.msrv,
.edition {
.edition,
.linecount {
> span {
cursor: help;
}
Expand All @@ -49,6 +51,7 @@
}
}

.linecount,
.bytes {
font-variant-numeric: tabular-nums;
}
Expand Down
15 changes: 15 additions & 0 deletions app/components/crate-sidebar.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Tooltip from 'crates-io/components/tooltip';
import dateFormat from 'crates-io/helpers/date-format';
import dateFormatDistanceToNow from 'crates-io/helpers/date-format-distance-to-now';
import dateFormatIso from 'crates-io/helpers/date-format-iso';
import formatShortNum from 'crates-io/helpers/format-short-num';
import prettyBytes from 'crates-io/helpers/pretty-bytes';

import { simplifyUrl } from './crate-sidebar/link';
Expand Down Expand Up @@ -125,6 +126,20 @@ export default class CrateSidebar extends Component {
</div>
{{/if}}

{{#if @version.linecounts.total_code_lines}}
<div class='linecount' data-test-linecounts>
{{svgJar 'code'}}
<span>
{{formatShortNum @version.linecounts.total_code_lines}}
SLoC
<Tooltip>
Source Lines of Code<br />
<small>(excluding comments, integration tests and example code)</small>
</Tooltip>
</span>
</div>
{{/if}}

{{#if @version.crate_size}}
<div class='bytes'>
{{svgJar 'weight'}}
Expand Down
41 changes: 41 additions & 0 deletions app/helpers/format-short-num.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Helper from '@ember/component/helper';
import { service } from '@ember/service';

/**
* This matches the implementation in https://github.com/rust-lang/crates_io_og_image/blob/v0.2.1/src/formatting.rs
* to ensure that we render roughly the same values in our user interface and the generated OpenGraph images.
*/
export default class FormatShortNumHelper extends Helper {
@service intl;

compute([value]) {
const THRESHOLD = 1500;
const UNITS = ['', 'K', 'M'];

let numValue = Number(value);
let unitIndex = 0;

// Keep dividing by 1000 until value is below threshold or we've reached the last unit
while (numValue >= THRESHOLD && unitIndex < UNITS.length - 1) {
numValue /= 1000;
unitIndex += 1;
}

let unit = UNITS[unitIndex];

// Special case for numbers without suffix - no decimal places
if (unitIndex === 0) {
return this.intl.formatNumber(value);
}

// For K and M, format with appropriate decimal places
// Determine number of decimal places to keep number under 4 chars
let fractionDigits = numValue < 10 ? 1 : 0;
let number = this.intl.formatNumber(numValue, {
minimumFractionDigits: fractionDigits,
maximumFractionDigits: fractionDigits,
});

return number + unit;
}
}
1 change: 1 addition & 0 deletions app/models/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default class Version extends Model {
@attr yanked;
@attr license;
@attr crate_size;
@attr linecounts;

/**
* The minimum supported Rust version of this crate version.
Expand Down
4 changes: 2 additions & 2 deletions app/services/intl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default class IntlService extends Service {
// `undefined` means "use the default language of the browser"
locale = undefined;

formatNumber(value) {
return Number(value).toLocaleString(this.locale);
formatNumber(value, options) {
return Number(value).toLocaleString(this.locale, options);
}
}
12 changes: 12 additions & 0 deletions e2e/acceptance/crate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,18 @@ test.describe('Acceptance | crate page', { tag: '@acceptance' }, () => {
await expect(page.locator('[data-test-license]')).toHaveText('MIT OR Apache-2.0');
});

test('sidebar shows correct information', async ({ page, msw }) => {
let crate = msw.db.crate.create({ name: 'foo' });
msw.db.version.create({ crate, num: '0.5.0' });
msw.db.version.create({ crate, num: '1.0.0' });

await page.goto('/crates/foo');
await expect(page.locator('[data-test-linecounts]')).toHaveText('1,119 SLoC');

await page.goto('/crates/foo/0.5.0');
await expect(page.locator('[data-test-linecounts]')).toHaveText('520 SLoC');
});

test.skip('crates can be yanked by owner', async ({ page, msw }) => {
loadFixtures(msw.db);

Expand Down
37 changes: 37 additions & 0 deletions packages/crates-io-msw/handlers/crates/downloads.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ test('includes related versions', async function () {
features: {},
id: 1,
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/rand/1.0.0/dependencies',
version_downloads: '/api/v1/crates/rand/1.0.0/downloads',
Expand All @@ -113,6 +129,27 @@ test('includes related versions', async function () {
features: {},
id: 2,
license: 'Apache-2.0',
linecounts: {
languages: {
CSS: {
code_lines: 503,
comment_lines: 42,
files: 2,
},
Python: {
code_lines: 284,
comment_lines: 91,
files: 3,
},
TypeScript: {
code_lines: 332,
comment_lines: 83,
files: 7,
},
},
total_code_lines: 1119,
total_comment_lines: 216,
},
links: {
dependencies: '/api/v1/crates/rand/1.0.1/dependencies',
version_downloads: '/api/v1/crates/rand/1.0.1/downloads',
Expand Down
80 changes: 80 additions & 0 deletions packages/crates-io-msw/handlers/crates/get.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ test('returns a crate object for known crates', async function () {
downloads: 3702,
features: {},
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/rand/1.0.0-beta.1/dependencies',
version_downloads: '/api/v1/crates/rand/1.0.0-beta.1/downloads',
Expand Down Expand Up @@ -121,6 +137,22 @@ test('works for non-canonical names', async function () {
downloads: 3702,
features: {},
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/foo-bar/1.0.0-beta.1/dependencies',
version_downloads: '/api/v1/crates/foo-bar/1.0.0-beta.1/downloads',
Expand Down Expand Up @@ -159,6 +191,17 @@ test('includes related versions', async function () {
downloads: 11_106,
features: {},
license: 'MIT/Apache-2.0',
linecounts: {
languages: {
Python: {
code_lines: 421,
comment_lines: 64,
files: 8,
},
},
total_code_lines: 421,
total_comment_lines: 64,
},
links: {
dependencies: '/api/v1/crates/rand/1.2.0/dependencies',
version_downloads: '/api/v1/crates/rand/1.2.0/downloads',
Expand All @@ -181,6 +224,27 @@ test('includes related versions', async function () {
downloads: 7404,
features: {},
license: 'Apache-2.0',
linecounts: {
languages: {
CSS: {
code_lines: 503,
comment_lines: 42,
files: 2,
},
Python: {
code_lines: 284,
comment_lines: 91,
files: 3,
},
TypeScript: {
code_lines: 332,
comment_lines: 83,
files: 7,
},
},
total_code_lines: 1119,
total_comment_lines: 216,
},
links: {
dependencies: '/api/v1/crates/rand/1.1.0/dependencies',
version_downloads: '/api/v1/crates/rand/1.1.0/downloads',
Expand All @@ -203,6 +267,22 @@ test('includes related versions', async function () {
downloads: 3702,
features: {},
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/rand/1.0.0/dependencies',
version_downloads: '/api/v1/crates/rand/1.0.0/downloads',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,27 @@ test('returns a paginated list of crate versions depending to the specified crat
downloads: 7404,
features: {},
license: 'Apache-2.0',
linecounts: {
languages: {
CSS: {
code_lines: 503,
comment_lines: 42,
files: 2,
},
Python: {
code_lines: 284,
comment_lines: 91,
files: 3,
},
TypeScript: {
code_lines: 332,
comment_lines: 83,
files: 7,
},
},
total_code_lines: 1119,
total_comment_lines: 216,
},
links: {
dependencies: '/api/v1/crates/baz/1.0.1/dependencies',
version_downloads: '/api/v1/crates/baz/1.0.1/downloads',
Expand All @@ -98,6 +119,22 @@ test('returns a paginated list of crate versions depending to the specified crat
downloads: 3702,
features: {},
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/bar/1.0.0/dependencies',
version_downloads: '/api/v1/crates/bar/1.0.0/downloads',
Expand Down
16 changes: 16 additions & 0 deletions packages/crates-io-msw/handlers/versions/follow-updates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ test('returns latest versions of followed crates', async function () {
downloads: 3702,
features: {},
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/foo/1.2.3/dependencies',
version_downloads: '/api/v1/crates/foo/1.2.3/downloads',
Expand Down
16 changes: 16 additions & 0 deletions packages/crates-io-msw/handlers/versions/get.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ test('returns a version object for known version', async function () {
features: {},
id: 1,
license: 'MIT',
linecounts: {
languages: {
JavaScript: {
code_lines: 325,
comment_lines: 80,
files: 8,
},
TypeScript: {
code_lines: 195,
comment_lines: 10,
files: 2,
},
},
total_code_lines: 520,
total_comment_lines: 90,
},
links: {
dependencies: '/api/v1/crates/rand/1.0.0-beta.1/dependencies',
version_downloads: '/api/v1/crates/rand/1.0.0-beta.1/downloads',
Expand Down
Loading
Loading