Merge pull request #8121 from opf/housekeeping/lazy-loaded-boards-module

Lazy load boards module
pull/8124/head
Oliver Günther 5 years ago committed by GitHub
commit 9ef414c387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      frontend/src/app/angular4-modules.ts
  2. 2
      frontend/src/app/modules/boards/board/board-actions/board-actions-registry.service.ts
  3. 2
      frontend/src/app/modules/boards/board/board-cache.service.ts
  4. 8
      frontend/src/app/modules/boards/board/board-dm.service.ts
  5. 18
      frontend/src/app/modules/boards/board/board-list/board-lists.service.ts
  6. 4
      frontend/src/app/modules/boards/board/board.service.ts
  7. 24
      frontend/src/app/modules/boards/boards-root/boards-root.component.ts
  8. 12
      frontend/src/app/modules/boards/boards-sidebar/boards-menu.component.ts
  9. 35
      frontend/src/app/modules/boards/openproject-boards.module.ts
  10. 20
      frontend/src/app/modules/router/openproject.routes.ts
  11. 3
      modules/boards/spec/features/board_navigation_spec.rb

@ -59,7 +59,6 @@ import {OpenprojectRouterModule} from "core-app/modules/router/openproject-route
import {OpenprojectWorkPackageRoutesModule} from "core-app/modules/work_packages/openproject-work-package-routes.module";
import {BrowserModule} from "@angular/platform-browser";
import {OpenprojectCalendarModule} from "core-app/modules/calendar/openproject-calendar.module";
import {OpenprojectBoardsModule} from "core-app/modules/boards/openproject-boards.module";
import {OpenprojectGlobalSearchModule} from "core-app/modules/global_search/openproject-global-search.module";
import {MainMenuToggleComponent} from "core-components/main-menu/main-menu-toggle.component";
import {MainMenuNavigationService} from "core-components/main-menu/main-menu-navigation.service";
@ -84,8 +83,6 @@ import {globalDynamicComponents} from "core-app/global-dynamic-components.const"
OpenprojectRouterModule,
// Hal Module
OpenprojectHalModule,
// Boards module
OpenprojectBoardsModule,
// CKEditor
OpenprojectEditorModule,

@ -1,7 +1,7 @@
import {Injectable} from "@angular/core";
import {BoardActionService} from "core-app/modules/boards/board/board-actions/board-action.service";
@Injectable()
@Injectable({ providedIn: 'root' })
export class BoardActionsRegistryService {
private mapping:{ [attribute:string]:BoardActionService } = {};

@ -4,7 +4,7 @@ import {multiInput, MultiInputState} from "reactivestates";
import {Board} from "core-app/modules/boards/board/board";
import {BoardDmService} from "core-app/modules/boards/board/board-dm.service";
@Injectable()
@Injectable({ providedIn: 'root' })
export class BoardCacheService extends StateCacheService<Board> {
protected _state = multiInput<Board>();

@ -1,6 +1,5 @@
import {Injectable} from "@angular/core";
import {from, Observable} from "rxjs";
import {BoardListsService} from "core-app/modules/boards/board/board-list/board-lists.service";
import {HalResourceService} from "core-app/modules/hal/services/hal-resource.service";
import {PathHelperService} from "core-app/modules/common/path-helper/path-helper.service";
import {GridDmService} from "core-app/modules/hal/dm-services/grid-dm.service";
@ -8,10 +7,9 @@ import {CurrentProjectService} from "core-components/projects/current-project.se
import {GridResource} from "core-app/modules/hal/resources/grid-resource";
import {map, tap} from "rxjs/operators";
import {Board, BoardType} from "core-app/modules/boards/board/board";
import {OpenprojectBoardsModule} from "core-app/modules/boards/openproject-boards.module";
import {AuthorisationService} from "core-app/modules/common/model-auth/model-auth.service";
@Injectable()
@Injectable({ providedIn: 'root' })
export class BoardDmService {
constructor(protected GridDm:GridDmService,
@ -30,8 +28,8 @@ export class BoardDmService {
const path = this.boardPath(projectIdentifier);
return from(
this.GridDm.list({ filters: [['scope', '=', [path]]] })
)
this.GridDm.list({ filters: [['scope', '=', [path]]] })
)
.pipe(
tap(collection => this.authorisationService.initModelAuth('boards', collection.$links)),
map(collection => collection.elements.map(grid => new Board(grid)))

@ -11,7 +11,7 @@ import {ApiV3Filter} from "core-components/api/api-v3/api-v3-filter-builder";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
@Injectable()
@Injectable({ providedIn: 'root' })
export class BoardListsService {
private readonly v3 = this.pathHelper.api.v3;
@ -31,8 +31,10 @@ export class BoardListsService {
return this.QueryFormDm
.loadWithParams(
{pageSize: 0,
filters: filterJson},
{
pageSize: 0,
filters: filterJson
},
undefined,
this.CurrentProject.identifier,
this.buildQueryRequest(params),
@ -53,8 +55,8 @@ export class BoardListsService {
* Add a free query to the board
*/
public addFreeQuery(board:Board, queryParams:Object) {
const filter = this.freeBoardQueryFilter();
return this.addQuery(board, queryParams, [filter]);
const filter = this.freeBoardQueryFilter();
return this.addQuery(board, queryParams, [filter]);
}
/**
@ -95,8 +97,8 @@ export class BoardListsService {
public: true,
"_links": {
"sortBy": [
{"href": this.v3.resource("/queries/sort_bys/manualSorting-asc")},
{"href": this.v3.resource("/queries/sort_bys/id-asc")},
{ "href": this.v3.resource("/queries/sort_bys/manualSorting-asc") },
{ "href": this.v3.resource("/queries/sort_bys/id-asc") },
]
},
...params
@ -104,6 +106,6 @@ export class BoardListsService {
}
private freeBoardQueryFilter():ApiV3Filter {
return {manualSort: {operator: 'ow', values: []}};
return { manualSort: { operator: 'ow', values: [] } };
}
}

@ -17,7 +17,7 @@ export interface CreateBoardParams {
attribute?:string;
}
@Injectable()
@Injectable({ providedIn: 'root' })
export class BoardService {
private loadAllPromise:Promise<Board[]>|undefined;
@ -25,7 +25,7 @@ export class BoardService {
private text = {
unnamed_board: this.I18n.t('js.boards.label_unnamed_board'),
action_board: (attr:string) => this.I18n.t('js.boards.board_type.action_by_attribute',
{ attribute: attr}),
{ attribute: attr }),
unnamed_list: this.I18n.t('js.boards.label_unnamed_list'),
};

@ -1,12 +1,30 @@
import {Component} from "@angular/core";
import {BoardCacheService} from "core-app/modules/boards/board/board-cache.service";
import {Component, Injector} from "@angular/core";
import {BoardConfigurationService} from "core-app/modules/boards/board/configuration-modal/board-configuration.service";
import {BoardActionsRegistryService} from "core-app/modules/boards/board/board-actions/board-actions-registry.service";
import {BoardStatusActionService} from "core-app/modules/boards/board/board-actions/status/status-action.service";
import {BoardVersionActionService} from "core-app/modules/boards/board/board-actions/version/version-action.service";
import {QueryUpdatedService} from "core-app/modules/boards/board/query-updated/query-updated.service";
@Component({
selector: 'boards-entry',
template: '<ui-view></ui-view>',
providers: [
BoardCacheService
BoardConfigurationService,
BoardStatusActionService,
BoardVersionActionService,
QueryUpdatedService
]
})
export class BoardsRootComponent {
constructor(readonly injector:Injector) {
// Register action services
const registry = injector.get(BoardActionsRegistryService);
const statusAction = injector.get(BoardStatusActionService);
const versionAction = injector.get(BoardVersionActionService);
registry.add('status', statusAction);
registry.add('version', versionAction);
}
}

@ -22,9 +22,13 @@ export class BoardsMenuComponent implements OnInit {
public boards$:Observable<Board[]> = this.boardCache.observeAll().pipe(
map((boards:Board[]) => {
return boards.sort(function(a, b){
if(a.name < b.name) { return -1; }
if(a.name > b.name) { return 1; }
return boards.sort(function (a, b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
});
})
@ -43,7 +47,7 @@ export class BoardsMenuComponent implements OnInit {
.onActivate('board_view')
.subscribe(() => {
this.focusBackArrow();
this.boardService.loadAllBoards()
this.boardService.loadAllBoards();
});
}

@ -26,25 +26,19 @@
// See docs/COPYRIGHT.rdoc for more details.
// ++
import {Injector, NgModule} from '@angular/core';
import {NgModule} from '@angular/core';
import {OpenprojectCommonModule} from "core-app/modules/common/openproject-common.module";
import {OpenprojectWorkPackagesModule} from "core-app/modules/work_packages/openproject-work-packages.module";
import {Ng2StateDeclaration, UIRouter, UIRouterModule} from "@uirouter/angular";
import {BoardComponent} from "core-app/modules/boards/board/board.component";
import {BoardListComponent} from "core-app/modules/boards/board/board-list/board-list.component";
import {BoardsRootComponent} from "core-app/modules/boards/boards-root/boards-root.component";
import {BoardListsService} from "core-app/modules/boards/board/board-list/board-lists.service";
import {BoardService} from "core-app/modules/boards/board/board.service";
import {BoardInlineAddAutocompleterComponent} from "core-app/modules/boards/board/inline-add/board-inline-add-autocompleter.component";
import {BoardCacheService} from "core-app/modules/boards/board/board-cache.service";
import {BoardsToolbarMenuDirective} from "core-app/modules/boards/board/toolbar-menu/boards-toolbar-menu.directive";
import {BoardConfigurationService} from "core-app/modules/boards/board/configuration-modal/board-configuration.service";
import {BoardConfigurationModal} from "core-app/modules/boards/board/configuration-modal/board-configuration.modal";
import {BoardsIndexPageComponent} from "core-app/modules/boards/index-page/boards-index-page.component";
import {BoardsMenuComponent} from "core-app/modules/boards/boards-sidebar/boards-menu.component";
import {BoardDmService} from "core-app/modules/boards/board/board-dm.service";
import {NewBoardModalComponent} from "core-app/modules/boards/new-board-modal/new-board-modal.component";
import {BoardActionsRegistryService} from "core-app/modules/boards/board/board-actions/board-actions-registry.service";
import {AddListModalComponent} from "core-app/modules/boards/board/add-list-modal/add-list-modal.component";
import {BoardHighlightingTabComponent} from "core-app/modules/boards/board/configuration-modal/tabs/highlighting-tab.component";
import {AddCardDropdownMenuDirective} from "core-app/modules/boards/board/add-card-dropdown/add-card-dropdown-menu.directive";
@ -53,9 +47,6 @@ import {DragScrollModule} from "cdk-drag-scroll";
import {BoardListMenuComponent} from "core-app/modules/boards/board/board-list/board-list-menu.component";
import {VersionBoardHeaderComponent} from "core-app/modules/boards/board/board-actions/version/version-board-header.component";
import {DynamicModule} from "ng-dynamic-component";
import {BoardStatusActionService} from "core-app/modules/boards/board/board-actions/status/status-action.service";
import {BoardVersionActionService} from "core-app/modules/boards/board/board-actions/version/version-action.service";
import {QueryUpdatedService} from "core-app/modules/boards/board/query-updated/query-updated.service";
const menuItemClass = 'board-view-menu-item';
@ -113,16 +104,6 @@ export function uiRouterBoardsConfiguration(uiRouter:UIRouter) {
);
}
export function registerBoardsModule(injector:Injector) {
// Register action services
const registry = injector.get(BoardActionsRegistryService);
const statusAction = injector.get(BoardStatusActionService);
const versionAction = injector.get(BoardVersionActionService);
registry.add('status', statusAction);
registry.add('version', versionAction);
}
@NgModule({
imports: [
OpenprojectCommonModule,
@ -138,17 +119,6 @@ export function registerBoardsModule(injector:Injector) {
config: uiRouterBoardsConfiguration
}),
],
providers: [
BoardService,
BoardDmService,
BoardListsService,
BoardCacheService,
BoardConfigurationService,
BoardActionsRegistryService,
BoardStatusActionService,
BoardVersionActionService,
QueryUpdatedService,
],
declarations: [
BoardsIndexPageComponent,
BoardComponent,
@ -168,8 +138,5 @@ export function registerBoardsModule(injector:Injector) {
]
})
export class OpenprojectBoardsModule {
constructor(injector:Injector) {
registerBoardsModule(injector);
}
}

@ -26,7 +26,7 @@
// See docs/COPYRIGHT.rdoc for more details.
// ++
import {StateDeclaration, StateService, Transition, TransitionService, UIRouter, UrlService} from '@uirouter/core';
import {StateDeclaration, StateService, Transition, TransitionService, UIRouter} from '@uirouter/core';
import {INotification, NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {CurrentProjectService} from "core-components/projects/current-project.service";
import {Injector} from "@angular/core";
@ -44,13 +44,19 @@ export const OPENPROJECT_ROUTES:Ng2StateDeclaration[] = [
params: {
// value: null makes the parameter optional
// squash: true avoids duplicate slashes when the parameter is not provided
projectPath: {type: 'path', value: null, squash: true},
projects: {type: 'path', value: null, squash: true},
projectPath: { type: 'path', value: null, squash: true },
projects: { type: 'path', value: null, squash: true },
// Allow passing of flash messages after routes load
flash_message: {dynamic: true, value: null, inherit: false}
flash_message: { dynamic: true, value: null, inherit: false }
}
},
{
name: 'boards.**',
parent: 'root',
url: '/boards',
loadChildren: () => import('../boards/openproject-boards.module').then(m => m.OpenprojectBoardsModule)
},
{
name: 'bim.**',
parent: 'root',
@ -182,8 +188,8 @@ export function initializeUiRouterListeners(injector:Injector) {
const projectIdentifier = toParams.projectPath || currentProject.identifier;
if (!toParams.projects && projectIdentifier) {
const newParams = _.clone(toParams);
_.assign(newParams, {projectPath: projectIdentifier, projects: 'projects'});
return $state.target(toState, newParams, {location: 'replace'});
_.assign(newParams, { projectPath: projectIdentifier, projects: 'projects' });
return $state.target(toState, newParams, { location: 'replace' });
}
// Abort the transition and move to the url instead
@ -198,7 +204,7 @@ export function initializeUiRouterListeners(injector:Injector) {
const path = window.location.pathname;
const target = stateService.href(toState, toParams);
if (path !== target) {
if (target && path !== target) {
window.location.href = target;
return false;
}

@ -82,7 +82,8 @@ describe 'Work Package boards spec', type: :feature, js: true do
item.find('.toggler').click
subitem = page.find('.main-menu--children-sub-item', text: 'My board', wait: 10)
expect(subitem[:href]).to end_with "/projects/#{project.identifier}/boards/#{board_view.id}"
# Ends with boards due to lazy route
expect(subitem[:href]).to end_with "/projects/#{project.identifier}/boards"
subitem.click

Loading…
Cancel
Save