Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8e2a374
feat(pat-api-integration): initial scopes fetching and store
rnastyuk Mar 31, 2025
e60f719
feat(pat-api-integration): added methods for token crud operations
rnastyuk Apr 1, 2025
7996464
feat(addons-api-integration): started integrating addons api
rnastyuk Apr 1, 2025
c66bcb4
feat(addons-api-integration): added addons images to assets
rnastyuk Apr 3, 2025
b1bea1e
feat(addons-api-integration): separated store selectors in their own …
rnastyuk Apr 3, 2025
7819926
Merge branch 'refs/heads/main' into feat/99-pat-addons-api-integration
rnastyuk Apr 8, 2025
8cfe37c
feat(pat-addons-api-integration): json-api service refactor
rnastyuk Apr 8, 2025
edfaeb7
Merge branch 'main' into feat/99-pat-addons-api-integration
rnastyuk Apr 8, 2025
9667b17
Merge branch 'refs/heads/main' into feat/99-pat-addons-api-integration
rnastyuk Apr 8, 2025
64bfd76
Merge branch 'refs/heads/main' into feat/99-pat-addons-api-integration
rnastyuk Apr 10, 2025
c3bf8fa
fix(api-service): fixes for json-api service
kpetrov24exoft Apr 11, 2025
b807cd0
fix(api-service): params fix
kpetrov24exoft Apr 11, 2025
62bbe6d
feat(pat-addons-api-integration): integrated pat api
rnastyuk Apr 11, 2025
1f6baa6
feat(pat-addons-api-integration): added new json api service methods …
rnastyuk Apr 11, 2025
c287d9d
feat(pat-addons-api-integration): added connecting addons functionality
rnastyuk Apr 17, 2025
12cbcd9
feat(pat-addons-api-integration): removed unused parameter
rnastyuk Apr 17, 2025
58930ad
chore(git): merge main
Apr 19, 2025
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,074 changes: 1,033 additions & 41 deletions bun.lock

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
inject,
OnInit,
} from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Store } from '@ngxs/store';
import { GetCurrentUser } from '@core/store/user';

@Component({
selector: 'osf-root',
Expand All @@ -9,6 +16,11 @@ import { RouterOutlet } from '@angular/router';
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
export class AppComponent implements OnInit {
#store = inject(Store);
title = 'osf';

ngOnInit(): void {
this.#store.dispatch(GetCurrentUser);
}
}
9 changes: 2 additions & 7 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@ import Aura from '@primeng/themes/aura';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideHttpClient } from '@angular/common/http';
import { ConfirmationService } from 'primeng/api';
import { AuthState } from '@core/store/auth';
import { HomeState } from '@core/store/home';
import { ResourceFiltersState } from '@shared/components/resources/resource-filters/store/resource-filters.state';
import { STATES } from '@core/helpers/ngxs-states.constant';
import { provideServiceWorker } from '@angular/service-worker';

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideStore(
[AuthState, HomeState, ResourceFiltersState],
withNgxsReduxDevtoolsPlugin({ disabled: false }),
),
provideStore(STATES, withNgxsReduxDevtoolsPlugin({ disabled: false })),
providePrimeNG({
theme: {
preset: Aura,
Expand Down
6 changes: 5 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import { NgModule } from '@angular/core';
import { NgxsModule } from '@ngxs/store';
import { AuthState } from '@core/store/auth';
import { HomeState } from '@core/store/home';
import { TokensState } from '@core/store/settings';
import { AddonsState } from '@core/store/settings/addons';

@NgModule({
imports: [NgxsModule.forRoot([AuthState, HomeState])],
imports: [
NgxsModule.forRoot([AuthState, TokensState, AddonsState, HomeState]),
],
})
export class AppModule {}
2 changes: 1 addition & 1 deletion src/app/core/components/topnav/topnav.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@use "assets/styles/mixins" as mix;

:host {
z-index: 2000;
z-index: 1300;

.nav-container {
@include mix.flex-center-between;
Expand Down
13 changes: 13 additions & 0 deletions src/app/core/helpers/ngxs-states.constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AuthState } from '@core/store/auth';
import { TokensState } from '@core/store/settings';
import { AddonsState } from '@core/store/settings/addons';
import { UserState } from '@core/store/user';
import { HomeState } from '@core/store/home';

export const STATES = [
AuthState,
TokensState,
AddonsState,
UserState,
HomeState,
];
9 changes: 3 additions & 6 deletions src/app/core/services/json-api/json-api.entity.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
export interface JsonApiResponse<T> {
data: T;
}

export interface JsonApiArrayResponse<T> {
data: T[];
export interface JsonApiResponse<Data, Included> {
data: Data;
included?: Included;
}

export interface ApiData<Attributes, Embeds> {
Expand Down
48 changes: 28 additions & 20 deletions src/app/core/services/json-api/json-api.service.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import { inject, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { map, Observable } from 'rxjs';
import {
JsonApiArrayResponse,
JsonApiResponse,
} from '@core/services/json-api/json-api.entity';
import { JsonApiResponse } from '@core/services/json-api/json-api.entity';

@Injectable({
providedIn: 'root',
})
export class JsonApiService {
http: HttpClient = inject(HttpClient);
readonly #token =
'Bearer 2rjFZwmdDG4rtKj7hGkEMO6XyHBM2lN7XBbsA1e8OqcFhOWu6Z7fQZiheu9RXtzSeVrgOt';
readonly #headers = new HttpHeaders({
Authorization: this.#token,
Accept: 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json',
});

get<T>(url: string, params?: Record<string, unknown>): Observable<T> {
return this.http
.get<JsonApiResponse<T>>(url, { params: this.buildHttpParams(params) })
.pipe(map((response) => response.data));
}

getArray<T>(url: string, params?: Record<string, unknown>): Observable<T[]> {
const headers = new HttpHeaders({
Authorization: 'ENTER_VALID_PAT',
return this.http.get<T>(url, {
params: this.buildHttpParams(params),
headers: this.#headers,
});

return this.http
.get<JsonApiArrayResponse<T>>(url, {
params: this.buildHttpParams(params),
headers: headers,
})
.pipe(map((response) => response.data));
}

private buildHttpParams(params?: Record<string, unknown>): HttpParams {
Expand All @@ -40,7 +32,7 @@ export class JsonApiService {

if (Array.isArray(value)) {
value.forEach((item) => {
httpParams = httpParams.append(`${key}[]`, item); // Handles arrays
httpParams = httpParams.append(`${key}`, item);
});
} else {
httpParams = httpParams.set(key, value as string);
Expand All @@ -50,4 +42,20 @@ export class JsonApiService {

return httpParams;
}

post<T>(url: string, body: unknown): Observable<T> {
return this.http
.post<JsonApiResponse<T, null>>(url, body, { headers: this.#headers })
.pipe(map((response) => response.data));
}

patch<T>(url: string, body: unknown): Observable<T> {
return this.http
.patch<JsonApiResponse<T, null>>(url, body, { headers: this.#headers })
.pipe(map((response) => response.data));
}

delete(url: string): Observable<void> {
return this.http.delete<void>(url, { headers: this.#headers });
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
export interface UserUS {
full_name: string;
given_name: string;
id: string;
type: string;
attributes: {
full_name: string;
given_name: string;
family_name: string;
email: string;
};
relationships: Record<string, unknown>;
links: Record<string, string>;
}
7 changes: 5 additions & 2 deletions src/app/core/services/mappers/users/users.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { UserUS } from '@core/services/json-api/underscore-entites/user/user-us.

export function mapUserUStoUser(user: UserUS): User {
return {
fullName: user.full_name,
givenName: user.given_name,
id: user.id,
fullName: user.attributes.full_name,
givenName: user.attributes.given_name,
familyName: user.attributes.family_name,
email: user.attributes.email,
};
}
2 changes: 2 additions & 0 deletions src/app/core/services/user/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export interface User {
id: string;
fullName: string;
givenName: string;
familyName: string;
email?: string;
}
16 changes: 11 additions & 5 deletions src/app/core/services/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { inject, Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';
import { JsonApiService } from '@core/services/json-api/json-api.service';
import { User } from '@core/services/user/user.entity';
import { UserUS } from '@core/services/json-api/underscore-entites/user/user-us.entity';
import { mapUserUStoUser } from '@core/services/mappers/users/users.mapper';
import { JsonApiResponse } from '@core/services/json-api/json-api.entity';

@Injectable({
providedIn: 'root',
})
export class UserService {
baseUrl = 'https://api.staging4.osf.io/v2/';
jsonApiService = inject(JsonApiService);

// getMe(): Observable<User> {
// return this.jsonApiService
// .get<UserUS>('https://api.test.osf.io/v2/users/me')
// .pipe(map((user) => mapUserUStoUser(user)));
// }
getCurrentUser(): Observable<User> {
return this.jsonApiService
.get<JsonApiResponse<UserUS, null>>(this.baseUrl + 'users/me')
.pipe(map((user) => mapUserUStoUser(user.data)));
}
}
53 changes: 53 additions & 0 deletions src/app/core/store/settings/addons/addons.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { AddonRequest } from '@osf/features/settings/addons/entities/addons.entities';

export class GetStorageAddons {
static readonly type = '[Addons] Get Storage Addons';
}

export class GetCitationAddons {
static readonly type = '[Addons] Get Citation Addons';
}

export class GetAuthorizedStorageAddons {
static readonly type = '[Addons] Get Authorized Storage Addons';

constructor(public referenceId: string) {}
}

export class GetAuthorizedCitationAddons {
static readonly type = '[Addons] Get Authorized Citation Addons';

constructor(public referenceId: string) {}
}

export class CreateAuthorizedAddon {
static readonly type = '[Addons] Create Storage Addon';

constructor(
public payload: AddonRequest,
public addonType: string,
) {}
}

export class UpdateAuthorizedAddon {
static readonly type = '[Addons] Update Storage Addon';

constructor(
public payload: AddonRequest,
public addonType: string,
public addonId: string,
) {}
}

export class GetAddonsUserReference {
static readonly type = '[Addons] Get Addons User Reference';
}

export class DeleteAuthorizedAddon {
static readonly type = '[Addons] Delete Authorized Addon';

constructor(
public payload: string,
public addonType: string,
) {}
}
15 changes: 15 additions & 0 deletions src/app/core/store/settings/addons/addons.models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {
Addon,
AuthorizedAddon,
AddonResponse,
UserReference,
} from '@osf/features/settings/addons/entities/addons.entities';

export interface AddonsStateModel {
storageAddons: Addon[];
citationAddons: Addon[];
authorizedStorageAddons: AuthorizedAddon[];
authorizedCitationAddons: AuthorizedAddon[];
addonsUserReference: UserReference[];
createdUpdatedAuthorizedAddon: AddonResponse | null;
}
36 changes: 36 additions & 0 deletions src/app/core/store/settings/addons/addons.selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Selector } from '@ngxs/store';
import { AddonsStateModel } from './addons.models';
import { Addon } from '@osf/features/settings/addons/entities/addons.entities';
import { AddonsState } from '@core/store/settings/addons/addons.state';

export class AddonsSelectors {
@Selector([AddonsState])
static getStorageAddons(state: AddonsStateModel): Addon[] {
return state.storageAddons;
}

@Selector([AddonsState])
static getCitationAddons(state: AddonsStateModel): Addon[] {
return state.citationAddons;
}

@Selector([AddonsState])
static getAuthorizedStorageAddons(state: AddonsStateModel) {
return state.authorizedStorageAddons;
}

@Selector([AddonsState])
static getAuthorizedCitationAddons(state: AddonsStateModel) {
return state.authorizedCitationAddons;
}

@Selector([AddonsState])
static getAddonUserReference(state: AddonsStateModel) {
return state.addonsUserReference;
}

@Selector([AddonsState])
static getCreatedOrUpdatedStorageAddon(state: AddonsStateModel) {
return state.createdUpdatedAuthorizedAddon;
}
}
Loading