Skip to content

Commit e2840ac

Browse files
authored
[ENG-10371][ENG-10368] Delete draft preprint functionality was not included in Angular update (#932)
- Ticket: [ENG-10371](https://openscience.atlassian.net/browse/ENG-10371) - Feature flag: n/a ## Summary of Changes 1. Added delete button for preprint draft. 2. Fixed issue with loader.
1 parent bb0a296 commit e2840ac

32 files changed

Lines changed: 547 additions & 88 deletions

package-lock.json

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

src/app/app.component.spec.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ import { Subject } from 'rxjs';
66

77
import { ComponentFixture, TestBed } from '@angular/core/testing';
88
import { By } from '@angular/platform-browser';
9-
import { NavigationEnd, Router } from '@angular/router';
9+
import {
10+
NavigationCancel,
11+
NavigationEnd,
12+
NavigationError,
13+
NavigationStart,
14+
ResolveStart,
15+
Router,
16+
} from '@angular/router';
1017

1118
import { CookieConsentBannerComponent } from '@core/components/osf-banners/cookie-consent-banner/cookie-consent-banner.component';
1219
import { ENVIRONMENT } from '@core/provider/environment.provider';
@@ -18,17 +25,20 @@ import { TranslateServiceMock } from '../testing/mocks/translate.service.mock';
1825
import { FullScreenLoaderComponent } from './shared/components/full-screen-loader/full-screen-loader.component';
1926
import { ToastComponent } from './shared/components/toast/toast.component';
2027
import { CustomDialogService } from './shared/services/custom-dialog.service';
28+
import { LoaderService } from './shared/services/loader.service';
2129
import { AppComponent } from './app.component';
2230

2331
import { OSFTestingModule } from '@testing/osf.testing.module';
2432
import { CustomDialogServiceMockBuilder } from '@testing/providers/custom-dialog-provider.mock';
33+
import { LoaderServiceMock } from '@testing/providers/loader-service.mock';
2534
import { GoogleTagManagerService } from 'angular-google-tag-manager';
2635

2736
describe('Component: App', () => {
2837
let routerEvents$: Subject<any>;
2938
let gtmServiceMock: jest.Mocked<GoogleTagManagerService>;
3039
let fixture: ComponentFixture<AppComponent>;
3140
let mockCustomDialogService: ReturnType<CustomDialogServiceMockBuilder['build']>;
41+
let loaderServiceMock: LoaderServiceMock;
3242

3343
beforeEach(async () => {
3444
mockCustomDialogService = CustomDialogServiceMockBuilder.create().build();
@@ -37,6 +47,7 @@ describe('Component: App', () => {
3747
gtmServiceMock = {
3848
pushTag: jest.fn(),
3949
} as any;
50+
loaderServiceMock = new LoaderServiceMock();
4051

4152
await TestBed.configureTestingModule({
4253
imports: [
@@ -47,6 +58,7 @@ describe('Component: App', () => {
4758
providers: [
4859
provideStore([UserState, UserEmailsState]),
4960
MockProvider(CustomDialogService, mockCustomDialogService),
61+
MockProvider(LoaderService, loaderServiceMock),
5062
TranslateServiceMock,
5163
{ provide: GoogleTagManagerService, useValue: gtmServiceMock },
5264
{
@@ -103,4 +115,55 @@ describe('Component: App', () => {
103115
expect(gtmServiceMock.pushTag).not.toHaveBeenCalled();
104116
});
105117
});
118+
119+
describe('Loader routing behavior', () => {
120+
it('should not show loader on NavigationStart', () => {
121+
fixture.detectChanges();
122+
123+
routerEvents$.next(new NavigationStart(1, '/next'));
124+
125+
expect(loaderServiceMock.show).not.toHaveBeenCalled();
126+
});
127+
128+
it('should show loader on ResolveStart', () => {
129+
fixture.detectChanges();
130+
131+
routerEvents$.next(new ResolveStart(1, '/next', '/next', {} as any));
132+
133+
expect(loaderServiceMock.show).toHaveBeenCalled();
134+
});
135+
136+
it('should hide loader on NavigationEnd after delay', () => {
137+
jest.useFakeTimers();
138+
fixture.detectChanges();
139+
140+
routerEvents$.next(new NavigationEnd(1, '/previous', '/current'));
141+
jest.advanceTimersByTime(500);
142+
143+
expect(loaderServiceMock.hide).toHaveBeenCalled();
144+
jest.useRealTimers();
145+
});
146+
147+
it('should hide loader on NavigationCancel after delay', () => {
148+
jest.useFakeTimers();
149+
fixture.detectChanges();
150+
151+
routerEvents$.next(new NavigationCancel(1, '/current', 'cancelled'));
152+
jest.advanceTimersByTime(500);
153+
154+
expect(loaderServiceMock.hide).toHaveBeenCalled();
155+
jest.useRealTimers();
156+
});
157+
158+
it('should hide loader on NavigationError after delay', () => {
159+
jest.useFakeTimers();
160+
fixture.detectChanges();
161+
162+
routerEvents$.next(new NavigationError(1, '/current', new Error('test')));
163+
jest.advanceTimersByTime(500);
164+
165+
expect(loaderServiceMock.hide).toHaveBeenCalled();
166+
jest.useRealTimers();
167+
});
168+
});
106169
});

src/app/app.component.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,7 @@ import { switchMap, timer } from 'rxjs';
55
import { isPlatformBrowser } from '@angular/common';
66
import { ChangeDetectionStrategy, Component, DestroyRef, effect, inject, OnInit, PLATFORM_ID } from '@angular/core';
77
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
8-
import {
9-
NavigationCancel,
10-
NavigationEnd,
11-
NavigationError,
12-
NavigationStart,
13-
Router,
14-
RouterOutlet,
15-
} from '@angular/router';
8+
import { NavigationCancel, NavigationEnd, NavigationError, ResolveStart, Router, RouterOutlet } from '@angular/router';
169

1710
import { ENVIRONMENT } from '@core/provider/environment.provider';
1811
import { GetCurrentUser } from '@core/store/user';
@@ -65,7 +58,7 @@ export class AppComponent implements OnInit {
6558

6659
if (this.isBrowser) {
6760
this.router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
68-
if (event instanceof NavigationStart) {
61+
if (event instanceof ResolveStart) {
6962
this.loaderService.show();
7063
} else if (
7164
event instanceof NavigationEnd ||

src/app/features/preprints/components/stepper/author-assertion-step/author-assertions-step.component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ <h2>{{ 'preprints.preprintStepper.authorAssertions.publicPreregistration.title'
226226
severity="info"
227227
(onClick)="backButtonClicked()"
228228
/>
229+
<p-button
230+
class="w-6 md:w-6rem"
231+
styleClass="w-full"
232+
[label]="'common.buttons.delete' | translate"
233+
severity="danger"
234+
(onClick)="deletePreprint()"
235+
/>
229236
<p-button
230237
class="w-6 md:w-9rem"
231238
styleClass="w-full"

src/app/features/preprints/components/stepper/author-assertion-step/author-assertions-step.component.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,15 @@ describe('AuthorAssertionsStepComponent', () => {
284284
expect(emitSpy).toHaveBeenCalled();
285285
});
286286

287+
it('should emit deleteClicked when deletePreprint is called', () => {
288+
setup({ detectChanges: false });
289+
const emitSpy = jest.spyOn(component.deleteClicked, 'emit');
290+
291+
component.deletePreprint();
292+
293+
expect(emitSpy).toHaveBeenCalled();
294+
});
295+
287296
it('should handle discard confirmation callbacks when there are unsaved changes', () => {
288297
setup();
289298
const emitSpy = jest.spyOn(component.backClicked, 'emit');

src/app/features/preprints/components/stepper/author-assertion-step/author-assertions-step.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export class AuthorAssertionsStepComponent {
126126

127127
nextClicked = output<void>();
128128
backClicked = output<void>();
129+
deleteClicked = output<void>();
129130

130131
constructor() {
131132
effect(() => {
@@ -259,6 +260,10 @@ export class AuthorAssertionsStepComponent {
259260
});
260261
}
261262

263+
deletePreprint() {
264+
this.deleteClicked.emit();
265+
}
266+
262267
private disableAndClearValidators(control: AbstractControl): void {
263268
if (control instanceof FormArray) {
264269
while (control.length !== 0) {

src/app/features/preprints/components/stepper/file-step/file-step.component.html

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,6 @@ <h2>{{ 'preprints.preprintStepper.file.title' | translate }}</h2>
130130
<osf-icon [iconClass]="'fas fa-file'" />
131131
<p data-test-file-name>{{ preprintFile()!.name }}</p>
132132
</div>
133-
134-
<p-button
135-
class="danger-icon-btn"
136-
icon="fas fa-trash"
137-
severity="danger"
138-
text
139-
[ariaLabel]="'common.buttons.delete' | translate"
140-
(onClick)="versionFile()"
141-
/>
142133
</section>
143134
}
144135
</section>
@@ -152,6 +143,13 @@ <h2>{{ 'preprints.preprintStepper.file.title' | translate }}</h2>
152143
severity="info"
153144
(onClick)="backButtonClicked()"
154145
/>
146+
<p-button
147+
class="w-6 md:w-6rem"
148+
styleClass="w-full"
149+
[label]="'common.buttons.delete' | translate"
150+
severity="danger"
151+
(onClick)="deletePreprint()"
152+
/>
155153
<p-button
156154
class="w-6 md:w-9rem"
157155
styleClass="w-full"

src/app/features/preprints/components/stepper/file-step/file-step.component.spec.ts

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ describe('FileStepComponent', () => {
199199
expect(emitSpy).toHaveBeenCalled();
200200
});
201201

202+
it('should emit deleteClicked when deletePreprint is called', () => {
203+
setup({ detectChanges: false });
204+
const emitSpy = jest.spyOn(component.deleteClicked, 'emit');
205+
206+
component.deletePreprint();
207+
208+
expect(emitSpy).toHaveBeenCalled();
209+
});
210+
202211
it('should handle nextButtonClicked for allowed and blocked states', () => {
203212
setup({ detectChanges: false });
204213
const emitSpy = jest.spyOn(component.nextClicked, 'emit');
@@ -303,29 +312,6 @@ describe('FileStepComponent', () => {
303312
expect(store.dispatch).toHaveBeenCalledWith(new FetchPreprintPrimaryFile());
304313
});
305314

306-
it('should set version mode and reset selected source on version file confirmation', () => {
307-
setup({ detectChanges: false });
308-
309-
component.versionFile();
310-
const options = confirmationServiceMock.confirmContinue.mock.calls[0][0];
311-
options.onConfirm();
312-
313-
expect(component.versionFileMode()).toBe(true);
314-
expect(store.dispatch).toHaveBeenCalledWith(new SetSelectedPreprintFileSource(PreprintFileSource.None));
315-
});
316-
317-
it('should not change mode or selected source on version file reject', () => {
318-
setup({ detectChanges: false });
319-
320-
component.versionFile();
321-
const options = confirmationServiceMock.confirmContinue.mock.calls[0][0];
322-
(store.dispatch as jest.Mock).mockClear();
323-
options.onReject();
324-
325-
expect(component.versionFileMode()).toBe(false);
326-
expect(store.dispatch).not.toHaveBeenCalledWith(new SetSelectedPreprintFileSource(PreprintFileSource.None));
327-
});
328-
329315
it('should handle cancelButtonClicked for file present and file missing states', () => {
330316
setup({ detectChanges: false });
331317

src/app/features/preprints/components/stepper/file-step/file-step.component.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export class FileStepComponent implements OnInit {
120120

121121
nextClicked = output<void>();
122122
backClicked = output<void>();
123+
deleteClicked = output<void>();
123124

124125
isFileSourceSelected = computed(() => this.selectedFileSource() !== PreprintFileSource.None);
125126
canProceedToNext = computed(() => !!this.preprintFile() && !this.versionFileMode());
@@ -163,6 +164,10 @@ export class FileStepComponent implements OnInit {
163164
this.nextClicked.emit();
164165
}
165166

167+
deletePreprint() {
168+
this.deleteClicked.emit();
169+
}
170+
166171
onFileSelected(event: Event): void {
167172
const input = event.target as HTMLInputElement;
168173
const file = input.files?.[0];
@@ -204,18 +209,6 @@ export class FileStepComponent implements OnInit {
204209
this.actions.copyFileFromProject(file).subscribe(() => this.actions.fetchPreprintFile());
205210
}
206211

207-
versionFile() {
208-
this.customConfirmationService.confirmContinue({
209-
headerKey: 'preprints.preprintStepper.file.versionFile.header',
210-
messageKey: 'preprints.preprintStepper.file.versionFile.message',
211-
onConfirm: () => {
212-
this.versionFileMode.set(true);
213-
this.actions.setSelectedFileSource(PreprintFileSource.None);
214-
},
215-
onReject: () => null,
216-
});
217-
}
218-
219212
cancelButtonClicked() {
220213
if (this.preprintFile()) {
221214
return;

src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ <h2 class="mb-4">{{ 'preprints.preprintStepper.metadata.publicationCitationTitle
106106
severity="info"
107107
(onClick)="backButtonClicked()"
108108
/>
109+
<p-button
110+
class="w-6 md:w-6rem"
111+
styleClass="w-full"
112+
[label]="'common.buttons.delete' | translate"
113+
severity="danger"
114+
(onClick)="deletePreprint()"
115+
/>
109116
<p-button
110117
class="w-6 md:w-9rem"
111118
styleClass="w-full"

0 commit comments

Comments
 (0)