diff --git a/src/app/core/auth/auth.actions.ts b/src/app/core/auth/auth.actions.ts index 60440d371e..6bc4565682 100644 --- a/src/app/core/auth/auth.actions.ts +++ b/src/app/core/auth/auth.actions.ts @@ -17,6 +17,7 @@ export const AuthActionTypes = { AUTHENTICATED_SUCCESS: type('dspace/auth/AUTHENTICATED_SUCCESS'), CHECK_AUTHENTICATION_TOKEN: type('dspace/auth/CHECK_AUTHENTICATION_TOKEN'), CHECK_AUTHENTICATION_TOKEN_COOKIE: type('dspace/auth/CHECK_AUTHENTICATION_TOKEN_COOKIE'), + SET_AUTH_COOKIE_STATUS: type('dspace/auth/SET_AUTH_COOKIE_STATUS'), RETRIEVE_AUTH_METHODS: type('dspace/auth/RETRIEVE_AUTH_METHODS'), RETRIEVE_AUTH_METHODS_SUCCESS: type('dspace/auth/RETRIEVE_AUTH_METHODS_SUCCESS'), RETRIEVE_AUTH_METHODS_ERROR: type('dspace/auth/RETRIEVE_AUTH_METHODS_ERROR'), @@ -150,6 +151,19 @@ export class CheckAuthenticationTokenCookieAction implements Action { public type: string = AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE; } +/** + * Sets the authentication cookie status to flag an external authentication response. + */ +export class SetAuthCookieStatus implements Action { + public type: string = AuthActionTypes.SET_AUTH_COOKIE_STATUS; + + payload = false; + + constructor(exists: boolean) { + this.payload = exists; + } +} + /** * Sign out. * @class LogOutAction @@ -425,6 +439,7 @@ export type AuthActions | AuthenticationSuccessAction | CheckAuthenticationTokenAction | CheckAuthenticationTokenCookieAction + | SetAuthCookieStatus | RedirectWhenAuthenticationIsRequiredAction | RedirectWhenTokenExpiredAction | AddAuthenticationMessageAction diff --git a/src/app/core/auth/auth.effects.spec.ts b/src/app/core/auth/auth.effects.spec.ts index f09db04d99..2e6ba917aa 100644 --- a/src/app/core/auth/auth.effects.spec.ts +++ b/src/app/core/auth/auth.effects.spec.ts @@ -214,12 +214,15 @@ describe('AuthEffects', () => { authenticated: true }) ); + spyOn((authEffects as any).authService, 'setExternalAuthStatus'); actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE } }); const expected = cold('--b-', { b: new RetrieveTokenAction() }); expect(authEffects.checkTokenCookie$).toBeObservable(expected); authEffects.checkTokenCookie$.subscribe(() => { + expect(authServiceStub.setExternalAuthStatus).toHaveBeenCalled(); + expect(authServiceStub.isExternalAuthentication).toBeTrue(); expect((authEffects as any).authorizationsService.invalidateAuthorizationsRequestCache).toHaveBeenCalled(); }); }); diff --git a/src/app/core/auth/auth.effects.ts b/src/app/core/auth/auth.effects.ts index 22d1bf35e7..281355b769 100644 --- a/src/app/core/auth/auth.effects.ts +++ b/src/app/core/auth/auth.effects.ts @@ -153,6 +153,7 @@ export class AuthEffects { return this.authService.checkAuthenticationCookie().pipe( map((response: AuthStatus) => { if (response.authenticated) { + this.authService.setExternalAuthStatus(true); this.authorizationsService.invalidateAuthorizationsRequestCache(); return new RetrieveTokenAction(); } else { diff --git a/src/app/core/auth/auth.reducer.spec.ts b/src/app/core/auth/auth.reducer.spec.ts index 8ebc9f6cb0..c0619adf79 100644 --- a/src/app/core/auth/auth.reducer.spec.ts +++ b/src/app/core/auth/auth.reducer.spec.ts @@ -8,6 +8,7 @@ import { AuthenticationErrorAction, AuthenticationSuccessAction, CheckAuthenticationTokenAction, + SetAuthCookieStatus, CheckAuthenticationTokenCookieAction, LogOutAction, LogOutErrorAction, @@ -219,6 +220,28 @@ describe('authReducer', () => { expect(newState).toEqual(state); }); + it('should set the authentication cookie status in response to a SET_AUTH_COOKIE_STATUS action', () => { + initialState = { + authenticated: true, + loaded: false, + blocking: false, + loading: true, + externalAuth: false, + idle: false + }; + const action = new SetAuthCookieStatus(true); + const newState = authReducer(initialState, action); + state = { + authenticated: true, + loaded: false, + blocking: false, + loading: true, + externalAuth: true, + idle: false + }; + expect(newState).toEqual(state); + }); + it('should properly set the state, in response to a LOG_OUT action', () => { initialState = { authenticated: true, diff --git a/src/app/core/auth/auth.reducer.ts b/src/app/core/auth/auth.reducer.ts index acdb8ef812..ba9c41326a 100644 --- a/src/app/core/auth/auth.reducer.ts +++ b/src/app/core/auth/auth.reducer.ts @@ -10,7 +10,7 @@ import { RedirectWhenTokenExpiredAction, RefreshTokenSuccessAction, RetrieveAuthenticatedEpersonSuccessAction, - RetrieveAuthMethodsSuccessAction, + RetrieveAuthMethodsSuccessAction, SetAuthCookieStatus, SetRedirectUrlAction } from './auth.actions'; // import models @@ -59,6 +59,8 @@ export interface AuthState { // all authentication Methods enabled at the backend authMethods?: AuthMethod[]; + externalAuth?: boolean, + // true when the current user is idle idle: boolean; @@ -73,6 +75,7 @@ const initialState: AuthState = { blocking: true, loading: false, authMethods: [], + externalAuth: false, idle: false }; @@ -104,6 +107,11 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut loading: true, }); + case AuthActionTypes.SET_AUTH_COOKIE_STATUS: + return Object.assign({}, state, { + externalAuth: (action as SetAuthCookieStatus).payload + }); + case AuthActionTypes.AUTHENTICATED_ERROR: case AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_ERROR: return Object.assign({}, state, { diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 3034c00197..6604936cde 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -25,7 +25,7 @@ import { import { CookieService } from '../services/cookie.service'; import { getAuthenticatedUserId, - getAuthenticationToken, + getAuthenticationToken, getExternalAuthCookieStatus, getRedirectUrl, isAuthenticated, isAuthenticatedLoaded, @@ -36,7 +36,7 @@ import { AppState } from '../../app.reducer'; import { CheckAuthenticationTokenAction, RefreshTokenAction, - ResetAuthenticationMessagesAction, + ResetAuthenticationMessagesAction, SetAuthCookieStatus, SetRedirectUrlAction, SetUserAsIdleAction, UnsetUserAsIdleAction @@ -156,6 +156,24 @@ export class AuthService { return this.store.pipe(select(isAuthenticatedLoaded)); } + /** + * Used to set the external authentication status when authenticating via an + * external authentication system (e.g. Shibboleth). + * @param external + */ + public setExternalAuthStatus(external: boolean) { + this.store.dispatch(new SetAuthCookieStatus(external)); + } + + /** + * Returns true if an external authentication system (e.g. Shibboleth) is being used + * for authentication. Returns false otherwise. + */ + public isExternalAuthentication(): Observable { + return this.store.pipe( + select(getExternalAuthCookieStatus)); + } + /** * Returns the href link to authenticated user * @returns {string} diff --git a/src/app/core/auth/selectors.ts b/src/app/core/auth/selectors.ts index ce8d38d6ba..aba739edf6 100644 --- a/src/app/core/auth/selectors.ts +++ b/src/app/core/auth/selectors.ts @@ -116,6 +116,8 @@ const _getRedirectUrl = (state: AuthState) => state.redirectUrl; const _getAuthenticationMethods = (state: AuthState) => state.authMethods; +const _getExternalAuthCookieStatus = (state: AuthState) => state.externalAuth; + /** * Returns true if the user is idle. * @function _isIdle @@ -178,6 +180,16 @@ export const isAuthenticated = createSelector(getAuthState, _isAuthenticated); */ export const isAuthenticatedLoaded = createSelector(getAuthState, _isAuthenticatedLoaded); +/** + * Returns the authentication cookie status. Expect to be true when external authentication + * is used. + * @function getExternalAuthCookieStatus + * @param {AuthState} state + * @param {any} props + * @return {boolean} + */ +export const getExternalAuthCookieStatus = createSelector(getAuthState, _getExternalAuthCookieStatus); + /** * Returns true if the authentication request is loading. * @function isAuthenticationLoading diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 0237a9eb53..319b42d58b 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -176,6 +176,7 @@ import { VocabularyEntryDetailsDataService } from './submission/vocabularies/voc import { IdentifierData } from '../shared/object-list/identifier-data/identifier-data.model'; import { Subscription } from '../shared/subscriptions/models/subscription.model'; import { SupervisionOrderDataService } from './supervision-order/supervision-order-data.service'; +import { ItemRequest } from './shared/item-request.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -369,6 +370,7 @@ export const models = AccessStatusObject, IdentifierData, Subscription, + ItemRequest, ]; @NgModule({ diff --git a/src/app/footer/themed-footer.component.ts b/src/app/footer/themed-footer.component.ts index c52a0af29f..e8f64f3434 100644 --- a/src/app/footer/themed-footer.component.ts +++ b/src/app/footer/themed-footer.component.ts @@ -7,7 +7,7 @@ import { FooterComponent } from './footer.component'; */ @Component({ selector: 'ds-themed-footer', - styleUrls: ['footer.component.scss'], + styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', }) export class ThemedFooterComponent extends ThemedComponent { @@ -20,6 +20,6 @@ export class ThemedFooterComponent extends ThemedComponent { } protected importUnthemedComponent(): Promise { - return import(`./footer.component`); + return import('./footer.component'); } } diff --git a/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts b/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts index 7f9c181fe2..02d09c44ef 100644 --- a/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts +++ b/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts @@ -3,11 +3,11 @@ import { ThemedComponent } from '../shared/theme-support/themed.component'; import { HeaderNavbarWrapperComponent } from './header-navbar-wrapper.component'; /** - * Themed wrapper for BreadcrumbsComponent + * Themed wrapper for {@link HeaderNavbarWrapperComponent} */ @Component({ selector: 'ds-themed-header-navbar-wrapper', - styleUrls: ['./themed-header-navbar-wrapper.component.scss'], + styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', }) export class ThemedHeaderNavbarWrapperComponent extends ThemedComponent { @@ -20,6 +20,6 @@ export class ThemedHeaderNavbarWrapperComponent extends ThemedComponent { - return import(`./header-navbar-wrapper.component`); + return import('./header-navbar-wrapper.component'); } } diff --git a/src/app/home-page/themed-home-page.component.ts b/src/app/home-page/themed-home-page.component.ts index e50f955cb1..c0ef723b38 100644 --- a/src/app/home-page/themed-home-page.component.ts +++ b/src/app/home-page/themed-home-page.component.ts @@ -8,8 +8,6 @@ import { Component } from '@angular/core'; templateUrl: '../shared/theme-support/themed.component.html', }) export class ThemedHomePageComponent extends ThemedComponent { - protected inAndOutputNames: (keyof HomePageComponent & keyof this)[]; - protected getComponentName(): string { return 'HomePageComponent'; diff --git a/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts b/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts index 4c32ba5376..2ad43f6883 100644 --- a/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts +++ b/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { NgxGalleryImage, NgxGalleryOptions } from '@kolkov/ngx-gallery'; import { MediaViewerItem } from '../../../core/shared/media-viewer-item.model'; import { NgxGalleryAnimation } from '@kolkov/ngx-gallery'; @@ -13,15 +13,16 @@ import { AuthService } from '../../../core/auth/auth.service'; templateUrl: './media-viewer-image.component.html', styleUrls: ['./media-viewer-image.component.scss'], }) -export class MediaViewerImageComponent implements OnInit { +export class MediaViewerImageComponent implements OnChanges, OnInit { @Input() images: MediaViewerItem[]; @Input() preview?: boolean; @Input() image?: string; thumbnailPlaceholder = './assets/images/replacement_image.svg'; - galleryOptions: NgxGalleryOptions[]; - galleryImages: NgxGalleryImage[]; + galleryOptions: NgxGalleryOptions[] = []; + + galleryImages: NgxGalleryImage[] = []; /** * Whether or not the current user is authenticated @@ -33,11 +34,7 @@ export class MediaViewerImageComponent implements OnInit { ) { } - /** - * Thi method sets up the gallery settings and data - */ - ngOnInit(): void { - this.isAuthenticated$ = this.authService.isAuthenticated(); + ngOnChanges(): void { this.galleryOptions = [ { preview: this.preview !== undefined ? this.preview : true, @@ -53,7 +50,6 @@ export class MediaViewerImageComponent implements OnInit { previewFullscreen: true, }, ]; - if (this.image) { this.galleryImages = [ { @@ -67,6 +63,11 @@ export class MediaViewerImageComponent implements OnInit { } } + ngOnInit(): void { + this.isAuthenticated$ = this.authService.isAuthenticated(); + this.ngOnChanges(); + } + /** * This method convert an array of MediaViewerItem into NgxGalleryImage array * @param medias input NgxGalleryImage array diff --git a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html index 0cc854b272..73f27e4d81 100644 --- a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html +++ b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html @@ -1,23 +1,22 @@ -
+
- + -
- +
+
diff --git a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html index 9c0039d263..ff98057334 100644 --- a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html +++ b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html @@ -16,13 +16,13 @@
- + -
- +
+
diff --git a/src/app/item-page/simple/metadata-representation-list/themed-metadata-representation-list.component.ts b/src/app/item-page/simple/metadata-representation-list/themed-metadata-representation-list.component.ts index e7a526bb05..a290b82dd9 100644 --- a/src/app/item-page/simple/metadata-representation-list/themed-metadata-representation-list.component.ts +++ b/src/app/item-page/simple/metadata-representation-list/themed-metadata-representation-list.component.ts @@ -19,7 +19,7 @@ export class ThemedMetadataRepresentationListComponent extends ThemedComponent { - protected inAndOutputNames: (keyof MyDSpacePageComponent & keyof this)[]; protected getComponentName(): string { return 'MyDSpacePageComponent'; diff --git a/src/app/search-page/themed-configuration-search-page.component.ts b/src/app/search-page/themed-configuration-search-page.component.ts index e4d6e93402..e367ee5238 100644 --- a/src/app/search-page/themed-configuration-search-page.component.ts +++ b/src/app/search-page/themed-configuration-search-page.component.ts @@ -28,19 +28,18 @@ export class ThemedConfigurationSearchPageComponent extends ThemedComponent { - return import(`./configuration-search-page.component`); + return import('./configuration-search-page.component'); } } diff --git a/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts index 27c883099d..3fb338186f 100644 --- a/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts +++ b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts @@ -11,11 +11,11 @@ export class ThemedCollectionDropdownComponent extends ThemedComponent(); + @Output() searchComplete: EventEmitter = new EventEmitter(); - @Output() theOnlySelectable = new EventEmitter(); + @Output() theOnlySelectable: EventEmitter = new EventEmitter(); - @Output() selectionChange = new EventEmitter(); + @Output() selectionChange = new EventEmitter(); protected inAndOutputNames: (keyof CollectionDropdownComponent & keyof this)[] = ['entityType', 'searchComplete', 'theOnlySelectable', 'selectionChange']; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts index f3d8421365..637941ce5b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts @@ -4,27 +4,14 @@ import { RelationshipOptions } from '../../../models/relationship-options.model' import { ListableObject } from '../../../../../object-collection/shared/listable-object.model'; import { Context } from '../../../../../../core/shared/context.model'; import { Item } from '../../../../../../core/shared/item.model'; -import { SEARCH_CONFIG_SERVICE } from '../../../../../../my-dspace-page/my-dspace-page.component'; -import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { Collection } from '../../../../../../core/shared/collection.model'; import { ExternalSource } from '../../../../../../core/shared/external-source.model'; import { DsDynamicLookupRelationExternalSourceTabComponent } from './dynamic-lookup-relation-external-source-tab.component'; -import { fadeIn, fadeInOut } from '../../../../../animations/fade'; @Component({ selector: 'ds-themed-dynamic-lookup-relation-external-source-tab', styleUrls: [], templateUrl: '../../../../../theme-support/themed.component.html', - providers: [ - { - provide: SEARCH_CONFIG_SERVICE, - useClass: SearchConfigurationService - } - ], - animations: [ - fadeIn, - fadeInOut - ] }) export class ThemedDynamicLookupRelationExternalSourceTabComponent extends ThemedComponent { protected inAndOutputNames: (keyof DsDynamicLookupRelationExternalSourceTabComponent & keyof this)[] = ['label', 'listId', @@ -44,7 +31,7 @@ export class ThemedDynamicLookupRelationExternalSourceTabComponent extends Theme @Input() repeatable: boolean; - @Output() importedObject: EventEmitter = new EventEmitter(); + @Output() importedObject: EventEmitter = new EventEmitter(); @Input() externalSource: ExternalSource; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts index da998ed5a6..d44f8f84a0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts @@ -10,19 +10,11 @@ import { Item } from '../../../../../../core/shared/item.model'; import { SearchResult } from '../../../../../search/models/search-result.model'; import { SearchObjects } from '../../../../../search/models/search-objects.model'; import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model'; -import { SEARCH_CONFIG_SERVICE } from '../../../../../../my-dspace-page/my-dspace-page.component'; -import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; @Component({ selector: 'ds-themed-dynamic-lookup-relation-search-tab', styleUrls: [], templateUrl: '../../../../../theme-support/themed.component.html', - providers: [ - { - provide: SEARCH_CONFIG_SERVICE, - useClass: SearchConfigurationService - } - ] }) export class ThemedDynamicLookupRelationSearchTabComponent extends ThemedComponent { protected inAndOutputNames: (keyof DsDynamicLookupRelationSearchTabComponent & keyof this)[] = ['relationship', 'listId', @@ -51,11 +43,11 @@ export class ThemedDynamicLookupRelationSearchTabComponent extends ThemedCompone @Input() isEditRelationship: boolean; - @Output() deselectObject: EventEmitter = new EventEmitter(); + @Output() deselectObject: EventEmitter = new EventEmitter(); - @Output() selectObject: EventEmitter = new EventEmitter(); + @Output() selectObject: EventEmitter = new EventEmitter(); - @Output() resultFound: EventEmitter> = new EventEmitter>(); + @Output() resultFound: EventEmitter> = new EventEmitter(); protected getComponentName(): string { return 'DsDynamicLookupRelationSearchTabComponent'; diff --git a/src/app/shared/loading/themed-loading.component.ts b/src/app/shared/loading/themed-loading.component.ts index ffdf9d3cbe..48773d75c8 100644 --- a/src/app/shared/loading/themed-loading.component.ts +++ b/src/app/shared/loading/themed-loading.component.ts @@ -14,8 +14,8 @@ import { ThemeService } from '../theme-support/theme.service'; export class ThemedLoadingComponent extends ThemedComponent { @Input() message: string; - @Input() showMessage = true; - @Input() spinner = false; + @Input() showMessage: boolean; + @Input() spinner: boolean; protected inAndOutputNames: (keyof LoadingComponent & keyof this)[] = ['message', 'showMessage', 'spinner']; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component.ts index ea5a38e3cb..9166e42040 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component.ts @@ -1,11 +1,10 @@ -import { ChangeDetectorRef, Component, ComponentFactoryResolver, Input } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { ThemedComponent } from '../../../theme-support/themed.component'; import { ItemListPreviewComponent } from './item-list-preview.component'; import { Item } from '../../../../core/shared/item.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { SearchResult } from '../../../search/models/search-result.model'; import { WorkflowItem } from 'src/app/core/submission/models/workflowitem.model'; -import { ThemeService } from 'src/app/shared/theme-support/theme.service'; /** * Themed wrapper for ItemListPreviewComponent @@ -24,22 +23,10 @@ export class ThemedItemListPreviewComponent extends ThemedComponent { - /** - * The view mode of the this component - */ - viewMode = ViewMode.ListElement; /** * The current pagination configuration @@ -37,18 +32,20 @@ export class ThemedObjectListComponent extends ThemedComponent