Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
26f117e
[ENG-10048] Add Registry Name to Registration Metadata (#858)
nsemets Jan 30, 2026
bf56c47
[ENG-10047] Display Affiliated Institution(s) on User Profile Page (#…
mkovalua Jan 30, 2026
cd31559
ENG-9720 | fix(addons): Fix GitLab pagination Load More button not sh…
sh-andriy Jan 30, 2026
0113de1
[ENG-9042] Each registries, preprints, and collections provider sets …
mkovalua Jan 30, 2026
4d85d51
[ENG-6719] Show Funder and Grant ID information on registries moderat…
mkovalua Jan 30, 2026
90213a3
fix(ssr-routes): removed home route due to auth (#866)
nsemets Jan 30, 2026
a2a9f35
[ENG-10148] Fix frontend state-management bug causing stale facet res…
nsemets Feb 2, 2026
91f8e0d
[ENG-10251] Standardize model file naming convention (#874)
nsemets Feb 6, 2026
ae6fc32
[ENG-10252] Add unit tests for the previously skipped tests in projec…
nsemets Feb 11, 2026
571ea01
[ENG-9157] [AOI] Add atomic ability to remove contributors from child…
nsemets Feb 13, 2026
5bb1c44
[ENG-10255] Part 1: Added unit tests for pages components in registri…
nsemets Feb 17, 2026
a13b596
[ENG-10255] Part 2: Added unit tests for pages components in registri…
nsemets Feb 17, 2026
b6e7d56
[ENG-9043] v2 (#878)
mkovalua Feb 17, 2026
2a6b2f1
[ENG-10255] Part 3: Added unit tests for pages components in registri…
nsemets Feb 17, 2026
70339af
[ENG-10042] fix(registry): moderators cannot approve registration upd…
Vlad0n20 Feb 18, 2026
5a3adbf
[ENG-10255] Part 4: Add unit test coverage for registries (#892)
nsemets Feb 20, 2026
38a7e46
[ENG-9731] Create a "tombstone" page for content that is flagged as s…
mkovalua Mar 3, 2026
2ae4c46
[ENG-10364] Part 1: Add unit tests for preprints (#895)
nsemets Mar 4, 2026
266a2da
[ENG-10364] Part 2: Add unit tests for preprints (#898)
nsemets Mar 4, 2026
eb2c7cf
[ENG-10364] Part 3: Add unit tests for preprints (#900)
nsemets Mar 4, 2026
71f3a65
fix(commands): updated commands for angular serve
nsemets Mar 5, 2026
ee5d1bb
fix(ENG-10087): Update preprint download url (#901)
Vlad0n20 Mar 5, 2026
83b7340
Merge remote-tracking branch 'upstream/feature/pbs-26-2' into pbs-26-2
nsemets Mar 5, 2026
4a85dd3
[ENG-10364] Part 4: Add unit tests for preprints (#902)
nsemets Mar 6, 2026
e8b9929
Merge remote-tracking branch 'upstream/feature/pbs-26-2' into pbs-26-2
nsemets Mar 10, 2026
1325bc9
[ENG-10529] Users can still submit to registries that are closed to n…
mkovalua Mar 10, 2026
2372b48
fix(ENG-10424): Fix view files in files section using VOL (#904)
Vlad0n20 Mar 10, 2026
d226c70
feat(registries): Add SCORE as registration provider (#905)
futa-ikeda Mar 10, 2026
fe1fc61
[ENG-10560] Make angular routing redirects have rel canonical links (…
nsemets Mar 13, 2026
dcfe028
Merge remote-tracking branch 'upstream/feature/pbs-26-2' into pbs-26-2
nsemets Mar 13, 2026
b37bb83
Merge remote-tracking branch 'upstream/develop' into fix/develop-merge
nsemets Mar 16, 2026
79e7732
Merge pull request #909 from nsemets/fix/develop-merge
adlius Mar 16, 2026
4909e37
Merge branch 'develop' into feature/pbs-26-2
adlius Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion docs/ngxs.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Typical NGXS-related files are organized as follows:
src/app/shared/stores/
└── addons/
├── addons.actions.ts # All action definitions
├── addons.models.ts # Interfaces & data models
├── addons.model.ts # Interfaces & data model
├── addons.state.ts # State implementation
├── addons.selectors.ts # Reusable selectors
```
Expand Down
975 changes: 762 additions & 213 deletions docs/testing.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module.exports = {
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
globalSetup: '<rootDir>/jest.global-setup.ts',
collectCoverage: false,
clearMocks: true,
restoreMocks: true,
coverageReporters: ['json-summary', 'lcov', 'clover'],
moduleNameMapper: {
'^@osf/(.*)$': '<rootDir>/src/app/$1',
Expand Down Expand Up @@ -36,12 +38,10 @@ module.exports = {
'!src/app/app.config.ts',
'!src/app/app.routes.ts',
'!src/app/**/*.routes.{ts,js}',
'!src/app/**/**/*.routes.{ts,js}',
'!src/app/**/*.route.{ts,js}',
'!src/app/**/mappers/**',
'!src/app/shared/mappers/**',
'!src/app/**/*.models.{ts.js}',
'!src/app/**/*.model.{ts.js}',
'!src/app/**/*.model.{ts,js}',
'!src/app/**/models/*.{ts,js}',
'!src/app/shared/models/**',
'!src/app/**/*.enum.{ts,js}',
Expand All @@ -54,10 +54,10 @@ module.exports = {
extensionsToTreatAsEsm: ['.ts'],
coverageThreshold: {
global: {
branches: 34.8,
functions: 38.0,
lines: 65.5,
statements: 66.0,
branches: 43.3,
functions: 42.7,
lines: 69.3,
statements: 69.8,
},
},
watchPathIgnorePatterns: [
Expand Down
8 changes: 8 additions & 0 deletions setup-jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,11 @@ jest.mock('@newrelic/browser-agent/loaders/browser-agent', () => ({
stop: jest.fn(),
})),
}));

if (!globalThis.structuredClone) {
Object.defineProperty(globalThis, 'structuredClone', {
value: <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T,
writable: true,
configurable: true,
});
}
4 changes: 0 additions & 4 deletions src/app/app.routes.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ export const serverRoutes: ServerRoute[] = [
path: 'forgotpassword',
renderMode: RenderMode.Prerender,
},
{
path: '',
renderMode: RenderMode.Prerender,
},
{
path: 'dashboard',
renderMode: RenderMode.Client,
Expand Down
15 changes: 15 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ export const routes: Routes = [
'@osf/features/preprints/pages/preprint-pending-moderation/preprint-pending-moderation.component'
).then((mod) => mod.PreprintPendingModerationComponent),
},
{
path: 'preprints/:providerId/:id/download',
loadComponent: () =>
import('@osf/features/preprints/pages/preprint-download-redirect/preprint-download-redirect.component').then(
(c) => c.PreprintDownloadRedirectComponent
),
},
{
path: 'preprints/:providerId/:id',
loadComponent: () =>
Expand Down Expand Up @@ -175,6 +182,14 @@ export const routes: Routes = [
import('./core/components/page-not-found/page-not-found.component').then((mod) => mod.PageNotFoundComponent),
data: { skipBreadcrumbs: true },
},
{
path: 'spam-content',
loadComponent: () =>
import('./core/components/resource-is-spammed/resource-is-spammed.component').then(
(mod) => mod.ResourceIsSpammedComponent
),
data: { skipBreadcrumbs: true },
},
{
path: 'project/:id/node/:nodeId/files/:provider/:fileId',
loadComponent: () =>
Expand Down
39 changes: 0 additions & 39 deletions src/app/core/animations/fade.in-out.animation.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Component: Cookie Consent Banner', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [OSFTestingModule, CookieConsentBannerComponent, MockComponent(IconComponent)],
imports: [CookieConsentBannerComponent, OSFTestingModule, MockComponent(IconComponent)],
providers: [{ provide: CookieService, useValue: cookieServiceMock }],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,20 @@ import { Message } from 'primeng/message';
import { isPlatformBrowser } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, PLATFORM_ID, signal } from '@angular/core';

import { fadeInOutAnimation } from '@core/animations/fade.in-out.animation';
import { IconComponent } from '@osf/shared/components/icon/icon.component';

/**
* Displays a cookie consent banner until the user accepts.
*
* - Uses `ngx-cookie-service` to persist acceptance across sessions.
* - Automatically hides the banner if consent is already recorded.
* - Animates in/out using the `fadeInOutAnimation`.
* - Supports translation via `TranslatePipe`.
*/
@Component({
selector: 'osf-cookie-consent-banner',
templateUrl: './cookie-consent-banner.component.html',
styleUrls: ['./cookie-consent-banner.component.scss'],
imports: [Button, TranslatePipe, IconComponent, Message],
animations: [fadeInOutAnimation],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CookieConsentBannerComponent {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
@if (maintenance() && !dismissed()) {
<p-message
class="block p-3"
styleClass="w-full"
icon="pi pi-info-circle"
[severity]="maintenance()?.severity"
[text]="maintenance()?.message"
[closable]="true"
(onClose)="dismiss()"
class="block p-3"
icon="pi pi-info-circle"
@fadeInOut
>
</p-message>
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { CookieService } from 'ngx-cookie-service';

import { MessageModule } from 'primeng/message';

import { of } from 'rxjs';

import { HttpClient } from '@angular/common/http';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

import { MaintenanceBannerComponent } from './maintenance-banner.component';

import { OSFTestingModule } from '@testing/osf.testing.module';

describe('Component: Maintenance Banner', () => {
let fixture: ComponentFixture<MaintenanceBannerComponent>;
let httpClient: { get: jest.Mock };
Expand All @@ -25,7 +24,7 @@ describe('Component: Maintenance Banner', () => {
httpClient = { get: jest.fn() } as any;

await TestBed.configureTestingModule({
imports: [MaintenanceBannerComponent, NoopAnimationsModule, MessageModule],
imports: [MaintenanceBannerComponent, OSFTestingModule],
providers: [
{ provide: CookieService, useValue: cookieService },
{ provide: HttpClient, useValue: httpClient },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { MessageModule } from 'primeng/message';
import { CommonModule, isPlatformBrowser } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, OnInit, PLATFORM_ID, signal } from '@angular/core';

import { fadeInOutAnimation } from '@core/animations/fade.in-out.animation';

import { MaintenanceModel } from '../models/maintenance.model';
import { MaintenanceService } from '../services/maintenance.service';

Expand All @@ -17,8 +15,6 @@ import { MaintenanceService } from '../services/maintenance.service';
* the banner. If not, it queries the maintenance status from the server and displays
* the maintenance message if one is active.
*
* The component supports animation via `fadeInOutAnimation` and is optimized with `OnPush` change detection.
*
* @example
* ```html
* <osf-maintenance-banner />
Expand All @@ -29,7 +25,6 @@ import { MaintenanceService } from '../services/maintenance.service';
imports: [CommonModule, MessageModule],
templateUrl: './maintenance-banner.component.html',
styleUrls: ['./maintenance-banner.component.scss'],
animations: [fadeInOutAnimation],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MaintenanceBannerComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<section class="text-center flex flex-column flex-1 my-7 mx-3 p-3 md:p-4">
<h2>{{ 'resourceSpammed.title' | translate }}</h2>

<p class="my-4">
{{ 'resourceSpammed.message' | translate }}
</p>

<p>
<span>{{ 'resourceSpammed.contact' | translate }}</span>
<a class="ml-1 font-bold" [href]="'mailto:' + supportEmail">{{ supportEmail }} </a>
<span>{{ 'resourceSpammed.footer' | translate }}</span>
</p>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@use "styles/mixins" as mix;

:host {
@include mix.flex-center;
flex: 1;
background: var(--gradient-3);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ResourceIsSpammedComponent } from './resource-is-spammed.component';

import { provideOSFCore } from '@testing/osf.testing.provider';

describe('ResourceIsSpammedComponent', () => {
let component: ResourceIsSpammedComponent;
let fixture: ComponentFixture<ResourceIsSpammedComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [ResourceIsSpammedComponent],
providers: [provideOSFCore()],
});

fixture = TestBed.createComponent(ResourceIsSpammedComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should set supportEmail from environment token', () => {
expect(component.supportEmail).toBe('support@test.com');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TranslatePipe } from '@ngx-translate/core';

import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ENVIRONMENT } from '@core/provider/environment.provider';

@Component({
selector: 'osf-resource-is-spammed',
imports: [TranslatePipe],
templateUrl: './resource-is-spammed.component.html',
styleUrl: './resource-is-spammed.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ResourceIsSpammedComponent {
private readonly environment = inject(ENVIRONMENT);
readonly supportEmail = this.environment.supportEmail;
}
2 changes: 1 addition & 1 deletion src/app/core/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { inject, Injectable } from '@angular/core';
import { ENVIRONMENT } from '@core/provider/environment.provider';
import { ProfileSettingsKey } from '@osf/shared/enums/profile-settings-key.enum';
import { UserMapper } from '@osf/shared/mappers/user';
import { UserData, UserModel } from '@osf/shared/models/user/user.model';
import { JsonApiService } from '@osf/shared/services/json-api.service';
import { ProfileSettingsUpdate } from '@shared/models/profile-settings-update.model';
import { UserData, UserModel } from '@shared/models/user/user.models';
import {
UserAcceptedTermsOfServiceJsonApi,
UserDataJsonApi,
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/store/user/user.actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Education } from '@osf/shared/models/user/education.model';
import { Employment } from '@osf/shared/models/user/employment.model';
import { SocialModel } from '@osf/shared/models/user/social.model';
import { UserModel } from '@osf/shared/models/user/user.models';
import { UserModel } from '@osf/shared/models/user/user.model';

export class GetCurrentUser {
static readonly type = '[User] Get Current User';
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/store/user/user.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AsyncStateModel } from '@osf/shared/models/store/async-state.model';
import { UserModel } from '@osf/shared/models/user/user.models';
import { UserModel } from '@osf/shared/models/user/user.model';

export interface UserStateModel {
currentUser: AsyncStateModel<UserModel | null>;
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/store/user/user.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Selector } from '@ngxs/store';
import { Education } from '@osf/shared/models/user/education.model';
import { Employment } from '@osf/shared/models/user/employment.model';
import { SocialModel } from '@osf/shared/models/user/social.model';
import { UserModel } from '@osf/shared/models/user/user.models';
import { UserModel } from '@osf/shared/models/user/user.model';

import { UserStateModel } from './user.model';
import { UserState } from './user.state';
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/store/user/user.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { UserService } from '@core/services/user.service';
import { ProfileSettingsKey } from '@osf/shared/enums/profile-settings-key.enum';
import { removeNullable } from '@osf/shared/helpers/remove-nullable.helper';
import { UserMapper } from '@osf/shared/mappers/user';
import { UserModel } from '@osf/shared/models/user/user.model';
import { SocialModel } from '@shared/models/user/social.model';
import { UserModel } from '@shared/models/user/user.models';

import {
AcceptTermsOfServiceByUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ActivatedRoute } from '@angular/router';
import { BarChartComponent } from '@osf/shared/components/bar-chart/bar-chart.component';
import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/loading-spinner.component';
import { StatisticCardComponent } from '@osf/shared/components/statistic-card/statistic-card.component';
import { DatasetInput } from '@osf/shared/models/charts/dataset-input';
import { DatasetInput } from '@osf/shared/models/charts/dataset-input.model';
import { SelectOption } from '@osf/shared/models/select-option.model';
import { DoughnutChartComponent } from '@shared/components/doughnut-chart/doughnut-chart.component';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Institution } from '@osf/shared/models/institutions/institutions.models';
import { Institution } from '@osf/shared/models/institutions/institutions.model';
import { AsyncStateModel } from '@osf/shared/models/store/async-state.model';
import { AsyncStateWithTotalCount } from '@osf/shared/models/store/async-state-with-total-count.model';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Selector } from '@ngxs/store';

import { Institution } from '@osf/shared/models/institutions/institutions.models';
import { Institution } from '@osf/shared/models/institutions/institutions.model';

import { InstitutionDepartment, InstitutionSearchFilter, InstitutionSummaryMetrics, InstitutionUser } from '../models';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { catchError, tap, throwError } from 'rxjs';
import { inject, Injectable } from '@angular/core';

import { handleSectionError } from '@osf/shared/helpers/state-error.handler';
import { Institution } from '@osf/shared/models/institutions/institutions.models';
import { Institution } from '@osf/shared/models/institutions/institutions.model';
import { InstitutionsService } from '@osf/shared/services/institutions.service';

import { InstitutionsAdminService } from '../services/institutions-admin.service';
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/analytics/analytics.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { ViewOnlyLinkMessageComponent } from '@osf/shared/components/view-only-l
import { IS_WEB } from '@osf/shared/helpers/breakpoints.tokens';
import { replaceBadEncodedChars } from '@osf/shared/helpers/format-bad-encoding.helper';
import { Primitive } from '@osf/shared/helpers/types.helper';
import { DatasetInput } from '@osf/shared/models/charts/dataset-input';
import { DatasetInput } from '@osf/shared/models/charts/dataset-input.model';
import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service';

import { AnalyticsKpiComponent } from './components';
Expand Down
Loading
Loading