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
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ module.exports = tseslint.config(
files: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
},
}
);
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
"@commitlint/cli": "^19.7.1",
"@commitlint/config-conventional": "^19.7.1",
"@compodoc/compodoc": "^1.1.26",
"@types/gapi": "^0.0.47",
"@types/gapi.auth2": "^0.0.61",
"@types/jest": "^29.5.14",
"@types/markdown-it": "^14.1.2",
"angular-eslint": "19.1.0",
Expand Down
10 changes: 10 additions & 0 deletions src/@types/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type gapi from 'gapi-script'; // or just `import gapi from 'gapi-script';`

declare global {
interface Window {
gapi: typeof gapi;
google: {
picker: typeof google.picker;
};
}
}
8 changes: 8 additions & 0 deletions src/app/core/constants/environment.token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { InjectionToken } from '@angular/core';

import { environment } from 'src/environments/environment';

export const ENVIRONMENT = new InjectionToken<typeof environment>('App Environment', {
providedIn: 'root',
factory: () => environment,
});
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Component: Configure Addon', () => {
});

it('should validate the constuctor values', () => {
expect(component.storageAddon()).toBeUndefined();
expect(component.storageAddon()).toBeNull();
expect(component.addon()).toEqual(
Object({
attributes: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class ConfigureAddonComponent implements OnInit {
* Signal representing the currently selected `Addon` from the list of available storage addons.
* This value updates reactively as the selection changes.
*/
public storageAddon = signal<AddonModel | undefined>(undefined);
public storageAddon = signal<AddonModel | null>(null);
/**
* Signal representing the currently selected and configured storage addon model.
* This may be `null` if no addon has been configured.
Expand Down Expand Up @@ -128,9 +128,7 @@ export class ConfigureAddonComponent implements OnInit {

if (addon) {
this.storageAddon.set(
this.store.selectSnapshot((state) =>
AddonsSelectors.getStorageAddon(state.addons, addon.externalStorageServiceId || '')
)
this.store.selectSnapshot(AddonsSelectors.getStorageAddon(addon.externalStorageServiceId || ''))
);

this.addon.set(addon);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ import { AddonConfigMap } from '@osf/features/project/addons/utils';
import { SubHeaderComponent } from '@osf/shared/components';
import { ProjectAddonsStepperValue } from '@osf/shared/enums';
import { getAddonTypeString } from '@osf/shared/helpers';
import { AuthorizedAccountModel } from '@osf/shared/models/addons/authorized-account.model';
import {
AddonSetupAccountFormComponent,
AddonTermsComponent,
FolderSelectorComponent,
} from '@shared/components/addons';
import { AddonModel, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonModel, AddonTerm, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonDialogService, AddonFormService, AddonOperationInvocationService, ToastService } from '@shared/services';
import {
AddonsSelectors,
Expand Down Expand Up @@ -74,9 +75,9 @@ export class ConnectConfiguredAddonComponent {
protected readonly stepper = viewChild(Stepper);
protected accountNameControl = new FormControl('');
protected terms = signal<AddonTerm[]>([]);
protected addon = signal<AddonModel | AuthorizedAddon | null>(null);
protected addon = signal<AddonModel | AuthorizedAccountModel | null>(null);
protected addonAuthUrl = signal<string>('/settings/addons');
protected currentAuthorizedAddonAccounts = signal<AuthorizedAddon[]>([]);
protected currentAuthorizedAddonAccounts = signal<AuthorizedAccountModel[]>([]);
protected chosenAccountId = signal('');
protected chosenAccountName = signal('');
protected selectedRootFolderId = signal('');
Expand Down Expand Up @@ -114,7 +115,6 @@ export class ConnectConfiguredAddonComponent {

protected resourceUri = computed(() => {
const id = this.route.parent?.parent?.snapshot.params['id'];

return `${environment.webUrl}/${id}`;
});

Expand All @@ -128,7 +128,7 @@ export class ConnectConfiguredAddonComponent {
});

constructor() {
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAddon;
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAccountModel;
if (!addon) {
this.router.navigate([`${this.baseUrl()}/addons`]);
}
Expand Down Expand Up @@ -243,7 +243,7 @@ export class ConnectConfiguredAddonComponent {

private processAuthorizedAddons(
addonConfig: AddonConfigMap[keyof AddonConfigMap],
currentAddon: AddonModel | AuthorizedAddon
currentAddon: AddonModel | AuthorizedAccountModel
) {
const authorizedAddons = addonConfig.getAuthorizedAddons();
const matchingAddons = this.findMatchingAddons(authorizedAddons, currentAddon);
Expand All @@ -261,9 +261,9 @@ export class ConnectConfiguredAddonComponent {
}

private findMatchingAddons(
authorizedAddons: AuthorizedAddon[],
currentAddon: AddonModel | AuthorizedAddon
): AuthorizedAddon[] {
authorizedAddons: AuthorizedAccountModel[],
currentAddon: AddonModel | AuthorizedAccountModel
): AuthorizedAccountModel[] {
return authorizedAddons.filter((addon) => addon.externalServiceName === currentAddon.externalServiceName);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Observable } from 'rxjs';

import { AuthorizedAddon } from '@shared/models';
import { AuthorizedAccountModel } from '@shared/models';

export interface AddonConfigActions {
getAddons: () => Observable<void>;
getAuthorizedAddons: () => AuthorizedAddon[];
getAuthorizedAddons: () => AuthorizedAccountModel[];
}
3 changes: 3 additions & 0 deletions src/app/features/settings/addons/addons.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ export class AddonsComponent {
}

constructor() {
// TODO There should not be three effects
effect(() => {
if (this.currentUser()) {
this.actions.getAddonsUserReference();
}
});

// TODO There should not be three effects
effect(() => {
if (this.currentUser() && this.userReferenceId()) {
const action = this.currentAction();
Expand All @@ -157,6 +159,7 @@ export class AddonsComponent {
}
});

// TODO There should not be three effects
effect(() => {
if (this.currentUser() && this.userReferenceId()) {
this.fetchAllAuthorizedAddons(this.userReferenceId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { SubHeaderComponent } from '@osf/shared/components';
import { ProjectAddonsStepperValue } from '@osf/shared/enums';
import { getAddonTypeString, isAuthorizedAddon } from '@osf/shared/helpers';
import { AddonSetupAccountFormComponent, AddonTermsComponent } from '@shared/components/addons';
import { AddonModel, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonModel, AddonTerm, AuthorizedAccountModel, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonsSelectors, CreateAuthorizedAddon, UpdateAuthorizedAddon } from '@shared/stores/addons';

@Component({
Expand Down Expand Up @@ -43,7 +43,7 @@ export class ConnectAddonComponent {
protected readonly ProjectAddonsStepperValue = ProjectAddonsStepperValue;

protected terms = signal<AddonTerm[]>([]);
protected addon = signal<AddonModel | AuthorizedAddon | null>(null);
protected addon = signal<AddonModel | AuthorizedAccountModel | null>(null);
protected addonAuthUrl = signal<string>('/settings/addons');

protected addonsUserReference = select(AddonsSelectors.getAddonsUserReference);
Expand All @@ -70,7 +70,7 @@ export class ConnectAddonComponent {
});

constructor() {
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAddon;
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAccountModel;
if (!addon) {
this.router.navigate([`${this.baseUrl()}/addons`]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TranslatePipe } from '@ngx-translate/core';
import { Component, input } from '@angular/core';

import { AddonCardComponent } from '@shared/components/addons';
import { AddonModel, AuthorizedAddon, ConfiguredStorageAddonModel } from '@shared/models';
import { AddonModel, AuthorizedAccountModel, ConfiguredStorageAddonModel } from '@shared/models';

@Component({
selector: 'osf-addon-card-list',
Expand All @@ -12,7 +12,7 @@ import { AddonModel, AuthorizedAddon, ConfiguredStorageAddonModel } from '@share
styleUrl: './addon-card-list.component.scss',
})
export class AddonCardListComponent {
cards = input<(AddonModel | AuthorizedAddon | ConfiguredStorageAddonModel)[]>([]);
cards = input<(AddonModel | AuthorizedAccountModel | ConfiguredStorageAddonModel)[]>([]);
cardButtonLabel = input<string>('');
showDangerButton = input<boolean>(false);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Router } from '@angular/router';

import { getAddonTypeString, isConfiguredAddon } from '@osf/shared/helpers';
import { CustomConfirmationService, LoaderService } from '@osf/shared/services';
import { AddonModel, AuthorizedAddon, ConfiguredStorageAddonModel } from '@shared/models';
import { AddonModel, AuthorizedAccountModel, ConfiguredStorageAddonModel } from '@shared/models';
import { DeleteAuthorizedAddon } from '@shared/stores/addons';

@Component({
Expand All @@ -24,7 +24,7 @@ export class AddonCardComponent {
private readonly loaderService = inject(LoaderService);
private readonly actions = createDispatchMap({ deleteAuthorizedAddon: DeleteAuthorizedAddon });

readonly card = input<AddonModel | AuthorizedAddon | ConfiguredStorageAddonModel | null>(null);
readonly card = input<AddonModel | AuthorizedAccountModel | ConfiguredStorageAddonModel | null>(null);
readonly cardButtonLabel = input<string>('');
readonly showDangerButton = input<boolean>(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';

import { AddonFormControls, CredentialsFormat } from '@shared/enums';
import { AddonForm, AddonModel, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonForm, AddonModel, AuthorizedAccountModel, AuthorizedAddonRequestJsonApi } from '@shared/models';
import { AddonFormService } from '@shared/services/addons/addon-form.service';

@Component({
Expand All @@ -22,7 +22,7 @@ import { AddonFormService } from '@shared/services/addons/addon-form.service';
export class AddonSetupAccountFormComponent {
private addonFormService = inject(AddonFormService);

addon = input.required<AddonModel | AuthorizedAddon>();
addon = input.required<AddonModel | AuthorizedAccountModel>();
userReferenceId = input.required<string>();
addonTypeString = input.required<string>();
isSubmitting = input<boolean>(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Component, computed, input } from '@angular/core';

import { isCitationAddon } from '@osf/shared/helpers';
import { ADDON_TERMS as addonTerms } from '@shared/constants';
import { AddonModel, AddonTerm, AuthorizedAddon } from '@shared/models';
import { AddonModel, AddonTerm, AuthorizedAccountModel } from '@shared/models';

@Component({
selector: 'osf-addon-terms',
Expand All @@ -16,7 +16,7 @@ import { AddonModel, AddonTerm, AuthorizedAddon } from '@shared/models';
styleUrls: ['./addon-terms.component.scss'],
})
export class AddonTermsComponent {
addon = input<AddonModel | AuthorizedAddon | null>(null);
addon = input<AddonModel | AuthorizedAccountModel | null>(null);
protected terms = computed(() => {
const addon = this.addon();
if (!addon) {
Expand All @@ -25,7 +25,7 @@ export class AddonTermsComponent {
return this.getAddonTerms(addon);
});

private getAddonTerms(addon: AddonModel | AuthorizedAddon): AddonTerm[] {
private getAddonTerms(addon: AddonModel | AuthorizedAccountModel): AddonTerm[] {
const supportedFeatures = addon.supportedFeatures;
const provider = addon.providerName;
const isCitationService = isCitationAddon(addon);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h3 class="mt-4 mb-2">
@if (isOperationInvocationSubmitting()) {
<p-skeleton width="100%" height="7.5rem" borderRadius="16" />
} @else if (isGoogleFilePicker()) {
<osf-google-file-picker></osf-google-file-picker>
<osf-google-file-picker [isFolderPicker]="true"></osf-google-file-picker>
} @else {
<div class="folders-table flex flex-column">
<div class="folders-table-heading flex justify-content-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ import { GoogleFilePickerComponent } from './google-file-picker/google-file-pick
export class FolderSelectorComponent implements OnInit {
private destroyRef = inject(DestroyRef);
private translateService = inject(TranslateService);

isGoogleFilePicker = input.required<boolean>();
accountName = input.required<string>();
operationInvocationResult = input.required<StorageItem[]>();
accountNameControl = input(new FormControl());
isCreateMode = input(false);

selectedRootFolderId = model<string>('/');
operationInvoke = output<OperationInvokeData>();
save = output<void>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
<section class="flex flex-column gap-4">Hello World again</section>

<!-- <div {{did-insert this.registerComponent}}
local-class='google-file-picker-container {{if this.isMobile 'mobile'}} {{if this.isFolderPicker 'file-picker'}}'
>
{{#if this.isFolderPicker}}
<div local-class='action-container'>
<button class='btn btn-primary btn-medium' local-class='authorize-button {{if this.visible 'visible'}}' type='button' id='authorize_button'
disabled={{this.isGFPDisabled}}
{{on 'click' (action this.createPicker)}}
>
{{t 'addons.configure.google-file-picker.select-root-folder'}}
</button>
</div>
{{/if}}
<script async defer src='https://apis.google.com/js/api.js' onload='window.GoogleFilePickerWidget.gapiLoaded()'></script>
</div> -->
<section class="google-file-picker-container" [class.file-picker]="this.isFolderPicker()">
@if (this.isFolderPicker()) {
<div local-class="action-container">
<p-button
[label]="'settings.addons.configureAddon.google-file-picker.select-root-folder' | translate"
class="authorize-button"
[class.visible]="visible()"
[disabled]="isGFPDisabled()"
(click)="createPicker()"
></p-button>
</div>
}
</section>
Loading