mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Remove uiRouter from TeamPlanner
This commit is contained in:
@@ -151,6 +151,8 @@ import {
|
||||
BoardEntryComponent,
|
||||
} from 'core-app/features/boards/board/board-partitioned-page/board-entry.component';
|
||||
import { CalendarEntryComponent } from 'core-app/features/calendar/calendar-entry.component';
|
||||
import { TeamPlannerEntryComponent } from 'core-app/features/team-planner/team-planner/team-planner-entry.component';
|
||||
import { TeamPlannerModule } from 'core-app/features/team-planner/team-planner/team-planner.module';
|
||||
import {
|
||||
StorageLoginButtonComponent,
|
||||
} from 'core-app/shared/components/storages/storage-login-button/storage-login-button.component';
|
||||
@@ -304,6 +306,8 @@ export function runBootstrap(appRef:ApplicationRef) {
|
||||
OpenprojectWorkPackageGraphsModule,
|
||||
// Calendar module
|
||||
OpenprojectCalendarModule,
|
||||
// Team Planner module
|
||||
TeamPlannerModule,
|
||||
|
||||
// MyPage
|
||||
OpenprojectMyPageModule,
|
||||
@@ -399,6 +403,7 @@ export class OpenProjectModule implements DoBootstrap {
|
||||
registerCustomElement('opce-wp-split-create', WorkPackageSplitCreateEntryComponent, { injector });
|
||||
registerCustomElement('opce-board-view', BoardEntryComponent, { injector });
|
||||
registerCustomElement('opce-calendar-view', CalendarEntryComponent, { injector });
|
||||
registerCustomElement('opce-team-planner-view', TeamPlannerEntryComponent, { injector });
|
||||
registerCustomElement('opce-wp-full-view', WorkPackageFullViewEntryComponent, { injector });
|
||||
registerCustomElement('opce-wp-full-create', WorkPackageFullCreateEntryComponent, { injector });
|
||||
registerCustomElement('opce-wp-full-copy', WorkPackageFullCopyEntryComponent, { injector });
|
||||
|
||||
@@ -39,7 +39,6 @@ import {
|
||||
mobileGuardActivated,
|
||||
redirectToMobileAlternative,
|
||||
} from 'core-app/shared/helpers/routing/mobile-guard.helper';
|
||||
import { TEAM_PLANNER_LAZY_ROUTES } from 'core-app/features/team-planner/team-planner/team-planner.lazy-routes';
|
||||
|
||||
export const OPENPROJECT_ROUTES:Ng2StateDeclaration[] = [
|
||||
{
|
||||
@@ -73,7 +72,6 @@ export const OPENPROJECT_ROUTES:Ng2StateDeclaration[] = [
|
||||
url: '/bcf',
|
||||
loadChildren: () => import('../../features/bim/ifc_models/openproject-ifc-models.module').then((m) => m.OpenprojectIFCModelsModule),
|
||||
},
|
||||
...TEAM_PLANNER_LAZY_ROUTES,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+1
-8
@@ -32,12 +32,9 @@ import { UrlParamsHelperService } from 'core-app/features/work-packages/componen
|
||||
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';
|
||||
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
|
||||
import { CalendarDragDropService } from 'core-app/features/team-planner/team-planner/calendar-drag-drop.service';
|
||||
import { splitViewRoute } from 'core-app/features/work-packages/routing/split-view-routes.helper';
|
||||
import { StateService } from '@uirouter/core';
|
||||
import { ActionsService } from 'core-app/core/state/actions/actions.service';
|
||||
import { teamPlannerEventRemoved } from 'core-app/features/team-planner/team-planner/planner/team-planner.actions';
|
||||
import { WorkPackageViewFiltersService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service';
|
||||
import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service';
|
||||
import { OpWorkPackagesCalendarService } from 'core-app/features/calendar/op-work-packages-calendar.service';
|
||||
|
||||
@Component({
|
||||
@@ -121,7 +118,6 @@ export class AddExistingPaneComponent extends UntilDestroyedMixin implements OnI
|
||||
private readonly urlParamsHelper:UrlParamsHelperService,
|
||||
private readonly workPackagesCalendar:OpWorkPackagesCalendarService,
|
||||
private readonly calendarDrag:CalendarDragDropService,
|
||||
private readonly $state:StateService,
|
||||
private readonly actions$:ActionsService,
|
||||
private readonly wpFilters:WorkPackageViewFiltersService,
|
||||
) {
|
||||
@@ -214,10 +210,7 @@ export class AddExistingPaneComponent extends UntilDestroyedMixin implements OnI
|
||||
}
|
||||
|
||||
openStateLink(event:{ workPackageId:string; requestedState:string }):void {
|
||||
void this.$state.go(
|
||||
`${splitViewRoute(this.$state)}.tabs`,
|
||||
{ workPackageId: event.workPackageId, tabIdentifier: 'overview' },
|
||||
);
|
||||
this.workPackagesCalendar.openSplitView(event.workPackageId);
|
||||
}
|
||||
|
||||
private addExistingFilters(filters:ApiV3FilterBuilder) {
|
||||
|
||||
+13
-1
@@ -31,7 +31,8 @@ import { OpWorkPackagesCalendarService } from 'core-app/features/calendar/op-wor
|
||||
import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: '../../../work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html',
|
||||
selector: 'op-team-planner-page',
|
||||
templateUrl: './team-planner-page.component.html',
|
||||
styleUrls: [
|
||||
'../../../work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.sass',
|
||||
],
|
||||
@@ -98,6 +99,17 @@ export class TeamPlannerPageComponent extends PartitionedQuerySpacePageComponent
|
||||
public ngOnInit():void {
|
||||
super.ngOnInit();
|
||||
|
||||
// Fix showToolbarSaveButton from actual URL params (not uiRouter state)
|
||||
this.showToolbarSaveButton = !!new URLSearchParams(window.location.search).get('query_props');
|
||||
|
||||
// Update save button reactively when query_props changes via pushState
|
||||
this.wpListChecksumService.visibleChecksum$
|
||||
.pipe(this.untilDestroyed())
|
||||
.subscribe((checksum) => {
|
||||
this.showToolbarSaveButton = !!checksum;
|
||||
this.cdRef.detectChanges();
|
||||
});
|
||||
|
||||
registerEffectCallbacks(this, this.untilDestroyed());
|
||||
|
||||
this.wpTableFilters.hidden.push(
|
||||
|
||||
+14
-53
@@ -40,7 +40,6 @@ import {
|
||||
import {
|
||||
CalendarOptions,
|
||||
DateSelectArg,
|
||||
DatesSetArg,
|
||||
EventApi,
|
||||
EventDropArg,
|
||||
EventInput,
|
||||
@@ -64,7 +63,6 @@ import {
|
||||
take,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
import { StateService } from '@uirouter/angular';
|
||||
import resourceTimelinePlugin from '@fullcalendar/resource-timeline';
|
||||
import interactionPlugin, {
|
||||
EventDragStartArg,
|
||||
@@ -78,8 +76,6 @@ import { ConfigurationService } from 'core-app/core/config/configuration.service
|
||||
import { WorkPackageViewFiltersService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service';
|
||||
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';
|
||||
import { CurrentProjectService } from 'core-app/core/current-project/current-project.service';
|
||||
import { splitViewRoute } from 'core-app/features/work-packages/routing/split-view-routes.helper';
|
||||
import { isClickedWithModifier } from 'core-app/shared/helpers/link-handling/link-handling';
|
||||
import { QueryFilterInstanceResource } from 'core-app/features/hal/resources/query-filter-instance-resource';
|
||||
import { PrincipalsResourceService } from 'core-app/core/state/principals/principals.service';
|
||||
import {
|
||||
@@ -98,7 +94,6 @@ import { MAGIC_PAGE_NUMBER } from 'core-app/core/apiv3/helpers/get-paginated-res
|
||||
import { CalendarDragDropService } from 'core-app/features/team-planner/team-planner/calendar-drag-drop.service';
|
||||
import { StatusResource } from 'core-app/features/hal/resources/status-resource';
|
||||
import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset';
|
||||
import { KeepTabService } from 'core-app/features/work-packages/components/wp-single-view-tabs/keep-tab/keep-tab.service';
|
||||
import { HalError } from 'core-app/features/hal/services/hal-error';
|
||||
import { ActionsService } from 'core-app/core/state/actions/actions.service';
|
||||
import {
|
||||
@@ -409,7 +404,6 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
};
|
||||
|
||||
constructor(
|
||||
private $state:StateService,
|
||||
private configuration:ConfigurationService,
|
||||
private principalsResourceService:PrincipalsResourceService,
|
||||
private capabilitiesResourceService:CapabilitiesResourceService,
|
||||
@@ -425,7 +419,6 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
readonly schemaCache:SchemaCacheService,
|
||||
readonly apiV3Service:ApiV3Service,
|
||||
readonly calendarDrag:CalendarDragDropService,
|
||||
readonly keepTab:KeepTabService,
|
||||
readonly actions$:ActionsService,
|
||||
readonly toastService:ToastService,
|
||||
readonly loadingIndicatorService:LoadingIndicatorService,
|
||||
@@ -514,19 +507,6 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
.then(() => {
|
||||
this.calendarOptions$.next(
|
||||
this.workPackagesCalendar.calendarOptions({
|
||||
// Override datesSet to persist cdate/cview via uiRouter instead of pushState,
|
||||
// because uiRouter manages the TeamPlanner URL and would otherwise strip these params.
|
||||
// Remove once uiRouter is removed.
|
||||
datesSet: (dates:DatesSetArg) => {
|
||||
void this.$state.go(
|
||||
'.',
|
||||
{
|
||||
cdate: this.workPackagesCalendar.timezoneService.formattedISODate(dates.view.calendar.getDate()),
|
||||
cview: (dates.view as unknown as { type:string }).type,
|
||||
},
|
||||
{ custom: { notify: false } },
|
||||
);
|
||||
},
|
||||
locales: allLocales,
|
||||
locale: this.I18n.locale,
|
||||
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
|
||||
@@ -843,48 +823,29 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
['$event.detail.start', '$event.detail.end', '$event.detail.assignee'],
|
||||
)
|
||||
openNewSplitCreate(start:string, end:string, resourceHref:string, nonWorkingDays?:boolean):void {
|
||||
const defaults = {
|
||||
startDate: start,
|
||||
dueDate: end,
|
||||
_links: {
|
||||
assignee: {
|
||||
href: resourceHref,
|
||||
},
|
||||
},
|
||||
ignoreNonWorkingDays: nonWorkingDays,
|
||||
};
|
||||
|
||||
void this.$state.go(
|
||||
splitViewRoute(this.$state, 'new'),
|
||||
{
|
||||
defaults,
|
||||
tabIdentifier: 'overview',
|
||||
},
|
||||
);
|
||||
const basePath = window.location.pathname.replace(/\/details\/.*$/, '');
|
||||
const search = new URLSearchParams(window.location.search);
|
||||
search.set('startDate', start);
|
||||
search.set('dueDate', end);
|
||||
if (resourceHref) {
|
||||
search.set('assignee_href', resourceHref);
|
||||
}
|
||||
if (nonWorkingDays) {
|
||||
search.set('ignoreNonWorkingDays', 'true');
|
||||
}
|
||||
Turbo.visit(`${basePath}/details/new?${search.toString()}`, { frame: 'content-bodyRight', action: 'advance' });
|
||||
}
|
||||
|
||||
openStateLink(event:{ workPackageId:string; requestedState:string }):void {
|
||||
const params = { workPackageId: event.workPackageId };
|
||||
|
||||
if (event.requestedState === 'split') {
|
||||
this.keepTab.goCurrentDetailsState(params);
|
||||
this.workPackagesCalendar.openSplitView(event.workPackageId);
|
||||
} else {
|
||||
this.keepTab.goCurrentShowState(params.workPackageId);
|
||||
this.workPackagesCalendar.openFullView(event.workPackageId);
|
||||
}
|
||||
}
|
||||
|
||||
onCardClicked({ workPackageId, event }:{ workPackageId:string, event:MouseEvent }):void {
|
||||
if (isClickedWithModifier(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only switch the split view if it is already open
|
||||
if (!window.location.pathname.includes('/details/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.workPackagesCalendar.wpTableSelection.setSelection(workPackageId, -1);
|
||||
this.keepTab.goCurrentDetailsState({ workPackageId });
|
||||
this.workPackagesCalendar.onCardClicked({ workPackageId, event });
|
||||
}
|
||||
|
||||
shouldShowAsGhost(id:string, globalDraggingId:string|undefined):boolean {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
OnDestroy,
|
||||
} from '@angular/core';
|
||||
import { populateInputsFromDataset } from 'core-app/shared/components/dataset-inputs';
|
||||
import {
|
||||
WorkPackageIsolatedQuerySpaceDirective,
|
||||
} from 'core-app/features/work-packages/directives/query-space/wp-isolated-query-space.directive';
|
||||
|
||||
@Component({
|
||||
hostDirectives: [WorkPackageIsolatedQuerySpaceDirective],
|
||||
template: '<op-team-planner-page />',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class TeamPlannerEntryComponent implements OnDestroy {
|
||||
constructor(readonly elementRef:ElementRef) {
|
||||
populateInputsFromDataset(this);
|
||||
document.body.classList.add('router--team-planner');
|
||||
}
|
||||
|
||||
ngOnDestroy():void {
|
||||
document.body.classList.remove('router--team-planner');
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
//-- copyright
|
||||
// OpenProject is an open source project management software.
|
||||
// Copyright (C) the OpenProject GmbH
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See COPYRIGHT and LICENSE files for more details.
|
||||
//++
|
||||
|
||||
import { Ng2StateDeclaration } from '@uirouter/angular';
|
||||
|
||||
export const TEAM_PLANNER_LAZY_ROUTES:Ng2StateDeclaration[] = [
|
||||
{
|
||||
name: 'team_planner.**',
|
||||
parent: 'optional_project',
|
||||
url: '/team_planner',
|
||||
loadChildren: () => import('./team-planner.module').then((m) => m.TeamPlannerModule),
|
||||
},
|
||||
];
|
||||
@@ -1,16 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { UIRouterModule } from '@uirouter/angular';
|
||||
import { DynamicModule } from 'ng-dynamic-component';
|
||||
import { FullCalendarModule } from '@fullcalendar/angular';
|
||||
import { IconModule } from 'core-app/shared/components/icon/icon.module';
|
||||
import { OpenprojectAutocompleterModule } from 'core-app/shared/components/autocompleter/openproject-autocompleter.module';
|
||||
import { OpenprojectPrincipalRenderingModule } from 'core-app/shared/components/principal/principal-rendering.module';
|
||||
import { OpenprojectWorkPackagesModule } from 'core-app/features/work-packages/openproject-work-packages.module';
|
||||
import { TEAM_PLANNER_ROUTES } from 'core-app/features/team-planner/team-planner/team-planner.routes';
|
||||
import { TeamPlannerComponent } from 'core-app/features/team-planner/team-planner/planner/team-planner.component';
|
||||
import { AddAssigneeComponent } from 'core-app/features/team-planner/team-planner/assignee/add-assignee.component';
|
||||
import { TeamPlannerPageComponent } from 'core-app/features/team-planner/team-planner/page/team-planner-page.component';
|
||||
import { TeamPlannerEntryComponent } from 'core-app/features/team-planner/team-planner/team-planner-entry.component';
|
||||
import { OpSharedModule } from 'core-app/shared/shared.module';
|
||||
import { AddExistingPaneComponent } from './add-work-packages/add-existing-pane.component';
|
||||
import { OpenprojectContentLoaderModule } from 'core-app/shared/components/op-content-loader/openproject-content-loader.module';
|
||||
@@ -20,16 +19,13 @@ import { TeamPlannerViewSelectMenuDirective } from 'core-app/features/team-plann
|
||||
declarations: [
|
||||
TeamPlannerComponent,
|
||||
TeamPlannerPageComponent,
|
||||
TeamPlannerEntryComponent,
|
||||
AddAssigneeComponent,
|
||||
AddExistingPaneComponent,
|
||||
TeamPlannerViewSelectMenuDirective,
|
||||
],
|
||||
imports: [
|
||||
OpSharedModule,
|
||||
// Routes for /team_planner
|
||||
UIRouterModule.forChild({
|
||||
states: TEAM_PLANNER_ROUTES,
|
||||
}),
|
||||
DynamicModule,
|
||||
CommonModule,
|
||||
IconModule,
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
//-- copyright
|
||||
// OpenProject is an open source project management software.
|
||||
// Copyright (C) the OpenProject GmbH
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See COPYRIGHT and LICENSE files for more details.
|
||||
//++
|
||||
|
||||
import { Ng2StateDeclaration } from '@uirouter/angular';
|
||||
import { makeSplitViewRoutes } from 'core-app/features/work-packages/routing/split-view-routes.template';
|
||||
import { WorkPackageSplitViewComponent } from 'core-app/features/work-packages/routing/wp-split-view/wp-split-view.component';
|
||||
import { WorkPackagesBaseComponent } from 'core-app/features/work-packages/routing/wp-base/wp--base.component';
|
||||
import { TeamPlannerPageComponent } from 'core-app/features/team-planner/team-planner/page/team-planner-page.component';
|
||||
import { TeamPlannerComponent } from 'core-app/features/team-planner/team-planner/planner/team-planner.component';
|
||||
|
||||
export const sidemenuId = 'team_planner_sidemenu';
|
||||
export const sideMenuOptions = {
|
||||
sidemenuId,
|
||||
hardReloadOnBaseRoute: true,
|
||||
defaultQuery: 'new',
|
||||
};
|
||||
|
||||
export const TEAM_PLANNER_ROUTES:Ng2StateDeclaration[] = [
|
||||
{
|
||||
name: 'team_planner',
|
||||
parent: 'optional_project',
|
||||
url: '/team_planners/:query_id?query_props&cdate&cview',
|
||||
redirectTo: 'team_planner.page',
|
||||
views: {
|
||||
'!$default': { component: WorkPackagesBaseComponent },
|
||||
},
|
||||
params: {
|
||||
query_id: { type: 'opQueryId', dynamic: true },
|
||||
cdate: { type: 'string', dynamic: true },
|
||||
cview: { type: 'string', dynamic: true },
|
||||
// Use custom encoder/decoder that ensures validity of URL string
|
||||
query_props: { type: 'opQueryString' },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'team_planner.page',
|
||||
component: TeamPlannerPageComponent,
|
||||
redirectTo: 'team_planner.page.show',
|
||||
data: {
|
||||
bodyClasses: 'router--team-planner',
|
||||
sideMenuOptions,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'team_planner.page.show',
|
||||
data: {
|
||||
baseRoute: 'team_planner.page.show',
|
||||
sideMenuOptions,
|
||||
},
|
||||
views: {
|
||||
'content-left': { component: TeamPlannerComponent },
|
||||
},
|
||||
},
|
||||
...makeSplitViewRoutes(
|
||||
'team_planner.page.show',
|
||||
undefined,
|
||||
WorkPackageSplitViewComponent,
|
||||
),
|
||||
];
|
||||
+11
-3
@@ -63,19 +63,27 @@ export class WorkPackageNewSplitViewComponent extends WorkPackageCreateComponent
|
||||
);
|
||||
}
|
||||
|
||||
// Apply date defaults passed via URL params (e.g. when dragging to create on the calendar).
|
||||
// Apply defaults passed via URL params (e.g. when dragging to create on the calendar/team planner).
|
||||
const startDate = params.get('startDate');
|
||||
const dueDate = params.get('dueDate');
|
||||
const ignoreNonWorkingDays = params.get('ignoreNonWorkingDays');
|
||||
if (startDate || dueDate || ignoreNonWorkingDays) {
|
||||
const assigneeHref = params.get('assignee_href');
|
||||
if (startDate || dueDate || ignoreNonWorkingDays || assigneeHref) {
|
||||
const existingDefaults = this.stateParams?.defaults;
|
||||
this.stateParams = {
|
||||
...this.stateParams,
|
||||
defaults: {
|
||||
_links: {},
|
||||
...this.stateParams?.defaults,
|
||||
...existingDefaults,
|
||||
...(startDate ? { startDate } : {}),
|
||||
...(dueDate ? { dueDate } : {}),
|
||||
...(ignoreNonWorkingDays ? { ignoreNonWorkingDays: true } : {}),
|
||||
...(assigneeHref ? {
|
||||
_links: {
|
||||
...(existingDefaults?._links || {}),
|
||||
assignee: { href: assigneeHref },
|
||||
},
|
||||
} : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ export class WorkPackageSplitCreateEntryComponent implements AfterViewInit, OnDe
|
||||
|
||||
constructor(readonly elementRef:ElementRef) {
|
||||
populateInputsFromDataset(this);
|
||||
document.body.classList.add('\'router--work-packages-partitioned-split-view-new');
|
||||
document.body.classList.add('router--work-packages-partitioned-split-view-new');
|
||||
}
|
||||
|
||||
ngAfterViewInit():void {
|
||||
@@ -73,6 +73,6 @@ export class WorkPackageSplitCreateEntryComponent implements AfterViewInit, OnDe
|
||||
}
|
||||
|
||||
ngOnDestroy():void {
|
||||
document.body.classList.remove('\'router--work-packages-partitioned-split-view-new');
|
||||
document.body.classList.remove('router--work-packages-partitioned-split-view-new');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ::TeamPlanner
|
||||
class TeamPlannerController < BaseController
|
||||
include EnterpriseHelper
|
||||
include Layout
|
||||
include WorkPackages::WithSplitView
|
||||
|
||||
before_action :load_and_authorize_in_optional_project
|
||||
before_action :build_plan_view, only: %i[new]
|
||||
before_action :find_plan_view, only: %i[destroy]
|
||||
before_action :find_plan_view, only: %i[destroy split_view]
|
||||
authorize_with_permission :add_work_packages, only: %i[split_create]
|
||||
|
||||
guard_enterprise_feature(:team_planner_view, except: %i[index overview]) do
|
||||
redirect_to action: :index
|
||||
@@ -21,6 +26,7 @@ module ::TeamPlanner
|
||||
render layout: "global"
|
||||
end
|
||||
|
||||
def show; end
|
||||
def new; end
|
||||
|
||||
def create
|
||||
@@ -37,8 +43,28 @@ module ::TeamPlanner
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
render layout: "angular/angular"
|
||||
def split_view
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if turbo_frame_request?
|
||||
render "work_packages/split_view", layout: false
|
||||
else
|
||||
render :show
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def split_create
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if turbo_frame_request?
|
||||
render "work_packages/split_create", layout: false
|
||||
else
|
||||
render :show
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def upsell; end
|
||||
@@ -63,12 +89,16 @@ module ::TeamPlanner
|
||||
|
||||
private
|
||||
|
||||
def split_view_base_route
|
||||
project_team_planner_path(@project, @view, request.query_parameters)
|
||||
end
|
||||
|
||||
def create_service_class
|
||||
TeamPlanner::Views::GlobalCreateService
|
||||
end
|
||||
|
||||
def plan_view_params
|
||||
params.require(:query).permit(:name, :public, :starred).merge(project_id: @project&.id)
|
||||
params.expect(query: %i[name public starred]).merge(project_id: @project&.id)
|
||||
end
|
||||
|
||||
def build_plan_view
|
||||
|
||||
@@ -1 +1,11 @@
|
||||
<% html_title(t("team_planner.label_team_planner")) -%>
|
||||
|
||||
<% content_for :content_body do %>
|
||||
<%= angular_component_tag "opce-team-planner-view" %>
|
||||
<% end %>
|
||||
|
||||
<% content_for :content_body_right do %>
|
||||
<%= turbo_stream.set_title(title: page_title(*html_title_parts)) if turbo_frame_request? %>
|
||||
<%= render(split_view_instance) if render_work_package_split_view? %>
|
||||
<%= render(split_create_instance) if render_work_package_split_create? %>
|
||||
<% end %>
|
||||
|
||||
@@ -19,6 +19,15 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
member do
|
||||
get "details/new",
|
||||
action: :split_create,
|
||||
as: :split_create,
|
||||
work_package_split_create: true
|
||||
get "details/:work_package_id(/:tab)",
|
||||
action: :split_view,
|
||||
defaults: { tab: :overview },
|
||||
as: :details,
|
||||
work_package_split_view: true
|
||||
get "(/*state)" => "team_planner/team_planner#show", as: ""
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,7 @@ module OpenProject::TeamPlanner
|
||||
dependencies: :work_package_tracking,
|
||||
enterprise_feature: "team_planner_view" do
|
||||
permission :view_team_planner,
|
||||
{ "team_planner/team_planner": %i[index show upsell overview],
|
||||
{ "team_planner/team_planner": %i[index show split_view split_create upsell overview],
|
||||
"team_planner/menus": %i[show] },
|
||||
permissible_on: :project,
|
||||
dependencies: %i[view_work_packages],
|
||||
|
||||
Reference in New Issue
Block a user