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. 4
      frontend/src/app/modules/boards/board/board-dm.service.ts
  5. 14
      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 {OpenprojectWorkPackageRoutesModule} from "core-app/modules/work_packages/openproject-work-package-routes.module";
import {BrowserModule} from "@angular/platform-browser"; import {BrowserModule} from "@angular/platform-browser";
import {OpenprojectCalendarModule} from "core-app/modules/calendar/openproject-calendar.module"; 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 {OpenprojectGlobalSearchModule} from "core-app/modules/global_search/openproject-global-search.module";
import {MainMenuToggleComponent} from "core-components/main-menu/main-menu-toggle.component"; import {MainMenuToggleComponent} from "core-components/main-menu/main-menu-toggle.component";
import {MainMenuNavigationService} from "core-components/main-menu/main-menu-navigation.service"; 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, OpenprojectRouterModule,
// Hal Module // Hal Module
OpenprojectHalModule, OpenprojectHalModule,
// Boards module
OpenprojectBoardsModule,
// CKEditor // CKEditor
OpenprojectEditorModule, OpenprojectEditorModule,

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

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

@ -1,6 +1,5 @@
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {from, Observable} from "rxjs"; 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 {HalResourceService} from "core-app/modules/hal/services/hal-resource.service";
import {PathHelperService} from "core-app/modules/common/path-helper/path-helper.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"; 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 {GridResource} from "core-app/modules/hal/resources/grid-resource";
import {map, tap} from "rxjs/operators"; import {map, tap} from "rxjs/operators";
import {Board, BoardType} from "core-app/modules/boards/board/board"; 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"; import {AuthorisationService} from "core-app/modules/common/model-auth/model-auth.service";
@Injectable() @Injectable({ providedIn: 'root' })
export class BoardDmService { export class BoardDmService {
constructor(protected GridDm:GridDmService, constructor(protected GridDm:GridDmService,

@ -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 {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service"; import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
@Injectable() @Injectable({ providedIn: 'root' })
export class BoardListsService { export class BoardListsService {
private readonly v3 = this.pathHelper.api.v3; private readonly v3 = this.pathHelper.api.v3;
@ -31,8 +31,10 @@ export class BoardListsService {
return this.QueryFormDm return this.QueryFormDm
.loadWithParams( .loadWithParams(
{pageSize: 0, {
filters: filterJson}, pageSize: 0,
filters: filterJson
},
undefined, undefined,
this.CurrentProject.identifier, this.CurrentProject.identifier,
this.buildQueryRequest(params), this.buildQueryRequest(params),
@ -95,8 +97,8 @@ export class BoardListsService {
public: true, public: true,
"_links": { "_links": {
"sortBy": [ "sortBy": [
{"href": this.v3.resource("/queries/sort_bys/manualSorting-asc")}, { "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/id-asc") },
] ]
}, },
...params ...params
@ -104,6 +106,6 @@ export class BoardListsService {
} }
private freeBoardQueryFilter():ApiV3Filter { private freeBoardQueryFilter():ApiV3Filter {
return {manualSort: {operator: 'ow', values: []}}; return { manualSort: { operator: 'ow', values: [] } };
} }
} }

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

@ -1,12 +1,30 @@
import {Component} from "@angular/core"; import {Component, Injector} from "@angular/core";
import {BoardCacheService} from "core-app/modules/boards/board/board-cache.service"; 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({ @Component({
selector: 'boards-entry', selector: 'boards-entry',
template: '<ui-view></ui-view>', template: '<ui-view></ui-view>',
providers: [ providers: [
BoardCacheService BoardConfigurationService,
BoardStatusActionService,
BoardVersionActionService,
QueryUpdatedService
] ]
}) })
export class BoardsRootComponent { 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( public boards$:Observable<Board[]> = this.boardCache.observeAll().pipe(
map((boards:Board[]) => { map((boards:Board[]) => {
return boards.sort(function(a, b){ return boards.sort(function (a, b) {
if(a.name < b.name) { return -1; } if (a.name < b.name) {
if(a.name > b.name) { return 1; } return -1;
}
if (a.name > b.name) {
return 1;
}
return 0; return 0;
}); });
}) })
@ -43,7 +47,7 @@ export class BoardsMenuComponent implements OnInit {
.onActivate('board_view') .onActivate('board_view')
.subscribe(() => { .subscribe(() => {
this.focusBackArrow(); this.focusBackArrow();
this.boardService.loadAllBoards() this.boardService.loadAllBoards();
}); });
} }

@ -26,25 +26,19 @@
// See docs/COPYRIGHT.rdoc for more details. // 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 {OpenprojectCommonModule} from "core-app/modules/common/openproject-common.module";
import {OpenprojectWorkPackagesModule} from "core-app/modules/work_packages/openproject-work-packages.module"; import {OpenprojectWorkPackagesModule} from "core-app/modules/work_packages/openproject-work-packages.module";
import {Ng2StateDeclaration, UIRouter, UIRouterModule} from "@uirouter/angular"; import {Ng2StateDeclaration, UIRouter, UIRouterModule} from "@uirouter/angular";
import {BoardComponent} from "core-app/modules/boards/board/board.component"; import {BoardComponent} from "core-app/modules/boards/board/board.component";
import {BoardListComponent} from "core-app/modules/boards/board/board-list/board-list.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 {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 {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 {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 {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 {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 {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 {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 {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 {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"; 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 {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 {VersionBoardHeaderComponent} from "core-app/modules/boards/board/board-actions/version/version-board-header.component";
import {DynamicModule} from "ng-dynamic-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'; 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({ @NgModule({
imports: [ imports: [
OpenprojectCommonModule, OpenprojectCommonModule,
@ -138,17 +119,6 @@ export function registerBoardsModule(injector:Injector) {
config: uiRouterBoardsConfiguration config: uiRouterBoardsConfiguration
}), }),
], ],
providers: [
BoardService,
BoardDmService,
BoardListsService,
BoardCacheService,
BoardConfigurationService,
BoardActionsRegistryService,
BoardStatusActionService,
BoardVersionActionService,
QueryUpdatedService,
],
declarations: [ declarations: [
BoardsIndexPageComponent, BoardsIndexPageComponent,
BoardComponent, BoardComponent,
@ -168,8 +138,5 @@ export function registerBoardsModule(injector:Injector) {
] ]
}) })
export class OpenprojectBoardsModule { export class OpenprojectBoardsModule {
constructor(injector:Injector) {
registerBoardsModule(injector);
}
} }

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

@ -82,7 +82,8 @@ describe 'Work Package boards spec', type: :feature, js: true do
item.find('.toggler').click item.find('.toggler').click
subitem = page.find('.main-menu--children-sub-item', text: 'My board', wait: 10) 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 subitem.click

Loading…
Cancel
Save