diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d07d0f7ab74..b794e08dda9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,9 @@ updates: fullcalendar: patterns: - '@fullcalendar*' + appsignal: + patterns: + - '@appsignal*' ignore: - dependency-name: "@angular*" update-types: ["version-update:semver-major"] diff --git a/.github/workflows/downstream-ci.yml b/.github/workflows/downstream-ci.yml index d133d1c71e2..ef16793c02b 100644 --- a/.github/workflows/downstream-ci.yml +++ b/.github/workflows/downstream-ci.yml @@ -3,12 +3,17 @@ on: push: branches: - dev - - release/* + - 'release/**' paths-ignore: - 'docs/**' - 'help/**' - pull_request: + # We run this in the less privileged mode to allow external PRs to use this workflow. + # This means the workflow will be executed on the base branch, making sure only our own workflow logic is used. + pull_request_target: types: [opened, reopened, synchronize] + branches: + - dev + - 'release/**' paths-ignore: - 'docs/**' - 'help/**' @@ -38,12 +43,43 @@ jobs: # * the name of the core branch that has to be checked out downstream to run the tests # * that is either dev, release/16.1 (for instance), or the pull request's branch name run: | - if [[ ! "${{ github.base_ref || github.ref_name }}" =~ dev|release/.+ ]]; then + echo Triggering downstream workflow + REF='' + CORE_REF='' + + if [ "${{ github.event_name }}" = "pull_request_target" ]; then + echo The workflow was triggered by a pull request targetting the dev or a release branch + REF="${{ github.base_ref }}" + CORE_REF="${{ github.event.pull_request.head.ref }}" + else + echo The workflow was triggered by a push to the dev or a release branch + REF="${{ github.ref_name }}" + CORE_REF="$REF" + fi + + if [[ ! "$REF" =~ dev|release/.+ ]]; then echo "Base branch is not dev or release branch. Cannot check downstream tests." exit 0 fi - curl -i --fail-with-body -H"authorization: Bearer $TOKEN" \ - -XPOST -H"Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/$REPOSITORY/actions/workflows/$WORKFLOW_ID/dispatches \ - -d '{"ref": "${{ github.base_ref || github.ref_name }}", "inputs": { "core_ref" : "${{ github.ref_name }}" }}' + PAYLOAD=$(printf '{"ref": "%s", "inputs": {"core_ref": "%s"}}' "$REF" "$CORE_REF") + OUTPUT_FILE=/tmp/request-output + + echo "Triggering $WORKFLOW_ID workflow on $REPOSITORY branch '$REF', which will check out core branch '$CORE_REF'" + + status=$( + curl -i --fail-with-body -s -o $OUTPUT_FILE -w "%{http_code}" \ + -H"authorization: Bearer $TOKEN" -H"Accept: application/vnd.github.v3+json" \ + -XPOST \ + -d "$PAYLOAD" \ + https://api.github.com/repos/$REPOSITORY/actions/workflows/$WORKFLOW_ID/dispatches + ) + + if [ "$status" = "204" ]; then + echo Downstream workflow triggered successfully + else + echo Failed to trigger downstream workflow: + echo + cat $OUTPUT_FILE + exit 1 + fi diff --git a/.ruby-version b/.ruby-version index f9892605c75..4f5e69734c9 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.4 +3.4.5 diff --git a/Gemfile b/Gemfile index 4f7a8ef381b..d4047b61655 100644 --- a/Gemfile +++ b/Gemfile @@ -64,7 +64,7 @@ gem "scimitar", "~> 2.11" gem "acts_as_list", "~> 1.2.0" gem "acts_as_tree", "~> 2.9.0" gem "awesome_nested_set", "~> 3.8.0" -gem "closure_tree", "~> 8.0.0" +gem "closure_tree", "~> 9.0.0" gem "rubytree", "~> 2.1.0" # Only used in down migrations now. # Is to be removed once the referencing migrations have been squashed. @@ -124,7 +124,7 @@ gem "sys-filesystem", "~> 1.5.0", require: false gem "bcrypt", "~> 3.1.6" -gem "multi_json", "~> 1.15.0" +gem "multi_json", "~> 1.17.0" gem "oj", "~> 3.16.0" gem "daemons" @@ -209,7 +209,7 @@ gem "plaintext", "~> 0.3.2" gem "ruby-progressbar", "~> 1.13.0", require: false -gem "mini_magick", "~> 5.2.0", require: false +gem "mini_magick", "~> 5.3.0", require: false gem "validate_url" @@ -365,7 +365,7 @@ group :development, :test do gem "erblint-github", require: false # Brakeman scanner - gem "brakeman", "~> 7.0.0" + gem "brakeman", "~> 7.1.0" # i18n-tasks helps find and manage missing and unused translations. gem "i18n-tasks", "~> 1.0.13", require: false @@ -378,7 +378,7 @@ gem "bootsnap", "~> 1.18.0", require: false # API gems gem "grape", "~> 2.3.0" -gem "grape_logging", "~> 1.8.4" +gem "grape_logging", "~> 2.1.1" gem "roar", "~> 1.2.0" # CORS for API @@ -394,19 +394,17 @@ gem "disposable", "~> 0.6.2" # Used for formula evaluation of calculated values gem "dentaku", "~> 3.5" -platforms :mri, :mingw, :x64_mingw do - group :postgres do - gem "pg", "~> 1.5.0" - end - - # Support application loading when no database exists yet. - gem "activerecord-nulldb-adapter", "~> 1.1.1" - - # Have application level locks on the database to have a mutex shared between workers/hosts. - # We e.g. employ this to safeguard the creation of journals. - gem "with_advisory_lock", "~> 5.3.0" +group :postgres do + gem "pg", "~> 1.5.0" end +# Support application loading when no database exists yet. +gem "activerecord-nulldb-adapter", "~> 1.1.1" + +# Have application level locks on the database to have a mutex shared between workers/hosts. +# We e.g. employ this to safeguard the creation of journals. +gem "with_advisory_lock", "~> 7.0.1" + # Load Gemfile.modules explicitly to allow dependabot to work eval_gemfile "./Gemfile.modules" diff --git a/Gemfile.lock b/Gemfile.lock index bc7fb643cc6..aaa2a38705a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -209,7 +209,7 @@ PATH remote: modules/two_factor_authentication specs: openproject-two_factor_authentication (1.0.0) - aws-sdk-sns (~> 1.100.0) + aws-sdk-sns (~> 1.101.0) messagebird-rest (~> 1.4.2) rotp (~> 6.1) webauthn (~> 3.0) @@ -345,23 +345,23 @@ GEM awesome_nested_set (3.8.0) activerecord (>= 4.0.0, < 8.1) aws-eventstream (1.4.0) - aws-partitions (1.1125.0) - aws-sdk-core (3.226.2) + aws-partitions (1.1132.0) + aws-sdk-core (3.227.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) base64 jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.106.0) - aws-sdk-core (~> 3, >= 3.225.0) + aws-sdk-kms (1.107.0) + aws-sdk-core (~> 3, >= 3.227.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.192.0) - aws-sdk-core (~> 3, >= 3.225.0) + aws-sdk-s3 (1.194.0) + aws-sdk-core (~> 3, >= 3.227.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) - aws-sdk-sns (1.100.0) - aws-sdk-core (~> 3, >= 3.225.0) + aws-sdk-sns (1.101.0) + aws-sdk-core (~> 3, >= 3.227.0) aws-sigv4 (~> 1.5) aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) @@ -392,7 +392,7 @@ GEM bindata (2.5.1) bootsnap (1.18.6) msgpack (~> 1.2) - brakeman (7.0.2) + brakeman (7.1.0) racc browser (6.2.0) builder (3.3.0) @@ -422,9 +422,9 @@ GEM childprocess (5.1.0) logger (~> 1.5) climate_control (1.2.0) - closure_tree (8.0.0) - activerecord (>= 7.1.0) - with_advisory_lock (>= 5.0.0, < 6.0.0) + closure_tree (9.0.0) + activerecord (>= 7.2.0) + with_advisory_lock (>= 7.0.0) coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) @@ -538,7 +538,7 @@ GEM activemodel equivalent-xml (0.6.0) nokogiri (>= 1.4.3) - erb (5.0.1) + erb (5.0.2) erb_lint (0.9.0) activesupport better_html (>= 2.0.1) @@ -553,14 +553,14 @@ GEM tzinfo eventmachine (1.2.7) eventmachine_httpserver (0.2.1) - excon (1.2.7) + excon (1.2.8) logger factory_bot (6.5.4) activesupport (>= 6.1.0) factory_bot_rails (6.5.0) factory_bot (~> 6.5) railties (>= 6.1.0) - faraday (2.13.2) + faraday (2.13.3) faraday-net_http (>= 2.0, < 3.5) json logger @@ -603,7 +603,7 @@ GEM fog-xml (0.1.5) fog-core nokogiri (>= 1.5.11, < 2.0.0) - formatador (1.1.0) + formatador (1.1.1) friendly_id (5.5.1) activerecord (>= 4.0.0) front_matter_parser (1.0.1) @@ -656,8 +656,8 @@ GEM mustermann-grape (~> 1.1.0) rack (>= 2) zeitwerk - grape_logging (1.8.4) - grape + grape_logging (2.1.1) + grape (< 2.4.0) rack gravatar_image_tag (1.2.0) hana (1.3.7) @@ -702,14 +702,14 @@ GEM ice_cube (0.17.0) ice_nine (0.11.2) interception (0.5) - io-console (0.8.0) + io-console (0.8.1) irb (1.15.2) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) iso8601 (0.13.0) jmespath (1.6.2) - json (2.12.2) + json (2.13.0) json-jwt (1.16.7) activesupport (>= 4.2) aes_key_wrap @@ -788,15 +788,14 @@ GEM mime-types (3.7.0) logger mime-types-data (~> 3.2025, >= 3.2025.0507) - mime-types-data (3.2025.0701) - mini_magick (5.2.0) - benchmark + mime-types-data (3.2025.0715) + mini_magick (5.3.0) logger mini_mime (1.1.5) mini_portile2 (2.8.9) minitest (5.25.5) msgpack (1.8.0) - multi_json (1.15.0) + multi_json (1.17.0) mustermann (3.0.3) ruby2_keywords (~> 0.0.1) mustermann-grape (1.1.0) @@ -815,24 +814,24 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.4) - nokogiri (1.18.8) + nokogiri (1.18.9) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.18.8-aarch64-linux-gnu) + nokogiri (1.18.9-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-aarch64-linux-musl) + nokogiri (1.18.9-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.18.8-arm-linux-gnu) + nokogiri (1.18.9-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-arm-linux-musl) + nokogiri (1.18.9-arm-linux-musl) racc (~> 1.4) - nokogiri (1.18.8-arm64-darwin) + nokogiri (1.18.9-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.8-x86_64-darwin) + nokogiri (1.18.9-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.8-x86_64-linux-gnu) + nokogiri (1.18.9-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-x86_64-linux-musl) + nokogiri (1.18.9-x86_64-linux-musl) racc (~> 1.4) oj (3.16.11) bigdecimal (>= 3.0) @@ -872,7 +871,7 @@ GEM openssl (> 2.0) optimist (3.2.1) os (1.1.4) - ostruct (0.6.2) + ostruct (0.6.3) ox (2.14.23) bigdecimal (>= 3.0) paper_trail (16.0.0) @@ -1051,14 +1050,14 @@ GEM rdoc (6.14.2) erb psych (>= 4.0.0) - recaptcha (5.19.0) + recaptcha (5.20.1) redcarpet (3.6.1) - redis (5.4.0) + redis (5.4.1) redis-client (>= 0.22.0) - redis-client (0.25.0) + redis-client (0.25.1) connection_pool regexp_parser (2.10.0) - reline (0.6.1) + reline (0.6.2) io-console (~> 0.5) representable (3.2.0) declarative (< 0.1.0) @@ -1112,7 +1111,7 @@ GEM rubocop-ast (>= 1.45.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.45.1) + rubocop-ast (1.46.0) parser (>= 3.3.7.2) prism (~> 1.4) rubocop-capybara (2.22.1) @@ -1221,7 +1220,7 @@ GEM unicode-display_width (>= 1.1.1, < 4) test-prof (1.4.4) text-hyphen (1.5.0) - thor (1.3.2) + thor (1.4.0) thread_safe (0.3.6) timecop (0.9.10) timeout (0.4.3) @@ -1292,9 +1291,9 @@ GEM websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) will_paginate (4.0.1) - with_advisory_lock (5.3.0) - activerecord (>= 6.1) - zeitwerk (>= 2.6) + with_advisory_lock (7.0.1) + activerecord (>= 7.2) + zeitwerk (>= 2.7) xpath (3.2.0) nokogiri (~> 1.8) yabeda (0.13.1) @@ -1353,7 +1352,7 @@ DEPENDENCIES axe-core-rspec bcrypt (~> 3.1.6) bootsnap (~> 1.18.0) - brakeman (~> 7.0.0) + brakeman (~> 7.1.0) browser (~> 6.2.0) budgets! byebug @@ -1363,7 +1362,7 @@ DEPENDENCIES carrierwave (~> 1.3.4) carrierwave_direct (~> 2.1.0) climate_control - closure_tree (~> 8.0.0) + closure_tree (~> 9.0.0) colored2 commonmarker (~> 2.3.0) compare-xml (~> 0.66) @@ -1400,7 +1399,7 @@ DEPENDENCIES google-apis-gmail_v1 googleauth grape (~> 2.3.0) - grape_logging (~> 1.8.4) + grape_logging (~> 2.1.1) grids! html-pipeline (~> 2.14.0) htmldiff @@ -1423,8 +1422,8 @@ DEPENDENCIES matrix (~> 0.4.3) md_to_pdf! meta-tags (~> 2.22.0) - mini_magick (~> 5.2.0) - multi_json (~> 1.15.0) + mini_magick (~> 5.3.0) + multi_json (~> 1.17.0) my_page! net-ldap (~> 0.19.0) nokogiri (~> 1.18.8) @@ -1544,7 +1543,7 @@ DEPENDENCIES warden-basic_auth (~> 0.2.1) webmock (~> 3.12) will_paginate (~> 4.0.0) - with_advisory_lock (~> 5.3.0) + with_advisory_lock (~> 7.0.1) yabeda-activerecord yabeda-prometheus-mmap yabeda-puma-plugin @@ -1584,11 +1583,11 @@ CHECKSUMS auto_strip_attributes (2.6.0) sha256=a7e2e0cf744de2bcd947fd68014220702bcc88c81274c1cd9ce6f7316aae39b0 awesome_nested_set (3.8.0) sha256=469daff411d80291dbb80d1973133e498048a7afc2519c545f62d2cdebc60eda aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b - aws-partitions (1.1125.0) sha256=f5b0085b37fc9da6746471f5ee3dde5a78d9d55270f5435daca9189f0f5ac273 - aws-sdk-core (3.226.2) sha256=ef85b574ccfa6e8a3d59c1eafd2b7388752121d8e62eee4f777ca55df9c4c9c7 - aws-sdk-kms (1.106.0) sha256=1737e3f154746dedcaf6aecf2e5490ab5e6447ac373bb5a57a19bb1184506007 - aws-sdk-s3 (1.192.0) sha256=0cd451b4119c9228cc97f6fb9a1e99cf77b827f3a15cf3ada760be12b3a620d0 - aws-sdk-sns (1.100.0) sha256=706bb13c5da789a5b9c6219b397980645536dd7f7301c09fbb8d3e8613f65a96 + aws-partitions (1.1132.0) sha256=fd06db674fbcd282ce6610cf693f0da551506e2b19bf708a04f29b5b51abce9f + aws-sdk-core (3.227.0) sha256=99071fc5e3ca9347873fd114574319740c3041745df3c74e27875bd912dfc79e + aws-sdk-kms (1.107.0) sha256=1ca8e16a29459349c88f17108573fa577287a43d6f113fab0aafae79168ffe1d + aws-sdk-s3 (1.194.0) sha256=44cf5e32ec7af4df68da2eab01eeb206514fc1e2991b08e87940fbf9cb9e006b + aws-sdk-sns (1.101.0) sha256=0baca6724431095a5f85ed4b243752ad9d4d34aee107da8a862b346690aa4d45 aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00 axe-core-api (4.10.3) sha256=6e10f3ed1c031804f16e8154d9d5dc658564d10850cee860e125fe665c3f0148 axe-core-rspec (4.10.3) sha256=ca21d0111e2d0fcd0f1da922c9071337336732aa6a3a8dc21bed94c9a701527e @@ -1600,7 +1599,7 @@ CHECKSUMS bigdecimal (3.2.2) sha256=39085f76b495eb39a79ce07af716f3a6829bc35eb44f2195e2753749f2fa5adc bindata (2.5.1) sha256=53186a1ec2da943d4cb413583d680644eb810aacbf8902497aac8f191fad9e58 bootsnap (1.18.6) sha256=0ae2393c1e911e38be0f24e9173e7be570c3650128251bf06240046f84a07d00 - brakeman (7.0.2) sha256=b602d91bcec6c5ce4d4bc9e081e01f621c304b7a69f227d1e58784135f333786 + brakeman (7.1.0) sha256=bbc708a75a53008490c8b9600b97fa85cb3d5a8818dd1560f18e0b89475d48af browser (6.2.0) sha256=281d5295788825c9396427c292c2d2be0a5c91875c93c390fde6e5d61a5ace2d budgets (1.0.0) builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f @@ -1614,7 +1613,7 @@ CHECKSUMS cgi (0.5.0) sha256=fe99f65bb2c146e294372ebb27602adbc3b4c008e9ea7038c6bd48c1ec9759da childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec climate_control (1.2.0) sha256=36b21896193fa8c8536fa1cd843a07cf8ddbd03aaba43665e26c53ec1bd70aa5 - closure_tree (8.0.0) sha256=9f33c8b2511db80d3cb418cba34da85176585bb9f1077c5d58e873e2495dbbcb + closure_tree (9.0.0) sha256=0aefc60e5e4b812ebaa34c38d8de5d7add2600f888485f266485787b17f034a8 coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b coercible (1.0.0) sha256=5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc color_conversion (0.1.2) sha256=99bea5fa412e1527a11389975aa6ad445ff8528ebae202c11d08c45ea2b94c96 @@ -1668,7 +1667,7 @@ CHECKSUMS em-synchrony (1.0.6) sha256=6e7470a684d9bbc00d61d552911b65711540bd89e95c157156f5aacdd6f306ca email_validator (2.2.4) sha256=5ab238095bec7aef9389f230e9e0c64c5081cdf91f19d6c5cecee0a93af20604 equivalent-xml (0.6.0) sha256=8919761efa848ad0846369ff8be1f646b17e5061698c4867b09829000cc3f487 - erb (5.0.1) sha256=760439803b36cc93eca8a266aab614614e588024a89bc30a62e78d98ff452c23 + erb (5.0.2) sha256=d30f258143d4300fb4ecf430042ac12970c9bb4b33c974a545b8f58c1ec26c0f erb_lint (0.9.0) sha256=dfb5e40ad839e8d1f0d56ca85ec9a7ac4c9cd966ec281138282f35b323ca7c31 erblint-github (1.0.1) sha256=9f28f7dc381a0dc68a0093ef7af3424ed9d2bb2b3e39bdc8e8cba86a0d31f2d0 erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 @@ -1676,10 +1675,10 @@ CHECKSUMS et-orbi (1.2.11) sha256=d26e868cc21db88280a9ec1a50aa3da5d267eb9b2037ba7b831d6c2731f5df64 eventmachine (1.2.7) sha256=994016e42aa041477ba9cff45cbe50de2047f25dd418eba003e84f0d16560972 eventmachine_httpserver (0.2.1) sha256=5db5e8a23754204d43592e5fcc2160457c57c870babe6307c4e61fc95019b809 - excon (1.2.7) sha256=3b3917dbdf0c65b8d872039fe2b37bf423da2f245ef05b0af07423027c4cfde5 + excon (1.2.8) sha256=150f57a0f3919b8d2b3f74535596f9876389c6dde157e0bfac8f26631eb135d0 factory_bot (6.5.4) sha256=4707fb7d80a7c14d71feb069460587bfc342e4ff1ef28097e0ad69d5ddfce613 factory_bot_rails (6.5.0) sha256=4a7b61635424a57cc60412a18b72b9dcfb02fabfce2c930447a01dce8b37c0a2 - faraday (2.13.2) sha256=5c19762e3bbe78e61d8007c5119f2968373c5296d6c6d6aa05b6f9cec34f2a1a + faraday (2.13.3) sha256=e9571e7a4ada595b385da5fc749edf7b11dc6aa9d98ab63286c3f28dc4ac01b7 faraday-follow_redirects (0.3.0) sha256=d92d975635e2c7fe525dd494fcd4b9bb7f0a4a0ec0d5f4c15c729530fdb807f9 faraday-net_http (3.4.1) sha256=095757fae7872b94eac839c08a1a4b8d84fd91d6886cfbe75caa2143de64ab3b fastimage (2.3.1) sha256=23c629f1f3e7d61bcfcc06c25b3d2418bc6bf41d2e615dbf5132c0e3b63ecce9 @@ -1700,7 +1699,7 @@ CHECKSUMS fog-core (2.6.0) sha256=3fe08aa83a23cddce42f4ba412040c08f890d7ff04c175c0ee59119371245be6 fog-json (1.2.0) sha256=dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe fog-xml (0.1.5) sha256=52b9fea10701461dd3eaf9d9839702169b418dbbf50426786b9b74fade373bd6 - formatador (1.1.0) sha256=54e23e2af4d60bb9327c7fac62b29968e4cf28cee0111f726d0bdeadc85e06d0 + formatador (1.1.1) sha256=cd0870fb00738204c98e9239f81fadc6f7966724d8037ba471684ed180fabbeb friendly_id (5.5.1) sha256=e018f2b89bfc143276fee6d378a64792385cd4fddd3d4fce501f59ec19c06207 front_matter_parser (1.0.1) sha256=bae298bda01db95788a4d6452f1670a3d198c6716c8d3727db9a95533deb7b7b fugit (1.11.1) sha256=e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868 @@ -1715,7 +1714,7 @@ CHECKSUMS google-logging-utils (0.2.0) sha256=675462b4ea5affa825a3442694ca2d75d0069455a1d0956127207498fca3df7b googleauth (1.14.0) sha256=62e7de11791890c3d3dc70582dfd9ab5516530e4e4f56d96451fd62c76475149 grape (2.3.0) sha256=99484ae2907b06a9e109edf2911c383809bf7f7c00d65554e4d01f0388728bda - grape_logging (1.8.4) sha256=efcc3e322dbd5d620a68f078733b7db043cf12680144cd03c982f14115c792d1 + grape_logging (2.1.1) sha256=7fc347bad894d4496970651971db8bdee874b67bb30255394620d082fa0b51bb gravatar_image_tag (1.2.0) sha256=eb5630fea846b711e713b934a0178fb9785f02f4eb9ced8d6faa4d537c40fdcf grids (1.0.0) hana (1.3.7) sha256=5425db42d651fea08859811c29d20446f16af196308162894db208cac5ce9b0d @@ -1738,11 +1737,11 @@ CHECKSUMS ice_cube (0.17.0) sha256=32deb45dda4b4acc53505c2f581f6d32b5afc04d29b9004769944a0df5a5fcbe ice_nine (0.11.2) sha256=5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db interception (0.5) sha256=a53818d636752a8df90d8c1bb2f7b6e13a7b828543cb02b50fbde98b849d7907 - io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2 + io-console (0.8.1) sha256=1e15440a6b2f67b6ea496df7c474ed62c860ad11237f29b3bd187f054b925fcb irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba iso8601 (0.13.0) sha256=298c2b15b7be5fa95a1372813d36a2257656cd8e906dfbc1f5cb409851425aa2 jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 - json (2.12.2) sha256=ba94a48ad265605c8fa9a50a5892f3ba6a02661aa010f638211f3cb36f44abf4 + json (2.13.0) sha256=a4bdf1ce8db5617ec6c59e021db4a398e54b57b335e1fa417ac7badc3fb7c1a0 json-jwt (1.16.7) sha256=ccabff4c6d1a14276b23178e8bebe513ef236399b72a0b886d7ed94800d172a5 json-schema (4.3.1) sha256=d5e68dc32b94408d0b06ad04f9382ccbb6fe5a44910e066f8547f56c471a7825 json_schemer (2.4.0) sha256=56cb6117bb5748d925b33ad3f415b513d41d25d0bbf57fe63c0a78ff05597c24 @@ -1770,13 +1769,13 @@ CHECKSUMS meta-tags (2.22.1) sha256=e5ae1febbd320d396c7226d7edb868e5d63466c14b9c8b06622a1a74e6dce354 method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5 mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56 - mime-types-data (3.2025.0701) sha256=1c7df686911260bf9127c7263840b94fd73ed4193f62d625aefc217af101e161 - mini_magick (5.2.0) sha256=2757ffbfdb1d38242d1da9ff1505360ab75d59dc02eb7ab79ff6d5acb1243f4a + mime-types-data (3.2025.0715) sha256=865f9759d5db11f983086a70379f8282e2e64fba7b82058b928c63a7ab79871d + mini_magick (5.3.0) sha256=6f13309c90f9ebe204b4c3f04d0a5a9265c5f734950894e83fa2480d4aa79ba4 mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756 msgpack (1.8.0) sha256=e64ce0212000d016809f5048b48eb3a65ffb169db22238fb4b72472fecb2d732 - multi_json (1.15.0) sha256=1fd04138b6e4a90017e8d1b804c039031399866ff3fbabb7822aea367c78615d + multi_json (1.17.0) sha256=76581f6c96aebf2e85f8a8b9854829e0988f335e8671cd1a56a1036eb75e4a1b mustermann (3.0.3) sha256=d1f8e9ba2ddaed47150ddf81f6a7ea046826b64c672fbc92d83bce6b70657e88 mustermann-grape (1.1.0) sha256=8d258a986004c8f01ce4c023c0b037c168a9ed889cf5778068ad54398fa458c5 mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751 @@ -1788,15 +1787,15 @@ CHECKSUMS net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9 - nokogiri (1.18.8) sha256=8c7464875d9ca7f71080c24c0db7bcaa3940e8be3c6fc4bcebccf8b9a0016365 - nokogiri (1.18.8-aarch64-linux-gnu) sha256=36badd2eb281fca6214a5188e24a34399b15d89730639a068d12931e2adc210e - nokogiri (1.18.8-aarch64-linux-musl) sha256=664e0f9a77a7122a66d6c03abba7641ca610769a4728db55ee1706a0838b78a2 - nokogiri (1.18.8-arm-linux-gnu) sha256=17de01ca3adf9f8e187883ed73c672344d3dbb3c260f88ffa1008e8dc255a28e - nokogiri (1.18.8-arm-linux-musl) sha256=6e6d7e71fc39572bd613a82d528cf54392c3de1ba5ce974f05c832b8187a040b - nokogiri (1.18.8-arm64-darwin) sha256=483b5b9fb33653f6f05cbe00d09ea315f268f0e707cfc809aa39b62993008212 - nokogiri (1.18.8-x86_64-darwin) sha256=024cdfe7d9ae3466bba6c06f348fb2a8395d9426b66a3c82f1961b907945cc0c - nokogiri (1.18.8-x86_64-linux-gnu) sha256=4a747875db873d18a2985ee2c320a6070c4a414ad629da625fbc58d1a20e5ecc - nokogiri (1.18.8-x86_64-linux-musl) sha256=ddd735fba49475a395b9ea793bb6474e3a3125b89960339604d08a5397de1165 + nokogiri (1.18.9) sha256=ac5a7d93fd0e3cef388800b037407890882413feccca79eb0272a2715a82fa33 + nokogiri (1.18.9-aarch64-linux-gnu) sha256=5bcfdf7aa8d1056a7ad5e52e1adffc64ef53d12d0724fbc6f458a3af1a4b9e32 + nokogiri (1.18.9-aarch64-linux-musl) sha256=55e9e6ca46c4ad1715e313f407d8481d15be1e3b65d9f8e52ba1c124d01676a7 + nokogiri (1.18.9-arm-linux-gnu) sha256=fe611ae65880e445a9c0f650d52327db239f3488626df4173c05beafd161d46e + nokogiri (1.18.9-arm-linux-musl) sha256=935605e14c0ba17da18d203922440bf6c0676c602659278d855d4622d756a324 + nokogiri (1.18.9-arm64-darwin) sha256=eea3f1f06463ff6309d3ff5b88033c4948d0da1ab3cc0a3a24f63c4d4a763979 + nokogiri (1.18.9-x86_64-darwin) sha256=e0d2deb03d3d7af8016e8c9df5ff4a7d692159cefb135cbb6a4109f265652348 + nokogiri (1.18.9-x86_64-linux-gnu) sha256=b52f5defedc53d14f71eeaaf990da66b077e1918a2e13088b6a96d0230f44360 + nokogiri (1.18.9-x86_64-linux-musl) sha256=e69359d6240c17e64cc9f43970d54f13bfc7b8cc516b819228f687e953425e69 oj (3.16.11) sha256=2aab609d2bc896529bd3c70d737f591c13932a640ba6164a0f7e414efdb052b1 okcomputer (1.19.0) sha256=8548935a82f725bdd8f2c329925a9f1a1bb2ce19ce26b47d7515665ee363b458 omniauth (1.9.2) @@ -1836,7 +1835,7 @@ CHECKSUMS openssl-signature_algorithm (1.3.0) sha256=a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80 optimist (3.2.1) sha256=8cf8a0fd69f3aa24ab48885d3a666717c27bc3d9edd6e976e18b9d771e72e34e os (1.1.4) sha256=57816d6a334e7bd6aed048f4b0308226c5fb027433b67d90a9ab435f35108d3f - ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0 + ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 overviews (1.0.0) ox (2.14.23) sha256=4a9aedb4d6c78c5ebac1d7287dc7cc6808e14a8831d7adb727438f6a1b461b66 paper_trail (16.0.0) sha256=e9b9f0fb1b8b590c8231cfa931b282ba92f90e066e393930a5e1c61ae4c5019d @@ -1897,12 +1896,12 @@ CHECKSUMS rbtrace (0.5.2) sha256=a2d7d222ab81363aaa0e91337ddbf70df834885d401a80ea0339d86c71f31895 rbtree3 (0.7.1) sha256=ab60ead728a5491b70df4f4065e180b18dbab5319f817ce1dbf5dd906f26d8ba rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226 - recaptcha (5.19.0) sha256=b69c021a5b788da06901d2c95ab86f10a8634e6496343096cc5167f0318b2a39 + recaptcha (5.20.1) sha256=34febe7e79ec9f67aad21e51883b5960d093042a7dfb1b074f53bd67dd8e4c29 redcarpet (3.6.1) sha256=d444910e6aa55480c6bcdc0cdb057626e8a32c054c29e793fa642ba2f155f445 - redis (5.4.0) sha256=798900d869418a9fc3977f916578375b45c38247a556b61d58cba6bb02f7d06b - redis-client (0.25.0) sha256=927dfd07a37346fd9111d80cac3199d2a02b4c084c79260acf7a5057bd742910 + redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae + redis-client (0.25.1) sha256=40130f8f95194c9c73eec322516781b0bfdd8293369a67dc175bd7bc391a68bd regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61 - reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb + reline (0.6.2) sha256=1dad26a6008872d59c8e05244b119347c9f2ddaf4a53dce97856cd5f30a02846 representable (3.2.0) sha256=cc29bf7eebc31653586849371a43ffe36c60b54b0a6365b5f7d95ec34d1ebace request_store (1.7.0) sha256=e1b75d5346a315f452242a68c937ef8e48b215b9453a77a6c0acdca2934c88cb responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a @@ -1921,7 +1920,7 @@ CHECKSUMS rspec-support (3.13.4) sha256=184b1814f6a968102b57df631892c7f1990a91c9a3b9e80ef892a0fc2a71a3f7 rspec-wait (1.0.2) sha256=865f921239325d3d26fc10ded4bdd485d8b58bcaaad1a28dd85ed15266b5a912 rubocop (1.78.0) sha256=8b74a6f912eb4fd3e6878851f7f7f45dcad8c7185c34250d4f952b0ee80d6bc0 - rubocop-ast (1.45.1) sha256=94042e49adc17f187ba037b33f941ba7398fede77cdf4bffafba95190a473a3e + rubocop-ast (1.46.0) sha256=0da7f6ad5b98614f89b74f11873c191059c823eae07d6ffd40a42a3338f2232b rubocop-capybara (2.22.1) sha256=ced88caef23efea53f46e098ff352f8fc1068c649606ca75cb74650970f51c0c rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe rubocop-openproject (0.3.0) sha256=9554496e7ef0a2cf65dc2b32bee1bfa223b4f9ae058a5c603489d34e9001a828 @@ -1970,7 +1969,7 @@ CHECKSUMS terminal-table (4.0.0) sha256=f504793203f8251b2ea7c7068333053f0beeea26093ec9962e62ea79f94301d2 test-prof (1.4.4) sha256=1a59513ed9d33a1f5ca17c0b89da4e70f60a91c83ec62e9a873dbb99141353ef text-hyphen (1.5.0) sha256=c44a4533b8a554e7ff7c955e131bcccc78a0b4c56ce1d73f2c8c11f43b075a06 - thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda + thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d thread_safe (0.3.6) sha256=9ed7072821b51c57e8d6b7011a8e282e25aeea3a4065eab326e43f66f063b05a timecop (0.9.10) sha256=12ba45ce57cdcf6b1043cb6cdffa6381fd89ce10d369c28a7f6f04dc1b0cd8eb timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e @@ -2004,7 +2003,7 @@ CHECKSUMS websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962 websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 will_paginate (4.0.1) sha256=107b226ebe1d393d274575956a7c472e1eefdd97d8828e01b72d425d15a875b9 - with_advisory_lock (5.3.0) sha256=bdb1864430853fe9081a7765f2d5b7cc42725c9ccf1901d20e9989828901b94e + with_advisory_lock (7.0.1) sha256=58b8a0a9a428e2d335e3791b745c9e98d092a6d5ee92dfafe400b40e8bcfde8a xpath (3.2.0) sha256=6dfda79d91bb3b949b947ecc5919f042ef2f399b904013eb3ef6d20dd3a4082e yabeda (0.13.1) sha256=3213025f22b7746602c8a4c41e2ed82d73a90bdc5489f6ef472142b06c1cf954 yabeda-activerecord (0.1.1) sha256=ae338213c264f20d8642e8bf47ac6058c49a6f7c8c00c892cd5765332914f45f @@ -2015,7 +2014,7 @@ CHECKSUMS zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85 RUBY VERSION - ruby 3.4.4p34 + ruby 3.4.5p51 BUNDLED WITH - 2.6.9 + 2.7.0 diff --git a/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_form_modal_component.rb b/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_form_modal_component.rb index 647e2fec7ac..953d9f321ae 100644 --- a/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_form_modal_component.rb +++ b/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_form_modal_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH @@ -32,8 +34,8 @@ module Admin class NewCustomFieldProjectsFormModalComponent < ApplicationComponent include OpTurbo::Streamable - DIALOG_ID = "new-custom-field-projects-modal".freeze - DIALOG_BODY_ID = "new-custom-field-projects-modal-body".freeze + DIALOG_ID = "new-custom-field-projects-modal" + DIALOG_BODY_ID = "new-custom-field-projects-modal-body" def initialize(custom_field_project_mapping:, custom_field:, **) @custom_field_project_mapping = custom_field_project_mapping diff --git a/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_modal_component.rb b/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_modal_component.rb index e264b251323..2f693987bda 100644 --- a/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_modal_component.rb +++ b/app/components/admin/custom_fields/custom_field_projects/new_custom_field_projects_modal_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH diff --git a/app/components/admin/custom_fields/custom_field_projects/row_component.rb b/app/components/admin/custom_fields/custom_field_projects/row_component.rb index d7b6ac1d62e..175d4f398f6 100644 --- a/app/components/admin/custom_fields/custom_field_projects/row_component.rb +++ b/app/components/admin/custom_fields/custom_field_projects/row_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH diff --git a/app/components/admin/custom_fields/custom_field_projects/table_component.rb b/app/components/admin/custom_fields/custom_field_projects/table_component.rb index 9cded59b611..d1d1c0d6d6f 100644 --- a/app/components/admin/custom_fields/custom_field_projects/table_component.rb +++ b/app/components/admin/custom_fields/custom_field_projects/table_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH diff --git a/app/components/admin/custom_fields/edit_form_header_component.rb b/app/components/admin/custom_fields/edit_form_header_component.rb index 04eac57114e..b1b3afce987 100644 --- a/app/components/admin/custom_fields/edit_form_header_component.rb +++ b/app/components/admin/custom_fields/edit_form_header_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH diff --git a/app/components/admin/custom_fields/hierarchy/item_form_component.rb b/app/components/admin/custom_fields/hierarchy/item_form_component.rb index 816ff30c795..09034d3b962 100644 --- a/app/components/admin/custom_fields/hierarchy/item_form_component.rb +++ b/app/components/admin/custom_fields/hierarchy/item_form_component.rb @@ -35,10 +35,14 @@ module Admin include OpTurbo::Streamable def item_options - options = { url:, method: http_verb, data: { test_selector: "op-custom-fields--new-item-form" } } - options[:data][:turbo_frame] = ItemsComponent.wrapper_key if model.new_record? - - options + { + url:, + method: http_verb, + data: { + turbo_frame: ItemsComponent.wrapper_key, + test_selector: "op-custom-fields--new-item-form" + } + } end def http_verb diff --git a/app/components/admin/custom_fields/hierarchy/items_component.html.erb b/app/components/admin/custom_fields/hierarchy/items_component.html.erb index e26ba1a85e6..50c30bb2fb1 100644 --- a/app/components/admin/custom_fields/hierarchy/items_component.html.erb +++ b/app/components/admin/custom_fields/hierarchy/items_component.html.erb @@ -31,62 +31,73 @@ See COPYRIGHT and LICENSE files for more details. <%= component_wrapper(tag: "turbo-frame", refresh: :morph, data: { turbo_action: :advance }) do - flex_layout do |container| - container.with_row do - render(Primer::OpenProject::SubHeader.new) do |subheader| - subheader.with_action_button(tag: :a, - scheme: :primary, - leading_icon: :plus, - label: t(:label_item), - href: new_item_path) do - I18n.t(:label_item) - end - end - end - container.with_row(mb: 3) do - render(Primer::Beta::BorderBox.new) do |box| - box.with_header { item_header } - - if children.empty? - box.with_row do - render(Primer::Beta::Blankslate.new(test_selector: "op-custom-fields--hierarchy-items-blankslate")) do |component| - component.with_visual_icon(icon: blank_icon) - - component.with_heading(tag: :h3).with_content(I18n.t(blank_header_text)) - component.with_description { I18n.t(blank_description_text) } - component.with_primary_action(tag: :a, href: new_item_path) do |button| - button.with_leading_visual_icon(icon: :plus) - I18n.t(:label_item) - end + render(Primer::Alpha::Layout.new(stacking_breakpoint: :md, classes: "custom-fields-hierarchy-page")) do |content| + content.with_main do + flex_layout do |container| + container.with_row do + render(Primer::OpenProject::SubHeader.new) do |subheader| + subheader.with_action_button( + tag: :a, + scheme: :primary, + leading_icon: :plus, + label: t(:label_item), + href: new_item_path + ) do + I18n.t(:label_item) end end - else - children.each do |item| - drag_controls = if item.persisted? - { - "data-controller": "admin--hierarchy-item", - "data-action": "dragstart->admin--hierarchy-item#dragstart + end + + container.with_row(mb: 3) do + render(Primer::Beta::BorderBox.new) do |box| + box.with_header { item_header } + + if children.empty? + box.with_row do + render(Primer::Beta::Blankslate.new(test_selector: "op-custom-fields--hierarchy-items-blankslate")) do |component| + component.with_visual_icon(icon: blank_icon) + + component.with_heading(tag: :h3).with_content(I18n.t(blank_header_text)) + component.with_description { I18n.t(blank_description_text) } + component.with_primary_action(tag: :a, href: new_item_path) do |button| + button.with_leading_visual_icon(icon: :plus) + I18n.t(:label_item) + end + end + end + else + children.each do |item| + drag_controls = if item.persisted? + { + "data-controller": "admin--hierarchy-item", + "data-action": "dragstart->admin--hierarchy-item#dragstart dragenter->admin--hierarchy-item#dragenter dragleave->admin--hierarchy-item#dragleave dragend->admin--hierarchy-item#dragend drop->admin--hierarchy-item#drop", - "data-hierarchy-item-id": item.id, - "data-sort-order": item.sort_order, - "data-frame-id": Admin::CustomFields::Hierarchy::ItemsComponent.wrapper_key, - "data-move-url": move_custom_field_item_url(root.custom_field_id, item), - "data-index-url": custom_field_item_url(root.custom_field_id, item.parent) - } - else - {} - end + "data-hierarchy-item-id": item.id, + "data-sort-order": item.sort_order, + "data-frame-id": Admin::CustomFields::Hierarchy::ItemsComponent.wrapper_key, + "data-move-url": move_custom_field_item_url(root.custom_field_id, item), + "data-index-url": custom_field_item_url(root.custom_field_id, item.parent) + } + else + {} + end - box.with_row(**drag_controls) do - render Admin::CustomFields::Hierarchy::ItemComponent.new(item: item) + box.with_row(**drag_controls) do + render Admin::CustomFields::Hierarchy::ItemComponent.new(item: item) + end + end end end end end end + + content.with_sidebar(row_placement: :start, col_placement: :start, border: true, border_bottom: 0, p: 3, classes: "custom-fields-hierarchy-page--sidebar") do + render Admin::CustomFields::Hierarchy::TreeViewComponent.new(custom_field: root.custom_field, active_item: model) + end end end %> diff --git a/app/components/admin/custom_fields/hierarchy/tree_view_component.rb b/app/components/admin/custom_fields/hierarchy/tree_view_component.rb index e99ab023524..fee4975405b 100644 --- a/app/components/admin/custom_fields/hierarchy/tree_view_component.rb +++ b/app/components/admin/custom_fields/hierarchy/tree_view_component.rb @@ -50,7 +50,7 @@ module Admin if child_hash.empty? tree.with_leaf(**item_options(item)) else - expanded = child_hash.any? { |child, _| current?(child) } + expanded = current?(item) || child_hash.any? { |child, _| current?(child) } tree.with_sub_tree(expanded: expanded, **item_options(item)) do |sub_tree| add_sub_tree(sub_tree, child_hash) diff --git a/app/components/concerns/op_turbo/streamable.rb b/app/components/concerns/op_turbo/streamable.rb index 5da280d7894..01a1d9df80a 100644 --- a/app/components/concerns/op_turbo/streamable.rb +++ b/app/components/concerns/op_turbo/streamable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH @@ -33,8 +35,10 @@ module OpTurbo # rubocop:enable OpenProject/AddPreviewForViewComponent INLINE_ACTIONS = %i[dialog flash].freeze + private_constant :INLINE_ACTIONS # Turbo allows the response method for these actions only: ACTIONS_WITH_METHOD = %i[update replace].freeze + private_constant :ACTIONS_WITH_METHOD extend ActiveSupport::Concern @@ -44,116 +48,127 @@ module OpTurbo end end - included do - def render_as_turbo_stream(view_context:, action: :update, method: nil, **attributes) - case action - when :update, *INLINE_ACTIONS - @inner_html_only = true - template = render_in(view_context) - when :replace - template = render_in(view_context) - when :remove - @wrapper_only = true - render_in(view_context) - template = nil - else - raise ArgumentError, "Unsupported action #{action}" - end - - if INLINE_ACTIONS.exclude?(action) && !wrapped? - raise MissingComponentWrapper, - "Wrap your component in a `component_wrapper` block in order to use turbo-stream methods" - end - - if method && !action.in?(ACTIONS_WITH_METHOD) - raise ArgumentError, "The #{action} action does not supports a method" - end - - OpTurbo::StreamComponent.new( - action:, - method:, - target: wrapper_key, - template:, - **attributes - ).render_in(view_context) + ## + # Renders the component as a Turbo Stream. + # + # The rendered component is wrapped in a `` tag. + # + # @example + # + # + # + # + # @param [ActionView::Context] view_context the view context to render in. + # @param [Symbol] action the Turbo Stream action. + # @param [String, nil] method the Turbo Stream method (if action is :update or :replace). + def render_as_turbo_stream(view_context:, action: :update, method: nil, **attributes) + case action + when :update, *INLINE_ACTIONS + @inner_html_only = true + template = render_in(view_context) + when :replace + template = render_in(view_context) + when :remove + @wrapper_only = true + render_in(view_context) + template = nil + else + raise ArgumentError, "Unsupported action #{action}" end - def insert_as_turbo_stream(component:, view_context:, action: :append) - template = component.render_in(view_context) - - # The component being inserted into the target component - # needs wrapping, not the target since it isn't the one - # that needs to be rendered to perform this turbo stream action. - unless component.wrapped? - raise MissingComponentWrapper, - "Wrap your component in a `component_wrapper` block in order to use turbo-stream methods" - end - - OpTurbo::StreamComponent.new( - action:, - target: insert_target_modified? ? insert_target_modifier_id : wrapper_key, - template: - ).render_in(view_context) + if INLINE_ACTIONS.exclude?(action) && !wrapped? + raise MissingComponentWrapper, + "Wrap your component in a `component_wrapper` block in order to use turbo-stream methods" end - def component_wrapper(method = nil, tag: "div", **kwargs, &block) - @wrapped = true - - wrapper_arguments = { id: wrapper_key }.merge(kwargs) - - if inner_html_only? - capture(&block) - elsif wrapper_only? - method ? send(method, wrapper_arguments) : content_tag(tag, wrapper_arguments) - else - method ? send(method, wrapper_arguments, &block) : content_tag(tag, wrapper_arguments, &block) - end + if method && !action.in?(ACTIONS_WITH_METHOD) + raise ArgumentError, "The #{action} action does not support a method" end - def wrapped? - !!@wrapped + OpTurbo::StreamComponent.new( + action:, + method:, + target: wrapper_key, + template:, + **attributes + ).render_in(view_context) + end + + def insert_as_turbo_stream(component:, view_context:, action: :append) + template = component.render_in(view_context) + + # The component being inserted into the target component + # needs wrapping, not the target since it isn't the one + # that needs to be rendered to perform this turbo stream action. + unless component.wrapped? + raise MissingComponentWrapper, + "Wrap your component in a `component_wrapper` block in order to use turbo-stream methods" end - def inner_html_only? - !!@inner_html_only + OpTurbo::StreamComponent.new( + action:, + target: insert_target_modified? ? insert_target_modifier_id : wrapper_key, + template: + ).render_in(view_context) + end + + def component_wrapper(method = nil, tag: "div", **kwargs, &) + @wrapped = true + + wrapper_arguments = { id: wrapper_key }.merge(kwargs) + + if inner_html_only? + capture(&) + elsif wrapper_only? + method ? send(method, wrapper_arguments) : content_tag(tag, wrapper_arguments) + else + method ? send(method, wrapper_arguments, &) : content_tag(tag, wrapper_arguments, &) + end + end + + def wrapped? + !!@wrapped + end + + def inner_html_only? + !!@inner_html_only + end + + def wrapper_only? + !!@wrapper_only + end + + def wrapper_key + if wrapper_uniq_by.nil? + self.class.wrapper_key + else + "#{self.class.wrapper_key}-#{wrapper_uniq_by}" + end + end + + def wrapper_uniq_by + # optionally implemented in subclass in order to make the wrapper key unique + end + + def insert_target_modified? + # optionally overriden (returning true) in subclass in order to indicate thate the insert target + # is modified and should not be the root inner html element + # insert_target_container needs to be present on component's erb template then + false + end + + def insert_target_container(tag: "div", class: nil, data: nil, style: nil, &) + unless insert_target_modified? + raise NotImplementedError, + "#insert_target_modified? needs to be implemented and return true if #insert_target_container is " \ + "used in this component" end - def wrapper_only? - !!@wrapper_only - end + content_tag(tag, id: insert_target_modifier_id, class:, data:, style:, &) + end - def wrapper_key - if wrapper_uniq_by.nil? - self.class.wrapper_key - else - "#{self.class.wrapper_key}-#{wrapper_uniq_by}" - end - end - - def wrapper_uniq_by - # optionally implemented in subclass in order to make the wrapper key unique - end - - def insert_target_modified? - # optionally overriden (returning true) in subclass in order to indicate thate the insert target - # is modified and should not be the root inner html element - # insert_target_container needs to be present on component's erb template then - false - end - - def insert_target_container(tag: "div", class: nil, data: nil, style: nil, &block) - unless insert_target_modified? - raise NotImplementedError, - "#insert_target_modified? needs to be implemented and return true if #insert_target_container is " \ - "used in this component" - end - - content_tag(tag, id: insert_target_modifier_id, class:, data:, style:, &block) - end - - def insert_target_modifier_id - "#{wrapper_key}-insert-target-modifier" - end + def insert_target_modifier_id + "#{wrapper_key}-insert-target-modifier" end end end diff --git a/app/components/enterprise_edition/buy_now_button_component.rb b/app/components/enterprise_edition/buy_now_button_component.rb index 49cf12bf830..7ab4a18d465 100644 --- a/app/components/enterprise_edition/buy_now_button_component.rb +++ b/app/components/enterprise_edition/buy_now_button_component.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true #-- copyright - # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH # diff --git a/app/components/filter/filter_component.html.erb b/app/components/filter/filter_component.html.erb index ff65952a801..17dac83f322 100644 --- a/app/components/filter/filter_component.html.erb +++ b/app/components/filter/filter_component.html.erb @@ -83,7 +83,7 @@ <%= helpers.op_icon("icon-add icon4") %> <%= t(:label_filter_add) %>: -