From b30deb44d625a4086d2e8742dc8ecee16e0b171c Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Thu, 24 Oct 2024 13:57:33 +0200 Subject: [PATCH] Extract content of the IncludeProjects modal into a separate component so that we can re-use it in the rails Primer::Dialog (wip) [ci skip] --- .../modal_dialog_component.html.erb | 22 +++ .../modal_dialog_component.rb | 50 +++++ .../index_page_header_component.html.erb | 14 +- .../index_page_header_component.rb | 7 - app/controllers/work_packages_controller.rb | 23 ++- config/routes.rb | 2 + frontend/src/app/app.module.ts | 2 + .../wp-calendar-page.component.ts | 4 +- .../page/team-planner-page.component.ts | 4 +- .../wp-view-page/wp-view-page.component.ts | 4 +- .../project-include-entry.component.ts | 57 ++++++ .../project-include-modal.component.html | 27 +++ .../project-include-modal.component.ts | 97 ++++++++++ .../project-include.component.html | 180 ++++++++---------- .../project-include.component.ts | 44 ++--- frontend/src/app/shared/shared.module.ts | 6 +- 16 files changed, 388 insertions(+), 155 deletions(-) create mode 100644 app/components/work_packages/include_projects/modal_dialog_component.html.erb create mode 100644 app/components/work_packages/include_projects/modal_dialog_component.rb create mode 100644 frontend/src/app/shared/components/project-include/project-include-entry.component.ts create mode 100644 frontend/src/app/shared/components/project-include/project-include-modal.component.html create mode 100644 frontend/src/app/shared/components/project-include/project-include-modal.component.ts diff --git a/app/components/work_packages/include_projects/modal_dialog_component.html.erb b/app/components/work_packages/include_projects/modal_dialog_component.html.erb new file mode 100644 index 000000000000..c73f6ebf44ed --- /dev/null +++ b/app/components/work_packages/include_projects/modal_dialog_component.html.erb @@ -0,0 +1,22 @@ +<%= render(Primer::Alpha::Dialog.new( + title: I18n.t("js.include_projects.title"), + size: :medium_portrait, + id: MODAL_ID +)) do |dialog| %> + <% dialog.with_header(variant: :large) %> + <% dialog.with_body do %> + <%= helpers.angular_component_tag "opce-include-projects", + inputs: { + showHeaderText: false, + } %> + <% end %> + <% dialog.with_footer do %> + <%= render(Primer::ButtonComponent.new(data: { "close-dialog-id": MODAL_ID })) { I18n.t(:button_cancel) } %> + <%= render(Primer::ButtonComponent.new( + data: { + "close-dialog-id": MODAL_ID, + }, + scheme: :primary, + type: :submit)) { I18n.t(:button_apply) } %> + <% end %> +<% end %> diff --git a/app/components/work_packages/include_projects/modal_dialog_component.rb b/app/components/work_packages/include_projects/modal_dialog_component.rb new file mode 100644 index 000000000000..b3b12737b39c --- /dev/null +++ b/app/components/work_packages/include_projects/modal_dialog_component.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# -- 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. +# ++ + +module WorkPackages + module IncludeProjects + class ModalDialogComponent < ApplicationComponent + MODAL_ID = "op-work-packages-include-projects-dialog" + EXPORT_FORM_ID = "op-work-packages-include-projects-dialog-form" + include OpTurbo::Streamable + include OpPrimer::ComponentHelpers + + attr_reader :query, :project, :query_params + + def initialize(query:, project:, title:) + super + + @query = query + @project = project + @query_params = ::API::V3::Queries::QueryParamsRepresenter.new(query).to_url_query(merge_params: { columns: [], title: }) + end + end + end +end diff --git a/app/components/work_packages/index_page_header_component.html.erb b/app/components/work_packages/index_page_header_component.html.erb index 6007c62ef207..111a1d79c9a7 100644 --- a/app/components/work_packages/index_page_header_component.html.erb +++ b/app/components/work_packages/index_page_header_component.html.erb @@ -6,11 +6,17 @@ end header.with_breadcrumbs(breadcrumb_items) - header.with_action_dialog(mobile_icon: :"op-include-projects", + header.with_action_button(tag: :a, + mobile_icon: :"op-include-projects", mobile_label: I18n.t("js.include_projects.toggle_title"), - dialog_arguments: { id: "my_dialog", title: "A great dialog" }, - button_arguments: { button_block: project_include_button_callback, test_selector: "project-include-button" }) do |d| - d.with_body { "TODO" } + href: @project.present? ? include_projects_dialog_project_work_packages_path(@project) : include_projects_dialog_work_packages_path(), + aria: { label: I18n.t("js.include_projects.toggle_title") }, + title: I18n.t("js.include_projects.toggle_title"), + data: { controller: "async-dialog" }, + test_selector: "project-include-button", + rel: "nofollow") do |button| + button.with_leading_visual_icon(icon: :"op-include-projects") + I18n.t("js.include_projects.toggle_title") end header.with_action_button(tag: :a, diff --git a/app/components/work_packages/index_page_header_component.rb b/app/components/work_packages/index_page_header_component.rb index 92a395a5703a..e681068cce87 100644 --- a/app/components/work_packages/index_page_header_component.rb +++ b/app/components/work_packages/index_page_header_component.rb @@ -54,13 +54,6 @@ def title @query&.name ? @query.name : t(:label_work_package_plural) end - def project_include_button_callback - lambda do |button| - button.with_leading_visual_icon(icon: :"op-include-projects") - I18n.t("js.include_projects.toggle_title") - end - end - def can_rename? # TODO true diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 41a90de8d0a0..4183aeb9919a 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -40,11 +40,12 @@ class WorkPackagesController < ApplicationController :project, only: :show 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 baseline_dialog] + before_action :find_optional_project, only: %i[split_view split_create baseline_dialog include_projects_dialog] before_action :load_and_authorize_in_optional_project, only: %i[index export_dialog new copy] - authorization_checked! :index, :show, :new, :copy, :export_dialog, :split_view, :split_create, :baseline_dialog + authorization_checked! :index, :show, :new, :copy, :export_dialog, :split_view, :split_create, :baseline_dialog, + :include_projects_dialog - before_action :load_and_validate_query, only: %i[index split_view split_create copy baseline_dialog] + before_action :load_and_validate_query, only: %i[index split_view split_create copy baseline_dialog include_projects_dialog] before_action :load_work_packages, only: :index, if: -> { request.format.atom? } before_action :load_and_validate_query_for_export, only: :export_dialog @@ -124,11 +125,21 @@ def share_upsale end def export_dialog - respond_with_dialog WorkPackages::Exports::ModalDialogComponent.new(query: @query, project: @project, title: params[:title]) + respond_with_dialog WorkPackages::Exports::ModalDialogComponent.new(query: @query, + project: @project, + title: params[:title]) end def baseline_dialog - respond_with_dialog WorkPackages::Baseline::ModalDialogComponent.new(query: @query, project: @project, title: params[:title]) + respond_with_dialog WorkPackages::Baseline::ModalDialogComponent.new(query: @query, + project: @project, + title: params[:title]) + end + + def include_projects_dialog + respond_with_dialog WorkPackages::IncludeProjects::ModalDialogComponent.new(query: @query, + project: @project, + title: params[:title]) end protected @@ -194,7 +205,7 @@ def per_page_param end def project - @project ||= work_package ? work_package.project : nil + @project ||= work_package&.project end def work_package diff --git a/config/routes.rb b/config/routes.rb index db2687847fb4..586ea3e53a68 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -347,6 +347,7 @@ get "menu" => "work_packages/menus#show" get "/export_dialog" => "work_packages#export_dialog" get "/baseline_dialog" => "work_packages#baseline_dialog" + get "/include_projects_dialog" => "work_packages#include_projects_dialog" end get "/copy" => "work_packages#copy", on: :member, as: "copy" @@ -620,6 +621,7 @@ get "/export_dialog" => "work_packages#export_dialog", on: :collection, as: "export_dialog" get "/baseline_dialog" => "work_packages#baseline_dialog", on: :collection, as: "baseline_dialog" + get "/include_projects_dialog" => "work_packages#include_projects_dialog", on: :collection, as: "include_projects_dialog" get "/split_view/update_counter" => "work_packages/split_view#update_counter", on: :member diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 37b326c93ead..17202cb50846 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -169,6 +169,7 @@ import { WorkPackageFullCopyEntryComponent } from 'core-app/features/work-packag import { WorkPackageFullCreateEntryComponent } from 'core-app/features/work-packages/routing/wp-full-create/wp-full-create-entry.component'; import { WorkPackageFullViewEntryComponent } from 'core-app/features/work-packages/routing/wp-full-view/wp-full-view-entry.component'; import { OpBaselineEntryComponent } from 'core-app/features/work-packages/components/wp-baseline/baseline/baseline-entry.component'; +import { OpIncludeProjectsEntryComponent } from 'core-app/shared/components/project-include/project-include-entry.component'; export function initializeServices(injector:Injector) { return () => { @@ -366,6 +367,7 @@ export class OpenProjectModule implements DoBootstrap { registerCustomElement('opce-wp-full-create', WorkPackageFullCreateEntryComponent, { injector }); registerCustomElement('opce-wp-full-copy', WorkPackageFullCopyEntryComponent, { injector }); registerCustomElement('opce-baseline', OpBaselineEntryComponent, { injector }); + registerCustomElement('opce-include-projects', OpIncludeProjectsEntryComponent, { injector }); registerCustomElement('opce-timer-account-menu', TimerAccountMenuComponent, { injector }); registerCustomElement('opce-remote-field-updater', RemoteFieldUpdaterComponent, { injector }); registerCustomElement('opce-modal-single-date-picker', OpModalSingleDatePickerComponent, { injector }); diff --git a/frontend/src/app/features/calendar/wp-calendar-page/wp-calendar-page.component.ts b/frontend/src/app/features/calendar/wp-calendar-page/wp-calendar-page.component.ts index 0f60b209f7ee..9c12761284b8 100644 --- a/frontend/src/app/features/calendar/wp-calendar-page/wp-calendar-page.component.ts +++ b/frontend/src/app/features/calendar/wp-calendar-page/wp-calendar-page.component.ts @@ -44,10 +44,10 @@ import { ZenModeButtonComponent } from 'core-app/features/work-packages/componen import { WorkPackageSettingsButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-settings-button/wp-settings-button.component'; import { QueryResource } from 'core-app/features/hal/resources/query-resource'; import { QueryParamListenerService } from 'core-app/features/work-packages/components/wp-query/query-param-listener.service'; -import { OpProjectIncludeComponent } from 'core-app/shared/components/project-include/project-include.component'; import { calendarRefreshRequest } from 'core-app/features/calendar/calendar.actions'; import { ActionsService } from 'core-app/core/state/actions/actions.service'; import { InjectField } from 'core-app/shared/helpers/angular/inject-field.decorator'; +import { OpProjectIncludeModalComponent } from 'core-app/shared/components/project-include/project-include-modal.component'; @Component({ templateUrl: '../../work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html', @@ -97,7 +97,7 @@ export class WorkPackagesCalendarPageComponent extends PartitionedQuerySpacePage /** Define the buttons shown in the toolbar */ toolbarButtonComponents:ToolbarButtonComponentDefinition[] = [ { - component: OpProjectIncludeComponent, + component: OpProjectIncludeModalComponent, }, { component: WorkPackageFilterButtonComponent, diff --git a/frontend/src/app/features/team-planner/team-planner/page/team-planner-page.component.ts b/frontend/src/app/features/team-planner/team-planner/page/team-planner-page.component.ts index b2bedf695353..1aef1cf5ad7b 100644 --- a/frontend/src/app/features/team-planner/team-planner/page/team-planner-page.component.ts +++ b/frontend/src/app/features/team-planner/team-planner/page/team-planner-page.component.ts @@ -16,7 +16,6 @@ import { QueryParamListenerService } from 'core-app/features/work-packages/compo import { QueryResource } from 'core-app/features/hal/resources/query-resource'; import { WorkPackageSettingsButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-settings-button/wp-settings-button.component'; import { CalendarDragDropService } from 'core-app/features/team-planner/team-planner/calendar-drag-drop.service'; -import { OpProjectIncludeComponent } from 'core-app/shared/components/project-include/project-include.component'; import { EffectCallback, registerEffectCallbacks, @@ -29,6 +28,7 @@ import { InjectField } from 'core-app/shared/helpers/angular/inject-field.decora import { ActionsService } from 'core-app/core/state/actions/actions.service'; import { OpWorkPackagesCalendarService } from 'core-app/features/calendar/op-work-packages-calendar.service'; import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service'; +import { OpProjectIncludeModalComponent } from 'core-app/shared/components/project-include/project-include-modal.component'; @Component({ templateUrl: '../../../work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html', @@ -79,7 +79,7 @@ export class TeamPlannerPageComponent extends PartitionedQuerySpacePageComponent /** Define the buttons shown in the toolbar */ toolbarButtonComponents:ToolbarButtonComponentDefinition[] = [ { - component: OpProjectIncludeComponent, + component: OpProjectIncludeModalComponent, }, { component: WorkPackageFilterButtonComponent, diff --git a/frontend/src/app/features/work-packages/routing/wp-view-page/wp-view-page.component.ts b/frontend/src/app/features/work-packages/routing/wp-view-page/wp-view-page.component.ts index c4b60fe8961a..c077acc253a0 100644 --- a/frontend/src/app/features/work-packages/routing/wp-view-page/wp-view-page.component.ts +++ b/frontend/src/app/features/work-packages/routing/wp-view-page/wp-view-page.component.ts @@ -43,8 +43,8 @@ import { ZenModeButtonComponent } from 'core-app/features/work-packages/componen import { WorkPackageSettingsButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-settings-button/wp-settings-button.component'; import { of } from 'rxjs'; import { WorkPackageFoldToggleButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-fold-toggle-button/wp-fold-toggle-button.component'; -import { OpProjectIncludeComponent } from 'core-app/shared/components/project-include/project-include.component'; import { OpBaselineModalComponent } from 'core-app/features/work-packages/components/wp-baseline/baseline-modal/baseline-modal.component'; +import { OpProjectIncludeModalComponent } from 'core-app/shared/components/project-include/project-include-modal.component'; @Component({ selector: 'wp-view-page', @@ -69,7 +69,7 @@ export class WorkPackageViewPageComponent extends PartitionedQuerySpacePageCompo }, }, { - component: OpProjectIncludeComponent, + component: OpProjectIncludeModalComponent, }, { component: OpBaselineModalComponent, diff --git a/frontend/src/app/shared/components/project-include/project-include-entry.component.ts b/frontend/src/app/shared/components/project-include/project-include-entry.component.ts new file mode 100644 index 000000000000..233ea34b5101 --- /dev/null +++ b/frontend/src/app/shared/components/project-include/project-include-entry.component.ts @@ -0,0 +1,57 @@ +//-- 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 { 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: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class OpIncludeProjectsEntryComponent { + @Input() showActionBar = false; + @Input() showHeaderText = true; + + constructor( + readonly elementRef:ElementRef, + ) { + populateInputsFromDataset(this); + } +} diff --git a/frontend/src/app/shared/components/project-include/project-include-modal.component.html b/frontend/src/app/shared/components/project-include/project-include-modal.component.html new file mode 100644 index 000000000000..5ba70860f462 --- /dev/null +++ b/frontend/src/app/shared/components/project-include/project-include-modal.component.html @@ -0,0 +1,27 @@ + + + + + diff --git a/frontend/src/app/shared/components/project-include/project-include-modal.component.ts b/frontend/src/app/shared/components/project-include/project-include-modal.component.ts new file mode 100644 index 000000000000..7c2d31dd2f50 --- /dev/null +++ b/frontend/src/app/shared/components/project-include/project-include-modal.component.ts @@ -0,0 +1,97 @@ +//-- 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, + HostBinding, + Input, + OnInit, +} from '@angular/core'; +import { BehaviorSubject, combineLatest } from 'rxjs'; +import { + debounceTime, + distinctUntilChanged, + filter, + map, + mergeMap, + shareReplay, + take, +} from 'rxjs/operators'; + +import { I18nService } from 'core-app/core/i18n/i18n.service'; +import { HalResource } from 'core-app/features/hal/resources/hal-resource'; +import { + WorkPackageViewFiltersService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service'; +import { + WorkPackageViewIncludeSubprojectsService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-include-subprojects.service'; +import { QueryFilterInstanceResource } from 'core-app/features/hal/resources/query-filter-instance-resource'; +import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; +import { HalResourceService } from 'core-app/features/hal/services/hal-resource.service'; +import { CurrentProjectService } from 'core-app/core/current-project/current-project.service'; +import { IProject } from 'core-app/core/state/projects/project.model'; +import { + SearchableProjectListService, +} from 'core-app/shared/components/searchable-project-list/searchable-project-list.service'; +import { IProjectData } from 'core-app/shared/components/searchable-project-list/project-data'; + +import { insertInList } from './insert-in-list'; +import { recursiveSort } from './recursive-sort'; +import { calculatePositions } from 'core-app/shared/components/project-include/calculate-positions'; + +@Component({ + selector: 'op-project-include-modal', + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: './project-include-modal.component.html', + providers: [ + SearchableProjectListService, + ], +}) +export class OpProjectIncludeModalComponent { + @HostBinding('class.op-project-include') className = true; + + @Input() public count?:number; + + public text = { + toggle_title: this.I18n.t('js.include_projects.toggle_title'), + title: this.I18n.t('js.include_projects.title'), + }; + + public opened = false; + + constructor( + readonly I18n:I18nService, + ) { + } + + public toggleOpen():void { + this.opened = !this.opened; + } +} diff --git a/frontend/src/app/shared/components/project-include/project-include.component.html b/frontend/src/app/shared/components/project-include/project-include.component.html index ba29d1e0eaf7..f247d915b21f 100644 --- a/frontend/src/app/shared/components/project-include/project-include.component.html +++ b/frontend/src/app/shared/components/project-include/project-include.component.html @@ -1,116 +1,90 @@ - +

{{ text.title }}

+ + +
- + slot="before" + class="spot-icon spot-icon_search" + > + - -
-

{{ text.title }}

- -
- - - - - - -
    + +
      - - - {{text.no_results}} - - -
      - -
      -
      - -
      -
      - - -
      -
      - + + + {{text.no_results}} + +
      +
      +
      + +
      +
      + + +
      +
      + + -
      diff --git a/frontend/src/app/shared/components/project-include/project-include.component.ts b/frontend/src/app/shared/components/project-include/project-include.component.ts index 6a3b9f1d4fa3..48db05c190de 100644 --- a/frontend/src/app/shared/components/project-include/project-include.component.ts +++ b/frontend/src/app/shared/components/project-include/project-include.component.ts @@ -30,6 +30,7 @@ import { ChangeDetectionStrategy, Component, HostBinding, + Input, OnInit, } from '@angular/core'; import { BehaviorSubject, combineLatest } from 'rxjs'; @@ -77,8 +78,11 @@ import { calculatePositions } from 'core-app/shared/components/project-include/c export class OpProjectIncludeComponent extends UntilDestroyedMixin implements OnInit { @HostBinding('class.op-project-include') className = true; + @Input() public showActionBar = true; + + @Input() public showHeaderText = true; + public text = { - toggle_title: this.I18n.t('js.include_projects.toggle_title'), title: this.I18n.t('js.include_projects.title'), filter_all: this.I18n.t('js.include_projects.selected_filter.all'), filter_selected: this.I18n.t('js.include_projects.selected_filter.selected'), @@ -89,8 +93,6 @@ export class OpProjectIncludeComponent extends UntilDestroyedMixin implements On no_results: this.I18n.t('js.include_projects.no_results'), }; - public opened = false; - public textFieldFocused = false; public query$ = this.wpTableFilters.querySpace.query.values$(); @@ -158,8 +160,6 @@ export class OpProjectIncludeComponent extends UntilDestroyedMixin implements On }), ); - public numberOfProjectsInFilter$ = this.projectsInFilter$.pipe(map((selected) => selected.length)); - public projects$ = combineLatest([ this.searchableProjectListService.allProjects$, this.displayMode$.pipe(distinctUntilChanged()), @@ -299,29 +299,23 @@ export class OpProjectIncludeComponent extends UntilDestroyedMixin implements On .subscribe((includeSubprojects) => { this.includeSubprojects = includeSubprojects; }); + + this.searchableProjectListService.loadAllProjects(); + this.projectsInFilter$ + .pipe( + take(1), + ) + .subscribe((selectedProjects) => { + this.displayMode = 'all'; + this.searchableProjectListService.searchText = ''; + this.selectedProjects = selectedProjects as string[]; + }); } public toggleIncludeSubprojects():void { this.wpIncludeSubprojects.setIncludeSubprojects(!this.wpIncludeSubprojects.current); } - public toggleOpen():void { - this.opened = !this.opened; - - if (this.opened) { - this.searchableProjectListService.loadAllProjects(); - this.projectsInFilter$ - .pipe( - take(1), - ) - .subscribe((selectedProjects) => { - this.displayMode = 'all'; - this.searchableProjectListService.searchText = ''; - this.selectedProjects = selectedProjects as string[]; - }); - } - } - public clearSelection():void { this.selectedProjects = [this.currentProjectService.apiv3Path || '']; } @@ -337,11 +331,5 @@ export class OpProjectIncludeComponent extends UntilDestroyedMixin implements On }); this.wpIncludeSubprojects.update(this.includeSubprojects); - - this.close(); - } - - public close():void { - this.opened = false; } } diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 00be06fa2270..b2cde2a05c8f 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -100,6 +100,8 @@ import { OpenprojectModalModule } from 'core-app/shared/components/modal/modal.m import { FullCalendarModule } from '@fullcalendar/angular'; import { OpDatePickerModule } from 'core-app/shared/components/datepicker/datepicker.module'; import { ShareUpsaleComponent } from 'core-app/features/enterprise/share-upsale/share-upsale.component'; +import { OpProjectIncludeModalComponent } from 'core-app/shared/components/project-include/project-include-modal.component'; +import { OpIncludeProjectsEntryComponent } from 'core-app/shared/components/project-include/project-include-entry.component'; export function bootstrapModule(injector:Injector):void { // Ensure error reporter is run @@ -193,7 +195,7 @@ export function bootstrapModule(injector:Injector):void { DynamicModule, OpOptionListComponent, - OpProjectIncludeComponent, + OpProjectIncludeModalComponent, OpProjectIncludeListComponent, OpLoadingProjectListComponent, @@ -245,6 +247,8 @@ export function bootstrapModule(injector:Injector):void { HomescreenNewFeaturesBlockComponent, OpOptionListComponent, + OpIncludeProjectsEntryComponent, + OpProjectIncludeModalComponent, OpProjectIncludeComponent, OpProjectIncludeListComponent, OpLoadingProjectListComponent,