Skip to content

Commit

Permalink
Create FullView::CreateComponent for WorkPackages which is now routed…
Browse files Browse the repository at this point in the history
… from rails instead of Angular
  • Loading branch information
HDinger committed Oct 15, 2024
1 parent 251eb77 commit 84b50fb
Show file tree
Hide file tree
Showing 15 changed files with 168 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= helpers.angular_component_tag "opce-wp-full-create",
inputs: {
type: @type,
projectIdentifier: @project.present? ? @project.identifier : nil,
routedFromAngular: false,
}
%>
17 changes: 17 additions & 0 deletions app/components/work_packages/full_view/create_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module WorkPackages
module FullView
class CreateComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

def initialize(type:, project:)
super

@type = type
@project = project
end
end
end
end
15 changes: 12 additions & 3 deletions app/controllers/work_packages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class WorkPackagesController < ApplicationController

before_action :authorize_on_work_package,
:project, only: :show
before_action :load_and_authorize_in_optional_project,
:check_allowed_export,
before_action :check_allowed_export,
:protect_from_unauthorized_export, only: %i[index export_dialog]
before_action :find_optional_project, only: %i[split_view split_create copy]
before_action :find_optional_project, only: %i[split_view split_create]
before_action :load_and_authorize_in_optional_project, only: %i[index export_dialog new copy]
authorization_checked! :index, :show, :copy, :export_dialog, :split_view, :split_create

before_action :load_and_validate_query, only: %i[index split_view split_create copy]
Expand Down Expand Up @@ -104,6 +104,15 @@ def copy
end
end

def new
respond_to do |format|
format.html do
render :new,
locals: { query: @query, project: @project, menu_name: project_or_global_menu }
end
end
end

def export_dialog
respond_with_dialog WorkPackages::Exports::ModalDialogComponent.new(query: @query, project: @project, title: params[:title])
end
Expand Down
44 changes: 44 additions & 0 deletions app/views/work_packages/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<%#-- 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.
++#%>

<% html_title(t('activerecord.attributes.project.work_packages')) -%>

<% content_for :sidebar do %>
<%= render partial: 'sidebar' %>
<% end %>

<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {query_id: query, format: 'atom', page: nil, key: User.current.rss_key}, title: t(:label_work_package_plural)) %>
<%= auto_discovery_link_tag(:atom, {controller: '/journals', action: 'index', query_id: query, format: 'atom', page: nil, key: User.current.rss_key}, title: t(:label_changes_details)) %>
<% end %>

<% content_for :content_body do %>
<%= render WorkPackages::FullView::CreateComponent.new(type: params[:type],
project: @project) %>
<% end %>
10 changes: 7 additions & 3 deletions config/initializers/permissions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@
{
versions: %i[index show status_by],
journals: %i[index],
work_packages: %i[show index copy],
work_packages: %i[show index],
work_packages_api: [:get],
"work_packages/reports": %i[report report_details],
"work_packages/menus": %i[show],
Expand All @@ -230,7 +230,9 @@
contract_actions: { work_packages: %i[read] }

wpt.permission :add_work_packages,
{},
{
work_packages: %i[new]
},
permissible_on: :project,
dependencies: :view_work_packages,
contract_actions: { work_packages: %i[create] }
Expand All @@ -252,7 +254,9 @@
contract_actions: { work_packages: %i[move] }

wpt.permission :copy_work_packages,
{},
{
work_packages: %i[copy]
},
permissible_on: %i[work_package project],
require: :loggedin,
dependencies: :view_work_packages
Expand Down
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,10 @@
on: :member

get "/copy" => "work_packages#copy", on: :member, as: "copy"
get "/new" => "work_packages#new", on: :collection, as: "new"

# states managed by client-side (angular) routing on work_package#show
get "/" => "work_packages#index", on: :collection, as: "index"
get "/new" => "work_packages#index", on: :collection, as: "new", state: "new"
# We do not want to match the work package export routes
get "(/*state)" => "work_packages#show", on: :member, as: "", constraints: { id: /\d+/, state: /(?!(shares|split_view|split_create|copy)).+/ }

Check notice on line 617 in config/routes.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] config/routes.rb#L617 <Layout/LineLength>

Line is too long. [146/130]
Raw output
config/routes.rb:617:131: C: Layout/LineLength: Line is too long. [146/130]
get "/share_upsale" => "work_packages#index", on: :collection, as: "share_upsale"
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ import { SpotSwitchComponent } from 'core-app/spot/components/switch/switch.comp
import { WorkPackagePrimerizedListViewComponent } from 'core-app/features/work-packages/routing/wp-list-view/wp-primerized-list-view.component';
import { WorkPackageSplitCreateEntryComponent } from 'core-app/features/work-packages/routing/wp-split-create/wp-split-create-entry.component';
import { WorkPackageFullCopyEntryComponent } from 'core-app/features/work-packages/routing/wp-full-copy/wp-full-copy-entry.component';
import { WorkPackageFullCreateEntryComponent } from 'core-app/features/work-packages/routing/wp-full-create/wp-full-create-entry.component';

export function initializeServices(injector:Injector) {
return () => {
Expand Down Expand Up @@ -359,6 +360,7 @@ export class OpenProjectModule implements DoBootstrap {
registerCustomElement('opce-share-upsale', ShareUpsaleComponent, { injector });
registerCustomElement('opce-wp-split-view', WorkPackageSplitViewEntryComponent, { injector });
registerCustomElement('opce-wp-split-create', WorkPackageSplitCreateEntryComponent, { injector });
registerCustomElement('opce-wp-full-create', WorkPackageFullCreateEntryComponent, { injector });
registerCustomElement('opce-wp-full-copy', WorkPackageFullCopyEntryComponent, { injector });
registerCustomElement('opce-timer-account-menu', TimerAccountMenuComponent, { injector });
registerCustomElement('opce-remote-field-updater', RemoteFieldUpdaterComponent, { injector });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,10 @@ import * as URI from 'urijs';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { splitViewRoute } from 'core-app/features/work-packages/routing/split-view-routes.helper';
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import {
HalResource,
HalSource,
} from 'core-app/features/hal/resources/hal-resource';
import { HalSource } from 'core-app/features/hal/resources/hal-resource';
import { OpTitleService } from 'core-app/core/html/op-title.service';
import { WorkPackageCreateService } from './wp-create.service';
import { HalError } from 'core-app/features/hal/services/hal-error';
import idFromLink from 'core-app/features/hal/helpers/id-from-link';

@Directive()
export class WorkPackageCreateComponent extends UntilDestroyedMixin implements OnInit {
Expand Down Expand Up @@ -125,13 +121,8 @@ export class WorkPackageCreateComponent extends UntilDestroyedMixin implements O
}

public switchToFullscreen() {
if (this.routedFromAngular) {
const type = idFromLink(this.change.value<HalResource>('type')?.href);
void this.$state.go('work-packages.new', { ...this.$state.params, type });
} else {
const link = this.stateParams.projectPath ? this.pathHelper.projectWorkPackageNewPath(this.stateParams.projectPath) : this.pathHelper.workPackageNewPath();
window.location.href = link + window.location.search;
}
const link = this.stateParams.projectPath ? this.pathHelper.projectWorkPackageNewPath(this.stateParams.projectPath) : this.pathHelper.workPackageNewPath();

Check failure on line 124 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L124 <@typescript-eslint/no-unsafe-member-access>(https://typescript-eslint.io/rules/no-unsafe-member-access)

Unsafe member access .projectPath on an `any` value.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":2,"message":"Unsafe member access .projectPath on an `any` value.","line":124,"column":35,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":124,"endColumn":46}

Check failure on line 124 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L124 <@typescript-eslint/no-unsafe-argument>(https://typescript-eslint.io/rules/no-unsafe-argument)

Unsafe argument of type `any` assigned to a parameter of type `string`.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-argument","severity":2,"message":"Unsafe argument of type `any` assigned to a parameter of type `string`.","line":124,"column":91,"nodeType":"MemberExpression","messageId":"unsafeArgument","endLine":124,"endColumn":119}

Check failure on line 124 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L124 <@typescript-eslint/no-unsafe-member-access>(https://typescript-eslint.io/rules/no-unsafe-member-access)

Unsafe member access .projectPath on an `any` value.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":2,"message":"Unsafe member access .projectPath on an `any` value.","line":124,"column":108,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":124,"endColumn":119}
window.location.href = link + window.location.search;
}

public onSaved(params:{ savedResource:WorkPackageResource, isInitial:boolean }) {
Expand Down Expand Up @@ -210,13 +201,19 @@ export class WorkPackageCreateComponent extends UntilDestroyedMixin implements O
}
}

public showNewWorkPackage(wp:WorkPackageResource) {
public showNewSplitWorkPackage(wp:WorkPackageResource) {
if (wp.id) {
const link = this.pathHelper.workPackageDetailsPath(wp.project.identifier, wp.id) + window.location.search;

Check failure on line 206 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L206 <@typescript-eslint/no-unsafe-argument>(https://typescript-eslint.io/rules/no-unsafe-argument)

Unsafe argument of type `any` assigned to a parameter of type `string`.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-argument","severity":2,"message":"Unsafe argument of type `any` assigned to a parameter of type `string`.","line":206,"column":59,"nodeType":"MemberExpression","messageId":"unsafeArgument","endLine":206,"endColumn":80}

Check failure on line 206 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L206 <@typescript-eslint/no-unsafe-member-access>(https://typescript-eslint.io/rules/no-unsafe-member-access)

Unsafe member access .identifier on an `any` value.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":2,"message":"Unsafe member access .identifier on an `any` value.","line":206,"column":70,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":206,"endColumn":80}
Turbo.visit(link, { frame: 'content-bodyRight', action: 'advance' });
}
}

public showNewFullWorkPackage(wp:WorkPackageResource) {
if (wp.id) {
window.location.href = this.pathHelper.projectWorkPackagePath(wp.project.identifier, wp.id) + window.location.search;

Check failure on line 213 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L213 <@typescript-eslint/no-unsafe-argument>(https://typescript-eslint.io/rules/no-unsafe-argument)

Unsafe argument of type `any` assigned to a parameter of type `string`.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-argument","severity":2,"message":"Unsafe argument of type `any` assigned to a parameter of type `string`.","line":213,"column":69,"nodeType":"MemberExpression","messageId":"unsafeArgument","endLine":213,"endColumn":90}

Check failure on line 213 in frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-create.component.ts#L213 <@typescript-eslint/no-unsafe-member-access>(https://typescript-eslint.io/rules/no-unsafe-member-access)

Unsafe member access .identifier on an `any` value.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":2,"message":"Unsafe member access .identifier on an `any` value.","line":213,"column":80,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":213,"endColumn":90}
}
}

protected createdWorkPackage() {
const defaults:HalSource = (this.stateParams.defaults as HalSource) || {};
defaults._links = defaults._links || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WorkPackageNewFullViewComponent extends WorkPackageCreateComponent {
public successState = this.$state.current.data.successState as string;
public successState = (this.$state?.current?.data?.successState as string) || '';

Check failure on line 39 in frontend/src/app/features/work-packages/components/wp-new/wp-new-full-view.component.ts

View workflow job for this annotation

GitHub Actions / eslint

[eslint] frontend/src/app/features/work-packages/components/wp-new/wp-new-full-view.component.ts#L39 <@typescript-eslint/no-unsafe-member-access>(https://typescript-eslint.io/rules/no-unsafe-member-access)

Unsafe member access .successState on an `any` value.
Raw output
{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":2,"message":"Unsafe member access .successState on an `any` value.","line":39,"column":54,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":39,"endColumn":66}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
<wp-single-view [workPackage]="newWorkPackage"
[showProject]="copying">
</wp-single-view>
<wp-edit-actions-bar (onCancel)="cancelAndBackToList()">
<wp-edit-actions-bar
(onSave)="showNewFullWorkPackage($event)"
(onCancel)="cancelAndBackToList()">
</wp-edit-actions-bar>
</edit-form>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div class="work-packages--details-toolbar-container">
<wp-edit-actions-bar
(onCancel)="cancelAndBackToList()"
(onSave)="showNewWorkPackage($event)"
(onSave)="showNewSplitWorkPackage($event)"
>
</wp-edit-actions-bar>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ import {
} from 'core-app/features/work-packages/routing/wp-list-view/wp-primerized-list-view.component';
import { WorkPackageSplitCreateEntryComponent } from 'core-app/features/work-packages/routing/wp-split-create/wp-split-create-entry.component';
import { WorkPackageFullCopyEntryComponent } from 'core-app/features/work-packages/routing/wp-full-copy/wp-full-copy-entry.component';
import { WorkPackageFullCreateEntryComponent } from 'core-app/features/work-packages/routing/wp-full-create/wp-full-create-entry.component';

@NgModule({
imports: [
Expand Down Expand Up @@ -611,7 +612,6 @@ import { WorkPackageFullCopyEntryComponent } from 'core-app/features/work-packag
WorkPackageSplitViewComponent,
WorkPackageSplitViewEntryComponent,
WorkPackageSplitCreateEntryComponent,
WorkPackageFullCopyEntryComponent,
WorkPackageBreadcrumbComponent,
WorkPackageSplitViewToolbarComponent,
WorkPackageWatcherButtonComponent,
Expand All @@ -620,6 +620,8 @@ import { WorkPackageFullCopyEntryComponent } from 'core-app/features/work-packag

// Full view
WorkPackagesFullViewComponent,
WorkPackageFullCopyEntryComponent,
WorkPackageFullCreateEntryComponent,

// Modals
WpTableConfigurationModalComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
//++

import { WpTabWrapperComponent } from 'core-app/features/work-packages/components/wp-tabs/components/wp-tab-wrapper/wp-tab-wrapper.component';
import { WorkPackageNewFullViewComponent } from 'core-app/features/work-packages/components/wp-new/wp-new-full-view.component';
import { WorkPackagesFullViewComponent } from 'core-app/features/work-packages/routing/wp-full-view/wp-full-view.component';
import { WorkPackageSplitViewComponent } from 'core-app/features/work-packages/routing/wp-split-view/wp-split-view.component';
import { Ng2StateDeclaration } from '@uirouter/angular';
Expand Down Expand Up @@ -69,25 +68,6 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [
name: { type: 'string', dynamic: true },
},
},
{
name: 'work-packages.new',
url: '/new?type&parent_id',
component: WorkPackageNewFullViewComponent,
reloadOnSearch: false,
params: {
defaults: {
value: null,
},
},
data: {
baseRoute: 'work-packages',
allowMovingInEditMode: true,
bodyClasses: 'router--work-packages-full-create',
menuItem: menuItemClass,
successState: 'work-packages.show',
sideMenuOptions,
},
},
{
name: 'work-packages.show',
url: '/{workPackageId:[0-9]+}',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//-- 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 { ChangeDetectionStrategy, Component, ElementRef, Input } from '@angular/core';
import {
WorkPackageIsolatedQuerySpaceDirective,
} from 'core-app/features/work-packages/directives/query-space/wp-isolated-query-space.directive';
import { populateInputsFromDataset } from 'core-app/shared/components/dataset-inputs';

/**
* An entry component to be rendered by Rails which opens an isolated query space
* for the work package split view
*/
@Component({
hostDirectives: [WorkPackageIsolatedQuerySpaceDirective],
template: `
<wp-new-full-view
[stateParams]="{ type: type, parent_id: parentId, projectPath: projectIdentifier }"
[routedFromAngular]="routedFromAngular"
></wp-new-full-view>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WorkPackageFullCreateEntryComponent {
@Input() type:string;
@Input() parentId?:string;
@Input() projectIdentifier?:string;
@Input() routedFromAngular:boolean;

constructor(readonly elementRef:ElementRef) {
populateInputsFromDataset(this);

document.body.classList.add('router--work-packages-full-create');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,6 @@ export class OpTypesContextMenuDirective extends OpContextMenuTrigger {
if (!this.active) {
return;
}

// Force full-view create if in mobile view
if (this.browserDetector.isMobile) {
this.stateName = 'work-packages.new';
}
}

protected open(evt:JQuery.TriggeredEvent) {
Expand Down

0 comments on commit 84b50fb

Please sign in to comment.