diff --git a/src/app/features/files/pages/files/files.component.ts b/src/app/features/files/pages/files/files.component.ts index a7dc18e84..08d8bc8b7 100644 --- a/src/app/features/files/pages/files/files.component.ts +++ b/src/app/features/files/pages/files/files.component.ts @@ -596,13 +596,13 @@ export class FilesComponent { }); } - updateFilesList() { + updateFilesList = (): void => { const currentFolder = this.currentFolder(); const filesLink = currentFolder?.links.filesLink; if (filesLink) { this.actions.getFiles(filesLink, this.pageNumber()); } - } + }; setCurrentFolder(folder: FileFolderModel) { this.actions.setCurrentFolder(folder); diff --git a/src/app/shared/components/google-file-picker/google-file-picker.component.spec.ts b/src/app/shared/components/google-file-picker/google-file-picker.component.spec.ts index b9e46b9a8..9a33c8ec0 100644 --- a/src/app/shared/components/google-file-picker/google-file-picker.component.spec.ts +++ b/src/app/shared/components/google-file-picker/google-file-picker.component.spec.ts @@ -4,6 +4,7 @@ import { Observable, of, throwError } from 'rxjs'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ENVIRONMENT } from '@core/provider/environment.provider'; import { SENTRY_TOKEN } from '@core/provider/sentry.provider'; import { GoogleFilePickerDownloadService } from '@osf/shared/services/google-file-picker.download.service'; @@ -296,5 +297,93 @@ describe('Component: Google File Picker', () => { expect(build).toHaveBeenCalledWith(); expect(setVisible).toHaveBeenCalledWith(true); }); + + it('should open picker with current token when oauth refresh fails', () => { + const errorStoreMock = { + dispatch: jest.fn().mockReturnValue(throwError(() => new Error('OAuth refresh failed'))), + selectSnapshot: jest.fn().mockReturnValue(null), + }; + + TestBed.resetTestingModule(); + TestBed.configureTestingModule({ + imports: [OSFTestingStoreModule, GoogleFilePickerComponent], + providers: [ + { provide: SENTRY_TOKEN, useValue: { captureException: jest.fn() } }, + { provide: GoogleFilePickerDownloadService, useValue: googlePickerServiceSpy }, + { provide: Store, useValue: errorStoreMock }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(GoogleFilePickerComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('isFolderPicker', false); + fixture.componentRef.setInput('rootFolder', { itemId: 'root-folder-id' }); + fixture.componentRef.setInput('handleFolderSelection', jest.fn()); + fixture.componentRef.setInput('accountId', 'account-id'); + fixture.detectChanges(); + + jest.clearAllMocks(); + component.createPicker(); + + expect(errorStoreMock.dispatch).toHaveBeenCalled(); + expect(setVisible).toHaveBeenCalledWith(true); + }); + }); + + describe('picker not configured', () => { + it('should disable picker when apiKey or appId is missing', async () => { + await TestBed.configureTestingModule({ + imports: [OSFTestingModule, GoogleFilePickerComponent], + providers: [ + { provide: SENTRY_TOKEN, useValue: { captureException: jest.fn() } }, + { provide: GoogleFilePickerDownloadService, useValue: googlePickerServiceSpy }, + { provide: Store, useValue: storeMock }, + ], + }) + .overrideProvider(ENVIRONMENT, { + useValue: { + googleFilePickerApiKey: '', + googleFilePickerAppId: '', + }, + }) + .compileComponents(); + + fixture = TestBed.createComponent(GoogleFilePickerComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('isFolderPicker', true); + fixture.detectChanges(); + + expect(component.isGFPDisabled()).toBeTruthy(); + expect(googlePickerServiceSpy.loadScript).not.toHaveBeenCalled(); + }); + + it('should not open picker when not configured', async () => { + await TestBed.configureTestingModule({ + imports: [OSFTestingModule, GoogleFilePickerComponent], + providers: [ + { provide: SENTRY_TOKEN, useValue: { captureException: jest.fn() } }, + { provide: GoogleFilePickerDownloadService, useValue: googlePickerServiceSpy }, + { provide: Store, useValue: storeMock }, + ], + }) + .overrideProvider(ENVIRONMENT, { + useValue: { + googleFilePickerApiKey: '', + googleFilePickerAppId: '', + }, + }) + .compileComponents(); + + fixture = TestBed.createComponent(GoogleFilePickerComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('isFolderPicker', true); + fixture.detectChanges(); + + jest.clearAllMocks(); + component.createPicker(); + + expect(build).not.toHaveBeenCalled(); + expect(setVisible).not.toHaveBeenCalled(); + }); }); }); diff --git a/src/app/shared/components/google-file-picker/google-file-picker.component.ts b/src/app/shared/components/google-file-picker/google-file-picker.component.ts index 98c284b82..b48ce6170 100644 --- a/src/app/shared/components/google-file-picker/google-file-picker.component.ts +++ b/src/app/shared/components/google-file-picker/google-file-picker.component.ts @@ -88,6 +88,31 @@ export class GoogleFilePickerComponent implements OnInit { createPicker(): void { if (!this.isPickerConfigured) return; + + this.refreshOauthTokenAndOpenPicker(); + } + + private refreshOauthTokenAndOpenPicker(): void { + if (!this.accountId()) { + this.openPickerWithCurrentToken(); + return; + } + + this.store.dispatch(new GetAuthorizedStorageOauthToken(this.accountId(), this.currentAddonType())).subscribe({ + complete: () => { + this.accessToken.set( + this.store.selectSnapshot(AddonsSelectors.getAuthorizedStorageAddonOauthToken(this.accountId())) + ); + this.isGFPDisabled.set(!this.accessToken()); + this.openPickerWithCurrentToken(); + }, + error: () => { + this.openPickerWithCurrentToken(); + }, + }); + } + + private openPickerWithCurrentToken(): void { const google = window.google; const googlePickerView = new google.picker.DocsView(google.picker.ViewId.DOCS);