Skip to content

Commit 256184a

Browse files
authored
[eng-8505] Add logic to get the external storage addon in the state model. (#283)
* chore(test-coverage): Removed actions from test coverage * chore(tests): Added tests for the state * refactor(model): Found two instances of a model and combined them' * refactor(extended-model): Extended the onfigured storage addon model * chore(docs): Added docs to low-hanging fruit' * feat(wbKey): Added the water butler key * feat(wbKey): Added the water butler key
1 parent 7b309cc commit 256184a

35 files changed

+958
-113
lines changed

jest.config.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ module.exports = {
3030
'src/app/**/*.{ts,js}',
3131
'!src/app/app.config.ts',
3232
'!src/app/**/*.routes.{ts.js}',
33+
'!src/app/**/*.actions.{ts.js}',
3334
'!src/app/**/*.models.{ts.js}',
3435
'!src/app/**/*.model.{ts.js}',
3536
'!src/app/**/*.route.{ts,js}',
@@ -45,10 +46,10 @@ module.exports = {
4546
extensionsToTreatAsEsm: ['.ts'],
4647
coverageThreshold: {
4748
global: {
48-
branches: 14.15,
49-
functions: 14.83,
50-
lines: 41.15,
51-
statements: 41.63,
49+
branches: 14.27,
50+
functions: 15.55,
51+
lines: 42.6,
52+
statements: 43.2,
5253
},
5354
},
5455
watchPathIgnorePatterns: [

src/app/features/files/pages/files/files.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import {
5151
SearchInputComponent,
5252
SubHeaderComponent,
5353
} from '@shared/components';
54-
import { ConfiguredStorageAddon, FilesTreeActions, OsfFile } from '@shared/models';
54+
import { ConfiguredStorageAddonModel, FilesTreeActions, OsfFile } from '@shared/models';
5555
import { FilesService } from '@shared/services';
5656

5757
import { CreateFolderDialogComponent } from '../../components';
@@ -346,7 +346,7 @@ export class FilesComponent {
346346
this.router.navigate([file.guid], { relativeTo: this.activeRoute });
347347
}
348348

349-
getAddonName(addons: ConfiguredStorageAddon[], provider: string): string {
349+
getAddonName(addons: ConfiguredStorageAddonModel[], provider: string): string {
350350
if (provider === 'osfstorage') {
351351
return 'Osf Storage';
352352
} else {

src/app/features/files/store/files.model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ContributorModel, OsfFile, ResourceMetadata } from '@shared/models';
2-
import { ConfiguredStorageAddon } from '@shared/models/addons';
2+
import { ConfiguredStorageAddonModel } from '@shared/models/addons';
33
import { AsyncStateModel } from '@shared/models/store';
44

55
import { FileProvider } from '../constants';
@@ -20,7 +20,7 @@ export interface FilesStateModel {
2020
fileRevisions: AsyncStateModel<OsfFileRevision[] | null>;
2121
tags: AsyncStateModel<string[]>;
2222
rootFolders: AsyncStateModel<OsfFile[] | null>;
23-
configuredStorageAddons: AsyncStateModel<ConfiguredStorageAddon[] | null>;
23+
configuredStorageAddons: AsyncStateModel<ConfiguredStorageAddonModel[] | null>;
2424
}
2525

2626
export const filesStateDefaults: FilesStateModel = {

src/app/features/files/store/files.selectors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Selector } from '@ngxs/store';
22

3-
import { ConfiguredStorageAddon, ContributorModel, OsfFile, ResourceMetadata } from '@shared/models';
3+
import { ConfiguredStorageAddonModel, ContributorModel, OsfFile, ResourceMetadata } from '@shared/models';
44

55
import { OsfFileCustomMetadata, OsfFileRevision } from '../models';
66

@@ -114,7 +114,7 @@ export class FilesSelectors {
114114
}
115115

116116
@Selector([FilesState])
117-
static getConfiguredStorageAddons(state: FilesStateModel): ConfiguredStorageAddon[] | null {
117+
static getConfiguredStorageAddons(state: FilesStateModel): ConfiguredStorageAddonModel[] | null {
118118
return state.configuredStorageAddons.data;
119119
}
120120

src/app/features/project/addons/components/configure-addon/configure-addon.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ <h2 class="align-self-center">
6363
(keydown.enter)="toggleEditMode()"
6464
></p-button>
6565
</div>
66+
<!-- @if (storageAddon()) {
67+
<p class="text-lg">
68+
{{ storageAddon()?.wbKey }}
69+
</p>
70+
} @else { -->
6671
<osf-folder-selector
6772
[accountName]="addon()?.displayName || ''"
6873
[operationInvocationResult]="operationInvocation()?.operationResult || []"
@@ -72,6 +77,7 @@ <h2 class="align-self-center">
7277
(save)="handleUpdateAddonConfiguration()"
7378
(cancelSelection)="toggleEditMode()"
7479
/>
80+
<!-- } -->
7581
</section>
7682
}
7783
</section>

src/app/features/project/addons/components/configure-addon/configure-addon.component.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createDispatchMap, select } from '@ngxs/store';
1+
import { createDispatchMap, select, Store } from '@ngxs/store';
22

33
import { TranslatePipe } from '@ngx-translate/core';
44

@@ -25,7 +25,7 @@ import { OperationNames } from '@osf/features/project/addons/enums';
2525
import { getAddonTypeString } from '@osf/shared/helpers';
2626
import { SubHeaderComponent } from '@shared/components';
2727
import { FolderSelectorComponent } from '@shared/components/addons/folder-selector/folder-selector.component';
28-
import { ConfiguredAddon } from '@shared/models';
28+
import { AddonModel, ConfiguredStorageAddonModel } from '@shared/models';
2929
import { AddonDialogService, AddonFormService, AddonOperationInvocationService, ToastService } from '@shared/services';
3030
import {
3131
AddonsSelectors,
@@ -63,9 +63,26 @@ export class ConfigureAddonComponent implements OnInit {
6363
private addonDialogService = inject(AddonDialogService);
6464
private addonFormService = inject(AddonFormService);
6565
private operationInvocationService = inject(AddonOperationInvocationService);
66-
66+
/**
67+
* Injected NGXS store used to access and dispatch state actions and selectors.
68+
*/
69+
private store = inject(Store);
70+
71+
/**
72+
* Form control for capturing or displaying the user’s selected account name.
73+
*/
6774
protected accountNameControl = new FormControl('');
68-
protected addon = signal<ConfiguredAddon | null>(null);
75+
/**
76+
* Signal representing the currently selected `Addon` from the list of available storage addons.
77+
* This value updates reactively as the selection changes.
78+
*/
79+
protected storageAddon = signal<AddonModel | undefined>(undefined);
80+
/**
81+
* Signal representing the currently selected and configured storage addon model.
82+
* This may be `null` if no addon has been configured.
83+
*/
84+
protected addon = signal<ConfiguredStorageAddonModel | null>(null);
85+
6986
protected isEditMode = signal<boolean>(false);
7087
protected selectedRootFolderId = signal('');
7188
protected addonsUserReference = select(AddonsSelectors.getAddonsUserReference);
@@ -101,9 +118,15 @@ export class ConfigureAddonComponent implements OnInit {
101118
}
102119

103120
private initializeAddon(): void {
104-
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as ConfiguredAddon;
121+
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as ConfiguredStorageAddonModel;
105122

106123
if (addon) {
124+
this.storageAddon.set(
125+
this.store.selectSnapshot((state) =>
126+
AddonsSelectors.getStorageAddon(state.addons, addon.externalStorageServiceId || '')
127+
)
128+
);
129+
107130
this.addon.set(addon);
108131
this.selectedRootFolderId.set(addon.selectedFolderId);
109132
this.accountNameControl.setValue(addon.displayName);
@@ -132,7 +155,7 @@ export class ConfigureAddonComponent implements OnInit {
132155
this.openDisconnectDialog(currentAddon);
133156
}
134157

135-
private openDisconnectDialog(addon: ConfiguredAddon): void {
158+
private openDisconnectDialog(addon: ConfiguredStorageAddonModel): void {
136159
const dialogRef = this.addonDialogService.openDisconnectDialog(addon);
137160

138161
dialogRef.subscribe((result) => {

src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ActivatedRoute, Navigation, Router, UrlTree } from '@angular/router';
1111

1212
import { SubHeaderComponent } from '@osf/shared/components';
1313
import { CredentialsFormat } from '@shared/enums';
14-
import { Addon } from '@shared/models';
14+
import { AddonModel } from '@shared/models';
1515
import { AddonsSelectors } from '@shared/stores/addons';
1616

1717
import { ConnectConfiguredAddonComponent } from './connect-configured-addon.component';
@@ -20,7 +20,7 @@ describe('ConnectAddonComponent', () => {
2020
let component: ConnectConfiguredAddonComponent;
2121
let fixture: ComponentFixture<ConnectConfiguredAddonComponent>;
2222

23-
const mockAddon: Addon = {
23+
const mockAddon: AddonModel = {
2424
id: 'test-addon-id',
2525
type: 'external-storage-services',
2626
displayName: 'Test Addon',

src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
AddonTermsComponent,
2424
FolderSelectorComponent,
2525
} from '@shared/components/addons';
26-
import { Addon, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
26+
import { AddonModel, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
2727
import { AddonDialogService, AddonFormService, AddonOperationInvocationService, ToastService } from '@shared/services';
2828
import {
2929
AddonsSelectors,
@@ -74,7 +74,7 @@ export class ConnectConfiguredAddonComponent {
7474
protected readonly stepper = viewChild(Stepper);
7575
protected accountNameControl = new FormControl('');
7676
protected terms = signal<AddonTerm[]>([]);
77-
protected addon = signal<Addon | AuthorizedAddon | null>(null);
77+
protected addon = signal<AddonModel | AuthorizedAddon | null>(null);
7878
protected addonAuthUrl = signal<string>('/settings/addons');
7979
protected currentAuthorizedAddonAccounts = signal<AuthorizedAddon[]>([]);
8080
protected chosenAccountId = signal('');
@@ -128,7 +128,7 @@ export class ConnectConfiguredAddonComponent {
128128
});
129129

130130
constructor() {
131-
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as Addon | AuthorizedAddon;
131+
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAddon;
132132
if (!addon) {
133133
this.router.navigate([`${this.baseUrl()}/addons`]);
134134
}
@@ -243,7 +243,7 @@ export class ConnectConfiguredAddonComponent {
243243

244244
private processAuthorizedAddons(
245245
addonConfig: AddonConfigMap[keyof AddonConfigMap],
246-
currentAddon: Addon | AuthorizedAddon
246+
currentAddon: AddonModel | AuthorizedAddon
247247
) {
248248
const authorizedAddons = addonConfig.getAuthorizedAddons();
249249
const matchingAddons = this.findMatchingAddons(authorizedAddons, currentAddon);
@@ -262,7 +262,7 @@ export class ConnectConfiguredAddonComponent {
262262

263263
private findMatchingAddons(
264264
authorizedAddons: AuthorizedAddon[],
265-
currentAddon: Addon | AuthorizedAddon
265+
currentAddon: AddonModel | AuthorizedAddon
266266
): AuthorizedAddon[] {
267267
return authorizedAddons.filter((addon) => addon.externalServiceName === currentAddon.externalServiceName);
268268
}

src/app/features/settings/addons/components/connect-addon/connect-addon.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { SubHeaderComponent } from '@osf/shared/components';
1414
import { ProjectAddonsStepperValue } from '@osf/shared/enums';
1515
import { getAddonTypeString, isAuthorizedAddon } from '@osf/shared/helpers';
1616
import { AddonSetupAccountFormComponent, AddonTermsComponent } from '@shared/components/addons';
17-
import { Addon, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
17+
import { AddonModel, AddonTerm, AuthorizedAddon, AuthorizedAddonRequestJsonApi } from '@shared/models';
1818
import { AddonsSelectors, CreateAuthorizedAddon, UpdateAuthorizedAddon } from '@shared/stores/addons';
1919

2020
@Component({
@@ -43,7 +43,7 @@ export class ConnectAddonComponent {
4343
protected readonly ProjectAddonsStepperValue = ProjectAddonsStepperValue;
4444

4545
protected terms = signal<AddonTerm[]>([]);
46-
protected addon = signal<Addon | AuthorizedAddon | null>(null);
46+
protected addon = signal<AddonModel | AuthorizedAddon | null>(null);
4747
protected addonAuthUrl = signal<string>('/settings/addons');
4848

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

7272
constructor() {
73-
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as Addon | AuthorizedAddon;
73+
const addon = this.router.getCurrentNavigation()?.extras.state?.['addon'] as AddonModel | AuthorizedAddon;
7474
if (!addon) {
7575
this.router.navigate([`${this.baseUrl()}/addons`]);
7676
}

src/app/shared/components/addons/addon-card-list/addon-card-list.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { TranslatePipe } from '@ngx-translate/core';
33
import { Component, input } from '@angular/core';
44

55
import { AddonCardComponent } from '@shared/components/addons';
6-
import { Addon, AuthorizedAddon, ConfiguredAddon } from '@shared/models';
6+
import { AddonModel, AuthorizedAddon, ConfiguredStorageAddonModel } from '@shared/models';
77

88
@Component({
99
selector: 'osf-addon-card-list',
@@ -12,7 +12,7 @@ import { Addon, AuthorizedAddon, ConfiguredAddon } from '@shared/models';
1212
styleUrl: './addon-card-list.component.scss',
1313
})
1414
export class AddonCardListComponent {
15-
cards = input<(Addon | AuthorizedAddon | ConfiguredAddon)[]>([]);
15+
cards = input<(AddonModel | AuthorizedAddon | ConfiguredStorageAddonModel)[]>([]);
1616
cardButtonLabel = input<string>('');
1717
showDangerButton = input<boolean>(false);
1818
}

0 commit comments

Comments
 (0)