Skip to content

Commit 60d8d54

Browse files
committed
Merge branch 'release/26.11.0'
2 parents 793034e + 37704e3 commit 60d8d54

246 files changed

Lines changed: 8488 additions & 3592 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
44

5+
26.11.0 (2026-05-27)
6+
====================
7+
8+
* PB&S 26-9 Release
9+
510
26.10.1 (2026-05-15)
611
====================
712

package-lock.json

Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "osf",
3-
"version": "26.10.1",
3+
"version": "26.11.0",
44
"scripts": {
55
"ng": "ng",
66
"analyze-bundle": "ng build --configuration=analyze-bundle && source-map-explorer dist/**/*.js --no-border-checks",

src/app/app.routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ export const routes: Routes = [
182182
import('./core/components/page-not-found/page-not-found.component').then((mod) => mod.PageNotFoundComponent),
183183
data: { skipBreadcrumbs: true },
184184
},
185+
{
186+
path: ':id/files/:fileGuid/preview',
187+
loadComponent: () =>
188+
import('./features/files/pages/file-preview/file-preview.component').then((m) => m.FilePreviewComponent),
189+
},
185190
{
186191
path: 'spam-content',
187192
loadComponent: () =>

src/app/core/components/layout/layout.component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919

2020
<osf-footer></osf-footer>
2121
</div>
22+
23+
@if (isMaintenanceMode()) {
24+
<section class="maintenance-overlay font-bold text-xl flex flex-column align-items-center justify-content-center">
25+
<p>{{ 'maintenance.title' | translate }}</p>
26+
<p>{{ 'maintenance.message' | translate }}</p>
27+
</section>
28+
}
2229
</main>
2330

2431
<p-confirm-dialog

src/app/core/components/layout/layout.component.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,10 @@
8484
}
8585
}
8686
}
87+
88+
.maintenance-overlay {
89+
position: fixed;
90+
inset: 0;
91+
z-index: 2000;
92+
background: var(--white);
93+
}

src/app/core/components/layout/layout.component.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { MockComponents, MockProvider } from 'ng-mocks';
22

3-
import { ConfirmationService } from 'primeng/api';
43
import { ConfirmDialog } from 'primeng/confirmdialog';
54

65
import { BehaviorSubject } from 'rxjs';
76

87
import { ComponentFixture, TestBed } from '@angular/core/testing';
98

9+
import { MaintenanceModeService } from '@core/services/maintenance-mode.service';
1010
import { IS_MEDIUM, IS_WEB } from '@osf/shared/helpers/breakpoints.tokens';
1111

1212
import { provideOSFCore } from '@testing/osf.testing.provider';
13+
import { MaintenanceModeServiceMock } from '@testing/providers/maintenance-mode.service.mock';
1314

1415
import { BreadcrumbComponent } from '../breadcrumb/breadcrumb.component';
1516
import { FooterComponent } from '../footer/footer.component';
@@ -47,7 +48,7 @@ describe('LayoutComponent', () => {
4748
provideOSFCore(),
4849
MockProvider(IS_WEB, isWebSubject),
4950
MockProvider(IS_MEDIUM, isMediumSubject),
50-
MockProvider(ConfirmationService),
51+
MockProvider(MaintenanceModeService, MaintenanceModeServiceMock.simple()),
5152
],
5253
});
5354

src/app/core/components/layout/layout.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
66
import { toSignal } from '@angular/core/rxjs-interop';
77
import { RouterOutlet } from '@angular/router';
88

9+
import { MaintenanceModeService } from '@core/services/maintenance-mode.service';
910
import { ScrollTopOnRouteChangeDirective } from '@osf/shared/directives/scroll-top.directive';
1011
import { IS_MEDIUM, IS_WEB } from '@osf/shared/helpers/breakpoints.tokens';
1112

@@ -35,6 +36,9 @@ import { TopnavComponent } from '../topnav/topnav.component';
3536
changeDetection: ChangeDetectionStrategy.OnPush,
3637
})
3738
export class LayoutComponent {
39+
private readonly maintenanceModeService = inject(MaintenanceModeService);
40+
3841
isWeb = toSignal(inject(IS_WEB));
3942
isMedium = toSignal(inject(IS_MEDIUM));
43+
isMaintenanceMode = this.maintenanceModeService.isActive;
4044
}

src/app/core/components/osf-banners/maintenance-banner/maintenance-banner.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
styleClass="w-full"
55
icon="pi pi-info-circle"
66
[severity]="maintenance()?.severity"
7-
[text]="maintenance()?.message"
87
[closable]="true"
98
(onClose)="dismiss()"
109
>
10+
{{ maintenance()?.message }}
1111
</p-message>
1212
}

src/app/core/interceptors/error.interceptor.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ import { Router } from '@angular/router';
99

1010
import { SENTRY_TOKEN } from '@core/provider/sentry.provider';
1111
import { AuthService } from '@core/services/auth.service';
12+
import { MaintenanceModeService } from '@core/services/maintenance-mode.service';
1213
import { UserSelectors } from '@core/store/user';
1314
import { ToastService } from '@osf/shared/services/toast.service';
1415
import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service';
1516

1617
import { provideOSFCore } from '@testing/osf.testing.provider';
1718
import { AuthServiceMock, AuthServiceMockType } from '@testing/providers/auth-service.mock';
1819
import { LoaderServiceMock, provideLoaderServiceMock } from '@testing/providers/loader-service.mock';
20+
import {
21+
MaintenanceModeServiceMock,
22+
MaintenanceModeServiceMockType,
23+
} from '@testing/providers/maintenance-mode.service.mock';
1924
import { RouterMockBuilder, RouterMockType } from '@testing/providers/router-provider.mock';
2025
import { SentryMock, SentryMockType } from '@testing/providers/sentry-provider.mock';
2126
import { provideMockStore } from '@testing/providers/store-provider.mock';
@@ -30,6 +35,7 @@ describe('errorInterceptor', () => {
3035
let toastServiceMock: ToastServiceMockType;
3136
let loaderServiceMock: LoaderServiceMock;
3237
let authServiceMock: AuthServiceMockType;
38+
let maintenanceModeServiceMock: MaintenanceModeServiceMockType;
3339
let viewOnlyHelperMock: ViewOnlyLinkHelperMockType;
3440
let sentryMock: SentryMockType;
3541

@@ -43,6 +49,7 @@ describe('errorInterceptor', () => {
4349
toastServiceMock = ToastServiceMock.simple();
4450
loaderServiceMock = new LoaderServiceMock();
4551
authServiceMock = AuthServiceMock.simple();
52+
maintenanceModeServiceMock = MaintenanceModeServiceMock.simple();
4653
viewOnlyHelperMock = ViewOnlyLinkHelperMock.simple(viewOnly);
4754
sentryMock = SentryMock.simple();
4855

@@ -56,6 +63,7 @@ describe('errorInterceptor', () => {
5663
MockProvider(Router, router),
5764
MockProvider(ToastService, toastServiceMock),
5865
MockProvider(AuthService, authServiceMock),
66+
MockProvider(MaintenanceModeService, maintenanceModeServiceMock),
5967
MockProvider(ViewOnlyLinkHelperService, viewOnlyHelperMock),
6068
MockProvider(PLATFORM_ID, platformId),
6169
{ provide: SENTRY_TOKEN, useValue: sentryMock },
@@ -181,4 +189,21 @@ describe('errorInterceptor', () => {
181189
expect(loaderServiceMock.hide).toHaveBeenCalled();
182190
expect(toastServiceMock.showError).not.toHaveBeenCalled();
183191
});
192+
193+
it('should activate maintenance mode on 503 maintenance response', async () => {
194+
setup('browser', false);
195+
const request = createRequest('/api/v2/');
196+
const error = new HttpErrorResponse({
197+
status: 503,
198+
error: { meta: { maintenance_mode: true } },
199+
url: request.url,
200+
});
201+
202+
const caught = await runInterceptor(request, error);
203+
204+
expect(caught?.status).toBe(503);
205+
expect(maintenanceModeServiceMock.activate).toHaveBeenCalled();
206+
expect(loaderServiceMock.hide).toHaveBeenCalled();
207+
expect(toastServiceMock.showError).not.toHaveBeenCalled();
208+
});
184209
});

0 commit comments

Comments
 (0)