Skip to content

Commit

Permalink
Start on using Primer components inside the datepicker modal
Browse files Browse the repository at this point in the history
  • Loading branch information
HDinger committed Dec 6, 2024
1 parent cc72da4 commit cc0f76c
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<%=
component_wrapper do
component_collection do |collection|
if show_banner?
collection.with_component(Primer::Alpha::Banner.new(scheme: banner_scheme,
full: true,
icon: :info,
description: banner_description,
mb: 3,
classes: "rounded-top-2")) do |banner|
banner.with_action_button(tag: :a, href: banner_link, target: "_blank") { I18n.t("work_packages.datepicker_modal.show_relations") }
banner_title
end
end

collection.with_component(Primer::Alpha::Dialog::Body.new) do
flex_layout do |body|
body.with_row(mb: 3) do
flex_layout(align_items: :flex_end, justify_content: :space_between) do |first_row|
first_row.with_column do
render(Primer::Alpha::FormControl.new(label: I18n.t("work_packages.datepicker_modal.mode.title"))) do |component|
component.with_input do
render(Primer::Alpha::SegmentedControl.new("aria-label": I18n.t("work_packages.datepicker_modal.mode.title"))) do |control|
control.with_item(tag: :a,
href: datepicker_dialog_content_work_package_path(manually_scheduled: true),
data: { turbo_stream: true },
label: I18n.t("work_packages.datepicker_modal.mode.manual"),
title: I18n.t("work_packages.datepicker_modal.mode.manual"),
selected: @manually_scheduled)
control.with_item(tag: :a,
href: datepicker_dialog_content_work_package_path(manually_scheduled: false),
data: { turbo_stream: true },
label: I18n.t("work_packages.datepicker_modal.mode.automatic"),
title: I18n.t("work_packages.datepicker_modal.mode.automatic"),
selected: !@manually_scheduled)
end
end
end
end

first_row.with_column(mb: 1) do
render(Primer::Alpha::CheckBox.new(name: "name",
label: I18n.t("work_packages.datepicker_modal.ignore_non_working_days.title"),
checked: @work_package.ignore_non_working_days))
end
end
end

body.with_row(mb: 3) do
flex_layout(justify_content: :space_between, gap: 3) do |second_row|
second_row.with_column do
render(Primer::Alpha::TextField.new(name: :start_date,
label: I18n.t("attributes.start_date"),
value: @work_package.start_date))
end
second_row.with_column do
render(Primer::Alpha::TextField.new(name: :due_date,
label: I18n.t("attributes.due_date"),
value: @work_package.due_date))
end
second_row.with_column do
render(Primer::Alpha::TextField.new(name: :duration,
label: I18n.t("activerecord.attributes.work_package.duration"),
value: @work_package.duration))
end
end
end
end
end
end
end
%>
101 changes: 101 additions & 0 deletions app/components/work_packages/date_picker/dialog_content_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# frozen_string_literal: true

module WorkPackages
module DatePicker
class DialogContentComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

def initialize(work_package:, manually_scheduled: true)
super

@work_package = work_package
@manually_scheduled = ActiveModel::Type::Boolean.new.cast(manually_scheduled)
end

private

def show_banner?
true # TODO
end

def banner_scheme
@manually_scheduled ? :warning : :default
end

def banner_link
gantt_index_path(
query_props: {
c: %w[id subject type status assignee project startDate dueDate],
tll: '{"left":"startDate","right":"subject","farRight":null}',
tzl: "auto",
t: "id:asc",
tv: true,
hi: true,
f: [
{ "n" => "id", "o" => "=", "v" => all_relational_wp_ids }
]
}.to_json.freeze
)
end

def banner_title
if @manually_scheduled
I18n.t("work_packages.datepicker_modal.banner.title.manually_scheduled")
elsif children.any?
I18n.t("work_packages.datepicker_modal.banner.title.automatic_with_children")
elsif predecessor_relations.any?
I18n.t("work_packages.datepicker_modal.banner.title.automatic_with_predecessor")
end
end

def banner_description
if @manually_scheduled
if children.any?
return I18n.t("work_packages.datepicker_modal.banner.description.manual_with_children")
elsif predecessor_relations.any?
if overlapping_predecessor?
return I18n.t("work_packages.datepicker_modal.banner.description.manual_overlap_with_predecessors")
elsif predecessor_with_large_gap?
return I18n.t("work_packages.datepicker_modal.banner.description.manual_gap_between_predecessors")
end
end
end

I18n.t("work_packages.datepicker_modal.banner.description.click_on_show_relations_to_open_gantt",
button_name: I18n.t("work_packages.datepicker_modal.show_relations"))
end

def overlapping_predecessor?
predecessor_work_packages.any? { |wp| wp.due_date.after?(@work_package.start_date) }
end

def predecessor_with_large_gap?
sorted = predecessor_work_packages.sort_by(&:due_date)
sorted.last.due_date.before?(@work_package.start_date - 2)
end

def predecessor_relations
@predecessor_relations ||= @work_package.follows_relations
end

def predecessor_work_packages
@predecessor_work_packages ||= predecessor_relations
.includes(:to)
.map(&:to)
end

def children
@children ||= @work_package.children
end

def all_relational_wp_ids
@work_package
.relations
.pluck(:from_id, :to_id)
.flatten
.uniq
end
end
end
end
28 changes: 26 additions & 2 deletions app/controllers/work_packages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ class WorkPackagesController < ApplicationController

before_action :authorize_on_work_package,
:project, only: %i[show generate_pdf_dialog generate_pdf]
before_action :authorize_on_work_package, only: %i[datepicker_dialog_content]
before_action :load_and_authorize_in_optional_project,
:check_allowed_export,
:protect_from_unauthorized_export, only: %i[index export_dialog]

before_action :authorize, only: :show_conflict_flash_message
authorization_checked! :index, :show, :export_dialog, :generate_pdf_dialog, :generate_pdf
authorization_checked! :index, :show, :export_dialog, :generate_pdf_dialog, :generate_pdf, :datepicker_dialog_content

before_action :load_and_validate_query, only: :index, unless: -> { request.format.html? }
before_action :load_work_packages, only: :index, if: -> { request.format.atom? }
Expand Down Expand Up @@ -106,6 +107,29 @@ def generate_pdf
redirect_back(fallback_location: work_package_path(work_package))
end

def datepicker_dialog_content
manually_scheduled = if params[:manually_scheduled].present?
params.delete(:manually_scheduled)
else
work_package.schedule_manually
end

respond_to do |format|
format.html do
render :datepicker_dialog_content,
locals: { work_package:, manually_scheduled:, params: },
layout: false
end

format.turbo_stream do
replace_via_turbo_stream(
component: WorkPackages::DatePicker::DialogContentComponent.new(work_package:, manually_scheduled:)
)
render turbo_stream: turbo_streams
end
end
end

Check notice on line 131 in app/controllers/work_packages_controller.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] app/controllers/work_packages_controller.rb#L110-L131 <Metrics/AbcSize>

Assignment Branch Condition size for datepicker_dialog_content is too high. [<2, 18, 2> 18.22/17]
Raw output
app/controllers/work_packages_controller.rb:110:3: C: Metrics/AbcSize: Assignment Branch Condition size for datepicker_dialog_content is too high. [<2, 18, 2> 18.22/17]

def show_conflict_flash_message
scheme = params[:scheme]&.to_sym || :danger

Expand Down Expand Up @@ -174,7 +198,7 @@ def per_page_param
end

def project
@project ||= work_package ? work_package.project : nil
@project ||= work_package&.project
end

def work_package
Expand Down
5 changes: 5 additions & 0 deletions app/views/work_packages/datepicker_dialog_content.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%=
content_tag("turbo-frame", id: "wp-datepicker-dialog--content") do
render(WorkPackages::DatePicker::DialogContentComponent.new(work_package:, manually_scheduled:))
end
%>
19 changes: 19 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,25 @@ en:
no_results_title_text: There are currently no workflows.

work_packages:
datepicker_modal:
banner:
description:
click_on_show_relations_to_open_gantt: 'Click on "%{button_name}" for Gantt overview.'
manual_gap_between_predecessors: "There is a gap between this and all predecessors."
manual_overlap_with_predecessors: "Overlaps with at least one predecessor."
manual_with_children: "This has child work package but their start dates are ignored."
title:
automatic_with_children: "The dates are determined by child work packages."
automatic_with_predecessor: "The start date is set by a predecessor."
manually_scheduled: "Manually scheduled. Dates not affected by relations."
ignore_non_working_days:
title: "Working days only"
mode:
title: "Scheduling mode"
automatic: "Automatic"
manual: "Manual"
show_relations: "Show relations"

x_descendants:
one: "One descendant work package"
other: "%{count} work package descendants"
Expand Down
9 changes: 0 additions & 9 deletions config/locales/js-en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -983,15 +983,6 @@ en:
comment_send_failed: "An error has occurred. Could not submit the comment."
comment_updated: "The comment was successfully updated."
confirm_edit_cancel: "Are you sure you want to cancel editing the work package?"
datepicker_modal:
automatically_scheduled_parent: "Automatically scheduled. Dates are derived from relations."
manually_scheduled: "Manual scheduling enabled, all relations ignored."
start_date_limited_by_relations: "Available start and finish dates are limited by relations."
changing_dates_affects_follow_relations: "Changing these dates will affect dates of related work packages."
click_on_show_relations_to_open_gantt: 'Click on "%{button_name}" for GANTT overview.'
show_relations: "Show relations"
ignore_non_working_days:
title: "Working days only"
description_filter: "Filter"
description_enter_text: "Enter text"
description_options_hide: "Hide options"
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@

get "/export_dialog" => "work_packages#export_dialog", on: :collection, as: "export_dialog"
get :show_conflict_flash_message, on: :collection # we don't need a specific work package for this
get "/datepicker_dialog_content" => "work_packages#datepicker_dialog_content", on: :member, as: "datepicker_dialog_content"

get "/split_view/update_counter" => "work_packages/split_view#update_counter",
on: :member
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/core/path-helper/path-helper.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ export class PathHelperService {
return `${this.workPackagePath(workPackageId)}/split_view/update_counter?counter=${counter}`;
}

public workPackageDatepickerDialogContentPath(workPackageId:string|number) {
return `${this.workPackagePath(workPackageId)}/datepicker_dialog_content`;
}

// Work Package Bulk paths

public workPackagesBulkEditPath() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { OpBasicDatePickerModule } from './basic-datepicker.module';
import { OpSpotModule } from 'core-app/spot/spot.module';
import { OpenprojectModalModule } from '../modal/modal.module';
import { OpDatePickerSheetComponent } from 'core-app/shared/components/datepicker/sheet/date-picker-sheet.component';
import { OpenprojectContentLoaderModule } from 'core-app/shared/components/op-content-loader/openproject-content-loader.module';

@NgModule({
imports: [
Expand All @@ -27,6 +28,7 @@ import { OpDatePickerSheetComponent } from 'core-app/shared/components/datepicke
OpSpotModule,
OpBasicDatePickerModule,
OpenprojectModalModule,
OpenprojectContentLoaderModule,
],

providers: [
Expand Down
Loading

0 comments on commit cc0f76c

Please sign in to comment.