Skip to content

Commit 5b4320f

Browse files
authored
Merge pull request #12390 from Turbo87/trustpub-only-ui
Implement `trustpub_only` user interface
2 parents 0b57f0c + 001f165 commit 5b4320f

File tree

10 files changed

+743
-107
lines changed

10 files changed

+743
-107
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.trustpub-only-checkbox {
2+
display: grid;
3+
grid-template:
4+
'checkbox label' auto
5+
'checkbox note' auto / 16px 1fr;
6+
row-gap: var(--space-3xs);
7+
column-gap: var(--space-xs);
8+
padding: var(--space-s) var(--space-m);
9+
cursor: pointer;
10+
}
11+
12+
.checkbox {
13+
grid-area: checkbox;
14+
}
15+
16+
.label {
17+
grid-area: label;
18+
font-weight: bold;
19+
}
20+
21+
.note {
22+
grid-area: note;
23+
font-size: 85%;
24+
color: var(--main-color-light);
25+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { on } from '@ember/modifier';
2+
import { action } from '@ember/object';
3+
import { service } from '@ember/service';
4+
import Component from '@glimmer/component';
5+
6+
import LoadingSpinner from 'crates-io/components/loading-spinner';
7+
8+
export default class TrustpubOnlyCheckbox extends Component {
9+
@service notifications;
10+
11+
@action async toggle(event) {
12+
let { checked } = event.target;
13+
try {
14+
await this.args.crate.setTrustpubOnlyTask.perform(checked);
15+
} catch (error) {
16+
let detail = error.errors?.[0]?.detail;
17+
if (detail && !detail.startsWith('{')) {
18+
this.notifications.error(detail);
19+
} else {
20+
this.notifications.error('Failed to update trusted publishing setting');
21+
}
22+
}
23+
}
24+
25+
<template>
26+
<label class='trustpub-only-checkbox' data-test-trustpub-only-checkbox ...attributes>
27+
<div class='checkbox'>
28+
{{#if @crate.setTrustpubOnlyTask.isRunning}}
29+
<LoadingSpinner data-test-spinner />
30+
{{else}}
31+
<input type='checkbox' checked={{@crate.trustpub_only}} data-test-checkbox {{on 'change' this.toggle}} />
32+
{{/if}}
33+
</div>
34+
<div class='label'>Require trusted publishing for all new versions</div>
35+
<div class='note'>
36+
When enabled, new versions can only be published through configured trusted publishers. Publishing with API
37+
tokens will be rejected.
38+
</div>
39+
</label>
40+
</template>
41+
}

app/controllers/crate/settings/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@ export default class CrateSettingsController extends Controller {
1313
username = '';
1414
@tracked addOwnerVisible = false;
1515

16+
/**
17+
* Tracks whether the trustpub_only checkbox was visible when the page loaded.
18+
* This prevents the checkbox from disappearing immediately when unchecked
19+
* if there are no configs - it will only disappear on the next page visit.
20+
*/
21+
trustpubOnlyCheckboxWasVisible = false;
22+
23+
get #hasConfigs() {
24+
return this.githubConfigs?.length > 0 || this.gitlabConfigs?.length > 0;
25+
}
26+
27+
get showTrustpubOnlyCheckbox() {
28+
return this.#hasConfigs || this.crate?.trustpub_only || this.trustpubOnlyCheckboxWasVisible;
29+
}
30+
31+
get showTrustpubOnlyWarning() {
32+
return this.crate?.trustpub_only && !this.#hasConfigs;
33+
}
34+
1635
@action showAddOwnerForm() {
1736
this.addOwnerVisible = true;
1837
this.username = '';

app/models/crate.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { waitForPromise } from '@ember/test-waiters';
44
import { cached } from '@glimmer/tracking';
55

66
import { apiAction } from '@mainmatter/ember-api-actions';
7-
import { task } from 'ember-concurrency';
7+
import { keepLatestTask, task } from 'ember-concurrency';
88

99
export default class Crate extends Model {
1010
@attr name;
@@ -29,6 +29,12 @@ export default class Crate extends Model {
2929
@attr documentation;
3030
@attr repository;
3131

32+
/**
33+
* Whether this crate can only be published via Trusted Publishing.
34+
* @type {boolean}
35+
*/
36+
@attr trustpub_only;
37+
3238
/**
3339
* This isn't an attribute in the crate response.
3440
* It's actually the `meta` attribute that belongs to `versions`
@@ -123,4 +129,10 @@ export default class Crate extends Model {
123129
let fut = reload === true ? versionsRef.reload() : versionsRef.load();
124130
return (await fut) ?? [];
125131
});
132+
133+
setTrustpubOnlyTask = keepLatestTask(async trustpubOnly => {
134+
let data = { crate: { trustpub_only: trustpubOnly } };
135+
let payload = await waitForPromise(apiAction(this, { method: 'PATCH', data }));
136+
this.store.pushPayload(payload);
137+
});
126138
}

app/routes/crate/settings/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ export default class SettingsIndexRoute extends Route {
1919
controller.set('crate', crate);
2020
controller.set('githubConfigs', githubConfigs);
2121
controller.set('gitlabConfigs', gitlabConfigs);
22+
23+
// Capture whether the trustpub_only checkbox should be visible on initial load
24+
let hasConfigs = githubConfigs?.length > 0 || gitlabConfigs?.length > 0;
25+
controller.set('trustpubOnlyCheckboxWasVisible', hasConfigs || crate.trustpub_only);
2226
}
2327
}

app/templates/crate/settings/index.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
background-color: light-dark(white, #141413);
5555
border-radius: var(--space-3xs);
5656
box-shadow: 0 1px 3px light-dark(hsla(51, 90%, 42%, .35), #232321);
57+
}
58+
59+
.trustpub table {
60+
width: 100%;
61+
border-spacing: 0;
5762

5863
:global(tbody) > :global(tr) > :global(td) {
5964
border-top: 1px solid light-dark(hsla(51, 90%, 42%, .25), #232321);
@@ -82,7 +87,7 @@
8287
display: none;
8388
}
8489

85-
tbody > tr > td:first-child {
90+
tbody > tr:not(.no-trustpub-config) > td:first-child {
8691
padding-bottom: 0;
8792
}
8893

@@ -109,6 +114,14 @@
109114
}
110115
}
111116

117+
.trustpub-only-warning {
118+
margin-bottom: var(--space-s);
119+
}
120+
121+
.trustpub-only-checkbox {
122+
border-top: 1px solid light-dark(hsla(51, 90%, 42%, 0.25), #232321);
123+
}
124+
112125
.email-column {
113126
width: 25%;
114127
color: var(--main-color-light);

0 commit comments

Comments
 (0)