diff --git a/app/components/open_project/common/work_package_card_box_component.rb b/app/components/open_project/common/work_package_card_box_component.rb index 11437d4436e..a2e18d19693 100644 --- a/app/components/open_project/common/work_package_card_box_component.rb +++ b/app/components/open_project/common/work_package_card_box_component.rb @@ -297,7 +297,7 @@ module OpenProject { # Existing callers share one mirror container target on the page until # parent-specific DnD handling is extracted in follow-up work. - generic_drag_and_drop_target: "container mirrorContainer", + generic_drag_and_drop_target: "container", target_container_accessor: ":scope > ul", target_id: drag_and_drop.fetch(:target_id), target_allowed_drag_type: drag_and_drop.fetch(:allowed_drag_type) diff --git a/docs/getting-started/projects/README.md b/docs/getting-started/projects/README.md index 72087e99931..76358f2ff52 100644 --- a/docs/getting-started/projects/README.md +++ b/docs/getting-started/projects/README.md @@ -89,7 +89,15 @@ Click **Continue** to proceed. ### Define project details -Next, enter the **name** and an optional **description** for your project. You can also integrate the project into your existing project hierarchy by selecting a **parent project**, which will make the new project a **subproject**. +Next, enter the **name** for your project. + +Based on the project name, OpenProject automatically suggests an **identifier**. You can edit the suggested identifier manually if needed. The identifier is validated automatically to ensure it follows the required rules. + +> [!NOTE] +> The identifier suggestion updates automatically when you change the project name. +> If you manually edit the identifier and later go back to change the project name again, OpenProject updates the identifier suggestion once more. + +You can also optionally enter a **description** for your project. You can also integrate the project into your existing project hierarchy by selecting a **parent project**, which will make the new project a **subproject**. Click **Complete** to finish the setup. diff --git a/docs/getting-started/projects/openproject_getting_started_create_new_project_name.png b/docs/getting-started/projects/openproject_getting_started_create_new_project_name.png index 9e85eae6810..3fa7d1dfb39 100644 Binary files a/docs/getting-started/projects/openproject_getting_started_create_new_project_name.png and b/docs/getting-started/projects/openproject_getting_started_create_new_project_name.png differ diff --git a/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.spec.ts b/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.spec.ts index d92674ef150..c3e5d3225e5 100644 --- a/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.spec.ts +++ b/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.spec.ts @@ -63,12 +63,6 @@ describe('GenericDragAndDropController', () => { return ariaPressedTarget.call(controller, el); } - function callResolveMirrorContainer():Element { - const resolveMirrorContainer = Reflect.get(controller, 'resolveMirrorContainer') as (this:GenericDragAndDropController) => Element; - - return resolveMirrorContainer.call(controller); - } - describe('canStartDrag', () => { it('allows dragging a draggable row in handle-less mode', () => { const row = draggableRow(); @@ -146,21 +140,4 @@ describe('GenericDragAndDropController', () => { expect(callAriaPressedTarget(row)).toBe(handle); }); }); - - describe('resolveMirrorContainer', () => { - it('returns the configured mirror container target when present', () => { - const mirrorContainer = document.createElement('div'); - - Object.defineProperty(controller, 'hasMirrorContainerTarget', { value: true, configurable: true }); - Object.defineProperty(controller, 'mirrorContainerTarget', { value: mirrorContainer, configurable: true }); - - expect(callResolveMirrorContainer()).toBe(mirrorContainer); - }); - - it('falls back to document.body when no mirror container target exists', () => { - Object.defineProperty(controller, 'hasMirrorContainerTarget', { value: false, configurable: true }); - - expect(callResolveMirrorContainer()).toBe(document.body); - }); - }); }); diff --git a/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.ts b/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.ts index f6704899834..440c892297f 100644 --- a/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.ts +++ b/frontend/src/stimulus/controllers/dynamic/generic-drag-and-drop.controller.ts @@ -43,12 +43,10 @@ interface TargetConfig { } export default class GenericDragAndDropController extends Controller { - static targets = ['container', 'scrollContainer', 'mirrorContainer']; + static targets = ['container', 'scrollContainer']; containerTargets:HTMLElement[]; scrollContainerTargets:HTMLElement[]; - declare readonly hasMirrorContainerTarget:boolean; - declare readonly mirrorContainerTarget:HTMLElement; static values = { handle: { type: Boolean, default: true }, @@ -129,7 +127,6 @@ export default class GenericDragAndDropController extends Controller { moves: (el, _source, handle, _sibling) => this.canStartDrag(el, handle), accepts: (el:Element, target:Element, source:Element, sibling:Element) => this.accepts(el, target, source, sibling), revertOnSpill: true, // enable reverting of elements if they are dropped outside of a valid target - mirrorContainer: this.resolveMirrorContainer(), }, ) .on('cloned', (clone, _original, type) => { @@ -260,10 +257,6 @@ export default class GenericDragAndDropController extends Controller { return container; } - private resolveMirrorContainer():Element { - return this.hasMirrorContainerTarget ? this.mirrorContainerTarget : document.body; - } - // Returns the data-draggable-id of the element preceding el in its container, // or null if el is the first item (signals "move to top"). private resolveTargetPrevious(el:Element):string|null { diff --git a/modules/backlogs/spec/components/backlogs/bucket_component_spec.rb b/modules/backlogs/spec/components/backlogs/bucket_component_spec.rb index 1fb0262ef48..ae770f93af8 100644 --- a/modules/backlogs/spec/components/backlogs/bucket_component_spec.rb +++ b/modules/backlogs/spec/components/backlogs/bucket_component_spec.rb @@ -119,7 +119,7 @@ RSpec.describe Backlogs::BucketComponent, type: :component do it "wires the bucket drop-target data on the box" do expect(rendered_component).to have_css(".Box") do |box| - expect(box["data-generic-drag-and-drop-target"]).to eq("container mirrorContainer") + expect(box["data-generic-drag-and-drop-target"]).to eq("container") expect(box["data-target-id"]).to eq("backlog_bucket:#{backlog_bucket.id}") expect(box["data-target-allowed-drag-type"]).to eq("story") end diff --git a/modules/backlogs/spec/components/backlogs/inbox_component_spec.rb b/modules/backlogs/spec/components/backlogs/inbox_component_spec.rb index 7942f41b965..0e362579e57 100644 --- a/modules/backlogs/spec/components/backlogs/inbox_component_spec.rb +++ b/modules/backlogs/spec/components/backlogs/inbox_component_spec.rb @@ -64,7 +64,7 @@ RSpec.describe Backlogs::InboxComponent, type: :component do it "wires drop-target data attributes for the inbox" do expect(page).to have_css(".Box#inbox_project_#{project.id}") do |box| - expect(box["data-generic-drag-and-drop-target"]).to eq("container mirrorContainer") + expect(box["data-generic-drag-and-drop-target"]).to eq("container") expect(box["data-target-id"]).to eq("inbox") expect(box["data-target-allowed-drag-type"]).to eq("story") end diff --git a/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb b/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb index 03b8e64ff6b..d35f6ddea96 100644 --- a/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb +++ b/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb @@ -94,7 +94,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do it "wires drop-target data attributes for the sprint" do expect(rendered_component).to have_css(".Box") do |box| - expect(box["data-generic-drag-and-drop-target"]).to eq("container mirrorContainer") + expect(box["data-generic-drag-and-drop-target"]).to eq("container") expect(box["data-target-container-accessor"]).to eq(":scope > ul") expect(box["data-target-id"]).to eq("sprint:#{sprint.id}") expect(box["data-target-allowed-drag-type"]).to eq("story") diff --git a/modules/backlogs/spec/requests/backlogs/backlog_spec.rb b/modules/backlogs/spec/requests/backlogs/backlog_spec.rb index 047a301f700..6030f09d203 100644 --- a/modules/backlogs/spec/requests/backlogs/backlog_spec.rb +++ b/modules/backlogs/spec/requests/backlogs/backlog_spec.rb @@ -106,26 +106,6 @@ RSpec.describe "Backlogs::Backlog", :skip_csrf, type: :rails_request do expect(response.body).to include('id="sprint_backlogs_container"') end end - - it "uses the inbox border box as the drag mirror container" do - get "/projects/#{project.identifier}/backlogs/backlog", headers: { "Turbo-Frame" => "backlogs_container" } - - expect(response).to have_http_status(:ok) - expect(response.body).to include(%(id="inbox_project_#{project.id}")) - expect(response.body).to include('data-generic-drag-and-drop-target="container mirrorContainer"') - end - - context "with backlog buckets enabled", with_flag: { backlog_buckets: true } do - shared_let(:backlog_bucket) { create(:backlog_bucket, project:) } - - it "uses each backlog bucket border box as the drag mirror container" do - get "/projects/#{project.identifier}/backlogs/backlog", headers: { "Turbo-Frame" => "backlogs_container" } - - expect(response).to have_http_status(:ok) - expect(response.body).to include(%(data-test-selector="backlog-bucket-#{backlog_bucket.id}")) - expect(response.body).to include('data-generic-drag-and-drop-target="container mirrorContainer"') - end - end end end diff --git a/spec/components/open_project/common/work_package_card_box_component_spec.rb b/spec/components/open_project/common/work_package_card_box_component_spec.rb index 98ff722e6ba..28c37760c64 100644 --- a/spec/components/open_project/common/work_package_card_box_component_spec.rb +++ b/spec/components/open_project/common/work_package_card_box_component_spec.rb @@ -165,7 +165,7 @@ RSpec.describe OpenProject::Common::WorkPackageCardBoxComponent, type: :componen it "uses the configured drag-and-drop data" do expect(rendered_component).to have_css(".Box") do |box| - expect(box["data-generic-drag-and-drop-target"]).to eq("container mirrorContainer") + expect(box["data-generic-drag-and-drop-target"]).to eq("container") expect(box["data-target-container-accessor"]).to eq(":scope > ul") expect(box["data-target-id"]).to eq("sprint:#{sprint.id}") expect(box["data-target-allowed-drag-type"]).to eq("story")