Skip to content

Commit c1fc374

Browse files
committed
Enable zoneless change detection
1 parent 961b50f commit c1fc374

24 files changed

+132
-178
lines changed

angular.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"base": "dist/console"
2222
},
2323
"index": "src/index.html",
24-
"polyfills": ["zone.js"],
2524
"tsConfig": "tsconfig.app.json",
2625
"inlineStyleLanguage": "scss",
2726
"assets": ["src/favicon.ico", "src/assets"],

package-lock.json

Lines changed: 1 addition & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
"@fontsource-variable/roboto": "^5.2.10",
2727
"@fontsource/material-icons": "^5.2.7",
2828
"rxjs": "~7.8.0",
29-
"tslib": "^2.3.0",
30-
"zone.js": "~0.15.1"
29+
"tslib": "^2.3.0"
3130
},
3231
"devDependencies": {
3332
"@angular/build": "^21.2.1",

src/app/app-details-screen/app-details-screen.component.html

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ <h2 class="section-header">Badge</h2>
1515
<p>Use the following HTML badge to share your app:</p>
1616
<mat-form-field>
1717
<textarea rows="4" readonly matInput>
18-
<a href="https://accrescent.app/app/{{ app?.id }}">
18+
<a href="https://accrescent.app/app/{{ app()?.id }}">
1919
<img alt="Get it on Accrescent" src="https://accrescent.app/badges/get-it-on.png" height="80">
2020
</a>
2121
</textarea
@@ -26,9 +26,9 @@ <h2 class="section-header">Badge</h2>
2626

2727
<div class="grid-forms">
2828
<acc-new-update-editor (formSubmit)="createUpdate($event)">
29-
@if (uploadProgress !== undefined) {
30-
<mat-progress-bar [value]="uploadProgress" />
31-
} @else if (submitDisabled) {
29+
@if (uploadProgress() !== undefined) {
30+
<mat-progress-bar [value]="uploadProgress()" />
31+
} @else if (submitDisabled()) {
3232
<mat-progress-bar mode="indeterminate" />
3333
}
3434
</acc-new-update-editor>
@@ -41,19 +41,19 @@ <h2 class="section-header">Badge</h2>
4141
<h2 class="section-header">Updates</h2>
4242
<mat-chip-listbox multiple>
4343
<mat-chip-option
44-
[selected]="showRejectedUpdates"
45-
(selectionChange)="showRejectedUpdates = $event.selected">
44+
[selected]="showRejectedUpdates()"
45+
(selectionChange)="showRejectedUpdates.set($event.selected)">
4646
Rejected
4747
</mat-chip-option>
4848
<mat-chip-option
49-
[selected]="showPublishedUpdates"
50-
(selectionChange)="showPublishedUpdates = $event.selected">
49+
[selected]="showPublishedUpdates()"
50+
(selectionChange)="showPublishedUpdates.set($event.selected)">
5151
Published
5252
</mat-chip-option>
5353
</mat-chip-listbox>
5454
<div class="grid-cards">
5555
@for (
56-
update of updates | updateFilter: showRejectedUpdates : showPublishedUpdates;
56+
update of updates() | updateFilter: showRejectedUpdates() : showPublishedUpdates();
5757
track update
5858
) {
5959
<acc-update-card
@@ -70,24 +70,24 @@ <h2 class="section-header">Updates</h2>
7070
<h2 class="section-header">Edits</h2>
7171
<mat-chip-listbox multiple>
7272
<mat-chip-option
73-
[selected]="showRejectedEdits"
74-
(selectionChange)="showRejectedEdits = $event.selected">
73+
[selected]="showRejectedEdits()"
74+
(selectionChange)="showRejectedEdits.set($event.selected)">
7575
Rejected
7676
</mat-chip-option>
7777
<mat-chip-option
78-
[selected]="showPublishedEdits"
79-
(selectionChange)="showPublishedEdits = $event.selected">
78+
[selected]="showPublishedEdits()"
79+
(selectionChange)="showPublishedEdits.set($event.selected)">
8080
Published
8181
</mat-chip-option>
8282
</mat-chip-listbox>
8383
<div class="grid-cards">
84-
@for (edit of edits | editFilter: showRejectedEdits : showPublishedEdits; track edit) {
84+
@for (edit of edits() | editFilter: showRejectedEdits() : showPublishedEdits(); track edit) {
8585
<acc-edit-card
8686
[edit]="edit"
8787
(delete)="deleteEdit($event)"
8888
(submitForReview)="submitEdit($event)" />
8989
}
90-
@if (edits.length === 0) {
90+
@if (edits().length === 0) {
9191
<p>No edits</p>
9292
}
9393
</div>

src/app/app-details-screen/app-details-screen.component.ts

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// SPDX-License-Identifier: AGPL-3.0-only
44

5-
import { Component, OnInit, inject } from "@angular/core";
5+
import { Component, OnInit, inject, signal } from "@angular/core";
66
import { HttpEventType, HttpResponse } from "@angular/common/http";
77
import { MatChipsModule } from "@angular/material/chips";
88
import { MatDialog, MatDialogModule } from "@angular/material/dialog";
@@ -62,60 +62,61 @@ export class AppDetailsScreenComponent implements OnInit {
6262
private snackbar = inject(MatSnackBar);
6363
private updateService = inject(UpdateService);
6464

65-
app?: App;
66-
updates: Update[] = [];
67-
edits: Edit[] = [];
68-
uploadProgress?: number = undefined;
65+
readonly app = signal<App | undefined>(undefined);
66+
readonly updates = signal<Update[]>([]);
67+
readonly edits = signal<Edit[]>([]);
68+
readonly uploadProgress = signal<number | undefined>(undefined);
6969

70-
showRejectedEdits = false;
71-
showPublishedEdits = false;
72-
showRejectedUpdates = false;
73-
showPublishedUpdates = false;
74-
submitDisabled = false;
70+
readonly showRejectedEdits = signal(false);
71+
readonly showPublishedEdits = signal(false);
72+
readonly showRejectedUpdates = signal(false);
73+
readonly showPublishedUpdates = signal(false);
74+
readonly submitDisabled = signal(false);
7575

7676
ngOnInit(): void {
7777
this.activatedRoute.paramMap.subscribe((params) => {
7878
// TODO: Handle error case
7979
const appId = params.get("id");
8080
if (appId !== null) {
8181
this.appService.getApp(appId).subscribe({
82-
next: (app) => (this.app = app),
82+
next: (app) => this.app.set(app),
8383
error: showApiErrorSnackbar(this.snackbar),
8484
});
8585
this.editService.getEdits(appId).subscribe({
86-
next: (edits) => (this.edits = edits),
86+
next: (edits) => this.edits.set(edits),
8787
error: showApiErrorSnackbar(this.snackbar),
8888
});
8989
this.updateService.getUpdates(appId).subscribe({
90-
next: (updates) => (this.updates = updates),
90+
next: (updates) => this.updates.set(updates),
9191
error: showApiErrorSnackbar(this.snackbar),
9292
});
9393
}
9494
});
9595
}
9696

9797
createUpdate(form: NewUpdateForm): void {
98-
if (this.app !== undefined) {
99-
this.submitDisabled = true;
98+
const app = this.app();
99+
if (app !== undefined) {
100+
this.submitDisabled.set(true);
100101
this.updateService
101-
.createUpdate(this.app.id, form)
102-
.pipe(finalize(() => (this.submitDisabled = false)))
102+
.createUpdate(app.id, form)
103+
.pipe(finalize(() => this.submitDisabled.set(false)))
103104
.subscribe({
104105
next: (event) => {
105106
if (event.type === HttpEventType.UploadProgress) {
106-
this.uploadProgress = (100 * event.loaded) / event.total!;
107+
this.uploadProgress.set((100 * event.loaded) / event.total!);
107108

108109
// Clear the progress bar once the upload is complete
109110
if (event.loaded === event.total!) {
110-
this.uploadProgress = undefined;
111+
this.uploadProgress.set(undefined);
111112
}
112113
} else if (event instanceof HttpResponse) {
113114
const update = event.body!;
114115

115-
this.updates.push(update);
116+
this.updates.update((updates) => [...updates, update]);
116117
this.dialog
117118
.open(UpdateSubmissionDialogComponent, {
118-
data: { app: this.app, update: update },
119+
data: { app, update },
119120
})
120121
.afterClosed()
121122
.subscribe((confirmed) => {
@@ -134,19 +135,20 @@ export class AppDetailsScreenComponent implements OnInit {
134135
this.updateService.submitUpdate(id).subscribe({
135136
next: (submittedUpdate) => {
136137
// Mark as submitted in the UI
137-
const update = this.updates.find(
138-
(update) => update.id === id && update.status === UpdateStatus.Unsubmitted,
138+
this.updates.update((updates) =>
139+
updates.map((update) =>
140+
update.id === id && update.status === UpdateStatus.Unsubmitted
141+
? { ...update, status: submittedUpdate.status }
142+
: update,
143+
),
139144
);
140-
if (update !== undefined) {
141-
update.status = submittedUpdate.status;
142-
}
143145
},
144146
error: showApiErrorSnackbar(this.snackbar),
145147
});
146148
}
147149

148150
deleteUpdate(id: string): void {
149-
const update = this.updates.find((update) => update.id === id);
151+
const update = this.updates().find((update) => update.id === id);
150152

151153
this.dialog
152154
.open(UpdateDeletionDialogComponent, { data: update })
@@ -156,10 +158,9 @@ export class AppDetailsScreenComponent implements OnInit {
156158
this.updateService.deleteUpdate(id).subscribe({
157159
next: () => {
158160
// Remove update from the UI
159-
const i = this.updates.findIndex((update) => update.id === id);
160-
if (i > -1) {
161-
this.updates.splice(i, 1);
162-
}
161+
this.updates.update((updates) =>
162+
updates.filter((update) => update.id !== id),
163+
);
163164
},
164165
error: showApiErrorSnackbar(this.snackbar),
165166
});
@@ -168,16 +169,17 @@ export class AppDetailsScreenComponent implements OnInit {
168169
}
169170

170171
createEdit(form: NewEditForm): void {
171-
if (this.app !== undefined) {
172-
this.editService.createEdit(this.app.id, form).subscribe({
172+
const app = this.app();
173+
if (app !== undefined) {
174+
this.editService.createEdit(app.id, form).subscribe({
173175
next: (event) => {
174176
if (event instanceof HttpResponse) {
175177
const edit = event.body!;
176178

177-
this.edits.push(edit);
179+
this.edits.update((edits) => [...edits, edit]);
178180
this.dialog
179181
.open(EditSubmissionDialogComponent, {
180-
data: { app: this.app, edit: edit },
182+
data: { app, edit },
181183
})
182184
.afterClosed()
183185
.subscribe((confirmed) => {
@@ -196,19 +198,20 @@ export class AppDetailsScreenComponent implements OnInit {
196198
this.editService.submitEdit(id).subscribe({
197199
next: () => {
198200
// Mark as submitted in the UI
199-
const edit = this.edits.find(
200-
(edit) => edit.id === id && edit.status === EditStatus.Unsubmitted,
201+
this.edits.update((edits) =>
202+
edits.map((edit) =>
203+
edit.id === id && edit.status === EditStatus.Unsubmitted
204+
? { ...edit, status: EditStatus.Submitted }
205+
: edit,
206+
),
201207
);
202-
if (edit !== undefined) {
203-
edit.status = EditStatus.Submitted;
204-
}
205208
},
206209
error: showApiErrorSnackbar(this.snackbar),
207210
});
208211
}
209212

210213
deleteEdit(id: string): void {
211-
const edit = this.edits.find((edit) => edit.id === id);
214+
const edit = this.edits().find((edit) => edit.id === id);
212215

213216
this.dialog
214217
.open(EditDeletionDialogComponent, { data: edit })
@@ -217,11 +220,8 @@ export class AppDetailsScreenComponent implements OnInit {
217220
if (confirmed) {
218221
this.editService.deleteEdit(id).subscribe({
219222
next: () => {
220-
// Remove update from the UI
221-
const i = this.edits.findIndex((edit) => edit.id === id);
222-
if (i > -1) {
223-
this.edits.splice(i, 1);
224-
}
223+
// Remove edit from the UI
224+
this.edits.update((edits) => edits.filter((edit) => edit.id !== id));
225225
},
226226
error: showApiErrorSnackbar(this.snackbar),
227227
});

src/app/app.config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// SPDX-License-Identifier: AGPL-3.0-only
44

55
import { provideHttpClient, withInterceptors } from "@angular/common/http";
6-
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core";
6+
import { ApplicationConfig } from "@angular/core";
77
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from "@angular/material/snack-bar";
88
import { provideRouter } from "@angular/router";
99

@@ -19,6 +19,5 @@ export const appConfig: ApplicationConfig = {
1919
useValue: { duration: 5000 },
2020
},
2121
provideRouter(routes),
22-
provideZoneChangeDetection({ eventCoalescing: true }),
2322
],
2423
};

src/app/apps-screen/apps-screen.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
<h2 class="section-header">Apps</h2>
1818
<div class="grid-container">
19-
@for (app of apps; track app) {
19+
@for (app of apps(); track app) {
2020
<acc-app-card [app]="app" />
2121
} @empty {
2222
<p>No published apps</p>
@@ -25,7 +25,7 @@ <h2 class="section-header">Apps</h2>
2525

2626
<h2 class="section-header">Drafts</h2>
2727
<div class="grid-container">
28-
@for (draft of drafts; track draft) {
28+
@for (draft of drafts(); track draft) {
2929
<acc-draft-card
3030
[draft]="draft"
3131
(delete)="deleteDraft($event)"

0 commit comments

Comments
 (0)