diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 84c9f0eebe9..9f8fb33d8d7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -40,6 +40,8 @@ updates: update-types: ["version-update:semver-major"] - dependency-name: "@openproject/octicons" - dependency-name: "@openproject/primer-view-components" + - dependency-name: "@primer/primitives" + - dependency-name: "@primer/css" - package-ecosystem: "bundler" directory: "/" schedule: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8710da37d9f..a5d38e38ead 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -137,30 +137,25 @@ jobs: - platform: linux/amd64 digest: amd64-slim bim_support: false - debian_base: trixie target: slim runner: runner=4cpu-linux-x64 - platform: linux/amd64 digest: amd64-bim bim_support: true - debian_base: bookworm target: slim-bim runner: runner=4cpu-linux-x64 - platform: linux/arm64/v8 digest: arm64-slim - debian_base: trixie bim_support: false target: slim runner: runner=4cpu-linux-arm64 - platform: linux/amd64 digest: amd64-aio - debian_base: bookworm bim_support: true target: all-in-one runner: runner=4cpu-linux-x64 - platform: linux/arm64/v8 digest: arm64-aio - debian_base: trixie bim_support: false target: all-in-one runner: runner=4cpu-linux-arm64 @@ -197,7 +192,7 @@ jobs: id: buildx uses: docker/setup-buildx-action@v4 - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -222,7 +217,7 @@ jobs: with: path: | vendor/bundle - key: ${{ matrix.platform }}-${{ matrix.debian_base }}-vendor-bundle-${{ github.ref }} + key: ${{ matrix.platform }}-trixie-vendor-bundle-${{ github.ref }} - name: Include vendor/bundle in this build (so we can use it from the cache above) run: | sed -i 's/vendor\/bundle//g' .dockerignore @@ -234,15 +229,14 @@ jobs: platforms: ${{ matrix.platform }} target: ${{ matrix.target }} build-args: | - DEBIAN_BASE=${{ matrix.debian_base }} BIM_SUPPORT=${{ matrix.bim_support }} BUILDKIT_PROGRESS=plain pull: true load: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},manifests_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} - cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},manifests_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max + cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/trixie,manifests_prefix=cache/${{ github.repository }}/trixie,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} + cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/trixie,manifests_prefix=cache/${{ github.repository }}/trixie,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max - name: Extract vendor/bundle from container run: | docker create --name bundle ${{ steps.build.outputs.imageid }} @@ -279,12 +273,11 @@ jobs: platforms: ${{ matrix.platform }} target: ${{ matrix.target }} build-args: | - DEBIAN_BASE=${{ matrix.debian_base }} BIM_SUPPORT=${{ matrix.bim_support }} labels: ${{ steps.meta.outputs.labels }} outputs: type=image,name=${{ needs.setup.outputs.registry_image }},push-by-digest=true,name-canonical=true,push=true - cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},manifests_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} - cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},manifests_prefix=cache/${{ github.repository }}/${{ matrix.debian_base }},region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max + cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/trixie,manifests_prefix=cache/${{ github.repository }}/trixie,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} + cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/trixie,manifests_prefix=cache/${{ github.repository }}/trixie,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max - name: Export digest run: | mkdir -p /tmp/digests @@ -342,7 +335,7 @@ jobs: tags: | ${{ needs.setup.outputs.docker_tags }} - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/email-notification.yml b/.github/workflows/email-notification.yml index 0f2d3cb0b9c..b4c532c89f6 100644 --- a/.github/workflows/email-notification.yml +++ b/.github/workflows/email-notification.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Send mail - uses: dawidd6/action-send-mail@v11 + uses: dawidd6/action-send-mail@v15 with: subject: ${{ inputs.subject }} body: ${{ inputs.body }} diff --git a/.github/workflows/hocuspocus-docker.yml b/.github/workflows/hocuspocus-docker.yml index fc1e60ed6d7..27b93b9d085 100644 --- a/.github/workflows/hocuspocus-docker.yml +++ b/.github/workflows/hocuspocus-docker.yml @@ -83,7 +83,7 @@ jobs: echo $REGISTRY:$LATEST_TAG >> $GITHUB_OUTPUT echo 'EOF' >> $GITHUB_OUTPUT - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -112,7 +112,7 @@ jobs: - name: Generate GHA token id: generate-gha-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.DEPLOY_APP_ID }} private-key: ${{ secrets.DEPLOY_APP_PRIVATE_KEY }} diff --git a/.github/workflows/packager.yml b/.github/workflows/packager.yml index 30ec8fb6abd..095491ece13 100644 --- a/.github/workflows/packager.yml +++ b/.github/workflows/packager.yml @@ -1,10 +1,11 @@ name: Package on: push: + tags: + - v* branches: - packaging/* - release/* - - stable/* workflow_dispatch: schedule: - cron: '0 3 * * *' # Daily at 03:00 @@ -42,6 +43,12 @@ jobs: run: | VERSION=$(ruby -r ./lib/open_project/version.rb -e "puts OpenProject::VERSION") echo "version=$VERSION" >> $GITHUB_OUTPUT + if [[ "${{ github.ref_type }}" == "tag" ]]; then + MAJOR=$(ruby -r ./lib/open_project/version.rb -e "puts OpenProject::VERSION::MAJOR") + echo "channel=stable/${MAJOR}" >> $GITHUB_OUTPUT + else + echo "channel=${{ github.ref_name }}" >> $GITHUB_OUTPUT + fi - name: Package uses: pkgr/action/package@main id: package @@ -58,5 +65,5 @@ jobs: target: ${{ matrix.target }} token: ${{ secrets.PACKAGER_PUBLISH_TOKEN }} repository: opf/openproject - channel: ${{ github.ref_name }} + channel: ${{ steps.setup.outputs.channel }} file: ${{ steps.package.outputs.package_path }} diff --git a/AGENTS.md b/AGENTS.md index dac00fe3410..7ec29b0adc3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,8 +20,6 @@ - Node: `^22.21.0` (see `package.json` engines) - Bundler: Latest 2.x -OpenProject supports two development setups: **Local** and **Docker**. Choose one based on your preference. - ### Local Development Setup ```bash @@ -34,59 +32,24 @@ bin/dev # Start all services (Rails, frontend, Good Job ### Docker Development Setup -The Docker development environment uses configurations in `docker/dev/` and the `bin/compose` wrapper script. - -```bash -# Initial setup (first time only) -bin/compose setup # Installs backend and frontend dependencies - -# Starting services -bin/compose start # Start backend and frontend in background -bin/compose run # Start frontend in background, backend in foreground (for debugging with pry) - -# Running tests -bin/compose rspec spec/models/user_spec.rb # Run specific tests in backend-test container - -# Other operations -bin/compose reset # Remove all containers and volumes (requires setup again) -bin/compose # Pass any docker-compose command directly -``` - -**Important Docker Notes:** -- **CRITICAL**: `config/database.yml` must NOT exist when using Docker (rename or delete it) -- Most developers use a local `docker-compose.override.yml` for custom port mappings and configurations -- Copy `docker-compose.override.example.yml` to `docker-compose.override.yml` and customize as needed -- Default ports: Backend at http://localhost:3000 (or 4200 for frontend dev server) -- Services: `backend`, `frontend`, `worker`, `db`, `db-test`, `backend-test`, `cache` -- Persisted volumes: `pgdata`, `bundle`, `npm`, `tmp`, `opdata` (data survives container restarts) -- Docker build context: Uses Dockerfiles in `docker/dev/backend/` and `docker/dev/frontend/` +See [`docker/dev/AGENTS.md`](docker/dev/AGENTS.md) for full Docker setup and commands. ## Project Structure ### Key Directories -- `app/` - Rails application code - - `app/components/` - ViewComponent-based UI components (Ruby + ERB) - - `app/contracts/` - Validation and authorization contracts - - `app/controllers/` - Rails controllers - - `app/models/` - ActiveRecord models - - `app/services/` - Service objects (business logic) - - `app/workers/` - Background job workers -- `config/` - Rails configuration, routes, locales -- `db/` - Database migrations and seeds -- `frontend/src/` - Frontend code - - `frontend/src/app/` - Legacy Angular modules/components - - `frontend/src/stimulus/` - Stimulus controllers - - `frontend/src/turbo/` - Turbo integration -- `lib/` - Ruby libraries and extensions -- `lookbook/` - ViewComponent previews (https://qa.openproject-edge.com/lookbook/) -- `modules/` - OpenProject plugin modules -- `spec/` - RSpec test suite - - `spec/features/` - System/feature tests (Capybara) - - `spec/models/` - Model unit tests - - `spec/requests/` - API/integration tests - - `spec/services/` - Service tests + +- `app/` — Rails application code +- `config/` — Rails configuration, routes, locales +- `db/` — Database migrations and seeds +- `docker/dev/` — Docker development environment +- `frontend/` — TypeScript/Angular/Stimulus frontend +- `lib/` — Ruby libraries and extensions +- `lookbook/` — ViewComponent previews () +- `modules/` — OpenProject plugin modules +- `spec/` — RSpec test suite ### Configuration Files + - `.ruby-version` - Ruby version - `.rubocop.yml` - Ruby linting rules - `.erb_lint.yml` - ERB template linting @@ -95,8 +58,6 @@ bin/compose # Pass any docker-compose command dire - `package.json` / `frontend/package.json` - Node.js dependencies - `lefthook.yml` - Git hooks configuration -## Building and Testing - ### Linting (Run Before Committing) ```bash @@ -114,125 +75,16 @@ erb_lint {files} bundle exec lefthook install ``` -### Running Tests +## Commit Messages -```bash -# Backend (RSpec) - prefer specific tests over running all -bundle exec rspec spec/models/user_spec.rb # Single file -bundle exec rspec spec/models/user_spec.rb:42 # Single line -bundle exec rspec spec/features # Directory -bundle exec rake parallel:spec # Parallel execution - -# Frontend (Jasmine/Karma) -cd frontend && npm test && cd .. -``` - -### Debugging CI Failures -```bash -./script/github_pr_errors | xargs bundle exec rspec # Run failed tests from CI -./script/bulk_run_rspec spec/path/to/flaky_spec.rb # Run tests multiple times -``` - -## Code Style Guidelines - -### Ruby -- Follow [Ruby community style guide](https://github.com/bbatsov/ruby-style-guide) -- Use service objects for complex business logic (return `ServiceResult`) -- Use contracts for validation and authorization -- Keep controllers thin, models focused -- Document with [YARD](https://yardoc.org/) -- Write RSpec tests for all new features - -### JavaScript/TypeScript -- **New development**: Use Hotwire (Turbo + Stimulus) with server-rendered HTML -- **Legacy code**: Follow ESLint rules -- Prefer TypeScript over JavaScript -- Use [Primer Design System](https://primer.style/product/) via ViewComponent - -### Templates -- Use ERB for server-rendered views -- Use ViewComponents for reusable UI (with Lookbook previews) -- Lint with erb_lint before committing - -### Database Migrations -- Follow Rails migration conventions -- Migrations are "squashed" between major releases (see `docs/development/migrations/`) - -### Translations -- UI strings must use translation keys (never hard-coded) -- Source translations in `**/config/locales/en.yml` can be modified directly -- Other translations managed via Crowdin - -### Commit Messages - First line: < 72 characters, then blank line, then detailed description - Reference work packages when applicable - Merge strategy: "Merge pull request" (not squash), except single-commit PRs can use "Rebase and merge" -## Important Commands Reference - -### Local Development Commands - -```bash -# Setup -bin/setup # Initial Rails setup -bin/setup_dev # Full dev environment setup - -# Database -bundle exec rails g migration MigrationName # Generate a migration -bundle exec rails db:migrate # Run migrations -bundle exec rails db:rollback # Rollback last migration -bundle exec rails db:seed # Seed sample data - -# Development -bin/dev # Start all services -bundle exec rails console # Rails console -bundle exec rails routes # List routes - -# Testing -bundle exec rspec # Run RSpec tests -bundle exec rails parallel:spec # Parallel tests -cd frontend && npm test # Frontend tests - -# Linting -bundle exec rubocop # Ruby linting -cd frontend && npx eslint src/ # JS/TS linting -erb_lint {files} # ERB linting -``` - -### Docker Development Commands - -```bash -# Setup and lifecycle -bin/compose setup # Setup Docker environment (first time) -bin/compose start # Start all services in background -bin/compose run # Start frontend in background, backend in foreground -bin/compose reset # Remove all containers and volumes -bin/compose stop # Stop all services -bin/compose down # Stop and remove containers - -# Testing -bin/compose rspec spec/models/user_spec.rb # Run specific tests -bin/compose exec backend bundle exec rspec # Run tests directly in backend container - -# Development -bin/compose exec backend bundle exec rails console # Rails console -bin/compose logs backend # View backend logs -bin/compose logs -f backend # Follow backend logs -bin/compose ps # List running containers - -# Database -bin/compose exec backend bundle exec rails db:migrate # Run migrations -bin/compose exec backend bundle exec rails db:seed # Seed data - -# Direct docker-compose commands -bin/compose up -d # Start services -bin/compose restart backend # Restart backend service -``` - ## Additional Documentation -- `docs/development/` - Development documentation -- `docs/development/running-tests/` - Testing guide -- `docs/development/code-review-guidelines/` - Code review standards -- `CONTRIBUTING.md` - Contribution workflow -- `.github/copilot-instructions.md` - Extended agent instructions with troubleshooting +- `docs/development/` — Development documentation +- `docs/development/running-tests/` — Testing guide +- `docs/development/code-review-guidelines/` — Code review standards +- `CONTRIBUTING.md` — Contribution workflow +- `.github/copilot-instructions.md` — Extended agent instructions with troubleshooting diff --git a/Gemfile b/Gemfile index 14b8a209569..78d1a139ecd 100644 --- a/Gemfile +++ b/Gemfile @@ -69,7 +69,7 @@ gem "scimitar", "~> 2.13" gem "acts_as_list", "~> 1.2.6" gem "acts_as_tree", "~> 2.9.0" gem "awesome_nested_set", "~> 3.9.0" -gem "closure_tree", "~> 9.6.0" +gem "closure_tree", "~> 9.6.1" gem "rubytree", "~> 2.2.0" gem "addressable", "~> 2.8.9" @@ -124,7 +124,7 @@ gem "sys-filesystem", "~> 1.5.0", require: false gem "bcrypt", "~> 3.1.6" gem "multi_json", "~> 1.19.0" -gem "oj", "~> 3.16.12" +gem "oj", "~> 3.16.16" gem "daemons" gem "good_job", "~> 4.13.3" # update should be done manually in sync with saas-openproject version. @@ -208,7 +208,7 @@ gem "aws-sdk-core", "~> 3.241" # File upload via fog + screenshots on travis gem "aws-sdk-s3", "~> 1.213" -gem "openproject-token", "~> 8.8.0" +gem "openproject-token", "~> 8.8.2" gem "plaintext", "~> 0.3.7" @@ -274,7 +274,7 @@ group :test do gem "rack_session_access" gem "rspec", "~> 3.13.2" # also add to development group, so 'spec' rake task gets loaded - gem "rspec-rails", "~> 8.0.3", group: :development + gem "rspec-rails", "~> 8.0.4", group: :development # Retry failures within the same environment gem "retriable", "~> 3.2.1" diff --git a/Gemfile.lock b/Gemfile.lock index e86c2226f17..48a73a9c7d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,6 +213,11 @@ PATH specs: openproject-webhooks (1.0.0) +PATH + remote: modules/wikis + specs: + openproject-wikis (1.0.0) + PATH remote: modules/xls_export specs: @@ -223,7 +228,7 @@ GEM remote: https://rubygems.org/ specs: Ascii85 (2.0.1) - action_text-trix (2.1.16) + action_text-trix (2.1.17) railties actioncable (8.1.2) actionpack (= 8.1.2) @@ -424,7 +429,7 @@ GEM childprocess (5.1.0) logger (~> 1.5) climate_control (1.2.0) - closure_tree (9.6.0) + closure_tree (9.6.1) activerecord (>= 7.2.0) with_advisory_lock (>= 7.5.0) zeitwerk (~> 2.7) @@ -573,7 +578,7 @@ GEM faraday (>= 1, < 3) faraday-net_http (3.4.2) net-http (~> 0.5) - fastimage (2.4.0) + fastimage (2.4.1) ferrum (0.17.1) addressable (~> 2.5) base64 (~> 0.2) @@ -740,7 +745,7 @@ GEM jmespath (1.6.2) job-iteration (1.12.0) activejob (>= 6.1) - json (2.18.1) + json (2.19.1) json-jwt (1.17.0) activesupport (>= 4.2) aes_key_wrap @@ -767,7 +772,7 @@ GEM addressable (~> 2.8) childprocess (~> 5.0) logger (~> 1.6) - lefthook (2.1.2) + lefthook (2.1.4) letter_opener (1.10.0) launchy (>= 2.2, < 4) letter_opener_web (3.0.0) @@ -868,7 +873,7 @@ GEM racc (~> 1.4) nokogiri (1.19.1-x86_64-linux-musl) racc (~> 1.4) - oj (3.16.15) + oj (3.16.16) bigdecimal (>= 3.0) ostruct (>= 0.2) okcomputer (1.19.1) @@ -900,7 +905,7 @@ GEM activesupport (>= 7.2.0) openproject-octicons (>= 19.30.1) view_component (>= 3.1, < 5.0) - openproject-token (8.8.0) + openproject-token (8.8.2) activemodel openssl (4.0.1) openssl-signature_algorithm (1.3.0) @@ -1083,7 +1088,7 @@ GEM ostruct (0.6.3) ox (2.14.23) bigdecimal (>= 3.0) - pagy (43.3.1) + pagy (43.3.3) json uri yaml @@ -1310,14 +1315,14 @@ GEM rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (8.0.3) + rspec-rails (8.0.4) actionpack (>= 7.2) activesupport (>= 7.2) railties (>= 7.2) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-core (>= 3.13.0, < 5.0.0) + rspec-expectations (>= 3.13.0, < 5.0.0) + rspec-mocks (>= 3.13.0, < 5.0.0) + rspec-support (>= 3.13.0, < 5.0.0) rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.13.7) @@ -1452,7 +1457,7 @@ GEM thor (1.5.0) thread_safe (0.3.6) timecop (0.9.10) - timeout (0.6.0) + timeout (0.6.1) tpm-key_attestation (0.14.1) bindata (~> 2.4) openssl (> 2.0) @@ -1588,7 +1593,7 @@ DEPENDENCIES carrierwave (~> 2.2.6) carrierwave_direct (~> 3.0.0) climate_control - closure_tree (~> 9.6.0) + closure_tree (~> 9.6.1) colored2 commonmarker (~> 2.6.0) compare-xml (~> 0.66) @@ -1656,7 +1661,7 @@ DEPENDENCIES my_page! net-ldap (~> 0.20.0) nokogiri (~> 1.19.1) - oj (~> 3.16.12) + oj (~> 3.16.16) okcomputer (~> 1.19.1) omniauth! omniauth-openid-connect! @@ -1684,9 +1689,10 @@ DEPENDENCIES openproject-reporting! openproject-storages! openproject-team_planner! - openproject-token (~> 8.8.0) + openproject-token (~> 8.8.2) openproject-two_factor_authentication! openproject-webhooks! + openproject-wikis! openproject-xls_export! opentelemetry-exporter-otlp (~> 0.31.0) opentelemetry-instrumentation-all (~> 0.90.0) @@ -1726,7 +1732,7 @@ DEPENDENCIES roar (~> 1.2.0) rouge (~> 4.7.0) rspec (~> 3.13.2) - rspec-rails (~> 8.0.3) + rspec-rails (~> 8.0.4) rspec-retry (~> 0.6.1) rspec-wait rubocop @@ -1785,7 +1791,7 @@ DEPENDENCIES CHECKSUMS Ascii85 (2.0.1) sha256=15cb5d941808543cbb9e7e6aea3c8ec3877f154c3461e8b3673e97f7ecedbe5a - action_text-trix (2.1.16) sha256=f645a2c21821b8449fd1d6770708f4031c91a2eedf9ef476e9be93c64e703a8a + action_text-trix (2.1.17) sha256=b44691639d77e67169dc054ceacd1edc04d44dc3e4c6a427aa155a2beb4cc951 actioncable (8.1.2) sha256=dc31efc34cca9cdefc5c691ddb8b4b214c0ea5cd1372108cbc1377767fb91969 actionmailbox (8.1.2) sha256=058b2fb1980e5d5a894f675475fcfa45c62631103d5a2596d9610ec81581889b actionmailer (8.1.2) sha256=f4c1d2060f653bfe908aa7fdc5a61c0e5279670de992146582f2e36f8b9175e9 @@ -1848,7 +1854,7 @@ CHECKSUMS cgi (0.5.1) sha256=e93fcafc69b8a934fe1e6146121fa35430efa8b4a4047c4893764067036f18e9 childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec climate_control (1.2.0) sha256=36b21896193fa8c8536fa1cd843a07cf8ddbd03aaba43665e26c53ec1bd70aa5 - closure_tree (9.6.0) sha256=75aac8f058597b0d96f2052f1419c912e8f4e92425e56273db122913cdae5d1e + closure_tree (9.6.1) sha256=f6af11243dea13d888788ffb0fd28014bd1077abe3a4233ea1e7044e52fc6377 coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b coercible (1.0.0) sha256=5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc color_conversion (0.1.2) sha256=99bea5fa412e1527a11389975aa6ad445ff8528ebae202c11d08c45ea2b94c96 @@ -1915,7 +1921,7 @@ CHECKSUMS faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c faraday-follow_redirects (0.5.0) sha256=5cde93c894b30943a5d2b93c2fe9284216a6b756f7af406a1e55f211d97d10ad faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c - fastimage (2.4.0) sha256=5fce375e27d3bdbb46c18dbca6ba9af29d3304801ae1eb995771c4796c5ac7e8 + fastimage (2.4.1) sha256=c64bebd46b6fd8943ab70c1e6e85ff728f970f2e48f92ecd249b6bc3a540ad20 ferrum (0.17.1) sha256=51d591120fc593e5a13b5d9d6474389f5145bb92a91e36eab147b5d096c8cbe7 ffi (1.17.3-aarch64-linux-gnu) sha256=28ad573df26560f0aedd8a90c3371279a0b2bd0b4e834b16a2baa10bd7a97068 ffi (1.17.3-aarch64-linux-musl) sha256=020b33b76775b1abacc3b7d86b287cef3251f66d747092deec592c7f5df764b2 @@ -1981,7 +1987,7 @@ CHECKSUMS iso8601 (0.13.0) sha256=298c2b15b7be5fa95a1372813d36a2257656cd8e906dfbc1f5cb409851425aa2 jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 job-iteration (1.12.0) sha256=0164057417750f6e9c3ed548f029f1136b18eb53975fa438b09304a525d6c6c0 - json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986 + json (2.19.1) sha256=dd94fdc59e48bff85913829a32350b3148156bc4fd2a95a2568a78b11344082d json-jwt (1.17.0) sha256=6ff99026b4c54281a9431179f76ceb81faa14772d710ef6169785199caadc4cc json-schema (4.3.1) sha256=d5e68dc32b94408d0b06ad04f9382ccbb6fe5a44910e066f8547f56c471a7825 json_schemer (2.5.0) sha256=2f01fb4cce721a4e08dd068fc2030cffd0702a7f333f1ea2be6e8991f00ae396 @@ -1990,7 +1996,7 @@ CHECKSUMS ladle (1.0.1) sha256=e8586964108c798d48bf57d2a65bd5602e8e5223a176b6602a0fb36c0bda90dc language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc launchy (3.1.1) sha256=72b847b5cc961589dde2c395af0108c86ff0119f42d4648d25b5440ebb10059e - lefthook (2.1.2) sha256=da5a2484d68ee00d7fcc7e072e925c0246363eb20d77499d536bea209ae6ae06 + lefthook (2.1.4) sha256=b3c5bba86911e85b239fea3861ba8c74740fc084ba9ac79dba3fe79267572d6a letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2 letter_opener_web (3.0.0) sha256=3f391efe0e8b9b24becfab5537dfb17a5cf5eb532038f947daab58cb4b749860 lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 @@ -2034,7 +2040,7 @@ CHECKSUMS nokogiri (1.19.1-x86_64-darwin) sha256=7093896778cc03efb74b85f915a775862730e887f2e58d6921e3fa3d981e68bf nokogiri (1.19.1-x86_64-linux-gnu) sha256=1a4902842a186b4f901078e692d12257678e6133858d0566152fe29cdb98456a nokogiri (1.19.1-x86_64-linux-musl) sha256=4267f38ad4fc7e52a2e7ee28ed494e8f9d8eb4f4b3320901d55981c7b995fc23 - oj (3.16.15) sha256=4d3324cac3e8fef54c0fa250b2af26a16dadd9f9788a1d6b1b2098b793a1b2cd + oj (3.16.16) sha256=3635b36128991796434f55da8decc0de236a323535adcb36fc04e6d0253c013d okcomputer (1.19.1) sha256=7df770e768434816d228407f0786563827cbf34cb379933578829720cb4f1e77 omniauth (1.9.2) omniauth-openid-connect (0.5.0) @@ -2065,9 +2071,10 @@ CHECKSUMS openproject-reporting (1.0.0) openproject-storages (1.0.0) openproject-team_planner (1.0.0) - openproject-token (8.8.0) sha256=832a493e05dcce806134faf63ae8011cc5a48422fbed9ebb552f8028912954d4 + openproject-token (8.8.2) sha256=081cbff7269d92a82fa1d63e9e09c87b70d47d7aefadcbb80d1e7368bc2cf096 openproject-two_factor_authentication (1.0.0) openproject-webhooks (1.0.0) + openproject-wikis (1.0.0) openproject-xls_export (1.0.0) openssl (4.0.1) sha256=e27974136b7b02894a1bce46c5397ee889afafe704a839446b54dc81cb9c5f7d openssl-signature_algorithm (1.3.0) sha256=a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80 @@ -2131,7 +2138,7 @@ CHECKSUMS ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 overviews (1.0.0) ox (2.14.23) sha256=4a9aedb4d6c78c5ebac1d7287dc7cc6808e14a8831d7adb727438f6a1b461b66 - pagy (43.3.1) sha256=78e6c3e5125463b817cbe48eb5ed7b552af062c7db90bef4810d1f442ec61744 + pagy (43.3.3) sha256=26b822c32ac5452f733736aa0e56bfd45d7fd02358c7d91c7d31bae61164e758 paper_trail (17.0.0) sha256=1c2842061d3874ca7015908e821e2aa14f9b982af2acb2a7974713bf79021c85 parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130 parallel_tests (4.10.1) sha256=df05458c691462b210f7a41fc2651d4e4e8a881e8190e6d1e122c92c07735d70 @@ -2215,7 +2222,7 @@ CHECKSUMS rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836 rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47 - rspec-rails (8.0.3) sha256=b0a440e7a10700317d898a014852e26660867298c4076dbc3baa99c768b79dc1 + rspec-rails (8.0.4) sha256=06235692fc0892683d3d34977e081db867434b3a24ae0dd0c6f3516bad4e22df rspec-retry (0.6.2) sha256=6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858 rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c rspec-wait (1.0.2) sha256=865f921239325d3d26fc10ded4bdd485d8b58bcaaad1a28dd85ed15266b5a912 @@ -2274,7 +2281,7 @@ CHECKSUMS thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 thread_safe (0.3.6) sha256=9ed7072821b51c57e8d6b7011a8e282e25aeea3a4065eab326e43f66f063b05a timecop (0.9.10) sha256=12ba45ce57cdcf6b1043cb6cdffa6381fd89ce10d369c28a7f6f04dc1b0cd8eb - timeout (0.6.0) sha256=6d722ad619f96ee383a0c557ec6eb8c4ecb08af3af62098a0be5057bf00de1af + timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb tpm-key_attestation (0.14.1) sha256=7fd4e4653a7afd0a386632ddfb05d10ecfdd47678299c5e69165bc9ae111193f trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3 tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f diff --git a/Gemfile.modules b/Gemfile.modules index bf1f2f7b5b9..a548efe06a1 100644 --- a/Gemfile.modules +++ b/Gemfile.modules @@ -40,6 +40,7 @@ group :opf_plugins do gem 'openproject-gantt', path: 'modules/gantt' gem 'openproject-calendar', path: 'modules/calendar' gem 'openproject-storages', path: 'modules/storages' + gem 'openproject-wikis', path: 'modules/wikis' gem 'openproject-documents', path: 'modules/documents' gem 'openproject-bim', path: 'modules/bim' diff --git a/app/AGENTS.md b/app/AGENTS.md new file mode 100644 index 00000000000..6da76af89b3 --- /dev/null +++ b/app/AGENTS.md @@ -0,0 +1,31 @@ +# App + +## Directory Structure + +- `app/components/` - ViewComponent-based UI components (Ruby + ERB) +- `app/contracts/` - Validation and authorization contracts +- `app/controllers/` - Rails controllers +- `app/models/` - ActiveRecord models +- `app/services/` - Service objects (business logic) +- `app/workers/` - Background job workers + +## Code Style + +### Ruby + +- Follow [Ruby community style guide](https://github.com/bbatsov/ruby-style-guide) +- Use service objects for complex business logic (return `ServiceResult`) +- Use contracts for validation and authorization +- Keep controllers thin, models focused +- Document with [YARD](https://yardoc.org/) +- Write RSpec tests for all new features + +### Templates + +- Use ERB for server-rendered views +- Use ViewComponents for reusable UI (with Lookbook previews) +- Lint with erb_lint before committing + +## Translations + +- UI strings must use translation keys (never hard-coded) diff --git a/app/CLAUDE.md b/app/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/app/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/app/components/work_packages/admin/settings/change_identifiers_dialog_component.html.erb b/app/components/work_packages/admin/settings/change_identifiers_dialog_component.html.erb new file mode 100644 index 00000000000..480cf64bb7c --- /dev/null +++ b/app/components/work_packages/admin/settings/change_identifiers_dialog_component.html.erb @@ -0,0 +1,64 @@ +<%# + -- 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. + + ++# +%> + +<%= + render( + Primer::OpenProject::DangerDialog.new( + id: "change-identifiers-dialog", + title: I18n.t("admin.settings.work_packages_identifier.dialog.title"), + confirm_button_text: I18n.t("admin.settings.work_packages_identifier.dialog.confirm_button"), + cancel_button_text: I18n.t("button_close"), + size: :large, + form_arguments: { + action: admin_settings_work_packages_identifier_path, + method: :patch + } + ) + ) do |dialog| + dialog.with_confirmation_message do |message| + message.with_heading(tag: :h2) do + I18n.t("admin.settings.work_packages_identifier.dialog.heading") + end + + message.with_description_content( + I18n.t("admin.settings.work_packages_identifier.dialog.description") + ) + end + + dialog.with_confirmation_check_box_content( + I18n.t("admin.settings.work_packages_identifier.dialog.checkbox_label") + ) + + dialog.with_additional_details(display: :none) do + hidden_field_tag("settings[work_packages_identifier]", Setting::WorkPackageIdentifier::ALPHANUMERIC) + end + end +%> diff --git a/app/components/work_packages/admin/settings/change_identifiers_dialog_component.rb b/app/components/work_packages/admin/settings/change_identifiers_dialog_component.rb new file mode 100644 index 00000000000..d9d7c380941 --- /dev/null +++ b/app/components/work_packages/admin/settings/change_identifiers_dialog_component.rb @@ -0,0 +1,40 @@ +# 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 Admin + module Settings + class ChangeIdentifiersDialogComponent < ApplicationComponent + include OpPrimer::ComponentHelpers + include OpTurbo::Streamable + end + end + end +end diff --git a/app/components/work_packages/admin/settings/identifier_autofix_section_component.html.erb b/app/components/work_packages/admin/settings/identifier_autofix_section_component.html.erb new file mode 100644 index 00000000000..a9ba02a0445 --- /dev/null +++ b/app/components/work_packages/admin/settings/identifier_autofix_section_component.html.erb @@ -0,0 +1,109 @@ +<%# + -- 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. + + ++# +%> + +<%= + render(Primer::Alpha::Banner.new(scheme: :warning, my: 3)) do + I18n.t( + "admin.settings.work_packages_identifier.banner.existing_identifiers_notice", + project_count: total_count + ) + end +%> + +<%= + render(border_box_container(mb: 3)) do |component| + component.with_header(font_weight: :bold) do + flex_layout do |header| + header.with_column(flex: 1) do + render(Primer::Beta::Text.new(font_weight: :semibold)) do + I18n.t("admin.settings.work_packages_identifier.box_header.label_project") + end + end + header.with_column(flex: 1) do + render(Primer::Beta::Text.new(font_weight: :semibold)) do + I18n.t("admin.settings.work_packages_identifier.box_header.label_previous_identifier") + end + end + header.with_column(flex: 1) do + render(Primer::Beta::Text.new(font_weight: :semibold)) do + I18n.t("admin.settings.work_packages_identifier.box_header.label_autofixed_suggestion") + end + end + header.with_column(flex: 1) do + render(Primer::Beta::Text.new(font_weight: :semibold)) do + I18n.t("admin.settings.work_packages_identifier.box_header.label_example_work_package_id") + end + end + end + end + + displayed.each do |entry| + component.with_row do + flex_layout(align_items: :center) do |row| + row.with_column(flex: 1) do + render(Primer::Beta::Link.new(href: project_path(entry[:project]))) do + entry[:project].name + end + end + row.with_column(flex: 1) do + flex_layout(direction: :column) do |col| + col.with_row do + render(Primer::Beta::Text.new) { entry[:current_identifier] } + end + col.with_row do + render(Primer::Beta::Text.new(color: :danger, font_size: :small)) do + error_label(entry[:error_reason]) + end + end + end + end + row.with_column(flex: 1) do + render(Primer::Beta::Text.new) { entry[:suggested_identifier] } + end + row.with_column(flex: 1) do + render(Primer::Beta::Text.new) { sample_wp_id(entry[:suggested_identifier]) } + end + end + end + end + + if remaining_count.positive? + component.with_row do + render(Primer::Beta::Text.new(color: :muted)) do + I18n.t( + "admin.settings.work_packages_identifier.autofix_preview.remaining_projects", + count: remaining_count + ) + end + end + end + end +%> diff --git a/app/components/work_packages/admin/settings/identifier_autofix_section_component.rb b/app/components/work_packages/admin/settings/identifier_autofix_section_component.rb new file mode 100644 index 00000000000..75ac28dd0db --- /dev/null +++ b/app/components/work_packages/admin/settings/identifier_autofix_section_component.rb @@ -0,0 +1,65 @@ +# 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 Admin + module Settings + class IdentifierAutofixSectionComponent < ApplicationComponent + include OpPrimer::ComponentHelpers + + DISPLAY_COUNT = WorkPackages::IdentifierAutofix::PreviewQuery::DISPLAY_COUNT + + def initialize(projects_data:, total_count: projects_data.size) + super() + @total_count = total_count + @displayed = projects_data.first(DISPLAY_COUNT) + @remaining_count = [total_count - @displayed.size, 0].max + end + + private + + attr_reader :total_count, :displayed, :remaining_count + + def error_label(error_reason) + I18n.t("admin.settings.work_packages_identifier.autofix_preview.error_#{error_reason}", + default: "") + end + + # Produces a realistic-looking example work package ID for the preview table. + # The sequence number is derived deterministically from the identifier so it looks + # varied across projects but is stable across renders. Range: 1–500. + def sample_wp_id(identifier) + n = (identifier.bytes.sum % 500) + 1 + "#{identifier}-#{n}" + end + end + end + end +end diff --git a/app/components/work_packages/admin/settings/identifier_settings_form_component.html.erb b/app/components/work_packages/admin/settings/identifier_settings_form_component.html.erb new file mode 100644 index 00000000000..43c130fc707 --- /dev/null +++ b/app/components/work_packages/admin/settings/identifier_settings_form_component.html.erb @@ -0,0 +1,99 @@ +<%# + -- 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. + + ++# +%> + +<%= component_wrapper(**wrapper_data_attrs) do %> + <%= + settings_primer_form_with( + scope: :settings, action: :update, method: :patch, + html: change_in_progress? ? {} : { id: form_id } + ) do |f| + render_inline_settings_form(f) do |form| + form.radio_button_group( + name: :work_packages_identifier, + label: I18n.t("settings.work_packages.work_package_identifier"), + required: true, + **radio_button_options + ) + + form.html_content do + if change_in_progress? + render(Primer::Beta::Text.new(my: 3)) do + render(Primer::Beta::Spinner.new(size: :small, mr: 2)).to_s + + I18n.t("admin.settings.work_packages_identifier.in_progress.banner_message") + end + elsif completed? + render(Primer::Alpha::Banner.new(scheme: :success, dismiss_scheme: :remove, mb: 3)) do + I18n.t("admin.settings.work_packages_identifier.success_banner") + end + end + end + end + end + %> + + <% unless change_in_progress? %> + <%= tag.div( + hidden: !show_autofix_section?, + data: { admin__work_packages_identifier_target: "autofixSection" } + ) do %> + <%= render( + WorkPackages::Admin::Settings::IdentifierAutofixSectionComponent.new( + projects_data:, + total_count: + ) + ) %> + <% end %> +
+ <%= render( + Primer::Beta::Button.new( + scheme: :primary, + type: :submit, + form: form_id, + hidden: show_autofix_section?, + data: { admin__work_packages_identifier_target: "saveButton" } + ) + ) { t("button_save") } %> + + <%= render( + Primer::Beta::Button.new( + tag: :a, + href: confirm_dialog_admin_settings_work_packages_identifier_path, + scheme: :primary, + hidden: !show_autofix_section?, + data: { + turbo_stream: true, + admin__work_packages_identifier_target: "autofixButton" + } + ) + ) { t("admin.settings.work_packages_identifier.button_autofix") } %> +
+ <% end %> +<% end %> diff --git a/app/components/work_packages/admin/settings/identifier_settings_form_component.rb b/app/components/work_packages/admin/settings/identifier_settings_form_component.rb new file mode 100644 index 00000000000..3e9c28d41dd --- /dev/null +++ b/app/components/work_packages/admin/settings/identifier_settings_form_component.rb @@ -0,0 +1,110 @@ +# 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 Admin + module Settings + class IdentifierSettingsFormComponent < ApplicationComponent + include OpPrimer::FormHelpers + include OpTurbo::Streamable + + STATES = %i[edit change_in_progress completed].freeze + + attr_reader :projects_data, :total_count, :state + + def initialize(state: :edit) + raise ArgumentError, "Unknown state: #{state}" unless STATES.include?(state) + + super() + @state = state + if state == :edit + result = WorkPackages::IdentifierAutofix::PreviewQuery.new.call + @projects_data = result.projects_data + @total_count = result.total_count + else + @projects_data = [] + @total_count = 0 + end + end + + def has_problematic_projects? + total_count > 0 + end + + private + + def form_id = "wp-identifier-settings-form" + + def show_autofix_section? + state == :edit && Setting::WorkPackageIdentifier.alphanumeric? && has_problematic_projects? + end + + def change_in_progress? = state == :change_in_progress + def completed? = state == :completed + + def wrapper_data_attrs + if change_in_progress? + poll_for_changes_controller_attrs + else + work_package_identifier_controller_attrs + end + end + + def poll_for_changes_controller_attrs + { + data: { + controller: "poll-for-changes", + poll_for_changes_url_value: url_helpers.status_admin_settings_work_packages_identifier_path, + poll_for_changes_interval_value: 5000 + } + } + end + + def work_package_identifier_controller_attrs + { + data: { + controller: "admin--work-packages-identifier", + admin__work_packages_identifier_has_problematic_projects_value: has_problematic_projects? + } + } + end + + def radio_button_options + if change_in_progress? + { button_options: { disabled: true } } + else + { button_options: { data: { action: "change->admin--work-packages-identifier#handleChange" } } } + end + end + end + end + end +end diff --git a/app/controllers/admin/settings/work_packages_identifier_controller.rb b/app/controllers/admin/settings/work_packages_identifier_controller.rb new file mode 100644 index 00000000000..1e4ecbb008f --- /dev/null +++ b/app/controllers/admin/settings/work_packages_identifier_controller.rb @@ -0,0 +1,85 @@ +# 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 Admin::Settings + class WorkPackagesIdentifierController < ::Admin::SettingsController + include OpTurbo::ComponentStream + + before_action :check_feature_flag + + current_menu_item :show do + :work_packages_identifier + end + + def show + @form_state = WorkPackages::IdentifierAutofix.job_in_progress? ? :change_in_progress : :edit + end + + def update + return render_400 unless params[:settings] + + if autofix_requested? + call = update_service.new(user: current_user).call(settings_params) + call.on_success do + WorkPackages::IdentifierAutofix::ApplyHandlesJob.perform_later + redirect_to action: "show" + end + call.on_failure { failure_callback(call) } + else + super + end + end + + def confirm_dialog + respond_with_dialog WorkPackages::Admin::Settings::ChangeIdentifiersDialogComponent.new + end + + def status + if WorkPackages::IdentifierAutofix.job_in_progress? + head :no_content + else + replace_via_turbo_stream( + component: WorkPackages::Admin::Settings::IdentifierSettingsFormComponent.new(state: :completed) + ) + respond_with_turbo_streams + end + end + + private + + def check_feature_flag + render_404 unless OpenProject::FeatureDecisions.semantic_work_package_ids_active? + end + + def autofix_requested? + ActiveRecord::Type::Boolean.new.cast(params[:confirm_dangerous_action]) + end + end +end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index ca726fe9136..3f3f2d6a9c6 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -111,8 +111,10 @@ class AdminController < ApplicationController @smtp_addr = ActionMailer::Base.smtp_settings[:address] @safe_ip = OpenProject::SsrfProtection.safe_ip?(@smtp_addr) - if !@safe_ip - flash[:error] = I18n.t :notice_smtp_address_unsafe, address: @smtp_addr + unless @safe_ip + flash[:error] = I18n.t :notice_smtp_address_unsafe_env_hint, + address: @smtp_addr, + env_name: Settings::Definition[:ssrf_protection_ip_allowlist].env_name redirect_to admin_settings_mail_notifications_path, status: :see_other end diff --git a/app/controllers/projects/creation_wizard_controller.rb b/app/controllers/projects/creation_wizard_controller.rb index b5c9f669b27..f444065596b 100644 --- a/app/controllers/projects/creation_wizard_controller.rb +++ b/app/controllers/projects/creation_wizard_controller.rb @@ -74,8 +74,8 @@ class Projects::CreationWizardController < ApplicationController def create_work_package_artifact # rubocop:disable Metrics/AbcSize creation_call = User.execute_as_admin(current_user) do - Projects::CreationWizard::CreateArtifactWorkPackageService - .new(user: current_user, model: @project) + Projects::CreationWizard::SubmitArtifactService + .new(user: current_user, project: @project) .call end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index dc003420aa9..d05ade3edd2 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -446,11 +446,11 @@ class RepositoriesController < ApplicationController end def send_raw(content, path) - # Force the download - send_opt = { filename: filename_for_content_disposition(path.split("/").last) } - send_type = OpenProject::MimeType.of(path) - send_opt[:type] = send_type.to_s if send_type - send_data content, send_opt + # Force the download as binary to prevent CSP bypass + send_data content, + filename: filename_for_content_disposition(path.split("/").last), + type: "application/octet-stream", + disposition: :attachment end def render_text_entry diff --git a/app/controllers/wiki_menu_items_controller.rb b/app/controllers/wiki_menu_items_controller.rb index bb7351753e8..ad27f786029 100644 --- a/app/controllers/wiki_menu_items_controller.rb +++ b/app/controllers/wiki_menu_items_controller.rb @@ -67,12 +67,11 @@ class WikiMenuItemsController < ApplicationController def update # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity wiki_menu_setting = wiki_menu_item_params[:setting] - parent_wiki_menu_item = params[:parent_wiki_menu_item] get_data_from_params(params) if wiki_menu_setting == "no_item" - unless @wiki_menu_item.nil? + if @wiki_menu_item if @wiki_menu_item.is_only_main_item? if @page.only_wiki_page? flash.now[:error] = t(:wiki_menu_item_delete_not_permitted) @@ -89,12 +88,8 @@ class WikiMenuItemsController < ApplicationController @wiki_menu_item.name = @page.slug @wiki_menu_item.title = wiki_menu_item_params[:title] || @page_title - if wiki_menu_setting == "sub_item" - @wiki_menu_item.parent_id = parent_wiki_menu_item - elsif wiki_menu_setting == "main_item" - @wiki_menu_item.parent_id = nil - assign_wiki_menu_item_params @wiki_menu_item - end + @wiki_menu_item.parent_id = nil + assign_wiki_menu_item_params @wiki_menu_item end if @wiki_menu_item.destroyed? || @wiki_menu_item.save diff --git a/app/forms/admin/settings/aggregation_settings_form.rb b/app/forms/admin/settings/aggregation_settings_form.rb new file mode 100644 index 00000000000..b3466f9b7cc --- /dev/null +++ b/app/forms/admin/settings/aggregation_settings_form.rb @@ -0,0 +1,47 @@ +# 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 Admin + module Settings + class AggregationSettingsForm < ApplicationForm + include Redmine::I18n + + settings_form do |f| + f.text_field name: :journal_aggregation_time_minutes, + type: :number, + min: 0, + input_width: :medium, + trailing_visual: { text: { text: I18n.t("datetime.units.minute_abbreviated", count: 2) } } + + f.submit + end + end + end +end diff --git a/app/forms/admin/settings/aggregation_settings_form/journal_aggregation_time_minutes_caption.html.erb b/app/forms/admin/settings/aggregation_settings_form/journal_aggregation_time_minutes_caption.html.erb new file mode 100644 index 00000000000..986e2aa67fd --- /dev/null +++ b/app/forms/admin/settings/aggregation_settings_form/journal_aggregation_time_minutes_caption.html.erb @@ -0,0 +1,8 @@ +<%= render(Primer::Beta::Text.new(tag: :p)) do %> + <%= link_translate("admin.journal_aggregation.caption", links: { webhook_link: url_helpers.admin_outgoing_webhooks_path }) %> +<% end %> +<%= render(Primer::OpenProject::InlineMessage.new(scheme: :warning, size: :small)) do %> + <%= render(Primer::Beta::Text.new(tag: :p)) do %> + <%= I18n.t(:text_hint_disable_with_0) %> + <% end %> +<% end %> diff --git a/app/forms/admin/settings/mail_notifications_setting_form.rb b/app/forms/admin/settings/mail_notifications_setting_form.rb new file mode 100644 index 00000000000..a944711699d --- /dev/null +++ b/app/forms/admin/settings/mail_notifications_setting_form.rb @@ -0,0 +1,113 @@ +# 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 Admin + module Settings + class MailNotificationsSettingForm < ApplicationForm + include ::Settings::FormHelper + + settings_form do |f| + if @deliveries + f.text_field name: :mail_from, input_width: :medium + f.check_box name: :bcc_recipients + f.check_box name: :plain_text_mail + f.select_list name: :emails_salutation, + values: [ + [User.human_attribute_name(:firstname), :firstname], + [I18n.t("mail.salutation_full_name"), :name] + ], + input_width: :medium + + f.fieldset_group(title: "#{I18n.t(:setting_emails_header)} & #{I18n.t(:setting_emails_footer)}", mt: 4) do |fg| + fg.multi_language_text_select(name: :emails_header) + fg.multi_language_text_select(name: :emails_footer) + end + end + + unless OpenProject::Configuration["email_delivery_configuration"] == "legacy" + email_methods = %i[smtp sendmail] + email_methods += [:letter_opener] if Rails.env.development? + + f.fieldset_group(title: I18n.t(:text_setup_mail_configuration), mt: 4) do |fg| + fg.select_list( + name: :email_delivery_method, + values: email_methods.map { |m| [m.to_s, m] }, + input_width: :small, + data: { + show_when_value_selected_target: "cause", + target_name: "email_delivery_method_settings" + } + ) + end + + f.group( + hidden: { true => Setting.email_delivery_method != :smtp }, + data: { + show_when_value_selected_target: "effect", + target_name: "email_delivery_method_settings", + value: "smtp" + } + ) do |smtp| + smtp.text_field(name: :smtp_address, input_width: :medium) + smtp.text_field(name: :smtp_port, type: :number, input_width: :xsmall) + smtp.text_field(name: :smtp_domain, input_width: :medium) + smtp.select_list(name: :smtp_authentication, + values: %i[none plain login cram_md5].map { |m| [m.to_s, m] }, + input_width: :small) + smtp.text_field(name: :smtp_user_name, input_width: :medium) + smtp.text_field(name: :smtp_password, input_width: :medium) + smtp.check_box(name: :smtp_enable_starttls_auto) + smtp.check_box(name: :smtp_ssl) + end + + f.group( + hidden: { true => Setting.email_delivery_method != :sendmail }, + data: { + show_when_value_selected_target: "effect", + target_name: "email_delivery_method_settings", + value: "sendmail" + } + ) do |sendmail| + sendmail.text_field(name: :sendmail_location) + sendmail.text_field(name: :sendmail_arguments) + end + end + + f.submit + end + + def initialize(deliveries:) + super() + + @deliveries = deliveries + end + end + end +end diff --git a/app/forms/versions/form.rb b/app/forms/versions/form.rb index 4297fa02f8c..d370e14c2eb 100644 --- a/app/forms/versions/form.rb +++ b/app/forms/versions/form.rb @@ -163,6 +163,12 @@ module Versions end end + f.hidden( + name: "project_id", + value: project.id, + scope_name_to_model: false + ) + render_custom_fields(form: f) f.submit( diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 7b3d9802693..5e8343e159d 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -114,13 +114,13 @@ module RepositoriesHelper end def render_changes_tree(tree) - return "" if tree.nil? + return "".html_safe if tree.nil? - output = +"
    " - tree.keys.sort.each do |file| - style = +"change" + items = tree.keys.sort.flat_map do |file| + style = "change" text = File.basename(file) - if s = tree[file][:s] + + if (s = tree[file][:s]) style += " folder" path_param = without_leading_slash(to_path_param(@repository.relative_path(file))) text = link_to(h(text), @@ -129,38 +129,40 @@ module RepositoriesHelper rev: @changeset.identifier), title: I18n.t(:label_folder)) - output += "
  • #{text}
  • " - output += render_changes_tree(s) - elsif c = tree[file][:c] + folder_li = content_tag(:li, text, + class: "#{style} icon icon-folder-#{calculate_folder_action(s)}") + [folder_li, render_changes_tree(s)] + elsif (c = tree[file][:c]) style += " change-#{c.action}" path_param = without_leading_slash(to_path_param(@repository.relative_path(c.path))) - unless c.action == "D" - title_text = changes_tree_change_title c.action + text_parts = [] + unless c.action == "D" text = link_to(h(text), entry_revision_project_repository_path(project_id: @project, repo_path: path_param, rev: @changeset.identifier), - title: title_text) + title: changes_tree_change_title(c.action)) end - text << raw(" - #{h(c.revision)}") if c.revision.present? + text_parts << text + text_parts << " - " << h(c.revision) if c.revision.present? if c.action == "M" - text << raw(" (" + link_to(I18n.t(:label_diff), - diff_revision_project_repository_path(project_id: @project, - repo_path: path_param, - rev: @changeset.identifier)) + ") ") + text_parts << " (" << link_to(I18n.t(:label_diff), + diff_revision_project_repository_path(project_id: @project, + repo_path: path_param, + rev: @changeset.identifier)) << ") " end - text << raw(" " + content_tag("span", h(c.from_path), class: "copied-from")) if c.from_path.present? + text_parts << " " << content_tag(:span, c.from_path, class: "copied-from") if c.from_path.present? - output += changes_tree_li_element(c.action, text, style) + [changes_tree_li_element(c.action, safe_join(text_parts), style)] end - end - output += "
" - output.html_safe + end.compact + + content_tag(:ul, safe_join(items)) end def to_utf8_for_repositories(str) @@ -296,19 +298,16 @@ module RepositoriesHelper def changes_tree_li_element(action, text, style) icon_name = case action - when "A" - "icon-add" - when "D" - "icon-delete" - when "C" - "icon-copy" - when "R" - "icon-rename" + when "A" then "icon-add" + when "D" then "icon-delete" + when "C" then "icon-copy" + when "R" then "icon-rename" else "icon-arrow-left-right" end - "
  • #{text}
  • " + content_tag(:li, text, + class: "#{style} icon #{icon_name}", + title: changes_tree_change_title(action)) end end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index b676788ac5f..0e06e9a0277 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -32,6 +32,8 @@ class CustomField < ApplicationRecord include CustomField::OrderStatements include CustomField::CalculatedValue + normalizes :name, with: OpenProject::RemoveAsciiControlCharacters + has_many :custom_values, dependent: :delete_all # WARNING: the inverse_of option is also required in order # for the 'touch: true' option on the custom_field association in CustomOption diff --git a/app/models/menu_item.rb b/app/models/menu_item.rb index 548248343aa..991d1fd1486 100644 --- a/app/models/menu_item.rb +++ b/app/models/menu_item.rb @@ -50,7 +50,9 @@ class MenuItem < ApplicationRecord elsif is_main_item? :main_item else - :sub_item + # backwards compatibility for removed configuration option + # sub items are not offered anymore and are effectively not visible + :no_item end end diff --git a/app/models/project.rb b/app/models/project.rb index 41fb0312f92..5a9479b5c6b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -77,7 +77,7 @@ class Project < ApplicationRecord has_many :principals, through: :member_principals, source: :principal has_many :calculated_value_errors, dependent: :delete_all, as: :customized - has_many :enabled_modules, dependent: :delete_all + has_many :enabled_modules, dependent: :delete_all, after_remove: :module_disabled has_and_belongs_to_many :types, -> { order("#{::Type.table_name}.position") } @@ -221,7 +221,8 @@ class Project < ApplicationRecord :assignable_parents, :available_custom_fields, :available_templates, - :visible + :visible, + :with_settings scope :has_module, ->(mod) { where(["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s]) @@ -349,4 +350,10 @@ class Project < ApplicationRecord OpenProject::AccessControl.allowed_actions(permission) end end + + def module_disabled(disabled_module) + OpenProject::Notifications.send( + OpenProject::Events::MODULE_DISABLED, disabled_module: + ) + end end diff --git a/app/models/projects/scopes/with_settings.rb b/app/models/projects/scopes/with_settings.rb new file mode 100644 index 00000000000..461821c873e --- /dev/null +++ b/app/models/projects/scopes/with_settings.rb @@ -0,0 +1,49 @@ +# 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 Projects::Scopes + module WithSettings + extend ActiveSupport::Concern + + class_methods do + def with_settings(**kwargs) + raise ArgumentError, "Provide at least one setting" if kwargs.empty? + + kwargs.reduce(all) do |scope, (key, value)| + if value.nil? + scope.where("settings->>? IS NULL", key) + else + scope.where("settings->>? = ?", key, value) + end + end + end + end + end +end diff --git a/app/models/setting/work_package_identifier.rb b/app/models/setting/work_package_identifier.rb new file mode 100644 index 00000000000..fb0004bada8 --- /dev/null +++ b/app/models/setting/work_package_identifier.rb @@ -0,0 +1,40 @@ +# 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. +#++ + +class Setting + module WorkPackageIdentifier + NUMERIC = "numeric" + ALPHANUMERIC = "alphanumeric" + ALLOWED_VALUES = [NUMERIC, ALPHANUMERIC].freeze + + def self.alphanumeric? = Setting[:work_packages_identifier] == ALPHANUMERIC + def self.numeric? = Setting[:work_packages_identifier] == NUMERIC + end +end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 0e1d169a9e0..3636607cfda 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -161,7 +161,7 @@ class WikiPage < ApplicationRecord content_to = journals.find_by(version: version_to) content_from = journals.find_by(version: version_from) - content_to && content_from ? Wikis::Diff.new(content_to, content_from) : nil + content_to && content_from ? WikiPage::Diff.new(content_to, content_from) : nil end def version @@ -171,7 +171,7 @@ class WikiPage < ApplicationRecord def annotate(compare_version = nil) compare_version = compare_version ? compare_version.to_i : version c = journals.find_by(version: compare_version) - c ? Wikis::Annotate.new(c) : nil + c ? WikiPage::Annotate.new(c) : nil end # Returns true if usr is allowed to edit the page, otherwise false diff --git a/app/models/wikis/annotate.rb b/app/models/wiki_page/annotate.rb similarity index 98% rename from app/models/wikis/annotate.rb rename to app/models/wiki_page/annotate.rb index 5a9ea79240f..49bb99494b5 100644 --- a/app/models/wikis/annotate.rb +++ b/app/models/wiki_page/annotate.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class Wikis::Annotate +class WikiPage::Annotate attr_reader :lines, :content def initialize(content) diff --git a/app/models/wikis/diff.rb b/app/models/wiki_page/diff.rb similarity index 96% rename from app/models/wikis/diff.rb rename to app/models/wiki_page/diff.rb index aa186cd88b5..b4f001e5ce7 100644 --- a/app/models/wikis/diff.rb +++ b/app/models/wiki_page/diff.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class Wikis::Diff < Redmine::Helpers::Diff +class WikiPage::Diff < Redmine::Helpers::Diff attr_reader :content_to, :content_from def initialize(content_to, content_from) diff --git a/app/services/projects/creation_wizard/create_artifact_work_package_service.rb b/app/services/projects/creation_wizard/create_artifact_work_package_service.rb index b2640ea2cac..eabe5c94bbc 100644 --- a/app/services/projects/creation_wizard/create_artifact_work_package_service.rb +++ b/app/services/projects/creation_wizard/create_artifact_work_package_service.rb @@ -39,7 +39,6 @@ module Projects::CreationWizard def initialize(user:, model:, contract_class: Projects::CreateArtifactWorkPackageContract) super(user:, contract_class:) self.model = model - @skip_creation = false end def project = model @@ -48,26 +47,7 @@ module Projects::CreationWizard attr_accessor :artifact_work_package - def skip_creation? = @skip_creation - def skip_creation! = @skip_creation = true - - def before_perform(service_call) - if WorkPackage.exists?(project.project_creation_wizard_artifact_work_package_id) - skip_creation! - end - - service_call - end - - def validate_contract(service_call) - return service_call if skip_creation? - - super - end - def persist(service_call) - return service_call if skip_creation? - creation_call = create_artifact_work_package creation_call.on_success do @@ -86,7 +66,7 @@ module Projects::CreationWizard def after_perform(service_call) send_notification_email - return service_call if store_attachment_locally? || skip_creation? + return service_call if store_attachment_locally? if project_storage.nil? service_call.errors.add(:base, I18n.t("projects.wizard.create_artifact_storage_error")) diff --git a/app/services/projects/creation_wizard/reupload_artifact_on_status_changes_service.rb b/app/services/projects/creation_wizard/reupload_artifact_on_status_changes_service.rb index 687f6e7f836..878602be3ca 100644 --- a/app/services/projects/creation_wizard/reupload_artifact_on_status_changes_service.rb +++ b/app/services/projects/creation_wizard/reupload_artifact_on_status_changes_service.rb @@ -30,10 +30,6 @@ module Projects::CreationWizard class ReuploadArtifactOnStatusChangesService - include Contracted - include ProjectsHelper - include ArtifactExporter - include Rails.application.routes.url_helpers prepend Projects::Concerns::UpdateDemoData attr_reader :current_user, :artifact_work_package @@ -61,45 +57,15 @@ module Projects::CreationWizard private def update_artifact - call = store_artifact + call = UploadArtifactService + .new(user: current_user, project:, work_package: artifact_work_package) + .call + if call.success? Rails.logger.debug { "Updated artifact for creation wizard in ##{artifact_work_package.id}" } else Rails.logger.error("Failed to process artifact change for ##{artifact_work_package.id}: ##{call.message}") end end - - def store_artifact - if store_attachment_locally? - return add_attachment_locally - end - - if project_storage.nil? - return ServiceResult.failure(message: I18n.t("projects.wizard.create_artifact_storage_error")) - end - - upload_artifact_to_storage - end - - def add_attachment_locally - export = create_pdf_export! - file = OpenProject::Files.create_uploaded_file( - name: export.title, - content_type: export.mime_type, - content: export.content, - binary: true - ) - - attachment = artifact_work_package.attachments.create( - author: current_user, - file: - ) - - if attachment.persisted? - ServiceResult.success(result: attachment) - else - ServiceResult.failure(result: attachment, errors: attachment.errors) - end - end end end diff --git a/app/services/projects/creation_wizard/submit_artifact_service.rb b/app/services/projects/creation_wizard/submit_artifact_service.rb new file mode 100644 index 00000000000..fead3b302a7 --- /dev/null +++ b/app/services/projects/creation_wizard/submit_artifact_service.rb @@ -0,0 +1,73 @@ +# 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 Projects::CreationWizard + class SubmitArtifactService + attr_reader :user, :project + + def initialize(user:, project:) + @user = user + @project = project + end + + def call + if artifact_work_package_exists? + upload_artifact + else + create_artifact_work_package + end + end + + private + + def artifact_work_package_exists? + WorkPackage.exists?(project.project_creation_wizard_artifact_work_package_id) + end + + def create_artifact_work_package + CreateArtifactWorkPackageService + .new(user:, model: project) + .call + end + + def upload_artifact + work_package = WorkPackage.find(project.project_creation_wizard_artifact_work_package_id) + upload_call = UploadArtifactService + .new(user:, project:, work_package:) + .call + + service_call = ServiceResult.success(result: project) + upload_call.on_failure do + service_call.merge!(upload_call, without_success: true) + end + service_call + end + end +end diff --git a/app/services/projects/creation_wizard/upload_artifact_service.rb b/app/services/projects/creation_wizard/upload_artifact_service.rb new file mode 100644 index 00000000000..8f24cd3de2e --- /dev/null +++ b/app/services/projects/creation_wizard/upload_artifact_service.rb @@ -0,0 +1,78 @@ +# 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 Projects::CreationWizard + class UploadArtifactService + include ArtifactExporter + + attr_reader :user, :project, :artifact_work_package + + def initialize(user:, project:, work_package:) + @user = user + @project = project + @artifact_work_package = work_package + end + + def call + if store_attachment_locally? + return add_attachment_locally + end + + if project_storage.nil? + return ServiceResult.failure(message: I18n.t("projects.wizard.create_artifact_storage_error")) + end + + upload_artifact_to_storage + end + + private + + def add_attachment_locally + export = create_pdf_export! + file = OpenProject::Files.create_uploaded_file( + name: export.title, + content_type: export.mime_type, + content: export.content, + binary: true + ) + + attachment = artifact_work_package.attachments.create( + author: user, + file: + ) + + if attachment.persisted? + ServiceResult.success(result: attachment) + else + ServiceResult.failure(result: attachment, errors: attachment.errors) + end + end + end +end diff --git a/app/services/work_packages/identifier_autofix.rb b/app/services/work_packages/identifier_autofix.rb new file mode 100644 index 00000000000..b1917080f79 --- /dev/null +++ b/app/services/work_packages/identifier_autofix.rb @@ -0,0 +1,39 @@ +# 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 IdentifierAutofix + def self.job_in_progress? + GoodJob::Job + .where(job_class: WorkPackages::IdentifierAutofix::ApplyHandlesJob.name) + .exists?(finished_at: nil) + end + end +end diff --git a/app/services/work_packages/identifier_autofix/preview_query.rb b/app/services/work_packages/identifier_autofix/preview_query.rb new file mode 100644 index 00000000000..3c478b5f152 --- /dev/null +++ b/app/services/work_packages/identifier_autofix/preview_query.rb @@ -0,0 +1,90 @@ +# 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 IdentifierAutofix + class PreviewQuery + Result = Data.define(:projects_data, :total_count) + DISPLAY_COUNT = 5 + + def call + total = problematic_scope.count + preview = problematic_scope + .select(:id, :name, :identifier) + .limit(DISPLAY_COUNT) + .to_a + + suggestions = WorkPackages::IdentifierAutofix::ProjectIdentifierSuggestionGenerator.call( + preview, + in_use_identifiers:, + reserved_identifiers: + ) + + projects_data = suggestions.map do |entry| + entry.merge(error_reason: error_reason(entry[:current_identifier])) + end + + Result.new(projects_data:, total_count: total) + end + + private + + def problematic_scope + @problematic_scope ||= Project.where( + "length(identifier) > ? OR identifier ~ ?", + ProjectIdentifierSuggestionGenerator::IDENTIFIER_LENGTH[:max], + "[^a-zA-Z0-9_]" + ) + end + + def error_reason(identifier) + if identifier.length > ProjectIdentifierSuggestionGenerator::IDENTIFIER_LENGTH[:max] + :too_long + elsif identifier.match?(/[^a-zA-Z0-9_]/) + :special_characters + elsif in_use_identifiers.include?(identifier) + :in_use + elsif reserved_identifiers.include?(identifier) + :reserved + end + end + + def in_use_identifiers + @in_use_identifiers ||= Project.where.not(id: problematic_scope.select(:id)).pluck(:identifier).to_set + end + + def reserved_identifiers + # TODO: OldProjectIdentifier.pluck(:identifier).to_set + # once the OldProjectIdentifier model and migration are added. + Set.new + end + end + end +end diff --git a/app/services/work_packages/identifier_autofix/project_identifier_suggestion_generator.rb b/app/services/work_packages/identifier_autofix/project_identifier_suggestion_generator.rb new file mode 100644 index 00000000000..25e0381b5fa --- /dev/null +++ b/app/services/work_packages/identifier_autofix/project_identifier_suggestion_generator.rb @@ -0,0 +1,217 @@ +# 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 IdentifierAutofix + # Generates a short uppercase semantic identifier for each project. + # + # Identifiers are 2–10 uppercase alphanumeric characters that always start + # with a letter. + # + # == Algorithm + # + # *Multi-word names* use word initials, truncated to +IDENTIFIER_LENGTH[:base]+ (5): + # "Flight Planning Algorithm" → "FPA" + # "A B C D E F G H I J K" → "ABCDE" + # + # *Single-word names* use the first +IDENTIFIER_LENGTH[:single_word]+ (3) characters: + # "Banana" → "BAN" + # + # *Accented characters* are transliterated ("Cécile" → "CEC"). + # *Non-Latin scripts* that have no transliteration fall back to "PROJ". + # + # == Collision resolution + # + # When a candidate is already taken, the identifier is progressively widened + # with more characters from the name, up to +IDENTIFIER_LENGTH[:max]+ (10): + # + # Multi-word: "SC" → "STC" → "STCO" → "STRCO" → … → "STREACOMMU" + # Single-word: "BAN" → "BANA" → "BANAN" → "BANANA" + # Initials: "ABCDE" → "ABCDEF" → … → "ABCDEFGHIJ" + # + # If all expansion candidates are exhausted, a numeric suffix is appended + # as a last resort ("GO" → "GO2"). + # + class ProjectIdentifierSuggestionGenerator + IDENTIFIER_LENGTH = { min: 2, max: 10, base: 5, single_word: 3 }.freeze + FALLBACK_IDENTIFIER = "PROJ" + SUFFIX_LIMIT = 10_000 + + def self.call(projects, reserved_identifiers: Set.new, in_use_identifiers: Set.new) + new.call(projects, reserved_identifiers:, in_use_identifiers:) + end + + # Returns a single suggested identifier string for the given project name. + # + def self.suggest_identifier(name, reserved_identifiers: Set.new, in_use_identifiers: Set.new) + new.suggest_identifier(name, reserved_identifiers:, in_use_identifiers:) + end + + def call(projects, reserved_identifiers:, in_use_identifiers:) + generate_suggestions(projects, reserved_identifiers:, in_use_identifiers:) + end + + def suggest_identifier(name, reserved_identifiers: Set.new, in_use_identifiers: Set.new) + used = reserved_identifiers | in_use_identifiers + candidates = identifier_candidates(name) + find_unique(candidates, used) + end + + private + + def generate_suggestions(projects, reserved_identifiers:, in_use_identifiers:) + used_identifiers = reserved_identifiers | in_use_identifiers + + projects.map do |project| + candidates = identifier_candidates(project.name) + identifier = find_unique(candidates, used_identifiers) + used_identifiers << identifier + + { + project:, + current_identifier: project.identifier, + suggested_identifier: identifier + } + end + end + + # Returns an ordered list of progressively longer identifier candidates + # derived from the project name. The first unique candidate wins. + def identifier_candidates(name) + words = transliterated_words(name) + return [FALLBACK_IDENTIFIER] if words.empty? + + candidates = words.size == 1 ? single_word_candidates(words.first) : multi_word_candidates(words) + candidates = candidates.filter_map do |c| + stripped = ensure_starts_with_letter(c) + stripped if stripped&.length.to_i >= IDENTIFIER_LENGTH[:min] + end + candidates.presence || [FALLBACK_IDENTIFIER] + end + + # Splits a name into words and transliterates each, returning only words + # that contain at least one ASCII-alphanumeric character. + def transliterated_words(name) + # Use POSIX [[:alpha:]] so accented letters (é, ñ, ü…) are kept inside + # their word rather than treated as separators by the ASCII-only [a-zA-Z]. + raw_words = name.to_s.scan(/[[:alpha:][:digit:]]+/) + raw_words.filter_map do |word| + t = I18n.with_locale(:en) { I18n.transliterate(word) } + clean = t.gsub(/[^A-Za-z0-9]/, "") + clean.presence + end + end + + # "Banana" → ["BAN", "BANA", "BANAN", "BANANA"] + def single_word_candidates(word) + chars = word.upcase + max_len = [chars.length, IDENTIFIER_LENGTH[:max]].min + return [] if max_len < IDENTIFIER_LENGTH[:min] + + start_len = IDENTIFIER_LENGTH[:single_word].clamp(IDENTIFIER_LENGTH[:min], max_len) + (start_len..max_len).map { chars[0, it] } + end + + # "Stream Communicator" → ["SC", "STC", "STCO", "STRCO", …] + # "A B C D E F G H I J K" → ["ABCDE", "ABCDEF", …, "ABCDEFGHIJ"] + # + # Starts with initials truncated to IDENTIFIER_LENGTH[:base], progressively + # includes more initials, then expands words beyond single chars. + def multi_word_candidates(words) + upcased_words = words.map(&:upcase) + candidates = initial_candidates(upcased_words) + + append_expansion_candidates!(candidates, upcased_words) if candidates.last.length < IDENTIFIER_LENGTH[:max] + candidates + end + + def initial_candidates(upcased_words) + initials = upcased_words.pluck(0).join[0, IDENTIFIER_LENGTH[:max]] + start = [IDENTIFIER_LENGTH[:base], initials.length].min + (start..initials.length).map { initials[0, it] } + end + + # Progressively pulls more characters from each word left-to-right. + def append_expansion_candidates!(candidates, upcased_words) + chars_per_word = upcased_words.map { 1 } + + loop do + expandable = upcased_words.each_index.find { |i| chars_per_word[i] < upcased_words[i].length } + break unless expandable + + chars_per_word[expandable] += 1 + candidate = build_candidate(upcased_words, chars_per_word) + candidates << candidate unless candidates.include?(candidate) + break if candidate.length >= IDENTIFIER_LENGTH[:max] + end + end + + def build_candidate(upcased_words, chars_per_word) + parts = upcased_words.each_with_index.map { |w, i| w[0, chars_per_word[i]] } + parts.join[0, IDENTIFIER_LENGTH[:max]] + end + + # Strips leading digits so identifiers always start with a letter. + # For names like "3D Printing Lab", initials "3PL" become "PL". + # This is lossy but acceptable for auto-generated suggestions. + def ensure_starts_with_letter(candidate) + candidate.sub(/\A\d+/, "").presence + end + + # Iterates through expansion candidates, then falls back to numeric suffix. + # Candidates are already filtered to start with a letter and meet min length. + def find_unique(candidates, used_identifiers) + candidates.each do |candidate| + return candidate unless used_identifiers.include?(candidate) + end + + base = candidates.last || FALLBACK_IDENTIFIER + numeric_suffix_fallback(base, used_identifiers) + end + + def numeric_suffix_fallback(base, used_identifiers) + # Ensure the base itself starts with a letter before appending digits. + base = ensure_starts_with_letter(base) || FALLBACK_IDENTIFIER + + counter = 2 + loop do + raise "Could not find a unique identifier for base '#{base}' within #{SUFFIX_LIMIT} attempts" \ + if counter > SUFFIX_LIMIT + + suffix = counter.to_s + candidate = "#{base[0, IDENTIFIER_LENGTH[:max] - suffix.length]}#{suffix}" + return candidate unless used_identifiers.include?(candidate) + + counter += 1 + end + end + end + end +end diff --git a/app/views/admin/settings/aggregation_settings/show.html.erb b/app/views/admin/settings/aggregation_settings/show.html.erb index 14308e9ff81..18ebddc5d73 100644 --- a/app/views/admin/settings/aggregation_settings/show.html.erb +++ b/app/views/admin/settings/aggregation_settings/show.html.erb @@ -40,25 +40,13 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= styled_form_tag(admin_settings_aggregation_path, method: :patch) do %> -
    - <%= setting_number_field :journal_aggregation_time_minutes, - unit: t(:label_minute_plural), - min: 0, - container_class: "-xslim" %> - - <%= t( - :"admin.journal_aggregation.explanation.text", - webhook_link: link_to( - t(:"admin.journal_aggregation.explanation.link"), - admin_outgoing_webhooks_path, - target: "_blank" - ) - ).html_safe %> -
    - <%= t(:text_hint_disable_with_0) %> -
    -
    - - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> -<% end %> +<%= + settings_primer_form_with( + url: admin_settings_aggregation_path, + scope: :settings, + method: :patch, + data: { turbo: false } + ) do |form| + render Admin::Settings::AggregationSettingsForm.new(form) + end +%> diff --git a/app/views/admin/settings/date_format_settings/show.html.erb b/app/views/admin/settings/date_format_settings/show.html.erb index 66a3ed5395b..5866ade0b77 100644 --- a/app/views/admin/settings/date_format_settings/show.html.erb +++ b/app/views/admin/settings/date_format_settings/show.html.erb @@ -40,40 +40,38 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= styled_form_tag( - admin_settings_date_format_path, - method: :patch, - class: "op-date-format-admin-settings" - ) do %> +<%= + settings_primer_form_with( + url: admin_settings_date_format_path, + scope: :settings, + method: :patch, + class: "op-date-format-admin-settings", + data: { turbo: false } + ) do |form| + render_inline_settings_form(form) do |f| + f.select_list name: :date_format, + values: Settings::Definition[:date_format].allowed.collect { |f| [Date.today.strftime(f), f] }, + input_width: :medium, + include_blank: t(:label_language_based) -
    + f.select_list name: :time_format, + values: Settings::Definition[:time_format].allowed.collect { |f| [Time.now.strftime(f), f] }, + input_width: :medium, + include_blank: t(:label_language_based) -
    - <%= setting_select :date_format, - Settings::Definition[:date_format].allowed.collect { |f| [Date.today.strftime(f), f] }, - blank: :label_language_based, - container_class: "-wide" %> -
    + f.select_list name: :start_of_week, + values: [[day_name(1), 1], [day_name(6), 6], [day_name(7), 7]], + input_width: :medium, + include_blank: t(:label_language_based) -
    - <%= setting_select :time_format, - Settings::Definition[:time_format].allowed.collect { |f| [Time.now.strftime(f), f] }, - blank: :label_language_based, - container_class: "-wide" %> -
    + f.select_list name: :first_week_of_year, + values: [[day_name(1), 1], [day_name(4), 4]], + input_width: :medium, + include_blank: t(:label_language_based), + caption: t("settings.date_format.first_week_of_year_text_html", + link: OpenProject::Static::Links.url_for(:date_format_settings_documentation)) -
    - <%= setting_select :start_of_week, [[day_name(1), "1"], [day_name(6), "6"], [day_name(7), "7"]], blank: :label_language_based, container_class: "-wide" %> -
    - -
    - <%= setting_select :first_week_of_year, [[day_name(1), "1"], [day_name(4), "4"]], blank: :label_language_based, container_class: "-wide" %> -
    -

    <%= t("settings.date_format.first_week_of_year_text_html", link: OpenProject::Static::Links.url_for(:date_format_settings_documentation)) %>

    -
    -
    - -
    - - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> -<% end %> + f.submit + end + end +%> diff --git a/app/views/admin/settings/icalendar_settings/show.html.erb b/app/views/admin/settings/icalendar_settings/show.html.erb index ac1885f1b22..e1459f83415 100644 --- a/app/views/admin/settings/icalendar_settings/show.html.erb +++ b/app/views/admin/settings/icalendar_settings/show.html.erb @@ -40,20 +40,20 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= styled_form_tag( - admin_settings_icalendar_path, - method: :patch, - class: "op-icalendar-admin-settings" - ) do %> +<%= + settings_primer_form_with( + url: admin_settings_icalendar_path, + scope: :settings, + method: :patch, + class: "op-icalendar-admin-settings", + data: { turbo: false } + ) do |form| + render_inline_settings_form(form) do |f| + f.check_box name: :ical_enabled, + caption: t("settings.icalendar.enable_subscriptions_text_html", + link: OpenProject::Static::Links.url_for(:ical_docs)) -
    -
    - <%= setting_check_box :ical_enabled, size: 6 %> -
    -

    <%= t("settings.icalendar.enable_subscriptions_text_html", link: OpenProject::Static::Links.url_for(:ical_docs)) %>

    -
    -
    -
    - - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> -<% end %> + f.submit + end + end +%> diff --git a/app/views/admin/settings/incoming_mails_settings/show.html.erb b/app/views/admin/settings/incoming_mails_settings/show.html.erb index 13df0d25774..5676f233229 100644 --- a/app/views/admin/settings/incoming_mails_settings/show.html.erb +++ b/app/views/admin/settings/incoming_mails_settings/show.html.erb @@ -40,21 +40,26 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= styled_form_tag(admin_settings_incoming_mails_path, method: :patch) do %> -
    -
    - <%= setting_text_area :mail_handler_body_delimiters, rows: 5, container_class: "-wide" %> -
    <%= t(:text_line_separated) %>
    -
    -
    - <%= setting_text_field :mail_handler_body_delimiter_regex, container_class: "-wide" %> -
    <%= t(:text_regexp_multiline) %>
    -
    -
    - <%= setting_text_area :mail_handler_ignore_filenames, rows: 5, container_class: "-wide" %> -
    <%= t("incoming_mails.ignore_filenames") %>
    -
    -
    +<%= + settings_primer_form_with( + url: admin_settings_incoming_mails_path, + scope: :settings, + method: :patch, + data: { turbo: false } + ) do |form| + render_inline_settings_form(form) do |f| + f.text_area name: :mail_handler_body_delimiters, + rows: 5, + caption: t(:text_line_separated) - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> -<% end %> + f.text_field name: :mail_handler_body_delimiter_regex, + caption: t(:text_regexp_multiline) + + f.text_area name: :mail_handler_ignore_filenames, + rows: 5, + caption: t("incoming_mails.ignore_filenames") + + f.submit + end + end +%> diff --git a/app/views/admin/settings/mail_notifications_settings/show.html.erb b/app/views/admin/settings/mail_notifications_settings/show.html.erb index 8ec62de0be2..31c2968dbf1 100644 --- a/app/views/admin/settings/mail_notifications_settings/show.html.erb +++ b/app/views/admin/settings/mail_notifications_settings/show.html.erb @@ -40,98 +40,34 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= - styled_form_tag( - admin_settings_mail_notifications_path, - method: :patch, - data: { controller: "show-when-value-selected" } - ) do -%> - <% if @deliveries %> -
    -
    <%= setting_text_field :mail_from, size: 60, container_class: "-middle" %>
    -
    <%= setting_check_box :bcc_recipients %>
    -
    <%= setting_check_box :plain_text_mail %>
    -
    - <%= setting_select :emails_salutation, - [ - [User.human_attribute_name(:firstname), :firstname], - [t("mail.salutation_full_name"), :name] - ], - container_class: "-middle" %> -
    -
    - -
    - <%= t(:setting_emails_header) %> - & <%= I18n.t(:setting_emails_footer) %> - <%= render Settings::TextSettingComponent.new(I18n.locale, name: "emails_header") %> - <%= render Settings::TextSettingComponent.new(I18n.locale, name: "emails_footer") %> -
    - <% else %> -
    - <%= simple_format(t(:text_email_delivery_not_configured)) %> -
    - <% end %> - - <% - email_methods = %i[smtp sendmail] - email_methods << :letter_opener if Rails.env.development? +<% unless @deliveries %> + <%= + render Primer::Alpha::Banner.new(scheme: :default) do + t(:text_email_delivery_not_configured) + end %> - <%= content_tag :fieldset, class: "form--fieldset" do %> - <%= t(:text_setup_mail_configuration) %> -
    - <%= - setting_select( - :email_delivery_method, - email_methods, - container_class: "-slim", - data: { - show_when_value_selected_target: "cause", - target_name: "email_delivery_method_settings" - } - ) - %> -
    -
    > -
    <%= setting_text_field :smtp_address, container_class: "-middle" %>
    -
    <%= setting_text_field :smtp_port, size: 6, container_class: "-xslim" %>
    -
    <%= setting_text_field :smtp_domain, container_class: "-middle" %>
    -
    <%= setting_select(:smtp_authentication, %i[none plain login cram_md5], container_class: "-slim") %>
    -
    <%= setting_text_field :smtp_user_name, container_class: "-middle" %>
    -
    <%= setting_password :smtp_password, container_class: "-middle" %>
    -
    <%= setting_check_box :smtp_enable_starttls_auto %>
    -
    <%= setting_check_box :smtp_ssl %>
    -
    -
    > -
    <%= setting_text_field :sendmail_location %>
    -
    <%= setting_text_field :sendmail_arguments %>
    -
    -
    > -

    Letter opener is used to render emails as a file in your Rails tmp folder. Mails will automatically open in - your browser if supported.

    -
    - <% end unless OpenProject::Configuration['email_delivery_configuration'] == 'legacy' %> - - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> - - <% if @deliveries %> -
    - <%= link_to t(:label_send_test_email), - { controller: "/admin", action: "test_email" }, - data: { turbo_method: :post } %> -
    - <% end %> +<% end %> + +<%= + settings_primer_form_with( + url: admin_settings_mail_notifications_path, + scope: :settings, + method: :patch, + data: { turbo: false, + controller: "show-when-value-selected" } + ) do |form| + render Admin::Settings::MailNotificationsSettingForm.new(form, deliveries: @deliveries) + end +%> + +<% if @deliveries %> + <%= render Primer::Beta::Link.new( + href: test_email_admin_index_path, + data: { turbo_method: :post }, + font_weight: :bold, + display: :block, + mt: 3 + ) do + t(:label_send_test_email) + end %> <% end %> diff --git a/app/views/admin/settings/work_packages_identifier/show.html.erb b/app/views/admin/settings/work_packages_identifier/show.html.erb new file mode 100644 index 00000000000..99633196920 --- /dev/null +++ b/app/views/admin/settings/work_packages_identifier/show.html.erb @@ -0,0 +1,48 @@ +<%# + -- copyright + OpenProject is an open source project management software. + Copyright (C) the OpenProject GmbH + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License version 3. + + OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: + Copyright (C) 2006-2013 Jean-Philippe Lang + Copyright (C) 2010-2013 the ChiliProject Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + See COPYRIGHT and LICENSE files for more details. + + ++# +%> + +<% html_title t(:label_administration), t(:label_work_package_plural), t(:label_identifier) -%> + +<%= + render Primer::OpenProject::PageHeader.new do |header| + header.with_title { t(:label_identifier) } + header.with_breadcrumbs( + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_work_packages_identifier_path, text: t(:label_work_package_plural), skip_for_mobile: true }, + t(:label_identifier)] + ) + header.with_description do + t("admin.settings.work_packages_identifier.page_header.description") + end + end +%> + +<%= render(WorkPackages::Admin::Settings::IdentifierSettingsFormComponent.new(state: @form_state)) %> diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb index 96f97626981..4ccba595b04 100644 --- a/app/views/layouts/base.html.erb +++ b/app/views/layouts/base.html.erb @@ -74,7 +74,7 @@ See COPYRIGHT and LICENSE files for more details. <%= render_top_menu_left %> -
    +
    <%= render_top_menu_center %>
    diff --git a/app/views/layouts/only_logo.html.erb b/app/views/layouts/only_logo.html.erb index 315db4ec378..311c4ebf6be 100644 --- a/app/views/layouts/only_logo.html.erb +++ b/app/views/layouts/only_logo.html.erb @@ -39,8 +39,13 @@ See COPYRIGHT and LICENSE files for more details. data: body_data_attributes(local_assigns) do %>
    "> -
    diff --git a/app/views/wiki_menu_items/edit.html.erb b/app/views/wiki_menu_items/edit.html.erb index b7041d88f1b..2624bcbed04 100644 --- a/app/views/wiki_menu_items/edit.html.erb +++ b/app/views/wiki_menu_items/edit.html.erb @@ -57,12 +57,6 @@ See COPYRIGHT and LICENSE files for more details. <%= form.radio_button "setting", :main_item %> <%= form.label "setting_main_item", t(:label_wiki_show_menu_item) %>

    -

    - <% disabled = @parent_menu_item_options.empty? %> - <%= form.radio_button "setting", :sub_item, disabled: disabled %> - <%= form.label "setting_sub_item", t(:label_wiki_show_submenu_item), { id: "with-select" } %> - <%= select_tag "parent_wiki_menu_item", options_for_select(@parent_menu_item_options, @selected_parent_menu_item_id), disabled: disabled %> -

    <%= styled_button_tag t(:button_save), method: :post, diff --git a/app/workers/import/jira_import_projects_job.rb b/app/workers/import/jira_import_projects_job.rb index 0b9f0f6ca02..eb431d59bf1 100644 --- a/app/workers/import/jira_import_projects_job.rb +++ b/app/workers/import/jira_import_projects_job.rb @@ -68,11 +68,12 @@ module Import Import::JiraProject.where(jira_id:, jira_project_id: project_ids).find_each do |jira_project| ### PROJECT + identifier = jira_project.payload.fetch("key").downcase service_call = Projects::CreateService .new(user:) .call( name: jira_project.payload.fetch("name"), - identifier: jira_project.payload.fetch("key").downcase, + identifier:, description: jira_project.payload.fetch("description"), active: true, public: false, @@ -231,6 +232,11 @@ module Import raise service_call.message end end + elsif (error = service_call.errors.find { |e| e.attribute == :identifier && e.type == :taken }) && error.present? + taken_identifier = error.options[:value] + project = Project.find_by!(identifier: taken_identifier) + raise "You are trying to import a project with already used " \ + "identifier: #{taken_identifier}. Existing project: #{project}." else raise service_call.message end diff --git a/app/workers/work_packages/identifier_autofix/apply_handles_job.rb b/app/workers/work_packages/identifier_autofix/apply_handles_job.rb new file mode 100644 index 00000000000..ff2107b4a3e --- /dev/null +++ b/app/workers/work_packages/identifier_autofix/apply_handles_job.rb @@ -0,0 +1,40 @@ +# 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. +#++ + +class WorkPackages::IdentifierAutofix::ApplyHandlesJob < ApplicationJob + # FIXME: The admin UI's job_in_progress? query and :change_in_progress state + # assume at most one active instance of this job at any given time. + # Enforce this with good_job_control_concurrency_with(perform_limit: 1) + # when the real migration body is implemented. + def perform + # FIXME: replace with actual project handle migration + sleep 5 + end +end diff --git a/bin/build-docker-aio b/bin/build-docker-aio index 1c75035df0c..34e1e94e412 100755 --- a/bin/build-docker-aio +++ b/bin/build-docker-aio @@ -1,4 +1,3 @@ #!/bin/bash -docker build -t openproject/openproject:$(git rev-parse --abbrev-ref HEAD | tr '/' '-') --build-arg DEBIAN_BASE=bookworm -f docker/prod/Dockerfile . - +docker build -t openproject/openproject:$(git rev-parse --abbrev-ref HEAD | tr '/' '-') -f docker/prod/Dockerfile . diff --git a/config/AGENTS.md b/config/AGENTS.md new file mode 100644 index 00000000000..c2f55641e23 --- /dev/null +++ b/config/AGENTS.md @@ -0,0 +1,14 @@ +# Config + +## Translations + +- UI strings must use translation keys (never hard-coded) +- Source translations in `**/config/locales/en.yml` can be modified directly +- Other translations managed via Crowdin + +```bash +bundle exec i18n-tasks missing # Show missing translation keys +bundle exec i18n-tasks unused # Show unused translation keys +bundle exec i18n-tasks normalize # Fix/normalize translation files +bundle exec i18n-tasks check-consistent-interpolations # Check interpolation consistency +``` diff --git a/config/CLAUDE.md b/config/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/config/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/config/constants/settings/definition.rb b/config/constants/settings/definition.rb index 6f18a21b143..2d6d5375dcc 100644 --- a/config/constants/settings/definition.rb +++ b/config/constants/settings/definition.rb @@ -1321,6 +1321,15 @@ module Settings work_packages_bulk_request_limit: { default: 10 }, + work_packages_identifier: { + description: "Defines how work packages are identified in the UI (e.g. in links and titles). " \ + "The 'numeric' option uses the work package numerical ID, " \ + "while 'alphanumeric' uses the project identifier and the work package ID separated by a dash " \ + "(e.g. 'PROJA-123').", + format: :string, + allowed: -> { Setting::WorkPackageIdentifier::ALLOWED_VALUES }, + default: "numeric" + }, work_package_list_default_highlighted_attributes: { default: ["status", "priority", "due_date"], allowed: -> { @@ -1400,6 +1409,14 @@ module Settings end end + def env_name + self.class.env_name(self) + end + + def possible_env_names + self.class.possible_env_names(self) + end + def derive_default(default) @default = default.is_a?(Hash) ? default.deep_stringify_keys : default @default.freeze @@ -1633,8 +1650,8 @@ module Settings env_var_hash_part .scan(/(?:[a-zA-Z0-9]|__)+/) .map do |seg| - unescape_underscores(seg.downcase) - end + unescape_underscores(seg.downcase) + end end # takes the path provided and transforms it into a deeply nested hash @@ -1689,8 +1706,6 @@ module Settings ].compact end - public :possible_env_names - def env_name_nested(definition) "#{ENV_PREFIX}#{definition.name.upcase.gsub('_', '__')}" end @@ -1709,6 +1724,8 @@ module Settings definition.env_alias.upcase end + public :possible_env_names, :env_name + ## # Extract the configuration value from the given environment variable # using YAML. diff --git a/config/initializers/00-load_plugins.rb b/config/initializers/00-load_plugins.rb index 2ea001b64f4..e2de30f5ab6 100644 --- a/config/initializers/00-load_plugins.rb +++ b/config/initializers/00-load_plugins.rb @@ -31,7 +31,16 @@ # TODO: check if this can be postponed and if some plugins can make use of the ActiveSupport.on_load hooks # Loads the core plugins located in lib_static/plugins -Dir.glob(Rails.root.join("lib_static/plugins/*")).each do |directory| +CORE_PLUGINS = %w[ + acts_as_attachable + acts_as_customizable + acts_as_event + acts_as_journalized + acts_as_searchable + verification +].freeze + +CORE_PLUGINS.map { |name| Rails.root.join("lib_static/plugins", name).to_s }.each do |directory| if File.directory?(directory) lib = File.join(directory, "lib") diff --git a/config/initializers/feature_decisions.rb b/config/initializers/feature_decisions.rb index 3c607f0716c..370e22da9bb 100644 --- a/config/initializers/feature_decisions.rb +++ b/config/initializers/feature_decisions.rb @@ -71,3 +71,8 @@ OpenProject::FeatureDecisions.add :scrum_projects, OpenProject::FeatureDecisions.add :user_working_times, description: "Enables tracking of user working hours and non-working days." + +OpenProject::FeatureDecisions.add :semantic_work_package_ids, + description: "Enables the use of semantic work package IDs, " \ + "in the schema -. " \ + "See #71626 for details." diff --git a/config/initializers/menus.rb b/config/initializers/menus.rb index 0bdf4b07678..94be869d12d 100644 --- a/config/initializers/menus.rb +++ b/config/initializers/menus.rb @@ -413,6 +413,12 @@ Redmine::MenuManager.map :admin_menu do |menu| caption: IssuePriority.model_name.human(count: :other), parent: :admin_work_packages + menu.push :work_packages_identifier, + { controller: "/admin/settings/work_packages_identifier", action: :show }, + if: ->(_) { OpenProject::FeatureDecisions.semantic_work_package_ids_active? && User.current.admin? }, + caption: :label_identifier, + parent: :admin_work_packages + menu.push :progress_tracking, { controller: "/admin/settings/progress_tracking", action: :show }, if: ->(_) { User.current.admin? }, diff --git a/config/initializers/permissions.rb b/config/initializers/permissions.rb index 75233ee0080..d7e7260c6a9 100644 --- a/config/initializers/permissions.rb +++ b/config/initializers/permissions.rb @@ -407,7 +407,8 @@ Rails.application.reloader.to_prepare do wpt.permission :add_work_package_attachments, {}, permissible_on: %i[work_package project], - dependencies: :view_work_packages + dependencies: :view_work_packages, + contract_actions: { work_package_attachments: %i[create] } # WorkPackage categories wpt.permission :manage_categories, diff --git a/config/initializers/store_attribute.rb b/config/initializers/store_attribute.rb index 37ded4b606b..1fb782ad849 100644 --- a/config/initializers/store_attribute.rb +++ b/config/initializers/store_attribute.rb @@ -31,4 +31,9 @@ # From v1.0 to v2.0 of store_attribute, the value for store_attribute_unset_values_fallback_to_default changed from # false to true. This initializer sets it back to false to keep the behavior consistent with the previous version. +# Keeping this false also avoids a subtle dirty-tracking issue with the `default:` option: assigning the +# default value to an attribute that has never been persisted is a no-op from dirty-tracking's perspective, +# so the store column is never written. Concretely, `create(:project, sprint_sharing: "no_sharing")` leaves +# `project.settings` as `{}` because "no_sharing" equals the declared default and is never saved. + StoreAttribute.store_attribute_unset_values_fallback_to_default = false diff --git a/config/locales/crowdin/af.yml b/config/locales/crowdin/af.yml index 7d4ce48ac48..31462553e6a 100644 --- a/config/locales/crowdin/af.yml +++ b/config/locales/crowdin/af.yml @@ -107,9 +107,8 @@ af: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ af: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anoniem" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Net vir die dinge wat ek dophou of betrokke in is" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ af: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Begin bladsy" label_work: "Work" label_work_package: "Werkspakket" @@ -4217,7 +4209,7 @@ af: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/ar.yml b/config/locales/crowdin/ar.yml index 6e4aacc3d85..8e09304a361 100644 --- a/config/locales/crowdin/ar.yml +++ b/config/locales/crowdin/ar.yml @@ -107,9 +107,8 @@ ar: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -4114,12 +4113,6 @@ ar: label_user_named: "User %{name}" label_user_activity: "نشاط %{value}'s" label_user_anonymous: "مجهول" - label_user_mail_option_all: "من أجل أي حدث في كافة المشاريع" - label_user_mail_option_none: "لا يوجد أحداث" - label_user_mail_option_only_assigned: "فقط لأشياء موكلة لي" - label_user_mail_option_only_my_events: "فقط لأشياء أشاهدها أو أشارك فيها" - label_user_mail_option_only_owner: "فقط لأشياء أملكها" - label_user_mail_option_selected: "من أجل أي حدث في المشاريع المحددة فقط" label_user_menu: "User menu" label_user_new: "مستخدم جديد" label_user_plural: "المستخدمين" @@ -4159,7 +4152,6 @@ ar: label_wiki_show_index_page_link: "إظهار عنصر القائمة الفرعية ’جدول المحتويات’" label_wiki_show_menu_item: "إظهار كعنصر قائمة في مشروع الملاحة" label_wiki_show_new_page_link: "إظهار عنصر القائمة الفرعية 'إنشاء صفحة فرعية جديدة'" - label_wiki_show_submenu_item: "إظهار كعنصر قائمة فرعية من " label_wiki_start: "صفحة البداية" label_work: "Work" label_work_package: "مجموعة العمل" @@ -4445,7 +4437,7 @@ ar: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "لم يتم حذف المشروع." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "اتصال ناجح." notice_successful_create: "إنشاء ناجح." notice_successful_delete: "حذف ناجح." diff --git a/config/locales/crowdin/az.yml b/config/locales/crowdin/az.yml index 5f6e5b90f5f..49b97ec5e7b 100644 --- a/config/locales/crowdin/az.yml +++ b/config/locales/crowdin/az.yml @@ -107,9 +107,8 @@ az: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ az: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ az: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ az: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/be.yml b/config/locales/crowdin/be.yml index e759195a542..4a8565f774f 100644 --- a/config/locales/crowdin/be.yml +++ b/config/locales/crowdin/be.yml @@ -107,9 +107,8 @@ be: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -4002,12 +4001,6 @@ be: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -4047,7 +4040,6 @@ be: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4331,7 +4323,7 @@ be: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/bg.yml b/config/locales/crowdin/bg.yml index 50c999cc691..c40eadfd279 100644 --- a/config/locales/crowdin/bg.yml +++ b/config/locales/crowdin/bg.yml @@ -107,9 +107,8 @@ bg: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ bg: label_user_named: "Потребител %{name}" label_user_activity: "дейност на %{value}" label_user_anonymous: "Анонимен" - label_user_mail_option_all: "За всяко събитие на всичките ми проекти" - label_user_mail_option_none: "Няма събития" - label_user_mail_option_only_assigned: "Само за неща, възложени на мен" - label_user_mail_option_only_my_events: "Само за неща, които наблюдавам или съм включен в тях" - label_user_mail_option_only_owner: "Само за неща, на които аз съм собственик" - label_user_mail_option_selected: "За всяко събитие само в избраните проекти" label_user_menu: "User menu" label_user_new: "Нов потребител" label_user_plural: "Потребители" @@ -3935,7 +3928,6 @@ bg: label_wiki_show_index_page_link: "Показване на елемент от подменюто \"Съдържание\"" label_wiki_show_menu_item: "Покажи като меню в проектната навигация" label_wiki_show_new_page_link: "Показване на елемент от подменю \"Създай нова подстраница\"" - label_wiki_show_submenu_item: "Покажи като елемент от подменюто на " label_wiki_start: "Начална страница" label_work: "Работа" label_work_package: "Работен пакет" @@ -4217,7 +4209,7 @@ bg: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Проектът не е изтрит." notice_project_not_found: "Проектът не е намерен." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Успешна връзка." notice_successful_create: "Успешно създаване." notice_successful_delete: "Успешно изтриване." diff --git a/config/locales/crowdin/ca.yml b/config/locales/crowdin/ca.yml index 34ba075e5cf..a3840f9b274 100644 --- a/config/locales/crowdin/ca.yml +++ b/config/locales/crowdin/ca.yml @@ -107,9 +107,8 @@ ca: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Les accions individuals d'un sol usuari (per exemple actualitzar dos cops un paquet de treball) seran agregades en una sola acció si la diferència temporal és menor a l'especificada. Aquests seran exposats com una acció individual dins l'aplicació. Això, també reduïra el número d'emails enviats i el retràs en el %{webhook_link} ja que les notificacións també seran retrasades." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3887,12 +3886,6 @@ ca: label_user_named: "Usuari %{name}" label_user_activity: "Activitat de %{value}" label_user_anonymous: "Anònim" - label_user_mail_option_all: "Per qualsevol esdeveniment en tots els meus projectes" - label_user_mail_option_none: "No hi ha esdeveniments" - label_user_mail_option_only_assigned: "Només pels objectes on estic assignat" - label_user_mail_option_only_my_events: "Només pels objectes que estic en observant o involucrat" - label_user_mail_option_only_owner: "Només pels objectes dels que en sóc propietari" - label_user_mail_option_selected: "Només per qualsevol esdeveniment dels projectes seleccionats" label_user_menu: "User menu" label_user_new: "Nou usuari" label_user_plural: "Usuaris" @@ -3932,7 +3925,6 @@ ca: label_wiki_show_index_page_link: "Mostra l'element del submenú 'Taula de continguts'" label_wiki_show_menu_item: "Mostrar com a element de menú en la navegació del projecte" label_wiki_show_new_page_link: "Mostra l'element submenú 'Crea nova pàgina fill'" - label_wiki_show_submenu_item: "Mostrar com element de submenú de " label_wiki_start: "Pàgina d'inici" label_work: "Treball" label_work_package: "Paquet de treball" @@ -4211,7 +4203,7 @@ ca: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "El projecte no s'ha suprimit." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "S'ha connectat correctament." notice_successful_create: "Creat correctament." notice_successful_delete: "Esborrat correctament." diff --git a/config/locales/crowdin/ckb-IR.yml b/config/locales/crowdin/ckb-IR.yml index 59f0899635c..5e172c2fb8c 100644 --- a/config/locales/crowdin/ckb-IR.yml +++ b/config/locales/crowdin/ckb-IR.yml @@ -107,9 +107,8 @@ ckb-IR: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ ckb-IR: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ ckb-IR: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ ckb-IR: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/cs.yml b/config/locales/crowdin/cs.yml index f107d4ff779..460d252f7d2 100644 --- a/config/locales/crowdin/cs.yml +++ b/config/locales/crowdin/cs.yml @@ -107,9 +107,8 @@ cs: trial: "Trial" jemalloc_allocator: Jemalloc alokátor paměti journal_aggregation: - explanation: - text: "Individuální akce/úpravy uživatele (např. dvojnásobná aktualizace pracovního balíčku se sečtou do jediné akce, pokud je jejich časový rozdíl menší než stanovený čas. Budou zobrazeny jako jedna akce v rámci aplikace. Toto také zpozdí oznámení o stejný čas a sníží tak počet zasílaných e-mailů a ovlivní se také zpoždění na adrese %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3960,7 +3959,7 @@ cs: label_subproject: "Podprojekt" label_subproject_new: "Nový podprojekt" label_subproject_plural: "Podprojekty" - label_subitems: "Subitems" + label_subitems: "Dílčí položky" label_subtask_plural: "Podúkoly" label_summary: "Souhrn" label_system: "Systém" @@ -4002,12 +4001,6 @@ cs: label_user_named: "Uživatel %{name}" label_user_activity: "Aktivita %{value}" label_user_anonymous: "Anonymní" - label_user_mail_option_all: "Pro všechny události všech mých projektů" - label_user_mail_option_none: "Žádné události" - label_user_mail_option_only_assigned: "Pouze pro věci, na které jsem přidělen" - label_user_mail_option_only_my_events: "Pouze pro věci, které sleduji nebo jsem v nich zapojen" - label_user_mail_option_only_owner: "Pouze pro věci, kde jsem majitelem" - label_user_mail_option_selected: "Pouze pro každou událost na vybraných projektech" label_user_menu: "User menu" label_user_new: "Nový uživatel" label_user_plural: "Uživatelé" @@ -4047,7 +4040,6 @@ cs: label_wiki_show_index_page_link: "Zobrazit položku podnabídky 'Obsah'" label_wiki_show_menu_item: "Zobrazit jako položku nabídky navigaci projektu" label_wiki_show_new_page_link: "Zobrazit položku menu \"Vytvořit novou podřízenou stránku\"" - label_wiki_show_submenu_item: "Zobrazit jako položku podnabídky " label_wiki_start: "Úvodní stránka" label_work: "Práce" label_work_package: "Pracovní balíček" @@ -4330,7 +4322,7 @@ cs: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projekt nebyl odstraněn." notice_project_not_found: "Projekt nebyl nalezen." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Úspěšné připojení." notice_successful_create: "Úspěšné vytvoření." notice_successful_delete: "Úspěšné odstranění." diff --git a/config/locales/crowdin/da.yml b/config/locales/crowdin/da.yml index 5090f8fe75f..6ac7a05f16e 100644 --- a/config/locales/crowdin/da.yml +++ b/config/locales/crowdin/da.yml @@ -107,9 +107,8 @@ da: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3888,12 +3887,6 @@ da: label_user_named: "User %{name}" label_user_activity: "%{value}s aktivitet" label_user_anonymous: "Anonymt" - label_user_mail_option_all: "For enhver hændelse i alle mine projekter" - label_user_mail_option_none: "Ingen hændelser" - label_user_mail_option_only_assigned: "Kun i forbindelse med det jeg er tilknyttet" - label_user_mail_option_only_my_events: "Kun for det jeg fører tilsyn med eller er involveret i" - label_user_mail_option_only_owner: "Kun for det jeg er ejer af" - label_user_mail_option_selected: "Kun for hændelser i de valgte projekter" label_user_menu: "User menu" label_user_new: "Ny bruger" label_user_plural: "Brugere" @@ -3933,7 +3926,6 @@ da: label_wiki_show_index_page_link: "Vis undermenupunkt 'Indhold'" label_wiki_show_menu_item: "Vis som menupunkt i projektnavigeringen" label_wiki_show_new_page_link: "Vis undermenupunktet 'Opret ny underside'" - label_wiki_show_submenu_item: "Vis som punkt i undermenu til " label_wiki_start: "Startside" label_work: "Work" label_work_package: "Arbejdspakke" @@ -4215,7 +4207,7 @@ da: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projektet blev ikke slettet." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Forbindelse gennemført." notice_successful_create: "Oprettelse gennemført." notice_successful_delete: "Sletning gennemført." diff --git a/config/locales/crowdin/de.yml b/config/locales/crowdin/de.yml index 1fa19d1ecc7..ac7954d9227 100644 --- a/config/locales/crowdin/de.yml +++ b/config/locales/crowdin/de.yml @@ -107,9 +107,8 @@ de: trial: "Probezeitraum" jemalloc_allocator: Jemalloc Speicher allocator journal_aggregation: - explanation: - text: "Individuelle Aktionen eines Benutzers (z.B. ein Arbeitspaket zweimal aktualisieren) werden zu einer einzigen Aktion zusammengefasst, wenn ihr Altersunterschied kleiner ist als der angegebene Zeitraum. Sie werden als eine einzige Aktion innerhalb der Anwendung angezeigt. Dadurch werden Benachrichtigungen um die gleiche Zeit verzögert, wodurch die Anzahl der gesendeten E-Mails verringert wird. Dies wirkt sich auch auf die Verzögerung von %{webhook_link} aus." - link: "Webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3882,12 +3881,6 @@ de: label_user_named: "Benutzer %{name}" label_user_activity: "Aktivität von %{value}" label_user_anonymous: "Anonym" - label_user_mail_option_all: "Für alle Ereignisse in all meinen Projekten" - label_user_mail_option_none: "Für keine Ereignisse" - label_user_mail_option_only_assigned: "Nur für Aufgaben, für die ich zuständig bin." - label_user_mail_option_only_my_events: "Nur für Aufgaben, die ich beobachte oder an welchen ich mitarbeite" - label_user_mail_option_only_owner: "Nur für Aufgaben, die ich angelegt habe" - label_user_mail_option_selected: "Für alle Ereignisse in den ausgewählten Projekten" label_user_menu: "Benutzermenü" label_user_new: "Neuer Benutzer" label_user_plural: "Benutzer" @@ -3927,7 +3920,6 @@ de: label_wiki_show_index_page_link: "'Inhaltsverzeichnis' Link als Untermenüpunkt anzeigen" label_wiki_show_menu_item: "als Menüpunkt in der Projektnavigation anzeigen" label_wiki_show_new_page_link: "'Neue Unterseite anlegen' Link als Untermenüpunkt anzeigen" - label_wiki_show_submenu_item: "als Untermenüpunkt anzeigen von " label_wiki_start: "Hauptseite" label_work: "Aufwand" label_work_package: "Arbeitspaket" @@ -4209,7 +4201,7 @@ de: notice_parent_item_not_found: "Übergeordnetes Element nicht gefunden." notice_project_not_deleted: "Das Projekt wurde nicht gelöscht." notice_project_not_found: "Projekt nicht gefunden." - notice_smtp_address_unsafe: "Die SMTP-Adresse %{address} ist nicht sicher. Bitte fügen Sie sie zu OPENPROJECT_SSRF_PROTECTION_ALLOWLIST hinzu." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Verbindung erfolgreich." notice_successful_create: "Erfolgreich angelegt." notice_successful_delete: "Erfolgreich gelöscht." diff --git a/config/locales/crowdin/el.yml b/config/locales/crowdin/el.yml index b77bd6605be..9ee312c8da4 100644 --- a/config/locales/crowdin/el.yml +++ b/config/locales/crowdin/el.yml @@ -107,9 +107,8 @@ el: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3886,12 +3885,6 @@ el: label_user_named: "Χρήστης %{name}" label_user_activity: "δραστηριότητα του %{value}" label_user_anonymous: "Ανώνυμος" - label_user_mail_option_all: "Για όλα τα συμβάντα σε όλα τα έργα μου" - label_user_mail_option_none: "Κανένα συμβάν" - label_user_mail_option_only_assigned: "Μόνο για αντικείμενα που έχουν ανατεθεί σε μένα" - label_user_mail_option_only_my_events: "Μόνο για αντικείμενα που παρακολουθώ ή συμμετέχω" - label_user_mail_option_only_owner: "Μόνο για αντικείμενα που μου ανήκουν" - label_user_mail_option_selected: "Για όλες τις εξελίξεις μόνο στα επιλεγμένα έργα" label_user_menu: "User menu" label_user_new: "Νέος χρήστης" label_user_plural: "Χρήστες" @@ -3931,7 +3924,6 @@ el: label_wiki_show_index_page_link: "Εμφάνιση του αντικειμένου υπομενού 'Πίνακας Περιεχομένων'" label_wiki_show_menu_item: "Εμφάνιση ως αντικείμενο μενού στην πλοήγηση έργου" label_wiki_show_new_page_link: "Εμφάνιση του αντικειμένου υπομενού 'Δημιουργία καινούργιας σελίδας παιδιού'" - label_wiki_show_submenu_item: "Εμφάνιση ως αντικείμενο υπομενού του " label_wiki_start: "Σελίδα έναρξης" label_work: "Work" label_work_package: "Εργασία" @@ -4212,7 +4204,7 @@ el: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Το έργο δεν διαγράφηκε." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Επιτυχής σύνδεση." notice_successful_create: "Επιτυχής δημιουργία." notice_successful_delete: "Επιτυχής διαγραφή." diff --git a/config/locales/crowdin/eo.yml b/config/locales/crowdin/eo.yml index b6518d29d63..266e900f561 100644 --- a/config/locales/crowdin/eo.yml +++ b/config/locales/crowdin/eo.yml @@ -107,9 +107,8 @@ eo: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ eo: label_user_named: "Uzanto %{name}" label_user_activity: "Aktiveco de %{value}" label_user_anonymous: "Aanonima" - label_user_mail_option_all: "Por ajna evento en ĉiuj miaj projektoj" - label_user_mail_option_none: "Ne estas eventoj" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "Nova uzanto" label_user_plural: "Uzantoj" @@ -3935,7 +3928,6 @@ eo: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Laborpakaĵo" @@ -4217,7 +4209,7 @@ eo: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/es.yml b/config/locales/crowdin/es.yml index 0e5879e962a..e38267c9e15 100644 --- a/config/locales/crowdin/es.yml +++ b/config/locales/crowdin/es.yml @@ -107,9 +107,8 @@ es: trial: "Prueba" jemalloc_allocator: Asignador de memoria Jemalloc journal_aggregation: - explanation: - text: "Las acciones individuales de un usuario (como actualizar dos veces un paquete de trabajo) se combinan en una sola acción si la diferencia de antigüedad es inferior al intervalo de tiempo especificado. Se mostrarán como una sola acción en la aplicación. También se retrasarán las notificaciones por la misma cantidad de tiempo, lo que reducirá el número de correos electrónicos enviados y causará también que se retrase el %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Importar" jira: @@ -3887,12 +3886,6 @@ es: label_user_named: "Usuario %{name}" label_user_activity: "Actividad de %{value} " label_user_anonymous: "Anónimo" - label_user_mail_option_all: "Para cualquier evento en todos mis proyectos" - label_user_mail_option_none: "No hay eventos" - label_user_mail_option_only_assigned: "Sólo para cosas asignadas a mí" - label_user_mail_option_only_my_events: "Sólo para cosas que controlo o en las que participo" - label_user_mail_option_only_owner: "Sólo para cosas de las que soy el dueño" - label_user_mail_option_selected: "Únicamente para cualquier evento de los proyectos seleccionados" label_user_menu: "Menú de usuario" label_user_new: "Nuevo usuario" label_user_plural: "Usuarios" @@ -3932,7 +3925,6 @@ es: label_wiki_show_index_page_link: "Mostrar el elemento de submenú 'Tabla de contenidos'" label_wiki_show_menu_item: "Mostrar como elemento de menú de navegación de proyecto" label_wiki_show_new_page_link: "Mostrar el elemento de submenú 'Crear nueva página hija'" - label_wiki_show_submenu_item: "Mostrar como elemento de submenú de " label_wiki_start: "Página de inicio" label_work: "Trabajo" label_work_package: "Paquete de trabajo" @@ -4214,7 +4206,7 @@ es: notice_parent_item_not_found: "Elemento padre no encontrado." notice_project_not_deleted: "El proyecto no fue eliminado." notice_project_not_found: "Proyecto no encontrado." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Conexión exitosa." notice_successful_create: "Creación exitosa." notice_successful_delete: "Eliminado con éxito." diff --git a/config/locales/crowdin/et.yml b/config/locales/crowdin/et.yml index a6fcc60babc..2097a65a155 100644 --- a/config/locales/crowdin/et.yml +++ b/config/locales/crowdin/et.yml @@ -107,9 +107,8 @@ et: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ et: label_user_named: "User %{name}" label_user_activity: "%{value}-s tegevus" label_user_anonymous: "Anonüümne" - label_user_mail_option_all: "Kõigi sündmuste kohta minu projektides" - label_user_mail_option_none: "Sündmusi pole" - label_user_mail_option_only_assigned: "Ainult minule määratud tööde kohta" - label_user_mail_option_only_my_events: "Ainult tööde kohta, mida ma jälgin või millega olen seotud" - label_user_mail_option_only_owner: "Ainult minu omanduses olevate asjade kohta" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "Uus kasutaja" label_user_plural: "Kasutajad" @@ -3935,7 +3928,6 @@ et: label_wiki_show_index_page_link: "Kuva alammenüü valik \"Sisukord\"" label_wiki_show_menu_item: "Näita lehe nime projektimenüüs" label_wiki_show_new_page_link: "Näita alammenüüs valikut 'Loo uus alamleht'" - label_wiki_show_submenu_item: "Näita kui alammenüüd (<--) " label_wiki_start: "Esileht" label_work: "Töö" label_work_package: "Teema" @@ -4217,7 +4209,7 @@ et: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projekti ei ole kustutatud." notice_project_not_found: "Projekti ei leitud." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Ühenduse loomine õnnestus." notice_successful_create: "Loomine õnnestus." notice_successful_delete: "Kustutamine õnnestus." diff --git a/config/locales/crowdin/eu.yml b/config/locales/crowdin/eu.yml index 572dcf3dbad..d256c03af4d 100644 --- a/config/locales/crowdin/eu.yml +++ b/config/locales/crowdin/eu.yml @@ -107,9 +107,8 @@ eu: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ eu: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ eu: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ eu: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/fa.yml b/config/locales/crowdin/fa.yml index dfb4d8e381c..78fd1f9d79d 100644 --- a/config/locales/crowdin/fa.yml +++ b/config/locales/crowdin/fa.yml @@ -107,9 +107,8 @@ fa: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ fa: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ fa: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "صفحه‌ی شروع" label_work: "Work" label_work_package: "کاربسته" @@ -4217,7 +4209,7 @@ fa: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/fi.yml b/config/locales/crowdin/fi.yml index 9bda2f6de4f..a7244449a04 100644 --- a/config/locales/crowdin/fi.yml +++ b/config/locales/crowdin/fi.yml @@ -107,9 +107,8 @@ fi: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ fi: label_user_named: "Käyttäjä %{name}" label_user_activity: "Käyttäjän %{value} historia" label_user_anonymous: "Anonyymi" - label_user_mail_option_all: "Kaikista tapahtumista kaikissa projekteistani" - label_user_mail_option_none: "Ei tapahtumia" - label_user_mail_option_only_assigned: "Vain niistä joihin olen liittynyt" - label_user_mail_option_only_my_events: "Vain niistä, joita seuraan tai joissa olen mukana" - label_user_mail_option_only_owner: "Vain niistä, jotka omistan" - label_user_mail_option_selected: "Kaikista tapahtumista vain valitsemistani projekteista" label_user_menu: "User menu" label_user_new: "Uusi käyttäjä" label_user_plural: "Käyttäjät" @@ -3935,7 +3928,6 @@ fi: label_wiki_show_index_page_link: "Näytä alivalikon vaihtoehto \"Sisällysluettelo\"" label_wiki_show_menu_item: "Näytä valikon kohta projekti navigaatio" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Aloitussivu" label_work: "Work" label_work_package: "Työpaketti" @@ -4217,7 +4209,7 @@ fi: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Yhteyden muodostus onnistui." notice_successful_create: "Luonti onnistui." notice_successful_delete: "Poisto onnistui." diff --git a/config/locales/crowdin/fil.yml b/config/locales/crowdin/fil.yml index cea711ea957..ab0051bcdf2 100644 --- a/config/locales/crowdin/fil.yml +++ b/config/locales/crowdin/fil.yml @@ -107,9 +107,8 @@ fil: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ fil: label_user_named: "User %{name}" label_user_activity: "%{value} aktibidad" label_user_anonymous: "Hindi kilala" - label_user_mail_option_all: "Sa kahit anong kaganapan sa lahat ng aking proyekto" - label_user_mail_option_none: "Walang mga kaganapan" - label_user_mail_option_only_assigned: "Sa mga bagay lamang ako nakatalaga sa" - label_user_mail_option_only_my_events: "Sa mga bagay ako tumingin o kasama ako sa" - label_user_mail_option_only_owner: "Sa mga bagay lamg ako na ako ang may-ari ng" - label_user_mail_option_selected: "Sa kahit anong kaganapan sa mga napiling proyekto lamang" label_user_menu: "User menu" label_user_new: "Bagong gumagamit" label_user_plural: "Mga gumagamit" @@ -3935,7 +3928,6 @@ fil: label_wiki_show_index_page_link: "Ipakita ang aytem ng submenu 'Talaan ng Nilalaman'" label_wiki_show_menu_item: "Ipakita bilanh aytem na pagpipilian sa proyektong nabigasyon" label_wiki_show_new_page_link: "Ipakita ang submenu aytem 'Lumikha ng bagong bata na pahina'" - label_wiki_show_submenu_item: "Ipakita bilang submenu. aytem ng " label_wiki_start: "Simulan ang pahina" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ fil: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Ang proyekto ay hindi nabura." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Matagumpay na ikonekta." notice_successful_create: "Matagumpay pagkalikha." notice_successful_delete: "Matagumpay ang pagtanggal." diff --git a/config/locales/crowdin/fr.seeders.yml b/config/locales/crowdin/fr.seeders.yml index b3e98234eb6..f9014f51e5b 100644 --- a/config/locales/crowdin/fr.seeders.yml +++ b/config/locales/crowdin/fr.seeders.yml @@ -154,7 +154,7 @@ fr: 5. *Activez d'autres modules* : → Accédez à [Paramètres du projet → Modules]({{opSetting:base_url}}/projects/demo-project/settings/modules). 6. *Complétez vos tâches dans le projet* : → Accédez à [Lots de travaux → Tâches]({{opSetting:base_url}}/projects/demo-project/work_packages/details/##wp.id:set_date_and_location_of_conference/overview?query_id=##query.id:demo_project__query__tasks). - Vous trouverez ici nos [Guides de l'utilisateur] (https://www.openproject.org/docs/user-guide/). + Vous trouverez ici nos [Guides de l'utilisateur](https://www.openproject.org/docs/user-guide/). Si vous avez des questions ou si avez besoin d'aide, n'hésitez pas à nous contacter : [support[at]openproject.com](mailto:support@openproject.com). item_5: options: diff --git a/config/locales/crowdin/fr.yml b/config/locales/crowdin/fr.yml index c2de1c2c5c7..8ae638ca522 100644 --- a/config/locales/crowdin/fr.yml +++ b/config/locales/crowdin/fr.yml @@ -20,7 +20,7 @@ #See COPYRIGHT and LICENSE files for more details. #++ fr: - no_results_title_text: Il n'y a présentement rien à afficher. + no_results_title_text: Il n'y a actuellement rien à afficher. activities: index: no_results_title_text: Il n’y a pas eu d'activité pour le projet pendant cette période. @@ -107,9 +107,8 @@ fr: trial: "Essai" jemalloc_allocator: Allocateur de mémoire Jemalloc journal_aggregation: - explanation: - text: "Les actions individuelles d'un utilisateur (par ex. mis à jour un lot de travaux deux fois) sont agrégés en une seule action si leur différence d'âge est inférieure à la période spécifiée. Elles seront affichées en une seule action dans l'application. Cela retardera également les notifications du même temps réduisant donc le nombre d'e-mails envoyés et affectera également le délai %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Importation" jira: @@ -185,8 +184,8 @@ fr: imported: "Mode révision" reverting: "Rétablissement en cours" revert_error: "Erreur lors de la restauration" - revert_cancelling: "Cancelling revert" - revert_cancelled: "Revert cancelled" + revert_cancelling: "Annulation de la réversion" + revert_cancelled: "Annulation de l'annulation" reverted: "Restauré" finalizing: "Finalisation" finalizing_error: "Erreur lors de la finalisation" @@ -446,7 +445,7 @@ fr: Si vous cochez cette case, OpenProject créera automatiquement de nouveaux utilisateurs à partir de leurs entrées LDAP lorsqu'ils s'authentifieront pour la première fois avec OpenProject. Laissez ceci non coché pour permettre uniquement aux comptes existants dans OpenProject de s'authentifier via LDAP! - connection_encryption: "Cryptage de la connexion" + connection_encryption: "Chiffrement de la connexion" encryption_details: "Options LDAPS / STARTTLS" system_account: "Compte système" system_account_legend: | @@ -615,11 +614,13 @@ fr: op_dry_validation: or: "ou" errors: + unexpected_key: "n'est pas autorisé." array?: "doit être un tableau." decimal?: "doit être une décimale." defined: "ne doit pas être défini." eql?: "doit être égal à %{left}." filled?: "doit être rempli." + format?: "est dans un format non valide." greater_or_equal_zero: "doit être supérieur ou égal à 0." gteq?: "doit être supérieur ou égal à %{num}." hash?: "doit être un hachage." @@ -646,7 +647,9 @@ fr: parent: not_descendant: "doit être un descendant de la racine de la hiérarchie." str?: "doit être une chaîne de caractères." + time?: "doit être un moment." type?: "doit être de type : %{type}." + uri?: "n’est pas une URL valide." rules: copy_workflow_from: "Type de copie du flux de travail" enabled: "Activé" @@ -1031,7 +1034,7 @@ fr: no_results_user: "Aucun utilisateur n'a été trouvé" invite_user: "Invité :" no_results_placeholder: "Aucun utilisateur fictif n'a été trouvé" - create_new_placeholder: "Créer un nouveau utilisateur fictif :" + create_new_placeholder: "Créer un nouvel utilisateur fictif :" no_results_group: "Aucun groupe n'a été trouvé" invite_to_project: "Inviter à rejoindre %{project_name}" required: @@ -1051,7 +1054,7 @@ fr: next_button: "Envoyer une invitation" success_message: user: "L'utilisateur peut maintenant se connecter pour accéder à %{project}. En attendant, vous pouvez déjà compter sur cet utilisateur et l'assigner à des lots de travaux, par exemple." - placeholder_user: "L'utilisateur fictif peut maintenant être utilisé dans %{project}. En attendant, vous pouvez déjà planifier des taches avec cet utilisateur et l'assigner à des lots de travaux, par exemple." + placeholder_user: "L'utilisateur fictif peut maintenant être utilisé dans %{project}. En attendant, vous pouvez déjà planifier des tâches avec cet utilisateur et l'assigner à des lots de travaux, par exemple." group: "Le groupe fait maintenant partie du projet %{project}. En attendant, vous pouvez déjà compter sur ce groupe et l'assigner à des lots de travaux, par exemple." page: text: "Texte" @@ -1178,7 +1181,7 @@ fr: matrix_check_uncheck_all_in_col_label_html: "Activer/désactiver les transitions de tous les anciens statuts vers %{new_status}" work_flows: index: - no_results_title_text: Il n'y a actuellement aucun flux de travaux. + no_results_title_text: Il n'y a actuellement aucun flux de travail. work_packages: datepicker_modal: banner: @@ -1871,7 +1874,7 @@ fr: reason: no_notification_reason: "ne peut pas être vide car IAN est choisi comme canal." reason_mail_digest: - no_notification_reason: "ne peut pas être vide car le digest d'email est est choisi comme un canal." + no_notification_reason: "ne peut pas être vide car le digest d'email est choisi comme un canal." non_working_day: attributes: date: @@ -2207,9 +2210,9 @@ fr: created_on: "créé le %{datetime}" created_on_time_entry: "temps enregistré le %{datetime}" updated_by_on: "mis à jour par %{user} le %{datetime}" - updated_by_on_time_entry: "temps enregistré mis à jour par %{user} le %{datetime}" + updated_by_on_time_entry: "temps consigné mis à jour par %{user} le %{datetime}" updated_on: "mis à jour le %{datetime}" - updated_on_time_entry: "temps enregistré mis à jour le %{datetime}" + updated_on_time_entry: "temps consigné mis à jour le %{datetime}" deleted_on: "supprimé le %{datetime}" deleted_by_on: "supprimé par %{user} le %{datetime}" added_on: "ajouté le %{datetime}" @@ -2633,7 +2636,7 @@ fr: other: "%{count} ans" x_seconds: one: "une seconde" - other: "%{count} seconde" + other: "%{count} secondes" x_seconds_abbreviated: one: "1 s" other: "%{count} s" @@ -2650,7 +2653,7 @@ fr: description_active: "Actif ?" description_attachment_toggle: "Afficher/Masquer les pièces jointes" description_autocomplete: > - Ce champ utilise la saisie semi-automatique. Lorsque vous tapez le titre d'un lot de travaux, vous recevrez une liste de choix possibles. Choisissez-en un en utilisant les flèches haut et bas et selectionnez-le avec Tab ou Entrée. Sinon, vous pouvez entrer le numéro de lot de travaux directement. + Ce champ utilise la saisie semi-automatique. Lorsque vous tapez le titre d'un lot de travaux, vous recevrez une liste de choix possibles. Choisissez-en un en utilisant les flèches haut et bas et sélectionnez-le avec Tab ou Entrée. Sinon, vous pouvez entrer le numéro de lot de travaux directement. description_available_columns: "Colonnes disponibles" description_choose_project: "Projets" description_compare_from: "Comparer avec" @@ -2890,8 +2893,8 @@ fr: error_unable_to_connect: "Impossible de se connecter (%{value})" error_unable_delete_wiki: "Impossible de supprimer la page wiki." error_unable_update_wiki: "Impossible de mettre la page wiki à jour." - error_workflow_copy_source: "Veuillez sélectioner un type de source ou rôle" - error_workflow_copy_target: "Veuillez sélectioner une cible type(s) et rôle(s)" + error_workflow_copy_source: "Veuillez sélectionner un type de source ou rôle" + error_workflow_copy_target: "Veuillez sélectionner une cible type(s) et rôle(s)" error_menu_item_not_created: L'élément de menu n'a pas pu être ajouté error_menu_item_not_saved: L'élément de menu n'a pas pu être sauvegardé error_wiki_root_menu_item_conflict: > @@ -3057,7 +3060,7 @@ fr: no_results_text: "Aucun résultat" toggle_switch: label_on: "Activé" - label_off: "Désactiver" + label_off: "Désactivé" general_csv_decimal_separator: "," general_csv_encoding: "UTF-8" general_csv_separator: "." @@ -3140,7 +3143,7 @@ fr: work_package_related_changed_times: par changement vers %{link} connexe work_package_duplicate_closed: Le statut a été mis à jour automatiquement par le doublon de lot de travaux %{link} unaccessable_work_package_changed: par changement vers un lot de travaux connexe - budget_deleted: La budget a été supprimé + budget_deleted: Le budget a été supprimé working_days_changed: changed: "par changement vers des jours ouvrables (%{changes})" days: @@ -3305,11 +3308,11 @@ fr: label_all_words: "Tous les mots" label_all_open_wps: "Tous les ouverts" label_always_visible: "Toujours affiché" - label_announcement: "Annonce ou avis. " + label_announcement: "Annonce" label_angular: "AngularJS" label_app_modules: "Modules %{app_title}" label_api_access_key: "Clé d'accès API" - label_api_access_key_created_on: "Clé d'accès API créé il y a %{value}" + label_api_access_key_created_on: "Clé d'accès API créée il y a %{value}" label_api_access_key_type: "API" label_auto_option: "(auto)" label_ical_access_key_type: "iCalendar" @@ -3358,7 +3361,7 @@ fr: label_branch: "Branche" label_browse: "Parcourir" label_builtin: "Intégré" - label_bulk_edit_selected_work_packages: "Edition en masse des Lots de Travaux selectionnés" + label_bulk_edit_selected_work_packages: "Édition en masse des lots de travaux sélectionnés" label_bundled: "(Inclus)" label_calendar: "Calendrier" label_calendars_and_dates: "Calendriers et dates" @@ -3406,7 +3409,7 @@ fr: label_copy_source: "Source" label_copy_target: "Cible" label_copy_workflow_from: "Copier flux de travail à partir de" - label_copy_project: "Copier projet" + label_copy_project: "Copie du projet" label_core_version: "Version du cœur" label_core_build: "Construction de base" label_created_by: "Créé par %{user}" @@ -3492,7 +3495,7 @@ fr: label_f_hour: "%{value} heure" label_f_hour_plural: "%{value} heures" label_favorite: "Favori" - label_feed_plural: "Fluxs" + label_feed_plural: "Flux" label_feeds_access_key: "Clé d'accès RSS" label_feeds_access_key_created_on: "Clé d'accès RSS créé il y a %{value}" label_feeds_access_key_type: "RSS" @@ -3675,7 +3678,7 @@ fr: label_not_configured: "Non configuré" label_not_found: "non trouvé" label_none: "aucune" - label_none_parentheses: "(none)" + label_none_parentheses: "(aucun)" label_not_contains: "ne contient pas" label_not_equals: "n'est pas" label_life_cycle_step_plural: "Cycle de vie du projet" @@ -3884,16 +3887,10 @@ fr: label_user_named: "Utilisateur %{name}" label_user_activity: "Activité de %{value}" label_user_anonymous: "Anonyme" - label_user_mail_option_all: "Tout évènement dans tous mes projets" - label_user_mail_option_none: "Aucun évènement" - label_user_mail_option_only_assigned: "Les éléments qui me sont assignés" - label_user_mail_option_only_my_events: "Uniquement pour les éléments que je suis ou auxquels je participe" - label_user_mail_option_only_owner: "Les éléments dont je suis le propriétaire" - label_user_mail_option_selected: "Pour chaque événement sur le projet selectionné seulement" label_user_menu: "Menu utilisateur" label_user_new: "Nouvel utilisateur" label_user_plural: "Utilisateurs" - label_user_search: "Recherche d'Utilisateurs" + label_user_search: "Recherche d'utilisateurs" label_user_settings: "Paramètres de l'utilisateur" label_users_settings: "Paramètres des utilisateurs" label_value_x: "Valeur : %{x}" @@ -3929,7 +3926,6 @@ fr: label_wiki_show_index_page_link: "Montrer l'entrée de sous-menu 'Table des Matières'" label_wiki_show_menu_item: "Afficher en tant qu'élément dans le menu de navigation du projet" label_wiki_show_new_page_link: "Montrer le sous-menu 'Créer une nouvelle page enfant'" - label_wiki_show_submenu_item: "Montrer comme sous-menu de " label_wiki_start: "Page d'accueil" label_work: "Travail" label_work_package: "Lot de travaux" @@ -3948,7 +3944,7 @@ fr: label_work_package_tracking: "Suivi des lots de travaux" label_work_package_view_all: "Afficher tous les lots de travaux" label_workflow: "Flux de travail" - label_workflow_copy: "Copier le processus d'entreprise" + label_workflow_copy: "Copier le flux de travail" label_workflow_plural: "Flux de travail" label_workflow_summary: "Résumé" label_working_days_and_hours: "Jours et heures travaillés" @@ -4211,8 +4207,8 @@ fr: notice_parent_item_not_found: "L'élément parent est introuvable." notice_project_not_deleted: "Le projet n'a pas été supprimé." notice_project_not_found: "Projet introuvable." - notice_smtp_address_unsafe: "L'adresse SMTP %{address} n'est pas sûre. Veuillez l'ajouter à OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." - notice_successful_connection: "Connection réussie." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." + notice_successful_connection: "Connexion réussie." notice_successful_create: "Création réussie." notice_successful_delete: "Suppression réussie." notice_successful_cancel: "Annulation réussie." @@ -4234,7 +4230,7 @@ fr: notice_wont_delete_auth_source: La connexion LDAP ne peut pas être supprimée tant que des utilisateurs l'utilisent. notice_project_cannot_update_custom_fields: "Vous ne pouvez pas mettre à jour les champs personnalisés disponibles du projet. Le projet n’est pas valide : %{errors}" notice_attachment_migration_wiki_page: > - Cette page a été générée automatiquement durant la mise à jour de OpenProject. Il contient toutes les pièces jointes précédemment associées à la %{container_type} « %{container_name} ». + Cette page a été générée automatiquement durant la mise à jour de OpenProject. Elle contient toutes les pièces jointes précédemment associées à la %{container_type} « %{container_name} ». #Default format for numbers number: format: @@ -4630,9 +4626,9 @@ fr: setting_use_wysiwyg_description: "Sélectionnez cette option pour activer l’éditeur CKEditor5 WYSIWYG pour tous les utilisateurs par défaut. CKEditor a des fonctionnalités limitées pour GFM Markdown." setting_column_options: "Colonnes de listes du lot de travaux par défaut" setting_commit_fix_keywords: "Réparer les mots clés" - setting_commit_logs_encoding: "Encoding of the Commit messages" - setting_commit_logtime_activity_id: "Activité pour les « Logged Time »" - setting_commit_logtime_enabled: "Activer « time logging »" + setting_commit_logs_encoding: "Encodage des messages de commit" + setting_commit_logtime_activity_id: "Activité pour le temps consignés" + setting_commit_logtime_enabled: "Activer la consignation de temps" setting_commit_ref_keywords: "Referencement des mots clés" setting_consent_time: "Moment de l'accord" setting_consent_info: "Texte d'information sur l'accord" @@ -4682,7 +4678,7 @@ fr: setting_work_package_startdate_is_adddate: "Utiliser la date actuelle comme date de début des nouveaux lots de travaux" setting_work_packages_projects_export_limit: "Limite d'exportation des lots de travaux/projets" setting_journal_aggregation_time_minutes: "Actions utilisateur agrégées dans" - setting_log_requesting_user: "Enregister le login utilisateur, nom et adresse e-mail pour toutes les requêtes" + setting_log_requesting_user: "Enregistrer le login utilisateur, nom et adresse e-mail pour toutes les requêtes" setting_login_required: "Authentification requise" setting_login_required_caption: "Lorsque cette case est cochée, toutes les requêtes envoyées à l'application doivent être authentifiées." setting_lost_password: "Activer la réinitialisation du mot de passe" @@ -4695,11 +4691,11 @@ fr: setting_new_project_user_role_id: "Rôle donné à un utilisateur non administrateur qui crée un projet" setting_new_project_send_confirmation_email: "Envoyer une notification à l'auteur lors de la création d'un nouveau projet" setting_new_project_notification_text: "Texte de la notification" - setting_password_active_rules: "Les classes de caractère activées" - setting_password_count_former_banned: "Nombre des plus récent mots des passe utilisé qui sont interdit de réutilisation." + setting_password_active_rules: "Classes de caractères actives" + setting_password_count_former_banned: "Nombre de mots de passe récents interdits de réutilisation" setting_password_days_valid: "Nombre de jours après lequel le changement de mot de passe est obligatoire" setting_password_min_length: "Longueur minimale" - setting_password_min_adhered_rules: "Nombre minimale des classe de caractère requise" + setting_password_min_adhered_rules: "Nombre minimal de classes de caractères requises" setting_per_page_options: "Options des objets par page" setting_percent_complete_on_status_closed: "% d'achèvement lorsque le statut est fermé" setting_percent_complete_on_status_closed_no_change: "Aucun changement" @@ -4722,7 +4718,7 @@ fr: setting_repository_checkout_base_url: "URL de base de « checkout »" setting_repository_checkout_text: "Texte d'instruction de « checkout »" setting_repository_log_display_limit: "Nombre maximal des révisions affichées sur « file log »" - setting_repository_truncate_at: "Le nombre maiximum de fichiers exposes au navigateur" + setting_repository_truncate_at: "Le nombre maximum de fichiers affichés dans le navigateur de dépôt" setting_self_registration: "Auto-enregistrement" setting_self_registration_caption: > Choisissez le mécanisme d'auto-inscription pour les utilisateurs. Faites attention au paramètre que vous choisissez, car certaines options permettent aux utilisateurs d'activer leurs propres comptes pour cette instance. @@ -4882,7 +4878,7 @@ fr: project_mandate: "Mandat du projet" submission: description_template: > - **Ce dossier de travail a été créé automatiquement à l'issue du flux de travail %{wizard_name} .** Un artefact PDF contenant toutes les informations soumises a été généré et joint à ce dossier de travail à des fins de référence et d'audit. Si vous avez besoin de mettre à jour ou de réexécuter les étapes d'initiation, vous pouvez rouvrir l'assistant à tout moment en utilisant le lien ci-dessous : + **Ce dossier de travail a été créé automatiquement à l'issue du flux de travail %{wizard_name}.** Un artefact PDF contenant toutes les informations soumises a été généré et joint à ce dossier de travail à des fins de référence et d'audit. Si vous avez besoin de mettre à jour ou de réexécuter les étapes d'initiation, vous pouvez rouvrir l'assistant à tout moment en utilisant le lien ci-dessous : description: "Lorsqu'un utilisateur envoie une demande de lancement de projet, un nouveau lot de travail est créé avec l'artefact de la demande en pièce jointe au format PDF. Les paramètres ci-dessous définissent le type, le statut et le destinataire de ce nouveau lot de travaux." work_package_type: "Type de lot de travaux" work_package_type_caption: "Le type de lot de travaux qui doit être utilisé pour stocker l'artefact terminé." @@ -5001,7 +4997,7 @@ fr: text_default_administrator_account_changed: "Le compte administrateur par défaut a été changé" text_default_encoding: "Défaut: UTF-8" text_destroy: "Supprimer" - text_destroy_with_associated: "There are additional objects associated with the work package(s) that are to be deleted. Those objects are of the following types:" + text_destroy_with_associated: "Il y a des objets supplémentaires associés à ce(s) lot(s) de travaux qui doivent être supprimés. Ces objets sont des types suivants :" text_destroy_what_to_do: "Que voulez-vous faire?" text_diff_truncated: "... Cette « diff » a été tronquée car elle dépasse la taille maximale d'affichage." text_email_delivery_not_configured: "L'envoi d'e-mails n'est pas configuré et les notifications sont désactivées.\nConfigurer votre serveur SMTP pour les activer." @@ -5042,12 +5038,12 @@ fr: text_load_default_configuration: "Charger la configuration par défaut" text_no_roles_defined: Il n'y a pas de rôles définis. text_no_access_tokens_configurable: "Il n'y a aucun jeton d'accès qui puisse être configuré." - text_no_configuration_data: "Les rôles, les types, l'état des lots de travaux et les flux de travaux n'ont pas encore été configurés.\nIl est fortement recommandé de charger la configuration par défaut. Vous serez capable de la modifier une fois chargée." + text_no_configuration_data: "Les rôles, les types, l'état des lots de travaux et les flux de travail n'ont pas encore été configurés.\nIl est fortement recommandé de charger la configuration par défaut. Vous serez capable de la modifier une fois chargée." text_no_notes: "Il n'existe aucun commentaire pour ce lot de travaux." text_notice_too_many_values_are_inperformant: "Remarque : L'affichage de plus de 100 articles par page peut augmenter le temps de chargement de la page." text_notice_security_badge_displayed_html: > Remarque : si cette option est activée, un badge indiquant l'état de votre installation s'affichera dans le panneau %{information_panel_label} administration et sur la page d'accueil. Il n'est affiché que pour les administrateurs.
    Le badge vérifiera votre version actuelle d'OpenProject par rapport à la base de données officielle d'OpenProject pour vous avertir de toute mise à jour ou vulnérabilité connue. Pour plus d'informations sur ce que la vérification fournit, quelles données sont nécessaires pour fournir les mises à jour disponibles, et comment désactiver cette vérification, veuillez visiter la documentation de configuration. - text_own_membership_delete_confirmation: "Vous êtes sur le point de retirer tout ou partie de vos permissions et ne pourrez peut-être plus modifier le projet par la suite.\nÊtes vous sûr de vouloir continuer?" + text_own_membership_delete_confirmation: "Vous êtes sur le point de retirer tout ou partie de vos permissions et ne pourrez peut-être plus modifier le projet par la suite.\nVoulez-vous vraiment continuer?" text_permanent_delete_confirmation_checkbox_label: "Je comprends que cette suppression ne peut pas être annulée" text_permanent_remove_confirmation_checkbox_label: "Je comprends que cette suppression ne peut pas être annulée" text_plugin_assets_writable: "Répertoire des « plugin assets » est accessible en écriture" @@ -5069,7 +5065,7 @@ fr: text_wrote: "a écrit" text_warn_on_leaving_unsaved: "Le lot de travaux contient du texte non sauvegardé qui sera perdu si vous quittez cette page." text_what_did_you_change_click_to_add_comment: "Qu’avez-vous changé ? Cliquez ici pour ajouter un commentaire" - text_wiki_destroy_confirmation: "Êtes vous sur de vouloir supprimer ce wiki et tout son contenu?" + text_wiki_destroy_confirmation: "Voulez-vous vraiment supprimer ce wiki et tout son contenu?" text_wiki_page_destroy_children: "Supprimer les pages enfants et toute leur descendance" text_wiki_page_destroy_question: "Cette page possède %{descendants} page(s) enfant et descendant(s). Que voulez vous faire?" text_wiki_page_nullify_children: "Garder les pages enfants en tant que pages d'origine" @@ -5126,7 +5122,7 @@ fr: all: "tous" active: "actif" activate: "Activer" - activate_and_reset_failed_logins: "Activer et réinitialiser les connexions echouées" + activate_and_reset_failed_logins: "Activer et réinitialiser les connexions échouées" authentication_provider: "Fournisseur d'authentification" identity_url_text: "L'identifiant unique interne fourni par le fournisseur d'authentification." authentication_settings_disabled_due_to_external_authentication: > @@ -5149,7 +5145,7 @@ fr: no_login: "Cet utilisateur s'authentifie avec un mot de passe. Tant que cela est désactivé, il ne peut s'authentifier." password_change_unsupported: Le changement de mot de passe n'est pas supporté. registered: "enregistré" - reset_failed_logins: "Réinitialiser les connexions echouées" + reset_failed_logins: "Réinitialiser les connexions échouées" status_user_and_brute_force: "%{user} et %{brute_force}" status_change: "Changement de statut" text_change_disabled_for_provider_login: "Le nom et l'adresse électronique sont définis par votre fournisseur d'accès et ne peuvent donc pas être modifiés." @@ -5471,7 +5467,7 @@ fr: none_given: "Aucune application OAuth n'a été autorisée à accéder à votre compte utilisateur." x_active_tokens: one: "un jeton actif" - other: "un jeton actif %{count}" + other: "%{count} jetons actifs" flows: authorization_code: "Flux de code d'autorisation" client_credentials: "Flux des informations d'identification client" @@ -5527,8 +5523,8 @@ fr: invalid_scope: "Vous n'êtes pas autorisé à accéder à la ressource demandée (invalid_scope)." http: request: - failed_authorization: "La requête côté serveur a échoué en s'autorisant elle-même." - missing_authorization: "La requête latérale du serveur a échoué en raison de l'absence d'informations d'autorisation." + failed_authorization: "La requête côté serveur a échoué lors de l'authentification." + missing_authorization: "La requête côté serveur a échoué en raison de l'absence d'informations d'autorisation." response: unexpected: "Réponse inattendue reçue." you: vous diff --git a/config/locales/crowdin/he.yml b/config/locales/crowdin/he.yml index 82f3fd67b62..17be71154c6 100644 --- a/config/locales/crowdin/he.yml +++ b/config/locales/crowdin/he.yml @@ -107,9 +107,8 @@ he: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -4002,12 +4001,6 @@ he: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "אנונימי" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "משתמש חדש" label_user_plural: "משתמשים" @@ -4047,7 +4040,6 @@ he: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "דף פתיחה" label_work: "Work" label_work_package: "חבילת עבודה" @@ -4331,7 +4323,7 @@ he: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/hi.yml b/config/locales/crowdin/hi.yml index ad8fa0e62ed..6b5d70bd0e4 100644 --- a/config/locales/crowdin/hi.yml +++ b/config/locales/crowdin/hi.yml @@ -107,9 +107,8 @@ hi: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3888,12 +3887,6 @@ hi: label_user_named: "उपयोगकर्ता %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "अज्ञात" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3933,7 +3926,6 @@ hi: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "प्रारंभ पृष्ठ" label_work: "Work" label_work_package: "कार्य पैकेज" @@ -4215,7 +4207,7 @@ hi: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/hr.yml b/config/locales/crowdin/hr.yml index 4cd1e2e5d6b..2e0e5a37496 100644 --- a/config/locales/crowdin/hr.yml +++ b/config/locales/crowdin/hr.yml @@ -107,9 +107,8 @@ hr: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3946,12 +3945,6 @@ hr: label_user_named: "User %{name}" label_user_activity: "%{value}-a aktivnost" label_user_anonymous: "Anonimno" - label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" - label_user_mail_option_none: "Nema novih događanja" - label_user_mail_option_only_assigned: "Samo stvari koje su mi dodijeljene" - label_user_mail_option_only_my_events: "Samo stvari koje nadgledam ili u koje sam uključen" - label_user_mail_option_only_owner: "Samo za stvari kojih sam vlasnik" - label_user_mail_option_selected: "Za bilo koji događaj na samo odabranim projektima" label_user_menu: "User menu" label_user_new: "Novi korisnik" label_user_plural: "Korisnici" @@ -3991,7 +3984,6 @@ hr: label_wiki_show_index_page_link: "Prikaži stavku podizbornika 'Kazalo sadržaja'" label_wiki_show_menu_item: "Prikaži kao stavku izbornika u izborniku projekta" label_wiki_show_new_page_link: "Prikaži stavku podizbornika 'Kreiraj novu podređenu stranicu'" - label_wiki_show_submenu_item: "Prikaži kao stavku podizbornika iz " label_wiki_start: "Početna stranica" label_work: "Work" label_work_package: "Radni paket" @@ -4274,7 +4266,7 @@ hr: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projekt nije izbrisan." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Uspješna spojen." notice_successful_create: "Uspješno kreirano." notice_successful_delete: "Brisanje uspješno." diff --git a/config/locales/crowdin/hu.yml b/config/locales/crowdin/hu.yml index adf2b2fa51b..f5af9fffa46 100644 --- a/config/locales/crowdin/hu.yml +++ b/config/locales/crowdin/hu.yml @@ -107,9 +107,8 @@ hu: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "A felhasználó egyes műveletei (pl. egy munkacsomag kétszeri frissítése) egyetlen műveletté egyesülnek, ha korkülönbségük kisebb, mint a megadott időtartam. Ezek egyetlen műveletként jelennek meg az alkalmazásban. Ez ugyanannyi idővel késlelteti az értesítéseket, csökkenti az elküldött emailek számát, valamint befolyásolja a %{webhook_link} késleltetését is.\n" - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3889,12 +3888,6 @@ hu: label_user_named: "Felhasználó: %{name}" label_user_activity: "%{value} tevékenység" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "Minden saját projektet érintő esetben" - label_user_mail_option_none: "Nem kérek értesítéseket" - label_user_mail_option_only_assigned: "Csak a hozzám rendelt feladatokról" - label_user_mail_option_only_my_events: "Csak a megfigyelt feladatok vagy amelyben részt veszek" - label_user_mail_option_only_owner: "Csak azok a feladatok, amelyeknek én vagyok a tulajdonosa" - label_user_mail_option_selected: "Minden eseményről a kiválasztott projektekben" label_user_menu: "User menu" label_user_new: "Új felhasználó" label_user_plural: "Felhasználók" @@ -3934,7 +3927,6 @@ hu: label_wiki_show_index_page_link: "Megjeleníti az almenüpont feladatainak \"Tartalomjegyzékét\"" label_wiki_show_menu_item: "Megjeleníti mint menüpont a projekt navigációban" label_wiki_show_new_page_link: "Almenüpont megjelenítése \" új gyermekoldal létrehozása\"" - label_wiki_show_submenu_item: "Megjelenítés mint: almenüpont " label_wiki_start: "Kezdő oldal" label_work: "Munka" label_work_package: "Feladatcsoport" @@ -4215,7 +4207,7 @@ hu: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "A projekt nem lett törölve." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Sikeresen létrejött a kapcsolat." notice_successful_create: "Sikeres létrehozás." notice_successful_delete: "Sikeres törlés." diff --git a/config/locales/crowdin/id.yml b/config/locales/crowdin/id.yml index 2957fc980f8..44c0c8fac20 100644 --- a/config/locales/crowdin/id.yml +++ b/config/locales/crowdin/id.yml @@ -107,9 +107,8 @@ id: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Setiap tindakan pengguna (mis. memperbarui paket kerja dua kali) digabungkan menjadi satu tindakan jika perbedaan usianya kurang dari rentang waktu yang ditentukan. Mereka akan ditampilkan sebagai tindakan tunggal dalam aplikasi. Ini juga akan menunda pemberitahuan dengan jumlah waktu yang sama sehingga mengurangi jumlah email yang dikirim dan juga akan memengaruhi penundaan %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3830,12 +3829,6 @@ id: label_user_named: "User %{name}" label_user_activity: "%{value} aktivitas" label_user_anonymous: "Anonimus" - label_user_mail_option_all: "Untuk semua Event pada semua proyek saya" - label_user_mail_option_none: "Tidak ada event" - label_user_mail_option_only_assigned: "Hanya untuk hal-hal yang saya ditugaskan untuk" - label_user_mail_option_only_my_events: "Hanya untuk hal-hal yang saya pantau atau saya terlibat didalamnya" - label_user_mail_option_only_owner: "Hanya untuk hal-hal yang saya sebagai Ownernya" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "User baru" label_user_plural: "User" @@ -3875,7 +3868,6 @@ id: label_wiki_show_index_page_link: "Tampilkan item submenu 'Daftar isi'" label_wiki_show_menu_item: "Tampilkan sebagai item menu navigasi Project" label_wiki_show_new_page_link: "Tampilkan submenu item 'Buat sub-halaman baru'" - label_wiki_show_submenu_item: "Tampilkan sebagai submenu item " label_wiki_start: "Homepage" label_work: "Work" label_work_package: "Paket-Penugasan" @@ -4156,7 +4148,7 @@ id: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Project tidak dihapus." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Sambungan berhasil." notice_successful_create: "Berhasil dibuat." notice_successful_delete: "Berhasil dihapus." diff --git a/config/locales/crowdin/it.yml b/config/locales/crowdin/it.yml index 831602def76..6fc282640d4 100644 --- a/config/locales/crowdin/it.yml +++ b/config/locales/crowdin/it.yml @@ -107,9 +107,8 @@ it: trial: "Prova" jemalloc_allocator: Allocatore di memoria Jemalloc journal_aggregation: - explanation: - text: "Le singole azioni di un utente (es. l'aggiornamento di una macro-attività due volte) vengono aggregate in un'unica azione se il tempo intercorso tra esse è inferiore al periodo minimo di tempo impostato. Verranno visualizzate quindi come un'unica azione all'interno dell'applicazione. Questo ritarderà anche le notifiche della stessa quantità di tempo, riducendo così il numero di email inviate, e influirà anche sul ritardo di %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Importa" jira: @@ -3887,12 +3886,6 @@ it: label_user_named: "Utente %{name}" label_user_activity: "attività di %{value}" label_user_anonymous: "Anonimo" - label_user_mail_option_all: "Per qualsiasi evento su tutti i miei progetti" - label_user_mail_option_none: "Per nessun evento" - label_user_mail_option_only_assigned: "Solo per cose alle quali sono stato assegnato" - label_user_mail_option_only_my_events: "Solo per le cose che osservo o nelle quali sono coinvolto" - label_user_mail_option_only_owner: "Solo per le cose di cui sono proprietario" - label_user_mail_option_selected: "Per qualsiasi evento solo nei progetti selezionati" label_user_menu: "Menu utente" label_user_new: "Nuovo utente" label_user_plural: "Utenti" @@ -3932,7 +3925,6 @@ it: label_wiki_show_index_page_link: "Mostra voce del sotto-menù 'Sommario'" label_wiki_show_menu_item: "Mostra come voce del menù nella navigazione del progetto" label_wiki_show_new_page_link: "Mostra voce del sotto-menù 'Crea nuova pagina figlio'" - label_wiki_show_submenu_item: "Mostra come voce di sottomenù di " label_wiki_start: "Pagina iniziale" label_work: "Lavoro" label_work_package: "Macro-attività" @@ -4214,7 +4206,7 @@ it: notice_parent_item_not_found: "L'elemento genitore non è stato trovato." notice_project_not_deleted: "Il progetto non è stato eliminato." notice_project_not_found: "Progetto non trovato." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Connesso con successo." notice_successful_create: "Creato con successo." notice_successful_delete: "Cancellato con successo." diff --git a/config/locales/crowdin/ja.yml b/config/locales/crowdin/ja.yml index 41d0383ae59..a266d2d5d6b 100644 --- a/config/locales/crowdin/ja.yml +++ b/config/locales/crowdin/ja.yml @@ -107,9 +107,8 @@ ja: trial: "試用版" jemalloc_allocator: Jemalloc メモリアロケータ journal_aggregation: - explanation: - text: "ユーザーの個々のアクション (例:ワークパッケージを2回更新する)は、指定された時間範囲よりも時間差が小さい場合、単一のアクションに集約されます。 これらはアプリケーション内で単一のアクションとして表示されます。 これにより、送信されるメールの数が減少し、 %{webhook_link} の遅延にも影響します。" - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3833,12 +3832,6 @@ ja: label_user_named: "ユーザー名 %{name}" label_user_activity: "%{value}の活動" label_user_anonymous: "匿名ユーザ" - label_user_mail_option_all: "参加しているプロジェクトの全イベント" - label_user_mail_option_none: "通知しない" - label_user_mail_option_only_assigned: "自分が担当している事柄のみ" - label_user_mail_option_only_my_events: "ウォッチまたは関係している事柄のみ" - label_user_mail_option_only_owner: "自分が作成した事柄のみ" - label_user_mail_option_selected: "選択したプロジェクトのみのイベントに対して" label_user_menu: "ユーザーメニュー" label_user_new: "新規ユーザ" label_user_plural: "ユーザ" @@ -3878,7 +3871,6 @@ ja: label_wiki_show_index_page_link: "下位のメニューで「目次」を表示" label_wiki_show_menu_item: "プロジェクトのメニューで項目として表示" label_wiki_show_new_page_link: "下位のメニューで「子ページを新規作成」の項目を表示" - label_wiki_show_submenu_item: "上位のメニュー項目" label_wiki_start: "開始ページ" label_work: "予定時間" label_work_package: "ワーク パッケージ" @@ -4159,7 +4151,7 @@ ja: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "プロジェクトを削除していません。" notice_project_not_found: "プロジェクトが見つかりません。" - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "正常に接続しました。" notice_successful_create: "正常に作成しました。" notice_successful_delete: "正常に削除しました。" diff --git a/config/locales/crowdin/js-fr.yml b/config/locales/crowdin/js-fr.yml index 517a25d0bda..0cd20ffc988 100644 --- a/config/locales/crowdin/js-fr.yml +++ b/config/locales/crowdin/js-fr.yml @@ -558,7 +558,7 @@ fr: date_alerts: milestone_date: "Date jalon" overdue: "En retard" - overdue_since: "pour %{difference_in_days}." + overdue_since: "de %{difference_in_days}." property_today: "a lieu aujourd'hui." property_is: "a lieu dans %{difference_in_days}." property_was: "avait lieu il y a %{difference_in_days}." @@ -993,7 +993,7 @@ fr: embedded_tab_disabled: "Cet onglet de configuration n'est pas disponible pour la vue intégrée que vous êtes en train de modifier." default: "défaut" display_settings: "Paramètres d'affichage" - default_mode: "Liste ombrée" + default_mode: "Liste" hierarchy_mode: "Hiérarchie" hierarchy_hint: "Tous les résultats du tableau filtrés seront augmentés de leurs ancêtres . Les hiérarchies peuvent être dépliées et repliées." display_sums_hint: "Afficher les sommes de tous les attributs sommables dans une ligne sous les résultats du tableau." diff --git a/config/locales/crowdin/ka.yml b/config/locales/crowdin/ka.yml index 6689745c517..67d57f04cc4 100644 --- a/config/locales/crowdin/ka.yml +++ b/config/locales/crowdin/ka.yml @@ -107,9 +107,8 @@ ka: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "ვებჰუკი" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ ka: label_user_named: "მომხმარებელი %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "ანონიმური" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "მოვლენების გარეშე" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "ახალი მომხმარებელი" label_user_plural: "მომხმარებლები" @@ -3935,7 +3928,6 @@ ka: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "საწყისი გვერდი" label_work: "სამუშაო" label_work_package: "სამუშაო პაკეტი" @@ -4217,7 +4209,7 @@ ka: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/kk.yml b/config/locales/crowdin/kk.yml index 2c7415da883..7733ec34ca1 100644 --- a/config/locales/crowdin/kk.yml +++ b/config/locales/crowdin/kk.yml @@ -107,9 +107,8 @@ kk: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ kk: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ kk: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ kk: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/ko.yml b/config/locales/crowdin/ko.yml index 4697b359e9e..fa6354fd687 100644 --- a/config/locales/crowdin/ko.yml +++ b/config/locales/crowdin/ko.yml @@ -107,9 +107,8 @@ ko: trial: "평가판" jemalloc_allocator: Jemalloc 메모리 할당기 journal_aggregation: - explanation: - text: "사용자의 개별 작업(예: 작업 패키지를 두 번 업데이트)은 연령 차이가 지정된 기간 미만인 경우 단일 작업으로 집계됩니다. 애플리케이션 내에서 단일 작업으로 표시됩니다. 또한 이는 전송되는 이메일 수를 줄이는 동일한 시간만큼 알림을 지연시키고 %{webhook_link} 지연에도 영향을 미칩니다." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "가져오기" jira: @@ -3834,12 +3833,6 @@ ko: label_user_named: "사용자 %{name}" label_user_activity: "%{value}의 작업" label_user_anonymous: "익명" - label_user_mail_option_all: "모든 내 프로젝트의 이벤트에 대해" - label_user_mail_option_none: "이벤트 없음" - label_user_mail_option_only_assigned: "나에게 할당된 사항만" - label_user_mail_option_only_my_events: "내가 주시하거나 관련된 사항만" - label_user_mail_option_only_owner: "내가 소유자인 사항만" - label_user_mail_option_selected: "선택된 프로젝트에서 발생하는 이벤트만" label_user_menu: "사용자 메뉴" label_user_new: "새 사용자" label_user_plural: "사용자" @@ -3879,7 +3872,6 @@ ko: label_wiki_show_index_page_link: "하위 메뉴 항목 '목차' 표시" label_wiki_show_menu_item: "프로젝트 탐색에서 메뉴 항목으로 표시" label_wiki_show_new_page_link: "하위 메뉴 항목 '새 자식 페이지 만들기' 표시" - label_wiki_show_submenu_item: "다음의 하위 메뉴 항목으로 표시: " label_wiki_start: "시작 페이지" label_work: "작업" label_work_package: "작업 패키지" @@ -4160,7 +4152,7 @@ ko: notice_parent_item_not_found: "부모 항목을 찾을 수 없습니다." notice_project_not_deleted: "프로젝트가 삭제되지 않았습니다." notice_project_not_found: "프로젝트를 찾을 수 없습니다." - notice_smtp_address_unsafe: "SMTP 주소 %{address}은(는) 안전하지 않습니다. OPENPROJECT_SSRF_PROTECTION_ALLOWLIST에 추가하세요." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "연결에 성공했습니다." notice_successful_create: "생성에 성공했습니다." notice_successful_delete: "삭제에 성공했습니다." diff --git a/config/locales/crowdin/lt.yml b/config/locales/crowdin/lt.yml index adc352b8586..efb0d065aa9 100644 --- a/config/locales/crowdin/lt.yml +++ b/config/locales/crowdin/lt.yml @@ -107,9 +107,8 @@ lt: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Visi atskiri naudotojo veiksmai (t.y. darbų paketo atnaujinimas du kartus) yra sugrupuojami į vieną veiksmą, jei laiko tarpas tarp jų yra mažesnis už šį nustatymą. Programoje jie bus rodomi kaip vienas veiksmas. Tiek pat bus pavėlinti ir pranešimai. Dėl to sumažės siunčiamų el.laiškų skaičius ir taipogi įtakos %{webhook_link} delsimą." - link: "tinklo jungtis" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3999,12 +3998,6 @@ lt: label_user_named: "Naudotojas %{name}" label_user_activity: "%{value} veikla" label_user_anonymous: "Anonimas" - label_user_mail_option_all: "Bet kokiam įvykiui visuose mano projektuose" - label_user_mail_option_none: "Jokių įvykių" - label_user_mail_option_only_assigned: "Tiktai dalykams, kuriems esu priskirtas" - label_user_mail_option_only_my_events: "Tiktai dalykams, kuriuos stebiu arba esu įtrauktas" - label_user_mail_option_only_owner: "Tiktai dalykams, kurių šeimininkas esu aš" - label_user_mail_option_selected: "Bet kokiam įvykiui tiktai pasirinktuose projektuose" label_user_menu: "User menu" label_user_new: "Naujas vartotojas" label_user_plural: "Naudotojai" @@ -4044,7 +4037,6 @@ lt: label_wiki_show_index_page_link: "Rodyti submeniu punktą „Turinys“" label_wiki_show_menu_item: "Rodyti kaip meniu punktą projekto navigacijoje" label_wiki_show_new_page_link: "Rodyti submeniu punktą „Sukurti naują vaiko puslapį“" - label_wiki_show_submenu_item: "Rodyti kaip submeniu punktą " label_wiki_start: "Pradžios puslapis" label_work: "Darbas" label_work_package: "Darbų paketas" @@ -4328,7 +4320,7 @@ lt: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projektas nebuvo panaikintas." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Sėkmingas susijungimas." notice_successful_create: "Sėkmingas sukūrimas." notice_successful_delete: "Sėkmingas panaikinimas." diff --git a/config/locales/crowdin/lv.yml b/config/locales/crowdin/lv.yml index 26388cf32d9..1db4f4c270b 100644 --- a/config/locales/crowdin/lv.yml +++ b/config/locales/crowdin/lv.yml @@ -107,9 +107,8 @@ lv: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3946,12 +3945,6 @@ lv: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "Par jebkuru notikumu, visos manos projektos" - label_user_mail_option_none: "Nevēlos saņemt e-pasta paziņojumus" - label_user_mail_option_only_assigned: "Tikai par lietām kas piešķirtas man" - label_user_mail_option_only_my_events: "Tikai par lietām, kam sekoju, vai es esmu iesaistīts" - label_user_mail_option_only_owner: "Tikai par lietām, kuras es esmu izveidojis" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Lietotāji" @@ -3991,7 +3984,6 @@ lv: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Sākuma lapa" label_work: "Work" label_work_package: "Darba pieteikums" @@ -4274,7 +4266,7 @@ lv: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/mn.yml b/config/locales/crowdin/mn.yml index 459ddc86681..ae2ba14fce3 100644 --- a/config/locales/crowdin/mn.yml +++ b/config/locales/crowdin/mn.yml @@ -107,9 +107,8 @@ mn: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ mn: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ mn: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ mn: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/ms.yml b/config/locales/crowdin/ms.yml index fecb0931294..b5544415285 100644 --- a/config/locales/crowdin/ms.yml +++ b/config/locales/crowdin/ms.yml @@ -107,9 +107,8 @@ ms: trial: "Trial" jemalloc_allocator: Pengagih ingatan Jemalloc journal_aggregation: - explanation: - text: "Tindakan individu pengguna (cth. mengemas kini pakej kerja dua kali) dikumpulkan ke dalam satu tindakan tunggal jika perbezaan umur mereka kurang daripada tempoh masa yang ditetapkan. Mereka akan dipaparkan sebagai tindakan tunggal dalam aplikasi. Ini juga akan menangguhkan pemberitahuan dengan jumlah masa yang sama, mengurangkan bilangan e-mel yang dihantar serta akan memberi kesan kepada penagguhan %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3832,12 +3831,6 @@ ms: label_user_named: "Pengguna %{name}" label_user_activity: "aktiviti %{value}" label_user_anonymous: "Anonim" - label_user_mail_option_all: "Untuk sebarang peristiwa pada semua projek saya" - label_user_mail_option_none: "Tiada peristiwa" - label_user_mail_option_only_assigned: "Hanya untuk perkara yang ditugaskan kepada saya" - label_user_mail_option_only_my_events: "Hanya untuk perkara yang saya perhatikan atau yang saya terlibat dalam" - label_user_mail_option_only_owner: "Hanya untuk perkara yang merupakan saya pemiliknya" - label_user_mail_option_selected: "Untuk sebarang peristiwa pada projek yang terpilih sahaja" label_user_menu: "User menu" label_user_new: "Pengguna baharu" label_user_plural: "Pengguna-pengguna" @@ -3877,7 +3870,6 @@ ms: label_wiki_show_index_page_link: "Paparkan item submenu 'Jadual Kandungan'" label_wiki_show_menu_item: "Paparkan sebagai item menu dalam navigasi projek" label_wiki_show_new_page_link: "Paparkan item submenu 'Cipta laman anak baharu'" - label_wiki_show_submenu_item: "Paparkan sebagai item submenu " label_wiki_start: "Halaman mula" label_work: "Kerja" label_work_package: "Pakej kerja" @@ -4158,7 +4150,7 @@ ms: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projek tersebut tidak dipadam." notice_project_not_found: "Projek tidak ditemui." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Sambungan berjaya." notice_successful_create: "Penciptaan yang berjaya." notice_successful_delete: "Pemadaman yang berjaya." diff --git a/config/locales/crowdin/ne.yml b/config/locales/crowdin/ne.yml index 687b15e21e0..28f107c8494 100644 --- a/config/locales/crowdin/ne.yml +++ b/config/locales/crowdin/ne.yml @@ -107,9 +107,8 @@ ne: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ ne: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ ne: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ ne: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/nl.yml b/config/locales/crowdin/nl.yml index e81aa4da576..b17ffaa38c7 100644 --- a/config/locales/crowdin/nl.yml +++ b/config/locales/crowdin/nl.yml @@ -107,9 +107,8 @@ nl: trial: "Trial" jemalloc_allocator: Jemalloc geheugentoewijzer journal_aggregation: - explanation: - text: "Individuele acties van een gebruiker (bijv. het bijwerken van een werkpakket twee keer) wordt samengevoegd tot een enkele actie als hun leeftijdverschil minder is dan de aangegeven timespat. Ze worden weergegeven als een enkele actie binnen de applicatie. Dit zal ook meldingen vertragen met dezelfde tijd die het aantal verstuurde e-mails vermindert en zal ook %{webhook_link} vertraging beïnvloeden." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3886,12 +3885,6 @@ nl: label_user_named: "Gebruiker %{name}" label_user_activity: "%{value} activiteit" label_user_anonymous: "Anoniem" - label_user_mail_option_all: "Voor een evenement op al mijn projecten" - label_user_mail_option_none: "Geen evenementen" - label_user_mail_option_only_assigned: "Alleen voor dingen die aan mij toegewezen zijn" - label_user_mail_option_only_my_events: "Alleen voor dingen die ik kijk of waar ik bij betrokken ben" - label_user_mail_option_only_owner: "Alleen voor dingen waar ik de eigenaar van ben" - label_user_mail_option_selected: "Voor een gebeurtenis op de geselecteerde projecten alleen" label_user_menu: "User menu" label_user_new: "Nieuwe gebruiker" label_user_plural: "Gebruikers" @@ -3931,7 +3924,6 @@ nl: label_wiki_show_index_page_link: "Toon submenu item 'Inhoudsopgave'" label_wiki_show_menu_item: "Weergeven als menu-item in project navigatie" label_wiki_show_new_page_link: "Vervolgmenu-item 'Maken nieuwe onderliggende pagina' weergeven" - label_wiki_show_submenu_item: "Toon als submenu-item van " label_wiki_start: "Startpagina" label_work: "Werk" label_work_package: "Werkpakket" @@ -4212,7 +4204,7 @@ nl: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Het project is niet verwijderd." notice_project_not_found: "Project niet gevonden." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Geslaagde verbinding." notice_successful_create: "Aanmaak geslaagd." notice_successful_delete: "Verwijdering geslaagd." diff --git a/config/locales/crowdin/no.yml b/config/locales/crowdin/no.yml index 3dfdb5c7143..b05690137f1 100644 --- a/config/locales/crowdin/no.yml +++ b/config/locales/crowdin/no.yml @@ -107,9 +107,8 @@ trial: "Trial" jemalloc_allocator: Jemalloc minne allokator journal_aggregation: - explanation: - text: "Individuelle handlinger av en bruker (f.eks. oppdatering av en arbeidspakke to ganger) aggregeres til en enkelt handling hvis aldersforskjellen er mindre enn det spesifiserte tidsrommet. De vil bli vist som en enkelt handling i programmet. Dette vil også forsinke varslinger med samme tidsperiode som reduserer antall e-poster som sendes, og vil også påvirke %{webhook_link} forsinkelse." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3889,12 +3888,6 @@ label_user_named: "Bruker %{name}" label_user_activity: "%{value}s aktivitet" label_user_anonymous: "Anonym" - label_user_mail_option_all: "For enhver hendelse i alle mine prosjekter" - label_user_mail_option_none: "Ingen hendelser" - label_user_mail_option_only_assigned: "Kun for ting jeg er involvert i" - label_user_mail_option_only_my_events: "Kun for ting jeg overvåker eller er involvert i" - label_user_mail_option_only_owner: "Kun for ting jeg står som eier av" - label_user_mail_option_selected: "For alle hendelser kun på valgte prosjekter" label_user_menu: "User menu" label_user_new: "Ny bruker" label_user_plural: "Brukere" @@ -3934,7 +3927,6 @@ label_wiki_show_index_page_link: "Vis undermenyelement 'Innholdsfortegnelse'" label_wiki_show_menu_item: "Vis som menyelement i prosjektmeny" label_wiki_show_new_page_link: "Vis undermenyelement 'Opprett ny underside'" - label_wiki_show_submenu_item: "Vis som undermenyelement for " label_wiki_start: "Startside" label_work: "Arbeid" label_work_package: "Arbeidspakke" @@ -4216,7 +4208,7 @@ notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Prosjektet ble ikke slettet." notice_project_not_found: "Prosjektet ble ikke funnet." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Vellykket tilkobling." notice_successful_create: "Opprettelsen var vellykket." notice_successful_delete: "Slettingen var vellykket." diff --git a/config/locales/crowdin/pl.yml b/config/locales/crowdin/pl.yml index 033e0aa738c..04aaf6e47be 100644 --- a/config/locales/crowdin/pl.yml +++ b/config/locales/crowdin/pl.yml @@ -107,9 +107,8 @@ pl: trial: "Wersja próbna" jemalloc_allocator: Alokator pamięci Jemalloc journal_aggregation: - explanation: - text: "Indywidualne działania użytkownika (np. dwukrotna aktualizacja pakietu roboczego) są agregowane w jedno działanie, jeśli różnica czasowa między nimi jest mniejsza niż określony przedział czasowy. Będą one wyświetlane jako jedno działanie w aplikacji. Spowoduje to również opóźnienie powiadomień o tę samą ilość czasu, zmniejszając liczbę wysyłanych wiadomości e-mail i wpłynie też na opóźnienie %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3998,12 +3997,6 @@ pl: label_user_named: "Użytkownik %{name}" label_user_activity: "Aktywność użytkownika: %{value}" label_user_anonymous: "Anonimowy" - label_user_mail_option_all: "Dla każdego zdarzenia we wszystkich moich projektach" - label_user_mail_option_none: "Brak zdarzeń" - label_user_mail_option_only_assigned: "Tylko do rzeczy do których jestem przydzielony" - label_user_mail_option_only_my_events: "Tylko to co obserwuję lub jestem zaangażowany" - label_user_mail_option_only_owner: "Tylko do rzeczy, których jestem właścicielem" - label_user_mail_option_selected: "Dla każdego zdarzenia w wybranych projektach" label_user_menu: "Menu użytkownika" label_user_new: "Nowy użytkownik" label_user_plural: "Użytkownicy" @@ -4043,7 +4036,6 @@ pl: label_wiki_show_index_page_link: "Pokaż element podmenu \"Spis treści\"" label_wiki_show_menu_item: "Pokaż jako element menu w nawigacji projektu" label_wiki_show_new_page_link: "Pokaż element podmenu \"Utwórz nową stronę podrzędną\"" - label_wiki_show_submenu_item: "Pokaż jako pozycję podmenu " label_wiki_start: "Strona startowa" label_work: "Praca" label_work_package: "Zadanie" @@ -4326,7 +4318,7 @@ pl: notice_parent_item_not_found: "Nie znaleziono elementu nadrzędnego." notice_project_not_deleted: "Projekt nie został usunięty." notice_project_not_found: "Nie znaleziono projektu." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Połączenie zakończone sukcesem." notice_successful_create: "Tworzenie zakończone sukcesem." notice_successful_delete: "Usuwanie zakończone sukcesem." diff --git a/config/locales/crowdin/pt-BR.yml b/config/locales/crowdin/pt-BR.yml index 66dabdb19a8..5da435df53b 100644 --- a/config/locales/crowdin/pt-BR.yml +++ b/config/locales/crowdin/pt-BR.yml @@ -107,9 +107,8 @@ pt-BR: trial: "Avaliação" jemalloc_allocator: Alocador de memória Jemalloc journal_aggregation: - explanation: - text: "As ações individuais de um usuário (por exemplo, atualizar um pacote de trabalho duas vezes) são agregadas em uma única ação se o intervalo de tempo for menor que o intervalo especificado. Eles serão exibidos como uma única ação dentro do aplicativo. Isso também atrasará as notificações no mesmo intervalo de tempo, reduzindo o número de e-mails enviados e também afetará o atraso de %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Importar" jira: @@ -3887,12 +3886,6 @@ pt-BR: label_user_named: "Usuário %{name}" label_user_activity: "atividade do %{value}" label_user_anonymous: "Anônimo" - label_user_mail_option_all: "Para qualquer evento em todos os meus projetos" - label_user_mail_option_none: "Não há eventos" - label_user_mail_option_only_assigned: "Só para coisas que estou designado" - label_user_mail_option_only_my_events: "Somente para as coisas que eu acompanho ou participo" - label_user_mail_option_only_owner: "Somente para as coisas que eu sou o dono" - label_user_mail_option_selected: "Para qualquer evento somente nos projetos selecionados" label_user_menu: "Menu de usuários" label_user_new: "Novo usuário" label_user_plural: "Usuários" @@ -3932,7 +3925,6 @@ pt-BR: label_wiki_show_index_page_link: "Mostrar submenu 'Tabela de Conteúdos'" label_wiki_show_menu_item: "Mostrar como item de menu de navegação do projeto" label_wiki_show_new_page_link: "Mostrar o item de submenu 'Criar nova página filho'" - label_wiki_show_submenu_item: "Mostrar como item do submenu de " label_wiki_start: "Página inicial" label_work: "Trabalho" label_work_package: "Pacote de trabalho" @@ -4213,7 +4205,7 @@ pt-BR: notice_parent_item_not_found: "Item pai não encontrado." notice_project_not_deleted: "O projeto não foi excluído." notice_project_not_found: "Projeto não encontrado." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Conectado com sucesso." notice_successful_create: "Criado com sucesso." notice_successful_delete: "Exclusão bem sucedida." diff --git a/config/locales/crowdin/pt-PT.yml b/config/locales/crowdin/pt-PT.yml index b2c08fb5418..d9b50b5c425 100644 --- a/config/locales/crowdin/pt-PT.yml +++ b/config/locales/crowdin/pt-PT.yml @@ -107,9 +107,8 @@ pt-PT: trial: "Teste" jemalloc_allocator: Alocador de memória Jemalloc journal_aggregation: - explanation: - text: "As ações individuais de um utilizador (por exemplo, atualizar um pacote de trabalho duas vezes) são agregadas numa única ação se a sua diferença de idade for menor que o intervalo de tempo especificado. Serão mostradas como uma única ação dentro da aplicação. Também vai atrasar as notificações pelo mesmo período de tempo, o que reduz o número de e-mails enviados, e afeta ainda o atraso de %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Importar" jira: @@ -3887,12 +3886,6 @@ pt-PT: label_user_named: "Utilizador %{name}" label_user_activity: "Atividade de %{value}" label_user_anonymous: "Anónimo" - label_user_mail_option_all: "Para qualquer evento em todos os meus projetos" - label_user_mail_option_none: "Sem eventos" - label_user_mail_option_only_assigned: "Só para coisas que estou designado" - label_user_mail_option_only_my_events: "Apenas para coisas que observo ou em que estou envolvido" - label_user_mail_option_only_owner: "Apenas para coisas das quais sou proprietário" - label_user_mail_option_selected: "Para qualquer evento apenas nos projetos selecionados" label_user_menu: "Menu do utilizador" label_user_new: "Novo Utilizador" label_user_plural: "Utilizadores" @@ -3932,7 +3925,6 @@ pt-PT: label_wiki_show_index_page_link: "Mostrar sub-menu 'Tabela de Conteúdos'" label_wiki_show_menu_item: "Mostrar como item de menu de navegação do projecto" label_wiki_show_new_page_link: "Mostrar o item de sub-menu 'Criar nova página filha'" - label_wiki_show_submenu_item: "Mostrar como item do sub-menu de " label_wiki_start: "Página inicial" label_work: "Trabalho" label_work_package: "Pacote de trabalho" @@ -4213,7 +4205,7 @@ pt-PT: notice_parent_item_not_found: "O elemento pai não foi encontrado." notice_project_not_deleted: "O projeto não foi eliminado." notice_project_not_found: "Projeto não encontrado." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Ligação bem sucedida." notice_successful_create: "Criado com sucesso." notice_successful_delete: "Eliminado com sucesso." diff --git a/config/locales/crowdin/ro.yml b/config/locales/crowdin/ro.yml index 3136130a27f..6742c0cb934 100644 --- a/config/locales/crowdin/ro.yml +++ b/config/locales/crowdin/ro.yml @@ -107,9 +107,8 @@ ro: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Acțiunile individuale ale unui utilizator (de exemplu, actualizarea de două ori a unui pachet de lucru) sunt agregate într-o singură acțiune dacă diferența de vechime dintre ele este mai mică decât intervalul de timp specificat. Acestea vor fi afișate ca o singură acțiune în cadrul aplicației. De asemenea, acest lucru va întârzia notificările cu aceeași perioadă de timp, reducând numărul de e-mailuri trimise și va afecta, de asemenea, întârzierea %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3946,12 +3945,6 @@ ro: label_user_named: "Utilizator %{name}" label_user_activity: "Activitatea lui %{value}" label_user_anonymous: "Anonim" - label_user_mail_option_all: "Pentru orice eveniment în toate proiectele mele" - label_user_mail_option_none: "Pentru niciun eveniment" - label_user_mail_option_only_assigned: "Doar pentru tichete pe care trebuie să le execut" - label_user_mail_option_only_my_events: "Doar pentru tichete pentru care sunt observator sau în care sunt implicat" - label_user_mail_option_only_owner: "Doar pentru tichete pentru care sunt responsabil" - label_user_mail_option_selected: "Pentru orice eveniment doar în proiectele selectate" label_user_menu: "User menu" label_user_new: "Utilizator nou" label_user_plural: "Utilizatori" @@ -3991,7 +3984,6 @@ ro: label_wiki_show_index_page_link: "Afișare submeniu 'Cuprins'" label_wiki_show_menu_item: "Afișare ca meniu în navigarea proiectului" label_wiki_show_new_page_link: "Afișează submeniu 'Creează pagină copil'" - label_wiki_show_submenu_item: "Afișare ca submeniu pentru " label_wiki_start: "Pagina de start" label_work: "Muncă" label_work_package: "Pachet de lucru" @@ -4273,7 +4265,7 @@ ro: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Proiectul nu a fost şters." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Conectare reușită." notice_successful_create: "Creare reuşită." notice_successful_delete: "Ştergere reuşită." diff --git a/config/locales/crowdin/ru.yml b/config/locales/crowdin/ru.yml index f5d29996295..999ed1c8670 100644 --- a/config/locales/crowdin/ru.yml +++ b/config/locales/crowdin/ru.yml @@ -107,9 +107,8 @@ ru: trial: "Пробная версия" jemalloc_allocator: Распределитель памяти Jemalloc journal_aggregation: - explanation: - text: "Личные действия пользователя (например, обновление пакета работ дважды) агрегируются в одно действие, если их разница во времени не больше указанной. Они будут отображаться как одно действие внутри приложения. Это также задерживает уведомление на такое же количество времени, уменьшая количество отправляемых писем и также повлияет на %{webhook_link} задержки." - link: "вебхук" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Импорт" jira: @@ -626,13 +625,13 @@ ru: op_dry_validation: or: "или" errors: - unexpected_key: "is not allowed." + unexpected_key: "не разрешено." array?: "должно быть массивом." decimal?: "должно быть десятичным." defined: "не должно быть определено." eql?: "должно быть равно %{left}." filled?: "должно быть заполнено." - format?: "is in invalid format." + format?: "неверный формат." greater_or_equal_zero: "должно быть больше или равно 0." gteq?: "должно быть больше или равно %{num}." hash?: "должно быть хэш." @@ -659,9 +658,9 @@ ru: parent: not_descendant: "должно быть потомком корневого уровня иерархии." str?: "должно быть строкой." - time?: "must be a time." + time?: "должно быть единицей времени." type?: "должно быть %{type}." - uri?: "is not a valid URI." + uri?: "не является допустимым URI." rules: copy_workflow_from: "Тип копии рабочего процесса" enabled: "Включено" @@ -4000,12 +3999,6 @@ ru: label_user_named: "Пользователь %{name}" label_user_activity: "%{value} деятельности" label_user_anonymous: "Анонимно" - label_user_mail_option_all: "Для любого события на моих проектах" - label_user_mail_option_none: "Нет событий" - label_user_mail_option_only_assigned: "Только для тех, которые мне поручены" - label_user_mail_option_only_my_events: "Только для тех, в которых я наблюдатель или участник" - label_user_mail_option_only_owner: "Только для тех, которыми я владею" - label_user_mail_option_selected: "Для любого события, но только для выбранных проектов" label_user_menu: "Пользовательское меню" label_user_new: "Новый пользователь" label_user_plural: "Пользователи" @@ -4045,7 +4038,6 @@ ru: label_wiki_show_index_page_link: "Показать пункт подменю «Содержание»" label_wiki_show_menu_item: "Показать как меню в навигации по проекту" label_wiki_show_new_page_link: "Показать пункт подменю «Создать новую дочернюю страницу»" - label_wiki_show_submenu_item: "Показать как пункт подменю " label_wiki_start: "Начальная страница" label_work: "Предполагаемое время" label_work_package: "Пакет работ" @@ -4328,7 +4320,7 @@ ru: notice_parent_item_not_found: "Родительский элемент не найден." notice_project_not_deleted: "Проект удалён не был." notice_project_not_found: "Проект не найден." - notice_smtp_address_unsafe: "SMTP-адрес %{address} небезопасен. Пожалуйста, добавьте его в список OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Подключение выполнено." notice_successful_create: "Создание выполнено." notice_successful_delete: "Удаление выполнено." @@ -5118,7 +5110,7 @@ ru: text_default_administrator_account_changed: "Первоначальная учетная запись администратора была изменена" text_default_encoding: "По-умолчанию: UTF-8" text_destroy: "Удалить" - text_destroy_with_associated: "There are additional objects associated with the work package(s) that are to be deleted. Those objects are of the following types:" + text_destroy_with_associated: "Есть дополнительные объекты, ассоцированные с пакетом(-ами) работ, которые должны быть удалены. Это объекты следующих типов:" text_destroy_what_to_do: "Что Вы хотите сделать?" text_diff_truncated: "... Этот разностность(diff) была усечена, так как она превышает максимальный размер, которые может быть отображен." text_email_delivery_not_configured: "Доставка электронной почты не настроена, уведомления отключены.\nНастройте SMTP-сервер, чтобы включить их." diff --git a/config/locales/crowdin/rw.yml b/config/locales/crowdin/rw.yml index 6e3ab78041c..9cb101a9340 100644 --- a/config/locales/crowdin/rw.yml +++ b/config/locales/crowdin/rw.yml @@ -107,9 +107,8 @@ rw: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ rw: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ rw: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ rw: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/si.yml b/config/locales/crowdin/si.yml index 4b4a440ab02..4c888d8305a 100644 --- a/config/locales/crowdin/si.yml +++ b/config/locales/crowdin/si.yml @@ -107,9 +107,8 @@ si: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ si: label_user_named: "පරිශීලක %{name}" label_user_activity: "%{value}ගේ ක්රියාකාරකම්" label_user_anonymous: "නිර්නාමික" - label_user_mail_option_all: "මගේ සියලු ව්යාපෘතිවල ඕනෑම සිදුවීමක් සඳහා" - label_user_mail_option_none: "සිදුවීම් නැත" - label_user_mail_option_only_assigned: "මට පවරා ඇති දේවල් සඳහා පමණි" - label_user_mail_option_only_my_events: "මම නරඹන දේවල් සඳහා පමණක් හෝ මම සම්බන්ධ වෙනවා" - label_user_mail_option_only_owner: "මම අයිතිකරු වන්නේ දේවල් සඳහා පමණි" - label_user_mail_option_selected: "තෝරාගත් ව්යාපෘතිවල ඕනෑම සිදුවීමක් සඳහා පමණි" label_user_menu: "User menu" label_user_new: "නව පරිශීලක" label_user_plural: "පරිශීලකයන්" @@ -3935,7 +3928,6 @@ si: label_wiki_show_index_page_link: "උප මෙනු අයිතමය පෙන්වන්න 'අන්තර්ගත වගුව'" label_wiki_show_menu_item: "ව්යාපෘති සංචලනය තුළ මෙනු අයිතමය ලෙස පෙන්වන්න" label_wiki_show_new_page_link: "උප මෙනු අයිතමය පෙන්වන්න 'නව ළමා පිටුව සාදන්න'" - label_wiki_show_submenu_item: "උප මෙනු අයිතමය ලෙස පෙන්වන්න " label_wiki_start: "ආරම්භක පිටුව" label_work: "Work" label_work_package: "වැඩ පැකේජය" @@ -4217,7 +4209,7 @@ si: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "ව්යාපෘතිය මකා දැමුවේ නැත." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "සාර්ථක සම්බන්ධතාවයක්." notice_successful_create: "සාර්ථක නිර්මාණය." notice_successful_delete: "සාර්ථක මකාදැමීම." diff --git a/config/locales/crowdin/sk.yml b/config/locales/crowdin/sk.yml index aac195608d9..a31637cb0c3 100644 --- a/config/locales/crowdin/sk.yml +++ b/config/locales/crowdin/sk.yml @@ -107,9 +107,8 @@ sk: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -4002,12 +4001,6 @@ sk: label_user_named: "Užívateľ %{name}" label_user_activity: "Aktivita používateľa %{value}" label_user_anonymous: "Anonymný" - label_user_mail_option_all: "Pre všetky udalosti všetkých mojich projektov" - label_user_mail_option_none: "Žiadne udalosti" - label_user_mail_option_only_assigned: "Len pre veci, na ktoré som priradený" - label_user_mail_option_only_my_events: "Len pre veci, ktoré sledujem, alebo v ktorých som zapojený" - label_user_mail_option_only_owner: "Len pre veci, ktorých som vlastníkom" - label_user_mail_option_selected: "Pre každú udalosť len na vybraných projektoch" label_user_menu: "User menu" label_user_new: "Nový uživateľ" label_user_plural: "Užívatelia" @@ -4047,7 +4040,6 @@ sk: label_wiki_show_index_page_link: "Zobraziť položku podmenu \"Obsah\"" label_wiki_show_menu_item: "Zobraziť ako položku menu v navigácii projektu" label_wiki_show_new_page_link: "Zobraziť položku submenu \"Vytvoriť novú podradenú stránku\"" - label_wiki_show_submenu_item: "Zobraziť ako položku submenu " label_wiki_start: "Úvodná stránka" label_work: "Work" label_work_package: "Pracovný balíček" @@ -4330,7 +4322,7 @@ sk: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projekt nebol odstránený." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Úspešne pripojené." notice_successful_create: "Úspešne vytvorené." notice_successful_delete: "Úspešne zmazané." diff --git a/config/locales/crowdin/sl.yml b/config/locales/crowdin/sl.yml index 4cef90ee241..4b044911670 100644 --- a/config/locales/crowdin/sl.yml +++ b/config/locales/crowdin/sl.yml @@ -107,9 +107,8 @@ sl: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -4001,12 +4000,6 @@ sl: label_user_named: "Uporabnik %{name}" label_user_activity: "%{value}'s aktivnost" label_user_anonymous: "Anonimno" - label_user_mail_option_all: "Za vsak dogodek na vseh mojih projektih" - label_user_mail_option_none: "Ni dogodkov" - label_user_mail_option_only_assigned: "Samo za stvari, ki smo mi dodeljene" - label_user_mail_option_only_my_events: "Samo za stvari, ki jih opazujem ali v katere sem vpleten" - label_user_mail_option_only_owner: "Samo za stvari katerih lastnik sem" - label_user_mail_option_selected: "Za vsak dogodek samo na izbranih projektih..." label_user_menu: "User menu" label_user_new: "Nov uporabnik" label_user_plural: "Uporabniki" @@ -4046,7 +4039,6 @@ sl: label_wiki_show_index_page_link: "Pokaži postavko podmenija „Vsebina“" label_wiki_show_menu_item: "Prikaži kot element v meniju navigacija projekta" label_wiki_show_new_page_link: "Pokaži element v podmeniju »Ustvari novo podrejeno stran«" - label_wiki_show_submenu_item: "Prikaži kot element podmenija v" label_wiki_start: "Začetna stran" label_work: "Work" label_work_package: "Delovni paket" @@ -4330,7 +4322,7 @@ sl: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projekt ni bil izbrisan." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Povezava uspela." notice_successful_create: "Ustvarjanje uspelo." notice_successful_delete: "Uspešen izbris." diff --git a/config/locales/crowdin/sr.yml b/config/locales/crowdin/sr.yml index 08d703ac8b2..ee64e4390f2 100644 --- a/config/locales/crowdin/sr.yml +++ b/config/locales/crowdin/sr.yml @@ -107,9 +107,8 @@ sr: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3946,12 +3945,6 @@ sr: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3991,7 +3984,6 @@ sr: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4274,7 +4266,7 @@ sr: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/sv.yml b/config/locales/crowdin/sv.yml index 7f8fcc46f81..fe6b260b1ce 100644 --- a/config/locales/crowdin/sv.yml +++ b/config/locales/crowdin/sv.yml @@ -107,9 +107,8 @@ sv: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ sv: label_user_named: "Användare %{name}" label_user_activity: "%{value}s aktivitet" label_user_anonymous: "Anonym" - label_user_mail_option_all: "För alla händelser i alla mina projekt" - label_user_mail_option_none: "Inga händelser" - label_user_mail_option_only_assigned: "Bara är saker jag tilldelade" - label_user_mail_option_only_my_events: "Endast för saker jag bevakar eller deltar i" - label_user_mail_option_only_owner: "Endast för saker är jag ägare till" - label_user_mail_option_selected: "Endast för alla händelser i valda projekt" label_user_menu: "Användarmeny" label_user_new: "Ny användare" label_user_plural: "Användare" @@ -3935,7 +3928,6 @@ sv: label_wiki_show_index_page_link: "Visa undermenyn \"Innehållsförteckning\"" label_wiki_show_menu_item: "Visa som menyobjekt i projektets meny" label_wiki_show_new_page_link: "Visa undermenyn \"Skapa ny underordnad sida\"" - label_wiki_show_submenu_item: "Visa som undermenyalternativ för " label_wiki_start: "Startsida" label_work: "Arbete" label_work_package: "Arbetspaket" @@ -4217,7 +4209,7 @@ sv: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "Projektet raderades ej." notice_project_not_found: "Projektet hittas inte." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Lyckad anslutning." notice_successful_create: "Skapades utan problem." notice_successful_delete: "Raderades utan problem." diff --git a/config/locales/crowdin/th.yml b/config/locales/crowdin/th.yml index 0e77bbd3055..ba4d2d5c081 100644 --- a/config/locales/crowdin/th.yml +++ b/config/locales/crowdin/th.yml @@ -107,9 +107,8 @@ th: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3834,12 +3833,6 @@ th: label_user_named: "User %{name}" label_user_activity: "กิจกรรมของ %{value}" label_user_anonymous: "ไม่ระบุชื่อ" - label_user_mail_option_all: "สำหรับเหตุการณ์ใด ๆ ก็ตามในโครงการทั้งหมดของฉัน" - label_user_mail_option_none: "ไม่พบเหตุการณ์" - label_user_mail_option_only_assigned: "เฉพาะสิ่งที่ฉันได้รับมอบหมาย" - label_user_mail_option_only_my_events: "เฉพาะสิ่งที่ฉันเฝ้าดูหรือมีความเกี่ยวข้องด้วย" - label_user_mail_option_only_owner: "เฉพาะสิ่งที่ฉันเป็นเจ้าของ" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "ผู้ใช้ใหม่" label_user_plural: "ผู้ใช้" @@ -3879,7 +3872,6 @@ th: label_wiki_show_index_page_link: "แสดงเมนูย่อยของ 'สารบัญ'" label_wiki_show_menu_item: "แสดงเป็นเมนูในการนำทางของโครงการ" label_wiki_show_new_page_link: "แสดงรายการเมนูย่อย 'สร้างหน้าย่อยใหม่'" - label_wiki_show_submenu_item: "แสดงเป็นรายการเมนูย่อยของ " label_wiki_start: "เพจเริ่มต้น" label_work: "Work" label_work_package: "ชุดภารกิจ" @@ -4160,7 +4152,7 @@ th: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "ไม่ได้ลบโครงการ" notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "การเชื่อมต่อสำเร็จ" notice_successful_create: "สร้างเรียบร้อยแล้ว" notice_successful_delete: "ลบเรียบร้อยแล้ว" diff --git a/config/locales/crowdin/tr.yml b/config/locales/crowdin/tr.yml index 4be1e4dc84f..77e7ecaff7b 100644 --- a/config/locales/crowdin/tr.yml +++ b/config/locales/crowdin/tr.yml @@ -107,9 +107,8 @@ tr: trial: "Deneme" jemalloc_allocator: Jemalloc bellek ayırıcı journal_aggregation: - explanation: - text: "Bir kullanıcının bireysel eylemleri (örneğin, bir iş paketini iki kez güncelleme), yaş farkı belirtilen zaman aralığından azsa tek bir eylemde toplanır. Uygulama içinde tek bir eylem olarak görüntülenecektir. Bu aynı zamanda gönderilen e-posta sayısını azaltarak bildirimleri aynı süre kadar geciktirecek ve ayrıca %{webhook_link} gecikmesini etkileyecektir." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ tr: label_user_named: "%{name} kullanıcısı" label_user_activity: "%{value}'ın faaliyet" label_user_anonymous: "Anonim" - label_user_mail_option_all: "Tüm projelerimdeki herhangi bir olay için" - label_user_mail_option_none: "Etkinlik yok" - label_user_mail_option_only_assigned: "Sadece bana atanan şeyler için" - label_user_mail_option_only_my_events: "Sadece takip ettiğim ya da dahil olduklarım için" - label_user_mail_option_only_owner: "Sadece sahibi olduğum şeyler için" - label_user_mail_option_selected: "Yalnızca seçilen projelerdeki herhangi bir etkinlik için" label_user_menu: "Kullanıcı menüsü" label_user_new: "Yeni kullanıcı" label_user_plural: "Kullanıcılar" @@ -3935,7 +3928,6 @@ tr: label_wiki_show_index_page_link: "Alt menü öğesini göster 'İçindekiler tablosu'" label_wiki_show_menu_item: "Proje gezintisinde menü öğesi olarak göster" label_wiki_show_new_page_link: "Alt menü öğesini göster 'Yeni alt sayfa oluştur'" - label_wiki_show_submenu_item: "Alt menü öğesi olarak göster " label_wiki_start: "Başlangıç sayfası" label_work: "Çalışma" label_work_package: "İş paketi" @@ -4216,7 +4208,7 @@ tr: notice_parent_item_not_found: "Üst öğe bulunamadı." notice_project_not_deleted: "Proje silinemedi." notice_project_not_found: "Proje bulunamadı." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Bağlantı başarılı." notice_successful_create: "Oluşturma başarılı." notice_successful_delete: "Silme başarılı." diff --git a/config/locales/crowdin/uk.yml b/config/locales/crowdin/uk.yml index e23a2de4ebc..a3868bf6259 100644 --- a/config/locales/crowdin/uk.yml +++ b/config/locales/crowdin/uk.yml @@ -107,9 +107,8 @@ uk: trial: "Пробний період" jemalloc_allocator: Розподіл пам'яті Jemalloc journal_aggregation: - explanation: - text: "Окремі дії користувача (напр., оновлення робочого пакета двічі) зводяться в одну дію, якщо відмінність у часі між ними менша за вказаний проміжок часу. Їх буде виведено як окремі дії в межах додатка. Крім того, це призведе до затримки сповіщень на такий самий проміжок часу, що зменшить кількість електронних листів, які надсилатимуться, а також вплине на затримку %{webhook_link}." - link: "вебгука" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Iмпорт" jira: @@ -3996,12 +3995,6 @@ uk: label_user_named: "User %{name}" label_user_activity: "Дії користувача %{value}" label_user_anonymous: "Невідомий" - label_user_mail_option_all: "Для всіх подій у всіх моїх проектах" - label_user_mail_option_none: "Ніяких подій" - label_user_mail_option_only_assigned: "Тільки за те що я призначений" - label_user_mail_option_only_my_events: "Тільки для речей які я дивлюся чи я займаюся" - label_user_mail_option_only_owner: "Тільки для речей, за якими я спостерігаю або є власником" - label_user_mail_option_selected: "Для будь-якої події на вибраних проектах" label_user_menu: "Меню користувача" label_user_new: "Новий користувач" label_user_plural: "Користувачі" @@ -4041,7 +4034,6 @@ uk: label_wiki_show_index_page_link: "Показати пункт підменю \"Зміст\"" label_wiki_show_menu_item: "Показати як пункт меню в навігації по проекту" label_wiki_show_new_page_link: "Показати елемент підменю \"Створити нову початкову сторінку\"" - label_wiki_show_submenu_item: "Показати як пункт підменю " label_wiki_start: "Початкова сторінка" label_work: "Робота" label_work_package: "Робочий пакет" @@ -4324,7 +4316,7 @@ uk: notice_parent_item_not_found: "Батьківський об’єкт не знайдено." notice_project_not_deleted: "Проект не був видалений." notice_project_not_found: "Проєкт не знайдено." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Підключення успішно встановлене." notice_successful_create: "Створення успішно завершене." notice_successful_delete: "Видалення успішно завершене." diff --git a/config/locales/crowdin/uz.yml b/config/locales/crowdin/uz.yml index 527805d7d3b..b223f6b21ec 100644 --- a/config/locales/crowdin/uz.yml +++ b/config/locales/crowdin/uz.yml @@ -107,9 +107,8 @@ uz: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3890,12 +3889,6 @@ uz: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -3935,7 +3928,6 @@ uz: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4217,7 +4209,7 @@ uz: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." diff --git a/config/locales/crowdin/vi.yml b/config/locales/crowdin/vi.yml index 618af7ac803..a97674e7712 100644 --- a/config/locales/crowdin/vi.yml +++ b/config/locales/crowdin/vi.yml @@ -107,9 +107,8 @@ vi: trial: "thử nghiệm" jemalloc_allocator: Bộ cấp phát bộ nhớ Jemalloc journal_aggregation: - explanation: - text: "Các hành động riêng lẻ của người dùng (ví dụ: cập nhật gói công việc hai lần) được tổng hợp thành một hành động nếu chênh lệch tuổi tác của họ nhỏ hơn khoảng thời gian đã chỉ định. Chúng sẽ được hiển thị dưới dạng một hành động duy nhất trong ứng dụng. Điều này cũng sẽ làm chậm thông báo với cùng một khoảng thời gian làm giảm số lượng email được gửi và cũng sẽ ảnh hưởng đến độ trễ %{webhook_link}." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3832,12 +3831,6 @@ vi: label_user_named: "Người dùng %{name}" label_user_activity: "%{value} hoạt động" label_user_anonymous: "vô danh" - label_user_mail_option_all: "Bất kỳ sự kiện trên tất cả dự án của tôi" - label_user_mail_option_none: "Không có sự kiện" - label_user_mail_option_only_assigned: "Chỉ những thứ tôi được phân công" - label_user_mail_option_only_my_events: "Chỉ những thứ tôi theo dõi hoặc liên quan" - label_user_mail_option_only_owner: "Chỉ những thứ tôi sở hữu" - label_user_mail_option_selected: "Chỉ dành cho bất kỳ sự kiện nào trên các dự án đã chọn" label_user_menu: "Trình đơn người dùng" label_user_new: "Người dùng mới" label_user_plural: "Người dùng" @@ -3877,7 +3870,6 @@ vi: label_wiki_show_index_page_link: "Hiển thị mục menu con 'Mục lục'" label_wiki_show_menu_item: "Hiển thị dưới dạng mục menu trong điều hướng dự án" label_wiki_show_new_page_link: "Hiển thị mục menu con 'Tạo trang con mới'" - label_wiki_show_submenu_item: "Hiển thị dưới dạng mục menu con của" label_wiki_start: "Trang bắt đầu" label_work: "làm việc" label_work_package: "Work Package" @@ -4158,7 +4150,7 @@ vi: notice_parent_item_not_found: "Không tìm thấy mục gốc." notice_project_not_deleted: "Dự án không bị xóa." notice_project_not_found: "Dự án không được tìm thấy." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Kết nối thành công." notice_successful_create: "Sáng tạo thành công." notice_successful_delete: "Xóa thành công." diff --git a/config/locales/crowdin/zh-CN.yml b/config/locales/crowdin/zh-CN.yml index cfd97f17da7..99ffac2256a 100644 --- a/config/locales/crowdin/zh-CN.yml +++ b/config/locales/crowdin/zh-CN.yml @@ -107,9 +107,8 @@ zh-CN: trial: "试用" jemalloc_allocator: 使用 jemalloc 内存分配器 journal_aggregation: - explanation: - text: "如果用户的多项操作(例如,更新工作包两次)的时间间隔小于指定的时间跨度,则这些操作将被聚合为单个操作,并在应用程序中显示为单个操作。这也会将通知延迟同等的时间,从而减少电子邮件的发送数量,并且还会影响 %{webhook_link} 延迟。" - link: "Webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "导入" jira: @@ -3830,12 +3829,6 @@ zh-CN: label_user_named: "用户 %{name}" label_user_activity: "%{value} 的活动" label_user_anonymous: "匿名" - label_user_mail_option_all: "对于我所有项目的任何事件" - label_user_mail_option_none: "没有事件" - label_user_mail_option_only_assigned: "仅为指派给我的内容" - label_user_mail_option_only_my_events: "仅为我关注或参与的内容" - label_user_mail_option_only_owner: "仅为我是所有者的内容" - label_user_mail_option_selected: "只对于所选项目的任何事件......" label_user_menu: "用户菜单" label_user_new: "新用户" label_user_plural: "用户" @@ -3875,7 +3868,6 @@ zh-CN: label_wiki_show_index_page_link: "显示‘目录’子菜单项" label_wiki_show_menu_item: "显示为项目导航中的菜单项" label_wiki_show_new_page_link: "显示‘创建新的子页面’子菜单项" - label_wiki_show_submenu_item: "显示为子菜单项" label_wiki_start: "起始页" label_work: "工时" label_work_package: "工作包" @@ -4154,7 +4146,7 @@ zh-CN: notice_parent_item_not_found: "未找到父项" notice_project_not_deleted: "项目没有被删除" notice_project_not_found: "未找到项目。" - notice_smtp_address_unsafe: "SMTP 地址 %{address} 不安全。请将其添加到 OPENPROJECT_SSRF_PROTECTION_ALLOWLIST。" + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "成功连接。" notice_successful_create: "成功创建。" notice_successful_delete: "成功删除。" diff --git a/config/locales/crowdin/zh-TW.yml b/config/locales/crowdin/zh-TW.yml index 225b8a20937..f3e4e36d2c0 100644 --- a/config/locales/crowdin/zh-TW.yml +++ b/config/locales/crowdin/zh-TW.yml @@ -107,9 +107,8 @@ zh-TW: trial: "試用" jemalloc_allocator: Jemalloc 記憶體分配器 journal_aggregation: - explanation: - text: "使用者的個別操作(例如:在短時間內更新同一工作套件兩次)若時間差距小於指定時長,系統會將這些操作合併為單一動作,並於應用程式中以單一動作顯示。\n此機制同時會延遲通知發送相同的時間,以減少電子郵件數量,並且會影響 %{webhook_link} 的延遲時間。" - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -3830,12 +3829,6 @@ zh-TW: label_user_named: "用戶名 %{name}" label_user_activity: "%{value} 的活動" label_user_anonymous: "匿名者" - label_user_mail_option_all: "對於我所有的專案的任何事件" - label_user_mail_option_none: "沒有事件" - label_user_mail_option_only_assigned: "只針對我被指派的事情" - label_user_mail_option_only_my_events: "只針對我關注的或者與我有關的事情" - label_user_mail_option_only_owner: "針對我是擁有者的事情" - label_user_mail_option_selected: "只有在已選取的專案的任何事件" label_user_menu: "使用者選單" label_user_new: "新增使用者" label_user_plural: "使用者" @@ -3875,7 +3868,6 @@ zh-TW: label_wiki_show_index_page_link: "顯示子功能表 '表格內容'" label_wiki_show_menu_item: "在專案導覽中以子功能表呈現" label_wiki_show_new_page_link: "顯示子功能表 '新增子頁面'" - label_wiki_show_submenu_item: "呈現於子功能表的 " label_wiki_start: "開始頁面" label_work: "工時" label_work_package: "工作套件" @@ -4155,7 +4147,7 @@ zh-TW: notice_parent_item_not_found: "未找到父項目。" notice_project_not_deleted: "專案沒有被刪除" notice_project_not_found: "未找到專案。" - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "連接成功" notice_successful_create: "建立成功" notice_successful_delete: "刪除成功" diff --git a/config/locales/en.yml b/config/locales/en.yml index 835c2f781d9..320943113c8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -116,9 +116,8 @@ en: trial: "Trial" jemalloc_allocator: Jemalloc memory allocator journal_aggregation: - explanation: - text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay." - link: "webhook" + caption: > + Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect the [webhook](webhook_link) delay. import: title: "Import" jira: @@ -397,6 +396,41 @@ en:

    Hello,

    A new project has been created: projectValue:name

    Thank you

    + work_packages_identifier: + page_header: + description: Choose between basic numerical work packages IDs or project-specific ones that prepend the project identifier to the work package ID. + banner: + existing_identifiers_notice: > + Existing identifiers for %{project_count} projects don't meet requirements for project-based alphanumerical identifiers. + OpenProject can automatically update these so that they are valid as in the examples below. + Click on 'Autofix and save' to update identifiers for all projects in this manner and enable project-based alphanumerical identifiers. + box_header: + label_project: Project + label_previous_identifier: Previous identifier + label_autofixed_suggestion: Future identifier + label_example_work_package_id: Example work package ID + autofix_preview: + error_too_long: Has to be fewer than 5 characters + error_special_characters: Special characters not allowed + error_in_use: Already in use as another project's active handle + error_reserved: Reserved by another project's handle history + remaining_projects: + one: "... 1 more project" + other: "... %{count} more projects" + button_autofix: Autofix and save + dialog: + title: Change work package identifiers + heading: Enable project-based work package IDs? + description: > + This will change IDs for all work packages in all projects in this instance. + Previous identifiers and URLs will continue to redirect properly. + This change will take some time to complete. + confirm_button: Change identifiers + checkbox_label: I understand that this will permanently change all work package IDs + success_banner: Successfully updated work package identifier format. + in_progress: + banner_message: Project identifiers are currently being updated to project-based alphanumerical identifiers. This may take some time. + workflows: tabs: default_transitions: "Default transitions" @@ -4132,12 +4166,6 @@ en: label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" - label_user_mail_option_all: "For any event on all my projects" - label_user_mail_option_none: "No events" - label_user_mail_option_only_assigned: "Only for things I am assigned to" - label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" - label_user_mail_option_only_owner: "Only for things I am the owner of" - label_user_mail_option_selected: "For any event on the selected projects only" label_user_menu: "User menu" label_user_new: "New user" label_user_plural: "Users" @@ -4177,7 +4205,6 @@ en: label_wiki_show_index_page_link: "Show submenu item 'Table of Contents'" label_wiki_show_menu_item: "Show as menu item in project navigation" label_wiki_show_new_page_link: "Show submenu item 'Create new child page'" - label_wiki_show_submenu_item: "Show as submenu item of " label_wiki_start: "Start page" label_work: "Work" label_work_package: "Work package" @@ -4492,7 +4519,7 @@ en: notice_parent_item_not_found: "Parent item not found." notice_project_not_deleted: "The project wasn't deleted." notice_project_not_found: "Project not found." - notice_smtp_address_unsafe: "SMTP address %{address} is not safe. Please add it to OPENPROJECT_SSRF_PROTECTION_ALLOWLIST." + notice_smtp_address_unsafe_env_hint: "SMTP address %{address} is not safe. Please add it to the whitelist using the %{env_name} environment variable." notice_successful_connection: "Successful connection." notice_successful_create: "Successful creation." notice_successful_delete: "Successful deletion." @@ -5102,6 +5129,12 @@ en: setting_welcome_text: "Welcome block text" setting_welcome_title: "Welcome block title" setting_welcome_on_homescreen: "Display welcome block on homescreen" + setting_work_packages_identifier_numeric: Instance-wide numerical sequence (default) + setting_work_packages_identifier_numeric_caption: > + Every work package gets a sequential number starting with 1 and incremented with every new one. The numbers are unique within this instance so they remain the same even if work packages are moved between projects. + setting_work_packages_identifier_alphanumeric: Project-based alphanumerical identifiers + setting_work_packages_identifier_alphanumeric_caption: > + Every project has a unique identifier that is prefixed to the work package ID. If a work package moved to another project, a new identifier is generated but the old one continues to function. setting_work_package_list_default_highlighting_mode: "Default highlighting mode" setting_work_package_list_default_highlighted_attributes: "Default inline highlighted attributes" setting_working_days: "Working days" @@ -5304,6 +5337,7 @@ en: section_work_week: "Work week" section_holidays_and_closures: "Holidays and closures" work_packages: + work_package_identifier: "Work package identifier" not_allowed_text: "You do not have the necessary permissions to view this page." activities: enable_internal_comments: "Enable internal comments" diff --git a/config/routes.rb b/config/routes.rb index 1dfb48f5d3c..45c99c9de41 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -660,6 +660,10 @@ Rails.application.routes.draw do # It is important to have this named something else than "work_packages". # Otherwise the angular ui-router will also recognize that as a WorkPackage page and apply according classes. resource :work_packages_general, controller: "/admin/settings/work_packages_general", only: %i[show update] + resource :work_packages_identifier, controller: "/admin/settings/work_packages_identifier", only: %i[show update] do + get :status, on: :member + get :confirm_dialog, on: :member, defaults: { format: :turbo_stream } + end resources :work_package_priorities, except: [:show] do member do put :move diff --git a/db/AGENTS.md b/db/AGENTS.md new file mode 100644 index 00000000000..a80ff4f767b --- /dev/null +++ b/db/AGENTS.md @@ -0,0 +1,30 @@ +# Database + +## Code Style + +### Database Migrations + +- Follow Rails migration conventions +- Migrations are "squashed" between major releases (see `docs/development/migrations/`) + +## Commands + +### Local + +```bash +bundle exec rails g migration MigrationName # Generate a migration +bundle exec rails db:migrate # Run migrations +bundle exec rails db:rollback # Rollback last migration +bundle exec rails db:seed # Seed sample data +``` + +### Docker + +```bash +bin/compose exec backend bundle exec rails db:migrate # Run migrations +bin/compose exec backend bundle exec rails db:seed # Seed data +``` + +## Important Note + +**CRITICAL**: `config/database.yml` must NOT exist when using Docker (rename or delete it) diff --git a/db/CLAUDE.md b/db/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/db/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/db/migrate/20260218095806_apply_work_package_attachment_settings_to_existing_projects.rb b/db/migrate/20260218095806_apply_work_package_attachment_settings_to_existing_projects.rb index 02b01642845..b0c7cb16e39 100644 --- a/db/migrate/20260218095806_apply_work_package_attachment_settings_to_existing_projects.rb +++ b/db/migrate/20260218095806_apply_work_package_attachment_settings_to_existing_projects.rb @@ -35,9 +35,12 @@ class ApplyWorkPackageAttachmentSettingsToExistingProjects < ActiveRecord::Migra SET settings = jsonb_set( settings, '{deactivate_work_package_attachments}', - (SELECT to_jsonb(not settings.value::boolean) - FROM settings - WHERE settings.name = 'show_work_package_attachments') + COALESCE( + (SELECT to_jsonb(not settings.value::boolean) + FROM settings + WHERE settings.name = 'show_work_package_attachments'), + 'false' + ) ) WHERE NOT (settings ? 'deactivate_work_package_attachments') SQL diff --git a/db/migrate/20260313120000_strip_control_characters_from_custom_field_names.rb b/db/migrate/20260313120000_strip_control_characters_from_custom_field_names.rb new file mode 100644 index 00000000000..aec50ce1ec6 --- /dev/null +++ b/db/migrate/20260313120000_strip_control_characters_from_custom_field_names.rb @@ -0,0 +1,43 @@ +# 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. +#++ + +class StripControlCharactersFromCustomFieldNames < ActiveRecord::Migration[7.1] + def up + execute <<~SQL.squish + UPDATE custom_fields + SET name = regexp_replace(name, E'[\\x01-\\x1F\\x7F]', '', 'g') + WHERE name ~ E'[\\x01-\\x1F\\x7F]' + SQL + end + + def down + # Irreversible — stripped characters cannot be restored + end +end diff --git a/docker/dev/AGENTS.md b/docker/dev/AGENTS.md new file mode 100644 index 00000000000..f7492804b5a --- /dev/null +++ b/docker/dev/AGENTS.md @@ -0,0 +1,61 @@ +# Docker Development + +The Docker development environment uses configurations in `docker/dev/` and the `bin/compose` wrapper script. + +## Setup + +```bash +# Initial setup (first time only) +bin/compose setup # Installs backend and frontend dependencies + +# Starting services +bin/compose start # Start backend and frontend in background +bin/compose run # Start frontend in background, backend in foreground (for debugging with pry) + +# Running tests +bin/compose rspec spec/models/user_spec.rb # Run specific tests in backend-test container + +# Other operations +bin/compose reset # Remove all containers and volumes (requires setup again) +bin/compose # Pass any docker-compose command directly +``` + +## Important Notes + +- **CRITICAL**: `config/database.yml` must NOT exist when using Docker (rename or delete it) +- Most developers use a local `docker-compose.override.yml` for custom port mappings and configurations +- Copy `docker-compose.override.example.yml` to `docker-compose.override.yml` and customize as needed +- Default ports: Backend at http://localhost:3000 (or 4200 for frontend dev server) +- Services: `backend`, `frontend`, `worker`, `db`, `db-test`, `backend-test`, `cache` +- Persisted volumes: `pgdata`, `bundle`, `npm`, `tmp`, `opdata` (data survives container restarts) +- Docker build context: Uses Dockerfiles in `docker/dev/backend/` and `docker/dev/frontend/` + +## Commands Reference + +```bash +# Setup and lifecycle +bin/compose setup # Setup Docker environment (first time) +bin/compose start # Start all services in background +bin/compose run # Start frontend in background, backend in foreground +bin/compose reset # Remove all containers and volumes +bin/compose stop # Stop all services +bin/compose down # Stop and remove containers + +# Testing +bin/compose rspec spec/models/user_spec.rb # Run specific tests +bin/compose exec backend bundle exec rspec # Run tests directly in backend container + +# Development +bin/compose exec backend bundle exec rails console # Rails console +bin/compose logs backend # View backend logs +bin/compose logs -f backend # Follow backend logs +bin/compose ps # List running containers + +# Database +bin/compose exec backend bundle exec rails db:migrate # Run migrations +bin/compose exec backend bundle exec rails db:seed # Seed data + +# Direct docker-compose commands +bin/compose up -d # Start services +bin/compose restart backend # Restart backend service +``` diff --git a/docker/dev/CLAUDE.md b/docker/dev/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/docker/dev/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 6cdef8d40c3..69d16e05961 100755 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -3,7 +3,7 @@ ARG DEBIAN_BASE="trixie" # Add SBOM scan context for intermediate steps ARG BUILDKIT_SBOM_SCAN_CONTEXT=true ARG BUILDKIT_SBOM_SCAN_STAGE=true -FROM ruby:${RUBY_VERSION}-slim-${DEBIAN_BASE} AS runtime-base +FROM ruby:${RUBY_VERSION}-slim-trixie AS runtime-base LABEL maintainer="operations@openproject.com" ARG NODE_VERSION="22.21.0" @@ -141,7 +141,7 @@ ENV PGDATA=/var/openproject/pgdata COPY --from=openproject/gosu /go/bin/gosu /usr/local/bin/gosu RUN chmod +x /usr/local/bin/gosu && gosu nobody true -COPY --from=openproject/hocuspocus:17.1.2 --chown=$APP_USER:$APP_USER /app /opt/hocuspocus +COPY --from=openproject/hocuspocus:17.2.2 --chown=$APP_USER:$APP_USER /app /opt/hocuspocus # Keep node/npm in all-in-one for bundled hocuspocus even when BIM support is disabled. COPY --from=build-base /usr/local/bin/node /usr/local/bin/node COPY --from=build-base /usr/local/lib/node_modules /usr/local/lib/node_modules diff --git a/docker/prod/setup/preinstall-common.sh b/docker/prod/setup/preinstall-common.sh index b857c907732..e69d0a6a058 100755 --- a/docker/prod/setup/preinstall-common.sh +++ b/docker/prod/setup/preinstall-common.sh @@ -94,7 +94,6 @@ apt-get purge -yq --auto-remove \ # curl/wget are only needed during installation in this stage. apt-get purge -yq --auto-remove \ - curl \ wget rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/pullpreview/docker-compose.yml b/docker/pullpreview/docker-compose.yml index 8bb3c2b6f04..c842df285e3 100644 --- a/docker/pullpreview/docker-compose.yml +++ b/docker/pullpreview/docker-compose.yml @@ -13,8 +13,6 @@ volumes: x-defaults: &defaults build: context: . - args: - DEBIAN_BASE: bookworm restart: unless-stopped env_file: - .env.pullpreview diff --git a/docs/bim-guide/bim-issue-management/Swicht_View_Mode.gif b/docs/bim-guide/bim-issue-management/Swicht_View_Mode.gif index 3bc043d9c5c..0a711717946 100644 Binary files a/docs/bim-guide/bim-issue-management/Swicht_View_Mode.gif and b/docs/bim-guide/bim-issue-management/Swicht_View_Mode.gif differ diff --git a/docs/bim-guide/ifc-viewer/2D_3D.gif b/docs/bim-guide/ifc-viewer/2D_3D.gif index cfb749562dd..37dced5b792 100644 Binary files a/docs/bim-guide/ifc-viewer/2D_3D.gif and b/docs/bim-guide/ifc-viewer/2D_3D.gif differ diff --git a/docs/bim-guide/ifc-viewer/Hide_IFC_classes.gif b/docs/bim-guide/ifc-viewer/Hide_IFC_classes.gif index 1606c0125dc..208760f8536 100644 Binary files a/docs/bim-guide/ifc-viewer/Hide_IFC_classes.gif and b/docs/bim-guide/ifc-viewer/Hide_IFC_classes.gif differ diff --git a/docs/bim-guide/ifc-viewer/Hide_Model.gif b/docs/bim-guide/ifc-viewer/Hide_Model.gif index 679c20f3645..9c15887537d 100644 Binary files a/docs/bim-guide/ifc-viewer/Hide_Model.gif and b/docs/bim-guide/ifc-viewer/Hide_Model.gif differ diff --git a/docs/bim-guide/ifc-viewer/Hide_building_storey.gif b/docs/bim-guide/ifc-viewer/Hide_building_storey.gif index 518e0489edb..da08ce0bd9b 100644 Binary files a/docs/bim-guide/ifc-viewer/Hide_building_storey.gif and b/docs/bim-guide/ifc-viewer/Hide_building_storey.gif differ diff --git a/docs/bim-guide/ifc-viewer/Hide_elements_Viewer_rubber.gif b/docs/bim-guide/ifc-viewer/Hide_elements_Viewer_rubber.gif index b8042d12506..4ce8b6c7070 100644 Binary files a/docs/bim-guide/ifc-viewer/Hide_elements_Viewer_rubber.gif and b/docs/bim-guide/ifc-viewer/Hide_elements_Viewer_rubber.gif differ diff --git a/docs/bim-guide/ifc-viewer/Model_Rotation.gif b/docs/bim-guide/ifc-viewer/Model_Rotation.gif index a421ec77e4d..5a9d8678d8a 100644 Binary files a/docs/bim-guide/ifc-viewer/Model_Rotation.gif and b/docs/bim-guide/ifc-viewer/Model_Rotation.gif differ diff --git a/docs/bim-guide/ifc-viewer/XRay.gif b/docs/bim-guide/ifc-viewer/XRay.gif index 917eb622ecf..c6114e1fe3f 100644 Binary files a/docs/bim-guide/ifc-viewer/XRay.gif and b/docs/bim-guide/ifc-viewer/XRay.gif differ diff --git a/docs/bim-guide/ifc-viewer/fit-view.gif b/docs/bim-guide/ifc-viewer/fit-view.gif index cc74ee353d9..15c6cc4bab2 100644 Binary files a/docs/bim-guide/ifc-viewer/fit-view.gif and b/docs/bim-guide/ifc-viewer/fit-view.gif differ diff --git a/docs/development/concepts/hotwire-view-components/README.md b/docs/development/concepts/hotwire-view-components/README.md index 7cd09fe8119..0a5da5f21c6 100644 --- a/docs/development/concepts/hotwire-view-components/README.md +++ b/docs/development/concepts/hotwire-view-components/README.md @@ -1,7 +1,7 @@ --- sidebar_navigation: title: Using Hotwire with ViewComponents -description: An introduction of how we use Hotwire alongside ViewComponets +description: An introduction of how we use Hotwire alongside ViewComponents keywords: Ruby on Rails, Hotwire, ViewComponents --- diff --git a/docs/development/concepts/inline-editing/basic-example.gif b/docs/development/concepts/inline-editing/basic-example.gif index eb238e823af..b5e1841ec43 100644 Binary files a/docs/development/concepts/inline-editing/basic-example.gif and b/docs/development/concepts/inline-editing/basic-example.gif differ diff --git a/docs/development/concepts/inline-editing/single-view-inline-editing.gif b/docs/development/concepts/inline-editing/single-view-inline-editing.gif index a1aaeb8fcb5..58c4172f3eb 100644 Binary files a/docs/development/concepts/inline-editing/single-view-inline-editing.gif and b/docs/development/concepts/inline-editing/single-view-inline-editing.gif differ diff --git a/docs/development/concepts/resource-changesets/type-switching.gif b/docs/development/concepts/resource-changesets/type-switching.gif index e467d67b757..214683d6966 100644 Binary files a/docs/development/concepts/resource-changesets/type-switching.gif and b/docs/development/concepts/resource-changesets/type-switching.gif differ diff --git a/docs/development/testing/handling-flaky-tests/README.md b/docs/development/testing/handling-flaky-tests/README.md index fe23041249b..e4332bb5224 100644 --- a/docs/development/testing/handling-flaky-tests/README.md +++ b/docs/development/testing/handling-flaky-tests/README.md @@ -21,6 +21,10 @@ Developers notice a failing spec in CI runs related to the PR they are working o The failing spec is suspicious as it seems unrelated to the changes introduced by the commits. +Out-of-hours correlation is a lead, not proof of a datetime bug. Evening or weekend failures can still be caused by +ordinary flakiness, branch-specific regressions, or infrastructure issues. Start by separating build/setup failures from +actual `Unit tests` or `Feature tests`, then look for recurring spec names before concluding that time-sensitive logic is involved. + To get the failing spec names, use `script/github_pr_errors` and give it the URL of the failing run as argument, for example: ```bash @@ -29,6 +33,16 @@ script/github_pr_errors https://github.com/opf/openproject/actions/runs/18215876 There are options to display images or display advice to reproduce the failures. Use `--help` to know more. +To aggregate recent `Test suite` failures and highlight specs that skew outside 09:00-18:00 Europe/Berlin Monday to Friday, +use: + +```bash +export GITHUB_TOKEN=... +script/report_out_of_hours_ci_failures --days 30 +``` + +The report focuses on `dev` and `release/*` runs by default and excludes failures that never reached the unit or feature test steps. + ## Confirming the spec is flaky To confirm the flakiness of the spec, either: diff --git a/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/README.md b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/README.md index 5a8c02eac55..3ab16aaad6b 100644 --- a/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/README.md +++ b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/README.md @@ -73,4 +73,8 @@ Please navigate to *Administration -> GDPR* and you can now review and sign your ![OpenProject DPA in OpenProject administration](openproject_enterprise_guide_gdpr.png) +Once you sign the DPA, you can **download** or **reset** it by clicking one of the respective buttons. + +![GDPR page in OpenProject administration, showing buttons to download signed DPA and to reset DPA](openproject_enterprise_guide_gdpr_dpa_signed.png) + Find out more about [OpenProject's security features](../../../security-and-privacy/statement-on-security/#openproject-security-features). diff --git a/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr.png b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr.png index 3ced3ead628..0f35fe6dd18 100644 Binary files a/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr.png and b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr.png differ diff --git a/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr_dpa_signed.png b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr_dpa_signed.png new file mode 100644 index 00000000000..939899049ae Binary files /dev/null and b/docs/enterprise-guide/enterprise-cloud-guide/gdpr-compliance/openproject_enterprise_guide_gdpr_dpa_signed.png differ diff --git a/docs/enterprise-guide/enterprise-on-premises-guide/activate-enterprise-on-premises/openproject_enterprise_guide_enterprise_token_form.png b/docs/enterprise-guide/enterprise-on-premises-guide/activate-enterprise-on-premises/openproject_enterprise_guide_enterprise_token_form.png index 3571073a920..d5914e92d76 100644 Binary files a/docs/enterprise-guide/enterprise-on-premises-guide/activate-enterprise-on-premises/openproject_enterprise_guide_enterprise_token_form.png and b/docs/enterprise-guide/enterprise-on-premises-guide/activate-enterprise-on-premises/openproject_enterprise_guide_enterprise_token_form.png differ diff --git a/docs/enterprise-guide/support/README.md b/docs/enterprise-guide/support/README.md index 0538216db5a..77190d084a3 100644 --- a/docs/enterprise-guide/support/README.md +++ b/docs/enterprise-guide/support/README.md @@ -50,9 +50,9 @@ The Premium support covers everything from the Basic and Professional support. I Onboarding training in the Premium support plan includes onboarding for a perfect start with OpenProject as well as consulting on special requirements and administrative configurations. -| Service hours | Support channels | Support services | -| ---------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------- | -| Mon-Fri, 9:30 - 17:30 CET
    Mon-Fri, 9:30 am - 5:30 pm ET | - Premium E-Mail support
    - Phone support | - Documentation and user guides
    - Tutorial videos
    | +| Service hours | Support channels | Support services | +| ---------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------ | +| Mon-Fri, 9:30 - 17:30 CET
    Mon-Fri, 9:30 am - 5:30 pm ET | - Premium E-Mail support
    - Phone support | - Documentation and user guides
    - Tutorial videos
    - Remote hands
    - Installation support
    - Upgrade assistance
    | ### Corporate support (on-premises only) diff --git a/docs/getting-started/work-packages-introduction/README.md b/docs/getting-started/work-packages-introduction/README.md index 641de8a638f..64690dfec24 100644 --- a/docs/getting-started/work-packages-introduction/README.md +++ b/docs/getting-started/work-packages-introduction/README.md @@ -27,7 +27,7 @@ A work package in OpenProject can basically be everything you need to keep track ## Create a new work package -To get started, create a new work package in your project, [open the project](../projects/#open-an-existing-project) with the project drop-down menu, navigate to the **work packages module** in the project menu. +To get started, create a new work package in your project, [open the project](../projects/#open-an-existing-project) with the project dropdown menu, navigate to the **work packages module** in the project menu. Within the work packages module, click the + Create button to create a new work package. In the drop down menu, choose which type of work package you want to create, e.g. a task or a milestone. @@ -69,7 +69,7 @@ Click any of the fields to **update a work package**, e.g. description. Click th ![Update a work package in a split screen view in OpenProject](openproject_getting_started_work_packages_wp_detailed_view_edit.png) -To **update the status**, click on the highlighted displayed status on top of the form and select the new status from the drop-down. +To **update the status**, click on the highlighted displayed status on top of the form and select the new status from the dropdown. ![Work package status dropdown menu opened in a detailed work package view in OpenProject](openproject_getting_started_work_packages_update_status.png) diff --git a/docs/glossary/README.md b/docs/glossary/README.md index 80e3bac562a..f874c66fc80 100644 --- a/docs/glossary/README.md +++ b/docs/glossary/README.md @@ -525,7 +525,7 @@ In OpenProject, a Weighted item list can be used both as a [custom field](#custo ### Widget -A widget in OpenProject is defined as a small and customizable element that provides relevant information at a glance. Use widgets on the [My page](#my-page) or on the project dashboardon the [project home page](#project-home). [See all available project overview widgets](../user-guide/project-home/project-widgets/#project-widgets-catalog) and read [how to add a widget to the project overview](../user-guide/project-home/project-widgets/#resize-and-reorder-widgets). +A widget in OpenProject is defined as a small and customizable element that provides relevant information at a glance. Use widgets on the [My page](#my-page) or on the project dashboard of the [project home page](#project-home). [See all available project overview widgets](../user-guide/project-home/project-widgets/#project-widgets-catalog) and read [how to add a widget to the project overview](../user-guide/project-home/project-widgets/#resize-and-reorder-widgets). ### Wiki diff --git a/docs/installation-and-operations/bim-edition/README.md b/docs/installation-and-operations/bim-edition/README.md index a3b433eb672..424f44a55ce 100644 --- a/docs/installation-and-operations/bim-edition/README.md +++ b/docs/installation-and-operations/bim-edition/README.md @@ -25,7 +25,7 @@ For `docker`, `docker-compose`, and `helm-chart` based installations, you are mo Please check what docker image you are using for the steps needed to switch to BIM: -- **openproject/openproject:VERSION-slim**: You need to replace your imag with `openproject/openproject:VERSION-slim-bim`, which is prebuilt with the BIM Edition enabled and the pipeline installed +- **openproject/openproject:VERSION-slim**: You need to replace your image with `openproject/openproject:VERSION-slim-bim`, which is prebuilt with the BIM Edition enabled and the pipeline installed - **openproject/openproject:VERSION**: You are using the [all-in-one container](../installation/docker#all-in-one-container), which includes BIM support. You only need to set the environment variable `OPENPROJECT_EDITION=bim` to the docker container and restart your container. Please note that we recommend against using this all-in-one variant in production systems. ### Packaged installation diff --git a/docs/installation-and-operations/configuration/outbound-emails/sendmail.png b/docs/installation-and-operations/configuration/outbound-emails/sendmail.png index 254ddc14e2c..dc56147ebe4 100644 Binary files a/docs/installation-and-operations/configuration/outbound-emails/sendmail.png and b/docs/installation-and-operations/configuration/outbound-emails/sendmail.png differ diff --git a/docs/installation-and-operations/system-requirements/README.md b/docs/installation-and-operations/system-requirements/README.md index d8fe1639098..a765d030626 100644 --- a/docs/installation-and-operations/system-requirements/README.md +++ b/docs/installation-and-operations/system-requirements/README.md @@ -24,7 +24,7 @@ This is for a single server running OpenProject for up to 200 total users. Depen ## Database -OpenProject officially supports [PostgreSQL version 16](https://www.postgresql.org/) or above since [OpenProject 16.0.0](https://www.openproject.org/docs/release-notes/16-0-0/). +OpenProject officially supports [PostgreSQL version 16](https://www.postgresql.org/) or above since [OpenProject 16.0.0](../../release-notes/16/16-0-0/). PostgreSQL versions 13 - 15 are not officially supported, but MAY continue to work, but could result in incompatibilities and degraded performance in the future. If you are using one of these versions currently, we have a [migration guide on how to upgrade to PostgreSQL 17](../misc/migration-to-postgresql17/) and strongly recommend you to upgrade your DBMS, as there are significant performance improvements. diff --git a/docs/mobile-app-guide/core-features/README.md b/docs/mobile-app-guide/core-features/README.md index e26a9d4274f..1c3e607eca6 100644 --- a/docs/mobile-app-guide/core-features/README.md +++ b/docs/mobile-app-guide/core-features/README.md @@ -36,6 +36,7 @@ The following core features are available in the mobile app: | [Work Packages](work-packages)| Create, view, and edit work packages directly from the app. Work packages are organized for quick access and easy collaboration. | | [Notification Center](notification-center) | Receive updates about comments, mentions, and work package changes — ensuring you never miss an important activity. | | [User Settings](user-settings) | Configure your account, manage app preferences, and tailor notifications to suit your workflow. | +| [Tablet support](tablet-support) | Use OpenProject mobile app on tablets. | > [!TIP] > For a seamless experience, use the mobile app alongside the web or desktop version of OpenProject. The app is designed as a companion, so you can stay informed, respond quickly, and keep your projects moving — even when you’re away from your desk. \ No newline at end of file diff --git a/docs/mobile-app-guide/core-features/tablet-support/README.md b/docs/mobile-app-guide/core-features/tablet-support/README.md new file mode 100644 index 00000000000..24bda328e2b --- /dev/null +++ b/docs/mobile-app-guide/core-features/tablet-support/README.md @@ -0,0 +1,31 @@ +--- +sidebar_navigation: + title: Tablet support + priority: 750 +description: Tablet support and split-screen navigation. +keywords: Mobile app tablet support, tablet ui, tablet, split screen tablet, tablet navigation +--- + +# Tablet support and split-screen navigation + +The OpenProject Mobile App is optimized not only for smartphones but also for larger devices such as **tablets**. The adaptive interface automatically adjusts to the available screen size, providing a more spacious and productive layout on tablets. + +![Work package full view on a tablet device](work-packages_split-screen.png) + +## Split-screen navigation + +On tablets, the mobile app uses a **split-screen layout** that allows you to keep lists and detailed views visible at the same time. + +This makes it easier to navigate through projects and work packages without constantly switching between screens. + +With the split-screen layout you can: +* View a **list of projects or work packages** on one side of the screen. +* Open the **details of a selected project or work package** on the other side. +* Navigate through items while keeping the list visible. +* Quickly switch between work packages when reviewing or updating tasks. + +This layout helps maintain context while browsing and makes it easier to work with multiple items in sequence. + +![Work package list with a work package open on a split view on a tablet device](work-packages_list.png) + +The tablet interface therefore provides a navigation experience that is closer to the desktop version while remaining fully optimized for touch interaction. \ No newline at end of file diff --git a/docs/mobile-app-guide/core-features/tablet-support/work-packages_list.png b/docs/mobile-app-guide/core-features/tablet-support/work-packages_list.png new file mode 100644 index 00000000000..c15280945ad Binary files /dev/null and b/docs/mobile-app-guide/core-features/tablet-support/work-packages_list.png differ diff --git a/docs/mobile-app-guide/core-features/tablet-support/work-packages_split-screen.png b/docs/mobile-app-guide/core-features/tablet-support/work-packages_split-screen.png new file mode 100644 index 00000000000..b4f6d1f7e37 Binary files /dev/null and b/docs/mobile-app-guide/core-features/tablet-support/work-packages_split-screen.png differ diff --git a/docs/mobile-app-guide/first-steps/README.md b/docs/mobile-app-guide/first-steps/README.md index ed508b9f64e..9ac74a68640 100644 --- a/docs/mobile-app-guide/first-steps/README.md +++ b/docs/mobile-app-guide/first-steps/README.md @@ -53,7 +53,7 @@ Enter the complete **base URL** of your instance (for example, `https://yourcomp ![Mobile app browser sign in screen](mobile-app-browser-sign-in.png) * The app will ask you for a permission to have full access to the **OpenProject API v3** to authorize your account and securely connect to your workspace. -![OpenProject mobile app browser API v3 authorisation screen](mobile-browser-oauth-authorization.png) +![OpenProject mobile app browser API v3 authorization screen](mobile-browser-oauth-authorization.png) ## Start Exploring diff --git a/docs/mobile-app-guide/first-steps/login-troubleshooting/README.md b/docs/mobile-app-guide/first-steps/login-troubleshooting/README.md index 56f0c955acc..01e59a71295 100644 --- a/docs/mobile-app-guide/first-steps/login-troubleshooting/README.md +++ b/docs/mobile-app-guide/first-steps/login-troubleshooting/README.md @@ -26,7 +26,7 @@ The URL you entered may be incorrect, inaccessible, or not using HTTPS. ## OAuth Application Not Enabled **Symptom:** -Login fails with a browser error such as _“An authorization error has occurred. The client is not authorised to perform this request using this method.”,_ or you are redirected back to the login screen without authentication. +Login fails with a browser error such as _“An authorization error has occurred. The client is not authorized to perform this request using this method.”, or you are redirected back to the login screen without authentication. **Cause:** The mobile app uses OAuth 2.0 for secure authentication. If the built-in OAuth applications are not enabled in your instance, the app cannot log you in. @@ -40,7 +40,7 @@ The mobile app uses OAuth 2.0 for secure authentication. If the built-in OAuth a ## Instance Not on Minimum Supported Version **Symptom:** -You know that your instance is running not on the minimum supported version, OpenProject 17.0.0, and the login fails with a browser error such as _“An authorization error has occurred. The client is not authorised to perform this request using this method.”_. +You know that your instance is running not on the minimum supported version, OpenProject 17.0.0, and the login fails with a browser error such as _“An authorization error has occurred. The client is not authorized to perform this request using this method.”_. **Cause:** The OpenProject Mobile App requires your instance to be on **OpenProject version 17.0.0 or higher**. diff --git a/docs/project-management-guide/8-closing-phase/08.02.png b/docs/project-management-guide/8-closing-phase/08.02.png index 25c25722e69..59a0876d9a0 100644 Binary files a/docs/project-management-guide/8-closing-phase/08.02.png and b/docs/project-management-guide/8-closing-phase/08.02.png differ diff --git a/docs/project-management-guide/8-closing-phase/08.04.png b/docs/project-management-guide/8-closing-phase/08.04.png index 76531479c7a..5813234f858 100644 Binary files a/docs/project-management-guide/8-closing-phase/08.04.png and b/docs/project-management-guide/8-closing-phase/08.04.png differ diff --git a/docs/release-notes/12/12-1-0/openproject-include-projects.gif b/docs/release-notes/12/12-1-0/openproject-include-projects.gif index 84b605856c4..ba9207b5658 100644 Binary files a/docs/release-notes/12/12-1-0/openproject-include-projects.gif and b/docs/release-notes/12/12-1-0/openproject-include-projects.gif differ diff --git a/docs/release-notes/12/12-4-0/openproject-team-planner-work-week.gif b/docs/release-notes/12/12-4-0/openproject-team-planner-work-week.gif index a9adcd45bb3..9775189a2c8 100644 Binary files a/docs/release-notes/12/12-4-0/openproject-team-planner-work-week.gif and b/docs/release-notes/12/12-4-0/openproject-team-planner-work-week.gif differ diff --git a/docs/release-notes/12/12-5-0/openproject-nextcloud-upload.gif b/docs/release-notes/12/12-5-0/openproject-nextcloud-upload.gif index 646c4b3ceb2..c2a5a091b85 100644 Binary files a/docs/release-notes/12/12-5-0/openproject-nextcloud-upload.gif and b/docs/release-notes/12/12-5-0/openproject-nextcloud-upload.gif differ diff --git a/docs/release-notes/16-0-0/README.md b/docs/release-notes/16/16-0-0/README.md similarity index 92% rename from docs/release-notes/16-0-0/README.md rename to docs/release-notes/16/16-0-0/README.md index a2f30fedcc1..b46ea241fef 100644 --- a/docs/release-notes/16-0-0/README.md +++ b/docs/release-notes/16/16-0-0/README.md @@ -32,11 +32,11 @@ Take a look at our release video showing the most important features introduced Meeting organization becomes even easier with OpenProject 16.0: Meeting backlogs allow users to collect, manage, and prepare agenda items more flexibly — both for one-time meetings and for recurring meeting series. -In one-time meetings, the new [**Agenda backlog**](../../user-guide/meetings/one-time-meetings/#agenda-backlogs) stores topics that are not yet assigned to the current meeting but may be added later. +In one-time meetings, the new [**Agenda backlog**](../../../user-guide/meetings/one-time-meetings/#agenda-backlogs) stores topics that are not yet assigned to the current meeting but may be added later. ![A one-time meeting in OpenProject with an Agenda backlog and info to 'Drag items here or create a new one'.](openproject-16-0-meeting-backlogs-one-time-highlighted.png) -In recurring meetings, the shared [**Series backlog**](../../user-guide/meetings/recurring-meetings/#meeting-backlogs-for-recurring-meetings) helps track open points across all meeting occurrences and move items between them as priorities change. +In recurring meetings, the shared [**Series backlog**](../../../user-guide/meetings/recurring-meetings/#meeting-backlogs-for-recurring-meetings) helps track open points across all meeting occurrences and move items between them as priorities change. ![A recurring meeting in OpenProject with a Series backlog and and options to Edit, add notes, Move to current meeting or Remove from agenda.](openproject-16-0-meeting-backlogs-recurring-options.png) @@ -64,7 +64,7 @@ All users with these permissions then see an "Internal comment" checkbox when ad > [!NOTE] > Starting with 16.0, **files uploaded in the Activity tab will not be included in the Files tab**. Even though internal comments are the technical trigger for this change, it applies to both regular and internal comments. -Find out more about [internal comments in this user guide](../../user-guide/activity/#internal-comments-enterprise-add-on) and [this blog article](https://www.openproject.org/blog/internal-comments/). +Find out more about [internal comments in this user guide](../../../user-guide/activity/#internal-comments-enterprise-add-on) and [this blog article](https://www.openproject.org/blog/internal-comments/). ## Automatically generated work package subjects (Enterprise add-on) @@ -74,11 +74,11 @@ OpenProject now supports automatically generated subjects for work packages. Thi This is especially useful for structured processes such as vacation requests, IT tickets, or maintenance reports, where consistent naming is required. Subject patterns can include static text as well as dynamic placeholders like project name, work package type, or custom field values. -Get an [introduction in the user guide](../../user-guide/work-packages/automatic-subjects/), learn more about [configuring automatically generated work package subjects in OpenProject system administration guide](../../system-admin-guide/manage-work-packages/work-package-types/automatic-subjects/), or consult this [blog article](https://www.openproject.org/blog/automatically-generated-work-package-subjects/) for more use case examples. +Get an [introduction in the user guide](../../../user-guide/work-packages/automatic-subjects/), learn more about [configuring automatically generated work package subjects in OpenProject system administration guide](../../../system-admin-guide/manage-work-packages/work-package-types/automatic-subjects/), or consult this [blog article](https://www.openproject.org/blog/automatically-generated-work-package-subjects/) for more use case examples. ## Separate time tracking module with calendar view -OpenProject 16.0 offers a separate time tracking module with a calendar view. It is accessible from the global view and listed in the left side bar navigation called [My time tracking](../../user-guide/time-and-costs/my-time-tracking/). There, users can view and edit their logged time with start and end times. Users can switch between daily, weekly, work week and monthly views and also log new time entries directly by clicking in the calendar. +OpenProject 16.0 offers a separate time tracking module with a calendar view. It is accessible from the global view and listed in the left side bar navigation called [My time tracking](../../../user-guide/time-and-costs/my-time-tracking/). There, users can view and edit their logged time with start and end times. Users can switch between daily, weekly, work week and monthly views and also log new time entries directly by clicking in the calendar. Each day shows the sum of the tracked time, and in the weekly and monthly views, the total tracked time is displayed in the lower right corner. @@ -86,7 +86,7 @@ Each day shows the sum of the tracked time, and in the weekly and monthly views, Please note that this module has to be activated by an administrator first. Navigate to *Administration → Time and costs → Defaults* and check the box next to 'Allow exact time tracking' to enable tracking start and finish dates. If 'Allow exact time tracking' is enabled, the calendar becomes the default view for the My time tracking module. If 'Require exact times' is checked, users must provide both start and end times when logging time. Otherwise, the list view remains the default. In the calendar view, all entries are then displayed at the top of the respective day column. -Learn more about My time tracking module in [this user guide](../../user-guide/time-and-costs/my-time-tracking/) and [this blog article](https://www.openproject.org/blog/time-tracking-module/). +Learn more about My time tracking module in [this user guide](../../../user-guide/time-and-costs/my-time-tracking/) and [this blog article](https://www.openproject.org/blog/time-tracking-module/). ### Time entries with legally required mandatory fields: start time and finish time @@ -104,7 +104,7 @@ From time to time an Enterprise add-on is released for the free Community versio The work package graph widgets display information about the work packages within a project and can be shown in different views, such as bar graphs or pie charts. -[Learn more about this feature in our user guide](../../user-guide/project-home/project-widgets/#work-package-graph-widgets). +[Learn more about this feature in our user guide](../../../user-guide/project-home/project-widgets/#work-package-graph-widgets). ![Different graphs displayed on a project overview page in OpenProject: Work package status in a pie chart, work packages progress in a graph with percentages, closed + open work packages sorted by type and number of assignees.](openproject-project-reports.png) @@ -116,7 +116,7 @@ As requested by our users, you can now add a parent work package relation by cho ## Save work package export configuration -When [exporting a (public or private) work package table](../../user-guide/work-packages/exporting/), users can now save their configuration settings, e.g. a specific order and display of columns or long text fields. This saves time and allows users to share the export settings with their team (e.g. for a defects and approval report). Please note that this setting is not individual and will **change the default configuration for this specific format and type for everyone**. +When [exporting a (public or private) work package table](../../../user-guide/work-packages/exporting/), users can now save their configuration settings, e.g. a specific order and display of columns or long text fields. This saves time and allows users to share the export settings with their team (e.g. for a defects and approval report). Please note that this setting is not individual and will **change the default configuration for this specific format and type for everyone**. ![OpenProject work package table export modal with a highlighted checkbox to save settings.](openproject-16-0-save-export-settings-highlighted.png) @@ -140,7 +140,7 @@ OpenProject 16.0 introduces a major improvement for customers of the Enterprise Instead of mutually acting as OAuth servers and clients, both OpenProject and Nextcloud can now authenticate against a common Identity Provider (IDP). This allows OpenProject to reuse the user session to call Nextcloud APIs directly — improving the user experience and reducing complexity in daily workflows. -Please see [our system admin guide](../../system-admin-guide/integrations/nextcloud/oidc-sso/) to learn how to set up this integration. +Please see [our system admin guide](../../../system-admin-guide/integrations/nextcloud/oidc-sso/) to learn how to set up this integration. This is the first version of OpenProject to support this new integration method with Nextcloud. Since this feature was not yet exposed to large installations, we still consider it experimental. Please share your feedback regarding this new feature with us and stay tuned @@ -148,7 +148,7 @@ for further enhancements around it. ## Breaking: API requests with JWT issued by OpenID Connect provider require scope -In [OpenProject 14.4.0](../../release-notes/14/14-0-0/) we introduced the possibility to access the OpenProject API through a JSON Web Token created by an OpenID Connect +In [OpenProject 14.4.0](../../../release-notes/14/14-0-0/) we introduced the possibility to access the OpenProject API through a JSON Web Token created by an OpenID Connect provider. Back then we only intended them to be used in the context of our APIv3. However, as OpenProject evolves further, we want to be able to use them in additional contexts. Starting with OpenProject 16.0.0, we will therefore require all tokens to carry a scope called `api_v3` for API requests to our APIv3. This is consistent with other tokens issued by OpenProject itself. @@ -300,4 +300,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [Gzyyy](https://crowdin.com/profile/gzyyy), for a great number of translations into Chinese simplified. - [rlmpereira](https://crowdin.com/profile/rlmpereira), for a great number of translations into Portuguese. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-0-0/openproject-16-0-automatically-generated-work-package-subjects-candidate-interview-explained.png b/docs/release-notes/16/16-0-0/openproject-16-0-automatically-generated-work-package-subjects-candidate-interview-explained.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-automatically-generated-work-package-subjects-candidate-interview-explained.png rename to docs/release-notes/16/16-0-0/openproject-16-0-automatically-generated-work-package-subjects-candidate-interview-explained.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-internal-comment.png b/docs/release-notes/16/16-0-0/openproject-16-0-internal-comment.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-internal-comment.png rename to docs/release-notes/16/16-0-0/openproject-16-0-internal-comment.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-meeting-backlogs-one-time-highlighted.png b/docs/release-notes/16/16-0-0/openproject-16-0-meeting-backlogs-one-time-highlighted.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-meeting-backlogs-one-time-highlighted.png rename to docs/release-notes/16/16-0-0/openproject-16-0-meeting-backlogs-one-time-highlighted.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-meeting-backlogs-recurring-options.png b/docs/release-notes/16/16-0-0/openproject-16-0-meeting-backlogs-recurring-options.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-meeting-backlogs-recurring-options.png rename to docs/release-notes/16/16-0-0/openproject-16-0-meeting-backlogs-recurring-options.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-my-time-tracking-work-week-final.png b/docs/release-notes/16/16-0-0/openproject-16-0-my-time-tracking-work-week-final.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-my-time-tracking-work-week-final.png rename to docs/release-notes/16/16-0-0/openproject-16-0-my-time-tracking-work-week-final.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-parent-relation.png b/docs/release-notes/16/16-0-0/openproject-16-0-parent-relation.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-parent-relation.png rename to docs/release-notes/16/16-0-0/openproject-16-0-parent-relation.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-save-export-settings-highlighted.png b/docs/release-notes/16/16-0-0/openproject-16-0-save-export-settings-highlighted.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-save-export-settings-highlighted.png rename to docs/release-notes/16/16-0-0/openproject-16-0-save-export-settings-highlighted.png diff --git a/docs/release-notes/16-0-0/openproject-16-0-timesheet-hours-user-day.png b/docs/release-notes/16/16-0-0/openproject-16-0-timesheet-hours-user-day.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-16-0-timesheet-hours-user-day.png rename to docs/release-notes/16/16-0-0/openproject-16-0-timesheet-hours-user-day.png diff --git a/docs/release-notes/16-0-0/openproject-project-reports.png b/docs/release-notes/16/16-0-0/openproject-project-reports.png similarity index 100% rename from docs/release-notes/16-0-0/openproject-project-reports.png rename to docs/release-notes/16/16-0-0/openproject-project-reports.png diff --git a/docs/release-notes/16-0-1/README.md b/docs/release-notes/16/16-0-1/README.md similarity index 100% rename from docs/release-notes/16-0-1/README.md rename to docs/release-notes/16/16-0-1/README.md diff --git a/docs/release-notes/16-1-0/README.md b/docs/release-notes/16/16-1-0/README.md similarity index 97% rename from docs/release-notes/16-1-0/README.md rename to docs/release-notes/16/16-1-0/README.md index 9a3cf22caa5..86d42ca335d 100644 --- a/docs/release-notes/16-1-0/README.md +++ b/docs/release-notes/16/16-1-0/README.md @@ -33,7 +33,7 @@ You’ll find the full life cycle directly in the project overview page, where y > [!NOTE] > With the Enterprise add-on available in the Premium plan or higher, you can configure existing project phases and phase gates and even create new ones. This is done in the global settings. The project-level features are available in all editions, with pre-defined phases based on the [open source PM² framework](https://www.openproject.org/pm2/). -[Read more about working with a project life cycle in OpenProject](../../system-admin-guide/projects/project-life-cycle/). +[Read more about working with a project life cycle in OpenProject](../../../system-admin-guide/projects/project-life-cycle/). ### Export meetings in PDF format @@ -51,7 +51,7 @@ The export is available via the More (⋯) menu for both one-time meetings and i The PDF is generated in A4 format and includes a clearly structured layout. -[Learn more about exporting meetings in PDF format in our documentation](../../user-guide/meetings/one-time-meetings/#export-a-meeting). +[Learn more about exporting meetings in PDF format in our documentation](../../../user-guide/meetings/one-time-meetings/#export-a-meeting). ![Overlay of Export PDF options for OpenProject meetings](openproject-16-1-export-meeting-to-pdf.png) @@ -69,7 +69,7 @@ To make setting reminders even quicker, OpenProject now offers pre-filled option Selecting one of the quick options will open the reminder dialog with a pre-filled date and time – typically at 9:00 local time on the selected future day. You can still adjust the date, time, and add a note before saving the reminder. -[Learn more about work package reminders in our documentation](../../user-guide/work-packages/edit-work-package/#work-package-reminders). +[Learn more about work package reminders in our documentation](../../../user-guide/work-packages/edit-work-package/#work-package-reminders). ![Dropdown menu on a work package when clicking on the reminder icon, with options to quickly choose a date to be reminded](openproject-16-1-reminder-options.png) @@ -92,7 +92,7 @@ Please note that negative lags can be counterintuitive: > [!NOTE] > **Only working days** are taken into account. For example: If work package A finishes on a Tuesday and Saturday/Sunday are non-working days, then a lag of -3 will schedule its successor (work package B) to start on the previous Friday. -[Learn more about work package relations in our documentation](../../user-guide/work-packages/work-package-relations-hierarchies/#work-package-relations). +[Learn more about work package relations in our documentation](../../../user-guide/work-packages/work-package-relations-hierarchies/#work-package-relations). ### Display hierarchy trees for hierarchy custom fields (Enterprise add-on) @@ -102,7 +102,7 @@ This tree helps you understand the position of the current item in the overall h Clicking on any entry in the tree opens that item in the same view, making it easy to move through even complex hierarchies without losing context. -[Learn more about custom fields in our system admin guide](../../system-admin-guide/custom-fields/). +[Learn more about custom fields in our system admin guide](../../../system-admin-guide/custom-fields/). ![Example of a hierarchy custom field with the new visualization, the hierarchical tree](openproject-hierarchy-custom-field-tree.png) @@ -220,4 +220,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [rmiyata](https://crowdin.com/profile/rmiyata), for a great number of translations into Japanese. - [William](https://crowdin.com/profile/williamfromtw), for a great number of translations into Chinese Traditional. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-1-0/openproject-16-1-export-meeting-to-pdf.png b/docs/release-notes/16/16-1-0/openproject-16-1-export-meeting-to-pdf.png similarity index 100% rename from docs/release-notes/16-1-0/openproject-16-1-export-meeting-to-pdf.png rename to docs/release-notes/16/16-1-0/openproject-16-1-export-meeting-to-pdf.png diff --git a/docs/release-notes/16-1-0/openproject-16-1-negative-lag.png b/docs/release-notes/16/16-1-0/openproject-16-1-negative-lag.png similarity index 100% rename from docs/release-notes/16-1-0/openproject-16-1-negative-lag.png rename to docs/release-notes/16/16-1-0/openproject-16-1-negative-lag.png diff --git a/docs/release-notes/16-1-0/openproject-16-1-project-life-cycle-project-overview-highlighted.png b/docs/release-notes/16/16-1-0/openproject-16-1-project-life-cycle-project-overview-highlighted.png similarity index 100% rename from docs/release-notes/16-1-0/openproject-16-1-project-life-cycle-project-overview-highlighted.png rename to docs/release-notes/16/16-1-0/openproject-16-1-project-life-cycle-project-overview-highlighted.png diff --git a/docs/release-notes/16-1-0/openproject-16-1-reminder-options.png b/docs/release-notes/16/16-1-0/openproject-16-1-reminder-options.png similarity index 100% rename from docs/release-notes/16-1-0/openproject-16-1-reminder-options.png rename to docs/release-notes/16/16-1-0/openproject-16-1-reminder-options.png diff --git a/docs/release-notes/16-1-0/openproject-hierarchy-custom-field-tree.png b/docs/release-notes/16/16-1-0/openproject-hierarchy-custom-field-tree.png similarity index 100% rename from docs/release-notes/16-1-0/openproject-hierarchy-custom-field-tree.png rename to docs/release-notes/16/16-1-0/openproject-hierarchy-custom-field-tree.png diff --git a/docs/release-notes/16-1-1/README.md b/docs/release-notes/16/16-1-1/README.md similarity index 100% rename from docs/release-notes/16-1-1/README.md rename to docs/release-notes/16/16-1-1/README.md diff --git a/docs/release-notes/16-2-0/README.md b/docs/release-notes/16/16-2-0/README.md similarity index 94% rename from docs/release-notes/16-2-0/README.md rename to docs/release-notes/16/16-2-0/README.md index 97e6a5f93f4..9355fcbea59 100644 --- a/docs/release-notes/16-2-0/README.md +++ b/docs/release-notes/16/16-2-0/README.md @@ -28,7 +28,7 @@ Please note that if you have customized the sidebar colors, your individual sett ### Primer design system added to project create and project copy forms -The forms for [creating and copying projects](../../getting-started/projects/#create-a-new-project) now use the [Primer design system](https://www.openproject.org/blog/primer-design-system/), providing a cleaner and more consistent interface. This improves accessibility and ensures the process remains just as familiar. +The forms for [creating and copying projects](../../../getting-started/projects/#create-a-new-project) now use the [Primer design system](https://www.openproject.org/blog/primer-design-system/), providing a cleaner and more consistent interface. This improves accessibility and ensures the process remains just as familiar. If you **copy** a project or create a project **based on a template**, you will immediately be able to choose which modules and parts you want to copy and which to skip. Also, the option to activate sending email notifications during the project copy is much more visible. Before 16.2, you had to click on Copy Options to unfold. @@ -38,7 +38,7 @@ If you **copy** a project or create a project **based on a template**, you will PDF work package exports in OpenProject now support **non-Latin characters and emojis**. This means that project information written in scripts such as Chinese, Arabic, Cyrillic, or accented characters — as well as any emojis you use in work packages, meetings, or descriptions — will display correctly in exported PDF files. This ensures that documents generated from OpenProject reflect your content accurately, no matter which language or symbols you use. -[Read more about work package PDF exports with OpenProject](../../user-guide/work-packages/exporting/) +[Read more about work package PDF exports with OpenProject](../../../user-guide/work-packages/exporting/) ![PDF export extract from an OpenProject work package that contains emojis, symbols and non-Latin characters](openproject-16-2-pdf-export.png) @@ -50,13 +50,13 @@ The + Relation menu has been reorganized with a new two-level structure, making ![OpenProject work package Relations tab when clicking on +Relation, showing some relations unfolded under 'Other relations'](openproject-user-guide-relations-second-level-navigation.png) -[Read more about relations in OpenProject](../../user-guide/work-packages/work-package-relations-hierarchies/). +[Read more about relations in OpenProject](../../../user-guide/work-packages/work-package-relations-hierarchies/). ### Select formats for custom fields and project attributes earlier in creation process When creating a new custom field, you can now select the format — such as text, list, or date — right at the beginning, on the index page of custom fields and project attributes. The same applies to project attributes. This streamlines the creation process and avoids unnecessary steps, since each type opens directly in the appropriate form. This improvement is especially helpful for administrators who frequently set up new custom fields or project attributes. -Read more about how to manage [custom fields](../../system-admin-guide/custom-fields/) and [project attributes](../../user-guide/projects/project-settings/project-attributes/) in OpenProject. +Read more about how to manage [custom fields](../../../system-admin-guide/custom-fields/) and [project attributes](../../../user-guide/projects/project-settings/project-attributes/) in OpenProject. ![OpenProject administration to add a new custom field: Dropdown lets you choose the type during the first step](openproject-16-2-custom-field-type.png) @@ -65,11 +65,11 @@ Read more about how to manage [custom fields](../../system-admin-guide/custom-fi In the **My time tracking** module, the week and work week views now automatically collapse future and past days while keeping today expanded. This helps you focus on logging time for the current and past days without being distracted by empty future slots. If you view a past week, all days are expanded as before. > [!TIP] -> Don't know the My time tracking module yet? We released it with [OpenProject 16.0.0](../../release-notes/16-0-0/). This module shows individual time entries in a calendar or list view, and is very helpful if you use start and end times for your time tracking. +> Don't know the My time tracking module yet? We released it with [OpenProject 16.0.0](../16-0-0/). This module shows individual time entries in a calendar or list view, and is very helpful if you use start and end times for your time tracking. ![OpenProject's My time tracking module in list view, only Today expanded](user-guide-my-time-tracking-module-list-view.png) -[Learn more about the My time tracking module in our documentation](../../user-guide/time-and-costs/my-time-tracking/). +[Learn more about the My time tracking module in our documentation](../../../user-guide/time-and-costs/my-time-tracking/). ### Option to disable keyboard shortcuts for better accessibility @@ -83,7 +83,7 @@ When you set a reminder for a work package, OpenProject now confirms this with a ![User information that appears when setting a reminder: Reminder set successfully. You will receive a notification for this work package tomorrow.](openproject-16-2-reminder.png) -[Learn more about work package reminders in OpenProject](../../user-guide/work-packages/edit-work-package/#work-package-reminders). +[Learn more about work package reminders in OpenProject](../../../user-guide/work-packages/edit-work-package/#work-package-reminders). ## Important technical changes @@ -93,7 +93,7 @@ OpenProject 16.2 adds a **SCIM server API**, available as an Enterprise add-on i ![OpenProject administration with option to add a new SCIM client](openproject-16-2-scim-api.png) -[Learn more about authentication methods with OpenProject](../../system-admin-guide/authentication/). +[Learn more about authentication methods with OpenProject](../../../system-admin-guide/authentication/). ### API support for internal comments @@ -101,7 +101,7 @@ The API has been extended to fully support **internal comments on work packages* ### Commenting on work packages fires a webhook -When a comment is added to a work package, it now triggers a webhook. This enables external systems to react in real time to comments in OpenProject, for example by updating dashboards or notifying integrated tools. [See our system admin guide to learn more about webhooks for OpenProject](../../system-admin-guide/api-and-webhooks/#webhooks). +When a comment is added to a work package, it now triggers a webhook. This enables external systems to react in real time to comments in OpenProject, for example by updating dashboards or notifying integrated tools. [See our system admin guide to learn more about webhooks for OpenProject](../../../system-admin-guide/api-and-webhooks/#webhooks). @@ -226,4 +226,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [rmiyata](https://crowdin.com/profile/rmiyata), for a great number of translations into Japanese. - [rubenpedrolopez](https://crowdin.com/profile/rubenpedrolopez), for a great number of translations into Spanish. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-2-0/openproject-16-2-create-project.png b/docs/release-notes/16/16-2-0/openproject-16-2-create-project.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-create-project.png rename to docs/release-notes/16/16-2-0/openproject-16-2-create-project.png diff --git a/docs/release-notes/16-2-0/openproject-16-2-custom-field-type.png b/docs/release-notes/16/16-2-0/openproject-16-2-custom-field-type.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-custom-field-type.png rename to docs/release-notes/16/16-2-0/openproject-16-2-custom-field-type.png diff --git a/docs/release-notes/16-2-0/openproject-16-2-design-updates.png b/docs/release-notes/16/16-2-0/openproject-16-2-design-updates.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-design-updates.png rename to docs/release-notes/16/16-2-0/openproject-16-2-design-updates.png diff --git a/docs/release-notes/16-2-0/openproject-16-2-pdf-export.png b/docs/release-notes/16/16-2-0/openproject-16-2-pdf-export.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-pdf-export.png rename to docs/release-notes/16/16-2-0/openproject-16-2-pdf-export.png diff --git a/docs/release-notes/16-2-0/openproject-16-2-reminder.png b/docs/release-notes/16/16-2-0/openproject-16-2-reminder.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-reminder.png rename to docs/release-notes/16/16-2-0/openproject-16-2-reminder.png diff --git a/docs/release-notes/16-2-0/openproject-16-2-scim-api.png b/docs/release-notes/16/16-2-0/openproject-16-2-scim-api.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-16-2-scim-api.png rename to docs/release-notes/16/16-2-0/openproject-16-2-scim-api.png diff --git a/docs/release-notes/16-2-0/openproject-user-guide-account-settings-interface.png b/docs/release-notes/16/16-2-0/openproject-user-guide-account-settings-interface.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-user-guide-account-settings-interface.png rename to docs/release-notes/16/16-2-0/openproject-user-guide-account-settings-interface.png diff --git a/docs/release-notes/16-2-0/openproject-user-guide-relations-second-level-navigation.png b/docs/release-notes/16/16-2-0/openproject-user-guide-relations-second-level-navigation.png similarity index 100% rename from docs/release-notes/16-2-0/openproject-user-guide-relations-second-level-navigation.png rename to docs/release-notes/16/16-2-0/openproject-user-guide-relations-second-level-navigation.png diff --git a/docs/release-notes/16-2-0/user-guide-my-time-tracking-module-list-view.png b/docs/release-notes/16/16-2-0/user-guide-my-time-tracking-module-list-view.png similarity index 100% rename from docs/release-notes/16-2-0/user-guide-my-time-tracking-module-list-view.png rename to docs/release-notes/16/16-2-0/user-guide-my-time-tracking-module-list-view.png diff --git a/docs/release-notes/16-2-1/README.md b/docs/release-notes/16/16-2-1/README.md similarity index 100% rename from docs/release-notes/16-2-1/README.md rename to docs/release-notes/16/16-2-1/README.md diff --git a/docs/release-notes/16-2-2/README.md b/docs/release-notes/16/16-2-2/README.md similarity index 100% rename from docs/release-notes/16-2-2/README.md rename to docs/release-notes/16/16-2-2/README.md diff --git a/docs/release-notes/16-3-0/README.md b/docs/release-notes/16/16-3-0/README.md similarity index 96% rename from docs/release-notes/16-3-0/README.md rename to docs/release-notes/16/16-3-0/README.md index 88c3582e777..09527a217d1 100644 --- a/docs/release-notes/16-3-0/README.md +++ b/docs/release-notes/16/16-3-0/README.md @@ -38,7 +38,7 @@ The setting is available as a checkbox in the meeting template form and lets you ![Screenshot showing OpenProject meeting template with overlay to disable email notifications](openproject-16-3-meeting-notifications-highlighted.png) -[Learn more about meeting management with OpenProject](../../user-guide/meetings/). +[Learn more about meeting management with OpenProject](../../../user-guide/meetings/). ### Ongoing timers shown in the My time tracking module @@ -54,19 +54,19 @@ Not familiar with the My time tracking module yet? [Learn more about it in our b In OpenProject 15.5, we introduced the ability to display a sum for the % Complete column in work package tables. In 16.3, this feature has been improved to ensure **accurate sums across different progress calculation modes**. This applies especially when some work packages do not contain values for Work or Remaining work. -[Learn more about progress tracking and reporting with OpenProject](../../user-guide/time-and-costs/progress-tracking/). +[Learn more about progress tracking and reporting with OpenProject](../../../user-guide/time-and-costs/progress-tracking/). ### Nextcloud Health check: Indicate missing token exchange capability (Enterprise add-on) Administrators using the Nextcloud integration in the Corporate plan can now benefit from a more specific health check. If **token exchange is configured but not supported by the linked identity provider** (e.g. due to older OIDC settings), the new check will now clearly identify this issue. This helps diagnose connection problems more reliably and avoids misleading error messages about token refresh failures. -[Learn more about monitoring your OpenProject installation](../../installation-and-operations/operation/monitoring/). +[Learn more about monitoring your OpenProject installation](../../../installation-and-operations/operation/monitoring/). ### Autocomplete for cost reporting user and work package fields Creating **cost reports** is now easier and faster. OpenProject 16.3 introduces **autocomplete for key filter fields** like User, Project and Work package, helping you find the right person or task with just a few keystrokes. -[Learn more about cost reporting with OpenProject](../../user-guide/time-and-costs/reporting/). +[Learn more about cost reporting with OpenProject](../../../user-guide/time-and-costs/reporting/). @@ -150,5 +150,5 @@ Last but not least, we are very grateful for our very engaged translation contri - [William](https://crowdin.com/profile/williamfromtw), for a great number of translations into Chinese Traditional. - [OlhaTrotska](https://crowdin.com/profile/OlhaTrotska), for a great number of translations into Ukrainian. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-3-0/openproject-16-3-header-menu-highlighted.png b/docs/release-notes/16/16-3-0/openproject-16-3-header-menu-highlighted.png similarity index 100% rename from docs/release-notes/16-3-0/openproject-16-3-header-menu-highlighted.png rename to docs/release-notes/16/16-3-0/openproject-16-3-header-menu-highlighted.png diff --git a/docs/release-notes/16-3-0/openproject-16-3-meeting-notifications-highlighted.png b/docs/release-notes/16/16-3-0/openproject-16-3-meeting-notifications-highlighted.png similarity index 100% rename from docs/release-notes/16-3-0/openproject-16-3-meeting-notifications-highlighted.png rename to docs/release-notes/16/16-3-0/openproject-16-3-meeting-notifications-highlighted.png diff --git a/docs/release-notes/16-3-0/openproject-16-3-my-time-tracking-timer-calendar-view-highlighted.png b/docs/release-notes/16/16-3-0/openproject-16-3-my-time-tracking-timer-calendar-view-highlighted.png similarity index 100% rename from docs/release-notes/16-3-0/openproject-16-3-my-time-tracking-timer-calendar-view-highlighted.png rename to docs/release-notes/16/16-3-0/openproject-16-3-my-time-tracking-timer-calendar-view-highlighted.png diff --git a/docs/release-notes/16-3-0/openproject_user_guide_log_time_right_hand_overlay_menu.png b/docs/release-notes/16/16-3-0/openproject_user_guide_log_time_right_hand_overlay_menu.png similarity index 100% rename from docs/release-notes/16-3-0/openproject_user_guide_log_time_right_hand_overlay_menu.png rename to docs/release-notes/16/16-3-0/openproject_user_guide_log_time_right_hand_overlay_menu.png diff --git a/docs/release-notes/16-3-1/README.md b/docs/release-notes/16/16-3-1/README.md similarity index 87% rename from docs/release-notes/16-3-1/README.md rename to docs/release-notes/16/16-3-1/README.md index 57a2d76d86a..29dee7915c7 100644 --- a/docs/release-notes/16-3-1/README.md +++ b/docs/release-notes/16/16-3-1/README.md @@ -12,7 +12,7 @@ Release date: 2025-08-13 We released OpenProject [OpenProject 16.3.1](https://community.openproject.org/versions/2218). -A bug was identified that prevents the user account menu from displaying correctly if you use a [direct login provider](../../system-admin-guide/authentication/login-registration-settings/) instead of the standard login form. +A bug was identified that prevents the user account menu from displaying correctly if you use a [direct login provider](../../../system-admin-guide/authentication/login-registration-settings/) instead of the standard login form. If you are not using a direct login provider, you are not affected by this. The release also contains some additional bug fixes that were not ready in time for the 16.3.0 release. diff --git a/docs/release-notes/16-3-2/README.md b/docs/release-notes/16/16-3-2/README.md similarity index 100% rename from docs/release-notes/16-3-2/README.md rename to docs/release-notes/16/16-3-2/README.md diff --git a/docs/release-notes/16-4-0/README.md b/docs/release-notes/16/16-4-0/README.md similarity index 96% rename from docs/release-notes/16-4-0/README.md rename to docs/release-notes/16/16-4-0/README.md index 7fc33efc580..17facf52229 100644 --- a/docs/release-notes/16-4-0/README.md +++ b/docs/release-notes/16/16-4-0/README.md @@ -25,7 +25,7 @@ Users can now enable **automatic color mode** under *Account settings → Interf > [!NOTE] > If a user has enabled dark mode — either by default or through automatic switching — this overrides the instance’s design settings for that user. -[Learn more about the *Look and feel* options in OpenProject](../../user-guide/account-settings/#look-and-feel). +[Learn more about the *Look and feel* options in OpenProject](../../../user-guide/account-settings/#look-and-feel). ![Screenshot of OpenProject 16.4: Account settings to adjust color mode, Automatic mode selected](openproject-16-4-color-mode-light-1.png) @@ -50,7 +50,7 @@ The exported PDF includes: - All selected attributes from the project list, shown in the same order as in the table. - Section titles linked to the respective project in OpenProject. -To export a project list, open the **More (three dots)** menu in the top right corner of the list and select Export. In the export modal, you can choose between XLS, CSV, or PDF. [Read more about project lists in our documentation](../../user-guide/projects/project-lists/#export-project-lists). +To export a project list, open the **More (three dots)** menu in the top right corner of the list and select Export. In the export modal, you can choose between XLS, CSV, or PDF. [Read more about project lists in our documentation](../../../user-guide/projects/project-lists/#export-project-lists). ![Screenshot of OpenProject 16.4: Export modal for PDF export of project lists, choosing the file format - XLS, CSV and PDF](openproject-16-4-export-project-list-highlighted.png) @@ -86,7 +86,7 @@ Other meetings improvements include: - Ability to remove participants directly from the dialog. - Cleaner display in the meeting right side and PDF export: only Attended is shown (no more 'Invited' label). -[Learn more about meeting management with OpenProject](../../user-guide/meetings/#meeting-management). +[Learn more about meeting management with OpenProject](../../../user-guide/meetings/#meeting-management). ![Screenshot of OpenProject 16.4: Meeting participants modal with autocomplete and 'Mark as attended' button](openproject-16-4-meeting-participants.png) @@ -102,7 +102,7 @@ Key capabilities include: - Distinguish between locally managed and synchronized memberships. - Retain full administrative control to rename or delete synced groups and memberships. -This provides flexibility for organizations, especially when self-registration is enabled. Unlike LDAP synchronization, group updates are applied on login, giving admins full control over membership changes. [Read more about OIDC in our documentation](../../system-admin-guide/authentication/openid-providers/). +This provides flexibility for organizations, especially when self-registration is enabled. Unlike LDAP synchronization, group updates are applied on login, giving admins full control over membership changes. [Read more about OIDC in our documentation](../../../system-admin-guide/authentication/openid-providers/). This feature was developed with the support of Helmholtz-Zentrum Berlin. @@ -112,7 +112,7 @@ With OpenProject 16.4, it is now easier to set up and track budgets. When creati In addition, **project lists** now include columns for planned budget, spent budget, spent percentage, and available budget, giving you a clearer overview across projects. -These updates make budgeting more practical for everyday use, and we will continue to expand budgets and cost management in future releases. [Read more about budgets in our user guide](../../user-guide/budgets/). +These updates make budgeting more practical for everyday use, and we will continue to expand budgets and cost management in future releases. [Read more about budgets in our user guide](../../../user-guide/budgets/). ![Screenshot of OpenProject 16.4: New budget with highlighted Base amount](openproject-16-4-budgets-highlighted.png) @@ -143,7 +143,7 @@ The SCIM server functionality (Enterprise add-on) introduced in OpenProject 16.2 - **Clear error for insufficient plan**: If the Enterprise subscription level does not include SCIM, the server now returns a 403 Forbidden with a clear message instead of a generic 401 error. -These changes make SCIM integrations more robust and transparent, improving interoperability with identity providers. [Read more about SCIM provisioning in our documentation](../../system-admin-guide/authentication/scim/). +These changes make SCIM integrations more robust and transparent, improving interoperability with identity providers. [Read more about SCIM provisioning in our documentation](../../../system-admin-guide/authentication/scim/). @@ -248,4 +248,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [William](https://crowdin.com/profile/williamfromtw), for a great number of translations into Chinese Traditional. - [OlhaTrotska](https://crowdin.com/profile/OlhaTrotska), for a great number of translations into Ukrainian. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-4-0/open_project_user_guide_project_settings_overview.png b/docs/release-notes/16/16-4-0/open_project_user_guide_project_settings_overview.png similarity index 100% rename from docs/release-notes/16-4-0/open_project_user_guide_project_settings_overview.png rename to docs/release-notes/16/16-4-0/open_project_user_guide_project_settings_overview.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-budgets-highlighted.png b/docs/release-notes/16/16-4-0/openproject-16-4-budgets-highlighted.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-budgets-highlighted.png rename to docs/release-notes/16/16-4-0/openproject-16-4-budgets-highlighted.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-color-mode-light-1.png b/docs/release-notes/16/16-4-0/openproject-16-4-color-mode-light-1.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-color-mode-light-1.png rename to docs/release-notes/16/16-4-0/openproject-16-4-color-mode-light-1.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-color-mode.png b/docs/release-notes/16/16-4-0/openproject-16-4-color-mode.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-color-mode.png rename to docs/release-notes/16/16-4-0/openproject-16-4-color-mode.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-export-project-list-highlighted.png b/docs/release-notes/16/16-4-0/openproject-16-4-export-project-list-highlighted.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-export-project-list-highlighted.png rename to docs/release-notes/16/16-4-0/openproject-16-4-export-project-list-highlighted.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-meeting-participants.png b/docs/release-notes/16/16-4-0/openproject-16-4-meeting-participants.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-meeting-participants.png rename to docs/release-notes/16/16-4-0/openproject-16-4-meeting-participants.png diff --git a/docs/release-notes/16-4-0/openproject-16-4-pdf-export-font-highlighted.png b/docs/release-notes/16/16-4-0/openproject-16-4-pdf-export-font-highlighted.png similarity index 100% rename from docs/release-notes/16-4-0/openproject-16-4-pdf-export-font-highlighted.png rename to docs/release-notes/16/16-4-0/openproject-16-4-pdf-export-font-highlighted.png diff --git a/docs/release-notes/16-4-1/README.md b/docs/release-notes/16/16-4-1/README.md similarity index 100% rename from docs/release-notes/16-4-1/README.md rename to docs/release-notes/16/16-4-1/README.md diff --git a/docs/release-notes/16-5-0/README.md b/docs/release-notes/16/16-5-0/README.md similarity index 95% rename from docs/release-notes/16-5-0/README.md rename to docs/release-notes/16/16-5-0/README.md index 8a90c7f8afd..7fab2908eaf 100644 --- a/docs/release-notes/16-5-0/README.md +++ b/docs/release-notes/16/16-5-0/README.md @@ -27,7 +27,7 @@ You can now place a work package directly into a specific agenda section when ad In the *Notes* section, you can add text that will be displayed together with the meeting title in the *Meetings* tab of the work package. -[See our user guide to learn more about how to add work packages to meetings](../../user-guide/work-packages/add-work-packages-to-meetings). +[See our user guide to learn more about how to add work packages to meetings](../../../user-guide/work-packages/add-work-packages-to-meetings). ![OpenProject work package, Meetings tab: Modal to "Select a meeting" with the Meeting selected being a Marketing daily and a "Add to section" dropdown with two sections to choose from.](openproject-16-5-meeting-tab-highlighted.png) @@ -42,7 +42,7 @@ Additionally, **checkboxes for high contrast** are now displayed, depending on t This new feature is particularly helpful for the automatic mode, where you can now differentiate whether you want high contrast to be displayed only in dark mode or only in light mode, for example. -[Learn more about the *Look and feel* options in OpenProject](../../user-guide/account-settings/#look-and-feel). +[Learn more about the *Look and feel* options in OpenProject](../../../user-guide/account-settings/#look-and-feel). ![OpenProject account settings / Interface: Look and feel options reduced to "Dark", "Light" and "Automatic". Automatic is selected and below two checkboxes are displayed:" Force high contrast when in Light mode" and "Force high-contrast when in Dark mode".](openproject-16-5-increase-contrast-automatic.png) @@ -114,7 +114,7 @@ This menu is useful not only for new users, but also for anyone looking for addi - Bugfix: ID link in notification center always points to last opened project \[[#66751](https://community.openproject.org/wp/66751)\] - Bugfix: Removing widgets from Projects Overview page is very slow/unresponsive \[[#66753](https://community.openproject.org/wp/66753)\] - Bugfix: Activity shows changes to admin only custom fields also to non admin users \[[#66925](https://community.openproject.org/wp/66925)\] -- Bugfix: LDAP Groupsync settings can't be edited in synced LDAP group \[[#66941](https://community.openproject.org/wp/66941)\] +- Bugfix: LDAP group sync settings can't be edited in synced LDAP group \[[#66941](https://community.openproject.org/wp/66941)\] - Bugfix: Do not use unspecified ServiceProviderConfig.AuthenticationSchemes.type \[[#67055](https://community.openproject.org/wp/67055)\] - Bugfix: Application password cannot be validated for Nextcloud storage using SSO \[[#67071](https://community.openproject.org/wp/67071)\] - Bugfix: Work packages export dialog description attribute dragger locale \[[#67181](https://community.openproject.org/wp/67181)\] @@ -122,7 +122,7 @@ This menu is useful not only for new users, but also for anyone looking for addi - Bugfix: User cannot create a folder in the File picker \[[#67233](https://community.openproject.org/wp/67233)\] - Bugfix: File picker UI lets user upload to root folder even though it's not permitted \[[#67235](https://community.openproject.org/wp/67235)\] - Bugfix: User doesn't get visual feedback their new OIDC provider was successfully saved \[[#67257](https://community.openproject.org/wp/67257)\] -- Bugfix: Meetings series is not correctly ended if series has more than 1 existing occurence \[[#67297](https://community.openproject.org/wp/67297)\] +- Bugfix: Meetings series is not correctly ended if series has more than 1 existing occurrence \[[#67297](https://community.openproject.org/wp/67297)\] - Bugfix: Incorrect terminology in docs and UI: "Favored" vs "Favorited" \[[#67312](https://community.openproject.org/wp/67312)\] - Bugfix: Older meetings show series backlog as 'untitled section' \[[#67381](https://community.openproject.org/wp/67381)\] - Bugfix: Cost reports month locale \[[#67466](https://community.openproject.org/wp/67466)\] @@ -162,8 +162,8 @@ This menu is useful not only for new users, but also for anyone looking for addi - Feature: Update the Getting started video linked in the application help menu \[[#67176](https://community.openproject.org/wp/67176)\] - Feature: Update help menu and widget on start page in application \[[#67177](https://community.openproject.org/wp/67177)\] - Feature: Update Enterprise plan text in widget on application start page \[[#67178](https://community.openproject.org/wp/67178)\] -- Feature: Add/remove projects from favourite via the API \[[#67241](https://community.openproject.org/wp/67241)\] -- Feature: Hide segmented control and include sub-itmes checkbox of the filterable tree view \[[#67541](https://community.openproject.org/wp/67541)\] +- Feature: Add/remove projects from favorite via the API \[[#67241](https://community.openproject.org/wp/67241)\] +- Feature: Hide segmented control and include sub-items checkbox of the filterable tree view \[[#67541](https://community.openproject.org/wp/67541)\] @@ -178,4 +178,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [Samo](https://crowdin.com/profile/SamoE), for a great number of translations into Turkish. - [Kuma Yamashita](https://crowdin.com/profile/dredgk), for a great number of translations into Japanese. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-5-0/openproject-16-5-deep-link.png b/docs/release-notes/16/16-5-0/openproject-16-5-deep-link.png similarity index 100% rename from docs/release-notes/16-5-0/openproject-16-5-deep-link.png rename to docs/release-notes/16/16-5-0/openproject-16-5-deep-link.png diff --git a/docs/release-notes/16-5-0/openproject-16-5-increase-contrast-automatic.png b/docs/release-notes/16/16-5-0/openproject-16-5-increase-contrast-automatic.png similarity index 100% rename from docs/release-notes/16-5-0/openproject-16-5-increase-contrast-automatic.png rename to docs/release-notes/16/16-5-0/openproject-16-5-increase-contrast-automatic.png diff --git a/docs/release-notes/16-5-0/openproject-16-5-meeting-tab-highlighted.png b/docs/release-notes/16/16-5-0/openproject-16-5-meeting-tab-highlighted.png similarity index 100% rename from docs/release-notes/16-5-0/openproject-16-5-meeting-tab-highlighted.png rename to docs/release-notes/16/16-5-0/openproject-16-5-meeting-tab-highlighted.png diff --git a/docs/release-notes/16-5-0/openproject-16-5-updated-on.png b/docs/release-notes/16/16-5-0/openproject-16-5-updated-on.png similarity index 100% rename from docs/release-notes/16-5-0/openproject-16-5-updated-on.png rename to docs/release-notes/16/16-5-0/openproject-16-5-updated-on.png diff --git a/docs/release-notes/16-5-1/README.md b/docs/release-notes/16/16-5-1/README.md similarity index 100% rename from docs/release-notes/16-5-1/README.md rename to docs/release-notes/16/16-5-1/README.md diff --git a/docs/release-notes/16-6-0/README.md b/docs/release-notes/16/16-6-0/README.md similarity index 96% rename from docs/release-notes/16-6-0/README.md rename to docs/release-notes/16/16-6-0/README.md index 9a0ab371b6d..dced69ed617 100644 --- a/docs/release-notes/16-6-0/README.md +++ b/docs/release-notes/16/16-6-0/README.md @@ -30,7 +30,7 @@ OpenProject 16.6 introduces new project attribute types that make portfolio eval **Weighted item lists** extend this concept by allowing administrators to assign numeric scores to list options, such as effort levels or risk ratings. These values can then be used as input for calculated results. -**Calculated values** enable automatic computations based on formulas using numeric project attributes, including scores from Weighted item lists or even other calculated values. The computed result is displayed directly on the project overview and in the project list. It automatically updates whenever one of its source attributes (e.g., *Benefit* or *Effort* in the example below) is changed. This allows teams to calculate project scores and prioritise consistently across the portfolio. +**Calculated values** enable automatic computations based on formulas using numeric project attributes, including scores from Weighted item lists or even other calculated values. The computed result is displayed directly on the project overview and in the project list. It automatically updates whenever one of its source attributes (e.g., *Benefit* or *Effort* in the example below) is changed. This allows teams to calculate project scores and prioritize consistently across the portfolio. Here's an example of a calculated value called 'Overall score (calculated)' with the following formula: `(Strategic impact * 0.6) + (Benefit ​* 0.3) - (Effort * 0.1)` @@ -61,11 +61,11 @@ While this is a small update by itself, it marks the beginning of a major improv ### Possibility to change parent of a custom field item (Enterprise add-on) -Administrators can now change the parent of an item within a [hierarchical custom field (Enterprise add-on)](../../system-admin-guide/custom-fields/#hierarchy-custom-field-enterprise-add-on) or project attribute. This makes it easier to rearrange existing items without recreating them from scratch. +Administrators can now change the parent of an item within a [hierarchical custom field (Enterprise add-on)](../../../system-admin-guide/custom-fields/#hierarchy-custom-field-enterprise-add-on) or project attribute. This makes it easier to rearrange existing items without recreating them from scratch. To do so, administrators need to navigate to *Administration → Custom fields*, select a custom field type hierarchy and click on the *Items* tab. Then they click on the *More* icon and select *Change parent*. A dialog opens showing the current hierarchy tree. From there, administrators can search, select a new parent, and save the updated structure. The hierarchy is updated immediately after saving. Like mentioned above, this also works for project attributes. -![OpenProject 16.6: Custom field type hierarchy in the administration, tab 'Items', one item is selected with the 'More' menu and the option to change parent is higlighted](openproject-16-6-custom-field-hierarchy-change-parent.png) +![OpenProject 16.6: Custom field type hierarchy in the administration, tab 'Items', one item is selected with the 'More' menu and the option to change parent is highlighted](openproject-16-6-custom-field-hierarchy-change-parent.png) ### Updated 'More' menu of meetings with a 'Move to section' option @@ -73,7 +73,7 @@ In the Meetings module, the *More (three dots) menu* for agenda items has been i The new *Move → Move to section* option opens a dialog where users can select the desired section from a dropdown list. Additionally, users can still move an agenda item to the backlog or to the next meeting (if it's part of a meeting series). -[Learn more about meeting management with OpenProject](../../user-guide/work-packages/add-work-packages-to-meetings). +[Learn more about meeting management with OpenProject](../../../user-guide/work-packages/add-work-packages-to-meetings). ![OpenProject 16.6: Meetings module showing the options when clicking on the More menu on an agenda item](meetings_move_menu.png) @@ -89,7 +89,7 @@ In *Administration → Work packages → Workflows*, the workflow table now feat Additionally, the table is now split into three tabs — *Default transitions*, *User is author*, and *User is assignee* — each showing the relevant workflow configuration. Before 16.6, these additional transitions were often overlooked as they were positioned below the table. -[Read more about managing work package workflows in OpenProject](../../system-admin-guide/manage-work-packages/work-package-workflows/). +[Read more about managing work package workflows in OpenProject](../../../system-admin-guide/manage-work-packages/work-package-workflows/). ![OpenProject 16.6: Administration for work package workflows highlighting the new tabs and that the header and right column are sticky when scrolling](openproject-16-6-work-package-workflow-highlighted.png) @@ -191,4 +191,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [Pickart](https://crowdin.com/profile/fantasmak10), for a great number of translations into Catalan. - [Maxime77](https://crowdin.com/profile/maxime77), for a great number of translations into French. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/16-6-0/meetings_move_menu.png b/docs/release-notes/16/16-6-0/meetings_move_menu.png similarity index 100% rename from docs/release-notes/16-6-0/meetings_move_menu.png rename to docs/release-notes/16/16-6-0/meetings_move_menu.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-custom-field-hierarchy-change-parent.png b/docs/release-notes/16/16-6-0/openproject-16-6-custom-field-hierarchy-change-parent.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-custom-field-hierarchy-change-parent.png rename to docs/release-notes/16/16-6-0/openproject-16-6-custom-field-hierarchy-change-parent.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-documents-index-page.png b/docs/release-notes/16/16-6-0/openproject-16-6-documents-index-page.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-documents-index-page.png rename to docs/release-notes/16/16-6-0/openproject-16-6-documents-index-page.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-project-attributes-calculated-value.png b/docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-calculated-value.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-project-attributes-calculated-value.png rename to docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-calculated-value.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-project-attributes-hierarchy.png b/docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-hierarchy.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-project-attributes-hierarchy.png rename to docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-hierarchy.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-project-attributes-overview-page.png b/docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-overview-page.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-project-attributes-overview-page.png rename to docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-overview-page.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-project-attributes-updated.png b/docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-updated.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-project-attributes-updated.png rename to docs/release-notes/16/16-6-0/openproject-16-6-project-attributes-updated.png diff --git a/docs/release-notes/16-6-0/openproject-16-6-work-package-workflow-highlighted.png b/docs/release-notes/16/16-6-0/openproject-16-6-work-package-workflow-highlighted.png similarity index 100% rename from docs/release-notes/16-6-0/openproject-16-6-work-package-workflow-highlighted.png rename to docs/release-notes/16/16-6-0/openproject-16-6-work-package-workflow-highlighted.png diff --git a/docs/release-notes/16-6-1/README.md b/docs/release-notes/16/16-6-1/README.md similarity index 100% rename from docs/release-notes/16-6-1/README.md rename to docs/release-notes/16/16-6-1/README.md diff --git a/docs/release-notes/16-6-2/README.md b/docs/release-notes/16/16-6-2/README.md similarity index 100% rename from docs/release-notes/16-6-2/README.md rename to docs/release-notes/16/16-6-2/README.md diff --git a/docs/release-notes/16-6-3/README.md b/docs/release-notes/16/16-6-3/README.md similarity index 100% rename from docs/release-notes/16-6-3/README.md rename to docs/release-notes/16/16-6-3/README.md diff --git a/docs/release-notes/16-6-4/README.md b/docs/release-notes/16/16-6-4/README.md similarity index 100% rename from docs/release-notes/16-6-4/README.md rename to docs/release-notes/16/16-6-4/README.md diff --git a/docs/release-notes/16-6-5/README.md b/docs/release-notes/16/16-6-5/README.md similarity index 93% rename from docs/release-notes/16-6-5/README.md rename to docs/release-notes/16/16-6-5/README.md index 455a4b37579..f13648f6a66 100644 --- a/docs/release-notes/16-6-5/README.md +++ b/docs/release-notes/16/16-6-5/README.md @@ -31,7 +31,7 @@ The vulnerability has been responsibly disclosed through the [YesWeHack bounty p ### CVE-2026-23721 - Users with "View Members" permission in any project can view all Group memberships -When using [groups](https://www.openproject.org/docs/system-admin-guide/users-permissions/groups/) in OpenProject to manage users, the group members should only be visible to users that have the *View Members* permission in **any project** that the group is also a member of. +When using [groups](../../../system-admin-guide/users-permissions/groups/) in OpenProject to manage users, the group members should only be visible to users that have the *View Members* permission in **any project** that the group is also a member of. Due to a failed permission check, if a user had the *View Members* permission in any project, they could enumerate all Groups and view which other users are part of the group. This vulnerability was assigned as CVE-2026-23721. diff --git a/docs/release-notes/16-6-6/README.md b/docs/release-notes/16/16-6-6/README.md similarity index 100% rename from docs/release-notes/16-6-6/README.md rename to docs/release-notes/16/16-6-6/README.md diff --git a/docs/release-notes/16-6-7/README.md b/docs/release-notes/16/16-6-7/README.md similarity index 100% rename from docs/release-notes/16-6-7/README.md rename to docs/release-notes/16/16-6-7/README.md diff --git a/docs/release-notes/16-6-8/README.md b/docs/release-notes/16/16-6-8/README.md similarity index 100% rename from docs/release-notes/16-6-8/README.md rename to docs/release-notes/16/16-6-8/README.md diff --git a/docs/release-notes/16/16-6-9/README.md b/docs/release-notes/16/16-6-9/README.md new file mode 100644 index 00000000000..612f924f57d --- /dev/null +++ b/docs/release-notes/16/16-6-9/README.md @@ -0,0 +1,89 @@ +--- +title: OpenProject 16.6.9 +sidebar_navigation: + title: 16.6.9 +release_version: 16.6.9 +release_date: 2026-03-16 +--- + + # OpenProject 16.6.9 + + Release date: 2026-03-16 + + We released OpenProject [OpenProject 16.6.9](https://community.openproject.org/versions/2285). + The release contains several bug fixes and we recommend updating to the newest version. + Below you will find a complete list of all changes and bug fixes. + + + +## Security fixes + + + +### CVE-2026-32698 - SQL Injection via Custom Field Name can be chained to Remote Code Execution + +OpenProject is vulnerable to an SQL injection attack via a custom field's name. When that custom field was used in a Cost Report, the custom field's name was injected into the SQL query without proper sanitation. This allowed an attacker to execute arbitrary SQL commands during the generation of a Cost Report.  + + + +As custom fields can only be generated by users with full administrator privileges, the attack surface is somewhat reduced. + + + +Together with another bug in the _Repositories_ module, that used the project identifier without sanitation to generate the checkout path for a git repository in the filesystem, this allowed an attacker to checkout a git repository to an arbitrarily chosen path on the server. If the checkout is done within certain paths within the OpenProject application, upon the next restart of the application, this allows the attacker to inject ruby code into the application. + + + +As the project identifier cannot be manually edited to any string containing special characters like dots or slashes, this needs to be changed via the SQL injection described above. + + + +This vulnerability was reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-jqhf-rf9x-9rhx](https://github.com/opf/openproject/security/advisories/GHSA-jqhf-rf9x-9rhx) + + + +### CVE-2026-32703 - Repository files are served with the MIME type allowing them to be used to bypass Content Security Policy + +When using the Repositories module in a project, it was possible to access the raw files via the browser with a URL like `/projects/{project}/repository/revisions/{commit_id}/raw/{file}.js.raw`. For those files, the MIME type was detected via the filename extension. For JavaScript and CSS files those files were then served from the same domain name as the application with the correct MIME type for active content and could be used to bypass the Content Security Policy. Together with other areas, where unsanitized HTML was served, this allowed persistent XSS attacks. + + + +The MIME type detection for Repository files has been removed and files are served as `application/octet-stream` which will block their execution via the Content Security Policy. + + + +Two places that could be used to abuse this vulnerability have been fixed: + + + +The Repositories module did not properly escape filenames displayed from repositories. This allowed an attacker with push access into the repository to create commits with filenames that included HTML code that was injected in the page without proper sanitation. This allowed a persisted XSS attack against all members of this project that accessed the repositories page to display a changeset where the maliciously crafted file was deleted. + + + +When a work package name contains HTML content and the work package is attached to a meeting, the work package name is rendered in the activities feed without proper sanitation. + + + +All of those vulnerabilities were reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-p423-72h4-fjvp](https://github.com/opf/openproject/security/advisories/GHSA-p423-72h4-fjvp) + + + + + + +## Bug fixes and changes + + + + + + + diff --git a/docs/release-notes/16/README.md b/docs/release-notes/16/README.md new file mode 100644 index 00000000000..c066a1fab85 --- /dev/null +++ b/docs/release-notes/16/README.md @@ -0,0 +1,36 @@ +--- +sidebar_navigation: + title: '16.x' +release_date: 2026-03-16 +title: OpenProject Version 16 Release Notes +--- + +# OpenProject Version 16 Release Notes + +| Version | Release date | +|-------------------------------|--------------| +| [OpenProject 16.6.9](16-6-9/) | 2026-03-16 | +| [OpenProject 16.6.8](16-6-8/) | 2026-02-18 | +| [OpenProject 16.6.7](16-6-7/) | 2026-02-06 | +| [OpenProject 16.6.6](16-6-6/) | 2026-01-27 | +| [OpenProject 16.6.5](16-6-5/) | 2026-01-16 | +| [OpenProject 16.6.4](16-6-4/) | 2026-01-08 | +| [OpenProject 16.6.3](16-6-3/) | 2025-12-11 | +| [OpenProject 16.6.2](16-6-2/) | 2025-12-02 | +| [OpenProject 16.6.1](16-6-1/) | 2025-11-13 | +| [OpenProject 16.6.0](16-6-0/) | 2025-11-05 | +| [OpenProject 16.5.1](16-5-1/) | 2025-10-15 | +| [OpenProject 16.5.0](16-5-0/) | 2025-10-08 | +| [OpenProject 16.4.1](16-4-1/) | 2025-09-16 | +| [OpenProject 16.4.0](16-4-0/) | 2025-09-10 | +| [OpenProject 16.3.2](16-3-2/) | 2025-08-25 | +| [OpenProject 16.3.1](16-3-1/) | 2025-08-13 | +| [OpenProject 16.3.0](16-3-0/) | 2025-08-13 | +| [OpenProject 16.2.2](16-2-2/) | 2025-08-07 | +| [OpenProject 16.2.1](16-2-1/) | 2025-08-04 | +| [OpenProject 16.2.0](16-2-0/) | 2025-07-16 | +| [OpenProject 16.1.1](16-1-1/) | 2025-06-26 | +| [OpenProject 16.1.0](16-1-0/) | 2025-06-18 | +| [OpenProject 16.0.1](16-0-1/) | 2025-06-05 | +| [OpenProject 16.0.0](16-0-0/) | 2025-05-21 | + diff --git a/docs/release-notes/17-0-0/README.md b/docs/release-notes/17-0-0/README.md index 2221b22f602..c7e63f06e94 100644 --- a/docs/release-notes/17-0-0/README.md +++ b/docs/release-notes/17-0-0/README.md @@ -105,7 +105,7 @@ See our user guide to [learn how to present a meeting in OpenProject](../../user Agenda items can now hold **multiple text-based outcomes**: The **+ Outcome** button remains available while the meeting is *In progress* and allows moderators to record more than one result for the same item. The first outcome is labelled "Outcome", additional ones are numbered ("Outcome 1", "Outcome 2", and so on). These outcomes are also supported in the PDF exports of meetings. This feature is a preparation for future improvements, such as [creating work packages as outcomes](https://community.openproject.org/work_packages/62093). -![OpenProject meeting which is in progess, below the first agenda item (a work package) are "Outcome 1" and "Outcome 2" displayed, and the + Outcome button is still available as well](openproject-17-0-meeting-multiple-outcomes.png) +![OpenProject meeting which is in progress, below the first agenda item (a work package) are "Outcome 1" and "Outcome 2" displayed, and the + Outcome button is still available as well](openproject-17-0-meeting-multiple-outcomes.png) #### Unified “My meetings” iCal subscription @@ -280,7 +280,7 @@ OpenProject now includes a built-in OAuth application that simplifies authentica ### Improved perceived performance of the project selector -The project selector has been optimised to feel significantly faster, especially in instances with many projects. Instead of loading the full project tree at once, OpenProject now loads up to 300 projects initially and fetches additional entries dynamically during search. This reduces waiting times and improves responsiveness across the application. +The project selector has been optimized to feel significantly faster, especially in instances with many projects. Instead of loading the full project tree at once, OpenProject now loads up to 300 projects initially and fetches additional entries dynamically during search. This reduces waiting times and improves responsiveness across the application. ### Removal of special semver @@ -377,7 +377,7 @@ Reference: \[[#67036](https://community.openproject.org/wp/67036)\] - Bugfix: Missing notification when a one-time meeting exits draft mode \[[#70109](https://community.openproject.org/wp/70109)\] - Bugfix: Missing notification when the title of a one-time meeting is updated \[[#70110](https://community.openproject.org/wp/70110)\] - Bugfix: Missing notification when a series is ended \[[#70111](https://community.openproject.org/wp/70111)\] -- Bugfix: Race condition allows to create resurces with the same name, bypassing our uniqueness validation \[[#70112](https://community.openproject.org/wp/70112)\] +- Bugfix: Race condition allows to create resources with the same name, bypassing our uniqueness validation \[[#70112](https://community.openproject.org/wp/70112)\] - Bugfix: Missing notification when restoring a cancelled occurrence \[[#70113](https://community.openproject.org/wp/70113)\] - Bugfix: Inconsistent label for „Status“ and „Project status“ \[[#70142](https://community.openproject.org/wp/70142)\] - Bugfix: Newly created project attributes are added as columns to the default project list \[[#70147](https://community.openproject.org/wp/70147)\] @@ -390,7 +390,7 @@ Reference: \[[#67036](https://community.openproject.org/wp/67036)\] - Bugfix: There is a recent change in Capabilities API without backward compatibility \[[#70356](https://community.openproject.org/wp/70356)\] - Bugfix: Fix close button accessibility errors found by eslint, ERB Lint \[[#70420](https://community.openproject.org/wp/70420)\] - Feature: Have specific role or permission to access templated project, but membership is not instantiated on copy \[[#43571](https://community.openproject.org/wp/43571)\] -- Feature: Reduce visibility of all users when addings members to a project \[[#55270](https://community.openproject.org/wp/55270)\] +- Feature: Reduce visibility of all users when adding members to a project \[[#55270](https://community.openproject.org/wp/55270)\] - Feature: Add work package type, status and meta status to what the global search is searching on during typeahead \[[#56831](https://community.openproject.org/wp/56831)\] - Feature: Configure project attribute sections to be shown as widgets on the project overview page \[[#61445](https://community.openproject.org/wp/61445)\] - Feature: A single 'My Meetings' iCal calendar subscription action so users can always have their calendars in sync with the meetings \[[#63463](https://community.openproject.org/wp/63463)\] @@ -444,7 +444,7 @@ Reference: \[[#67036](https://community.openproject.org/wp/67036)\] - Feature: Truncate breadcrumb in PageHeader \[[#68906](https://community.openproject.org/wp/68906)\] - Feature: Introduce "Create program" and "Create portfolio" permission \[[#68918](https://community.openproject.org/wp/68918)\] - Feature: Sync up last updated at via hocuspocus awareness protocol \[[#68939](https://community.openproject.org/wp/68939)\] -- Feature: Primerize Administation > Attribute help texts forms \[[#68953](https://community.openproject.org/wp/68953)\] +- Feature: Primerize Administration > Attribute help texts forms \[[#68953](https://community.openproject.org/wp/68953)\] - Feature: Style the rich-link workpackage macro (dark theme) \[[#68978](https://community.openproject.org/wp/68978)\] - Feature: Primerize Admin > System Settings forms \[[#69095](https://community.openproject.org/wp/69095)\] - Feature: Move "meetings" tab before GitHub and GitLab \[[#69118](https://community.openproject.org/wp/69118)\] diff --git a/docs/release-notes/17-0-1/README.md b/docs/release-notes/17-0-1/README.md index 51c7f8b40f0..47d5f270fdd 100644 --- a/docs/release-notes/17-0-1/README.md +++ b/docs/release-notes/17-0-1/README.md @@ -29,7 +29,7 @@ The vulnerability has been responsibly disclosed through the [YesWeHack bounty p ### CVE-2026-23721 - Users with "View Members" permission in any project can view all Group memberships -When using [groups](https://www.openproject.org/docs/system-admin-guide/users-permissions/groups/) in OpenProject to manage users, the group members should only be visible to users that have the *View Members* permission in **any project** that the group is also a member of. +When using [groups](../../system-admin-guide/users-permissions/groups/) in OpenProject to manage users, the group members should only be visible to users that have the *View Members* permission in **any project** that the group is also a member of. Due to a failed permission check, if a user had the *View Members* permission in any project, they could enumerate all Groups and view which other users are part of the group. This vulnerability was assigned as CVE-2026-23721. diff --git a/docs/release-notes/17-0-2/README.md b/docs/release-notes/17-0-2/README.md index 104b2c4b65e..9a1742775b1 100644 --- a/docs/release-notes/17-0-2/README.md +++ b/docs/release-notes/17-0-2/README.md @@ -30,7 +30,7 @@ For more information, please see the [GitHub advisory #GHSA-74p5-9pr3-r6pw](http ### CVE-2026-24772 - SSRF and CSWSH in Hocuspocus Synchronization Server -To enable the real time collaboration on documents, OpenProject 17.0 introduced a [synchronization server](https://github.com/opf/op-blocknote-hocuspocus). The OpenPrioject backend generates an authentication token that is currently valid for 24 hours, encrypts it with a shared secret only known to the synchronization server. The frontend hands this encrypted token and the backend URL over to the synchronization server to check user's ability to work on the document and perform intermittent saves while editing. +To enable the real time collaboration on documents, OpenProject 17.0 introduced a [synchronization server](https://github.com/opf/op-blocknote-hocuspocus). The OpenProject backend generates an authentication token that is currently valid for 24 hours, encrypts it with a shared secret only known to the synchronization server. The frontend hands this encrypted token and the backend URL over to the synchronization server to check user's ability to work on the document and perform intermittent saves while editing. The synchronization server does not properly validate the backend URL and sends a request with the decrypted authentication token to the endpoint that was given to the server. An attacker could use this vulnerability to decrypt a token that he intercepted by other means to gain an access token to interact with OpenProject on the victim's behalf. @@ -57,9 +57,9 @@ For more information, please see the [GitHub advisory #GHSA-35c6-x276-2pvc](http - Bugfix: Meeting outcomes cannot be saved with ctrl/cmd+enter \[[#69974](https://community.openproject.org/wp/69974)\] - Bugfix: AXe Accessibility error: invalid list structure \[[#70573](https://community.openproject.org/wp/70573)\] - Bugfix: Fix AXe Accessibility error: Navigation toggler must have discernible text \[[#70574](https://community.openproject.org/wp/70574)\] -- Bugfix: Documents module is missing meaningfull html title \[[#70614](https://community.openproject.org/wp/70614)\] +- Bugfix: Documents module is missing meaningful html title \[[#70614](https://community.openproject.org/wp/70614)\] - Bugfix: Users with the "Manage Users" permission did not see links to Lock/Unlock users \[[#70796](https://community.openproject.org/wp/70796)\] -- Bugfix: Cannot authorise OpenProject app with OpenProject when user has 2FA enabled \[[#70966](https://community.openproject.org/wp/70966)\] +- Bugfix: Cannot authorize OpenProject app with OpenProject when user has 2FA enabled \[[#70966](https://community.openproject.org/wp/70966)\] - Bugfix: Running docker slim image, runs slim-bim one \[[#70980](https://community.openproject.org/wp/70980)\] - Bugfix: 'For all projects' project attributes are not displayed during new project creation \[[#70982](https://community.openproject.org/wp/70982)\] - Bugfix: Fix revision parsing in git diff output \[[#71020](https://community.openproject.org/wp/71020)\] diff --git a/docs/release-notes/17-0-3/README.md b/docs/release-notes/17-0-3/README.md index bf83fe41d71..a00ed899f17 100644 --- a/docs/release-notes/17-0-3/README.md +++ b/docs/release-notes/17-0-3/README.md @@ -66,7 +66,7 @@ For more information, please see the [GitHub advisory #GHSA-x37c-hcg5-r5m7](http - Bugfix: Unable to change to earlier finish date for automatically scheduled successor \[[#65130](https://community.openproject.org/wp/65130)\] - Bugfix: DPA/AVV cannot be downloaded \[[#67323](https://community.openproject.org/wp/67323)\] -- Bugfix: hocupocus logs \[onAuthenticate\] fetch failed and connection to collaboration server not possible \[[#70542](https://community.openproject.org/wp/70542)\] +- Bugfix: hocuspocus logs \[onAuthenticate\] fetch failed and connection to collaboration server not possible \[[#70542](https://community.openproject.org/wp/70542)\] - Bugfix: Wrong sidebar sort order in System Admin Guide -> Authentication \[[#70914](https://community.openproject.org/wp/70914)\] - Bugfix: "form\_configuration-status=422" Unable to Change Custom fields in Work Packages without Enterprise Plan \[[#71093](https://community.openproject.org/wp/71093)\] diff --git a/docs/release-notes/17-0-4/README.md b/docs/release-notes/17-0-4/README.md index baf91c1766a..180751ffad7 100644 --- a/docs/release-notes/17-0-4/README.md +++ b/docs/release-notes/17-0-4/README.md @@ -62,7 +62,7 @@ For more information, please see the [GitHub advisory #GHSA-g62r-9rgf-h53q](http The application is vulnerable to HTML injection due to improper sanitization of user-supplied input for the project name. -An attacker can inject arbitrary HTML tags into the response, altering the structure of the page. and later while creating workpackages payload is executed. +An attacker can inject arbitrary HTML tags into the response, altering the structure of the page. and later while creating work packages payload is executed. diff --git a/docs/release-notes/17-0-5/README.md b/docs/release-notes/17-0-5/README.md index 34fd0dfb6cd..676be81c76b 100644 --- a/docs/release-notes/17-0-5/README.md +++ b/docs/release-notes/17-0-5/README.md @@ -220,7 +220,7 @@ For more information, please see the [GitHub advisory #GHSA-c76v-8735-35hq](http -### CVE-2026-27827 - Insecure Direct Object Reference in Project Storage Administrition Theft & Pre-Auth Remote Folder Deletion +### CVE-2026-27827 - Insecure Direct Object Reference in Project Storage Administration Theft & Pre-Auth Remote Folder Deletion An unscoped loading of Project Storages lead to users with the _Manage Files in Project_ permission in one project, to access project storages in other projects. This would give information about the storage that they were not supposed to see.  diff --git a/docs/release-notes/17-0-6/README.md b/docs/release-notes/17-0-6/README.md new file mode 100644 index 00000000000..18ae4060379 --- /dev/null +++ b/docs/release-notes/17-0-6/README.md @@ -0,0 +1,89 @@ +--- +title: OpenProject 17.0.6 +sidebar_navigation: + title: 17.0.6 +release_version: 17.0.6 +release_date: 2026-03-16 +--- + + # OpenProject 17.0.6 + + Release date: 2026-03-16 + + We released OpenProject [OpenProject 17.0.6](https://community.openproject.org/versions/2286). + The release contains several bug fixes and we recommend updating to the newest version. + Below you will find a complete list of all changes and bug fixes. + + + +## Security fixes + + + +### CVE-2026-32698 - SQL Injection via Custom Field Name can be chained to Remote Code Execution + +OpenProject is vulnerable to an SQL injection attack via a custom field's name. When that custom field was used in a Cost Report, the custom field's name was injected into the SQL query without proper sanitation. This allowed an attacker to execute arbitrary SQL commands during the generation of a Cost Report.  + + + +As custom fields can only be generated by users with full administrator privileges, the attack surface is somewhat reduced. + + + +Together with another bug in the _Repositories_ module, that used the project identifier without sanitation to generate the checkout path for a git repository in the filesystem, this allowed an attacker to checkout a git repository to an arbitrarily chosen path on the server. If the checkout is done within certain paths within the OpenProject application, upon the next restart of the application, this allows the attacker to inject ruby code into the application. + + + +As the project identifier cannot be manually edited to any string containing special characters like dots or slashes, this needs to be changed via the SQL injection described above. + + + +This vulnerability was reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-jqhf-rf9x-9rhx](https://github.com/opf/openproject/security/advisories/GHSA-jqhf-rf9x-9rhx) + + + +### CVE-2026-32703 - Repository files are served with the MIME type allowing them to be used to bypass Content Security Policy + +When using the Repositories module in a project, it was possible to access the raw files via the browser with a URL like `/projects/{project}/repository/revisions/{commit_id}/raw/{file}.js.raw`. For those files, the MIME type was detected via the filename extension. For JavaScript and CSS files those files were then served from the same domain name as the application with the correct MIME type for active content and could be used to bypass the Content Security Policy. Together with other areas, where unsanitized HTML was served, this allowed persistent XSS attacks. + + + +The MIME type detection for Repository files has been removed and files are served as `application/octet-stream` which will block their execution via the Content Security Policy. + + + +Two places that could be used to abuse this vulnerability have been fixed: + + + +The Repositories module did not properly escape filenames displayed from repositories. This allowed an attacker with push access into the repository to create commits with filenames that included HTML code that was injected in the page without proper sanitation. This allowed a persisted XSS attack against all members of this project that accessed the repositories page to display a changeset where the maliciously crafted file was deleted. + + + +When a work package name contains HTML content and the work package is attached to a meeting, the work package name is rendered in the activities feed without proper sanitation. + + + +All of those vulnerabilities were reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-p423-72h4-fjvp](https://github.com/opf/openproject/security/advisories/GHSA-p423-72h4-fjvp) + + + + + + +## Bug fixes and changes + + + + + + + diff --git a/docs/release-notes/17-1-0/README.md b/docs/release-notes/17-1-0/README.md index 7f9a62c4f98..df9d7de17be 100644 --- a/docs/release-notes/17-1-0/README.md +++ b/docs/release-notes/17-1-0/README.md @@ -168,7 +168,7 @@ This change prevents browser freezes and significantly improves responsiveness w - Bugfix: Error duplicating task with relation \[[#69309](https://community.openproject.org/wp/69309)\] - Bugfix: Truncate the name in the project list \[[#69445](https://community.openproject.org/wp/69445)\] - Bugfix: Timer cannot be started if log time modal has a mandatory field \[[#69483](https://community.openproject.org/wp/69483)\] -- Bugfix: Nexcloud returns 404 if OpenPorject app is not installed \[[#69492](https://community.openproject.org/wp/69492)\] +- Bugfix: Nextcloud returns 404 if OpenProject app is not installed \[[#69492](https://community.openproject.org/wp/69492)\] - Bugfix: Fine-tuning of margins in pdf exports \[[#69515](https://community.openproject.org/wp/69515)\] - Bugfix: Error in PDF exports if font file storage is broken \[[#69625](https://community.openproject.org/wp/69625)\] - Bugfix: Misleading text in Work Package meetings tab after mentioning WP in meeting outcome \[[#69646](https://community.openproject.org/wp/69646)\] @@ -183,7 +183,7 @@ This change prevents browser freezes and significantly improves responsiveness w - Bugfix: Project status button is missing colors in the dropdown \[[#70458](https://community.openproject.org/wp/70458)\] - Bugfix: Fix flickering in the Handling of 404 errors in AvatarWithFallback \[[#70460](https://community.openproject.org/wp/70460)\] - Bugfix: On mobile, global search result box shows a lot of white space \[[#70497](https://community.openproject.org/wp/70497)\] -- Bugfix: hocupocus logs \[onAuthenticate\] fetch failed and connection to collaboration server not possible \[[#70542](https://community.openproject.org/wp/70542)\] +- Bugfix: hocuspocus logs \[onAuthenticate\] fetch failed and connection to collaboration server not possible \[[#70542](https://community.openproject.org/wp/70542)\] - Bugfix: Images are broken on moved/duplicated meeting agenda item \[[#70585](https://community.openproject.org/wp/70585)\] - Bugfix: If user cancels a meeting that is currently happening, the meeting disappears from list \[[#70609](https://community.openproject.org/wp/70609)\] - Bugfix: Email wording is ambiguous for users who are uninvited from a meeting \[[#70610](https://community.openproject.org/wp/70610)\] @@ -225,8 +225,8 @@ This change prevents browser freezes and significantly improves responsiveness w - Feature: Button to open project creation wizard from overview \[[#69402](https://community.openproject.org/wp/69402)\] - Feature: Add relative link to project initiation request from work package comment \[[#69403](https://community.openproject.org/wp/69403)\] - Feature: Send out email when work package is created \[[#69414](https://community.openproject.org/wp/69414)\] -- Feature: Show breadcrumb with full project hierachy in Project Overview showing portfolios and programs \[[#69417](https://community.openproject.org/wp/69417)\] -- Feature: Allow duplicating/copy of agenda items to next meeting occurence \[[#69464](https://community.openproject.org/wp/69464)\] +- Feature: Show breadcrumb with full project hierarchy in Project Overview showing portfolios and programs \[[#69417](https://community.openproject.org/wp/69417)\] +- Feature: Allow duplicating/copy of agenda items to next meeting occurrence \[[#69464](https://community.openproject.org/wp/69464)\] - Feature: Primerize API settings form \[[#69702](https://community.openproject.org/wp/69702)\] - Feature: Show participant response in Meeting UI \[[#69733](https://community.openproject.org/wp/69733)\] - Feature: Responses before meeting was created should show up in iCal Feed \[[#69734](https://community.openproject.org/wp/69734)\] diff --git a/docs/release-notes/17-1-0/openproject-17-1-custom-fields-values.jpg b/docs/release-notes/17-1-0/openproject-17-1-custom-fields-values.jpg index b06a3c57e10..bb0cc9ac631 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-custom-fields-values.jpg and b/docs/release-notes/17-1-0/openproject-17-1-custom-fields-values.jpg differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-meeting-outcome-work-package-highlighted.png b/docs/release-notes/17-1-0/openproject-17-1-meeting-outcome-work-package-highlighted.png index 647ae25ccd2..2e6cf07afed 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-meeting-outcome-work-package-highlighted.png and b/docs/release-notes/17-1-0/openproject-17-1-meeting-outcome-work-package-highlighted.png differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-meetings-duplicate-agenda-item.png b/docs/release-notes/17-1-0/openproject-17-1-meetings-duplicate-agenda-item.png index e77d1de5864..b3a2897c104 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-meetings-duplicate-agenda-item.png and b/docs/release-notes/17-1-0/openproject-17-1-meetings-duplicate-agenda-item.png differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-meetings-mark-as-attended-highlighted.png b/docs/release-notes/17-1-0/openproject-17-1-meetings-mark-as-attended-highlighted.png deleted file mode 100644 index f03dd73a81f..00000000000 Binary files a/docs/release-notes/17-1-0/openproject-17-1-meetings-mark-as-attended-highlighted.png and /dev/null differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-meetings-participtants-status-highlighted.png b/docs/release-notes/17-1-0/openproject-17-1-meetings-participtants-status-highlighted.png index 55211959eb9..9907c72b120 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-meetings-participtants-status-highlighted.png and b/docs/release-notes/17-1-0/openproject-17-1-meetings-participtants-status-highlighted.png differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-wizard-attributes.png b/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-wizard-attributes.png index fde3f0aafc3..47bd9050095 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-wizard-attributes.png and b/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-wizard-attributes.png differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-work-package.png b/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-work-package.png index 72605c03959..93c05952d26 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-work-package.png and b/docs/release-notes/17-1-0/openproject-17-1-project-initiation-request-work-package.png differ diff --git a/docs/release-notes/17-1-0/openproject-17-1-warning-external-link.png b/docs/release-notes/17-1-0/openproject-17-1-warning-external-link.png index 452dfd8ecd8..4cd18a34fa7 100644 Binary files a/docs/release-notes/17-1-0/openproject-17-1-warning-external-link.png and b/docs/release-notes/17-1-0/openproject-17-1-warning-external-link.png differ diff --git a/docs/release-notes/17-1-0/openproject-project-initiation-request-work-package.png b/docs/release-notes/17-1-0/openproject-project-initiation-request-work-package.png deleted file mode 100644 index f0c512cf774..00000000000 Binary files a/docs/release-notes/17-1-0/openproject-project-initiation-request-work-package.png and /dev/null differ diff --git a/docs/release-notes/17-1-1/README.md b/docs/release-notes/17-1-1/README.md index 1b224004651..227681b781f 100644 --- a/docs/release-notes/17-1-1/README.md +++ b/docs/release-notes/17-1-1/README.md @@ -62,7 +62,7 @@ For more information, please see the [GitHub advisory #GHSA-g62r-9rgf-h53q](http The application is vulnerable to HTML injection due to improper sanitization of user-supplied input for the project name. -An attacker can inject arbitrary HTML tags into the response, altering the structure of the page. and later while creating workpackages payload is executed. +An attacker can inject arbitrary HTML tags into the response, altering the structure of the page. and later while creating work packages payload is executed. diff --git a/docs/release-notes/17-1-2/README.md b/docs/release-notes/17-1-2/README.md index e178aa7f0a5..0aae9aadbb8 100644 --- a/docs/release-notes/17-1-2/README.md +++ b/docs/release-notes/17-1-2/README.md @@ -220,7 +220,7 @@ For more information, please see the [GitHub advisory #GHSA-c76v-8735-35hq](http -### CVE-2026-27827 - Insecure Direct Object Reference in Project Storage Administrition Theft & Pre-Auth Remote Folder Deletion +### CVE-2026-27827 - Insecure Direct Object Reference in Project Storage Administration Theft & Pre-Auth Remote Folder Deletion An unscoped loading of Project Storages lead to users with the _Manage Files in Project_ permission in one project, to access project storages in other projects. This would give information about the storage that they were not supposed to see.  diff --git a/docs/release-notes/17-1-3/README.md b/docs/release-notes/17-1-3/README.md new file mode 100644 index 00000000000..47562ee6e61 --- /dev/null +++ b/docs/release-notes/17-1-3/README.md @@ -0,0 +1,91 @@ +--- +title: OpenProject 17.1.3 +sidebar_navigation: + title: 17.1.3 +release_version: 17.1.3 +release_date: 2026-03-16 +--- + + # OpenProject 17.1.3 + + Release date: 2026-03-16 + + We released OpenProject [OpenProject 17.1.3](https://community.openproject.org/versions/2282). + The release contains several bug fixes and we recommend updating to the newest version. + Below you will find a complete list of all changes and bug fixes. + + + +## Security fixes + + + +### CVE-2026-32698 - SQL Injection via Custom Field Name can be chained to Remote Code Execution + +OpenProject is vulnerable to an SQL injection attack via a custom field's name. When that custom field was used in a Cost Report, the custom field's name was injected into the SQL query without proper sanitation. This allowed an attacker to execute arbitrary SQL commands during the generation of a Cost Report.  + + + +As custom fields can only be generated by users with full administrator privileges, the attack surface is somewhat reduced. + + + +Together with another bug in the _Repositories_ module, that used the project identifier without sanitation to generate the checkout path for a git repository in the filesystem, this allowed an attacker to checkout a git repository to an arbitrarily chosen path on the server. If the checkout is done within certain paths within the OpenProject application, upon the next restart of the application, this allows the attacker to inject ruby code into the application. + + + +As the project identifier cannot be manually edited to any string containing special characters like dots or slashes, this needs to be changed via the SQL injection described above. + + + +This vulnerability was reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-jqhf-rf9x-9rhx](https://github.com/opf/openproject/security/advisories/GHSA-jqhf-rf9x-9rhx) + + + +### CVE-2026-32703 - Repository files are served with the MIME type allowing them to be used to bypass Content Security Policy + +When using the Repositories module in a project, it was possible to access the raw files via the browser with a URL like `/projects/{project}/repository/revisions/{commit_id}/raw/{file}.js.raw`. For those files, the MIME type was detected via the filename extension. For JavaScript and CSS files those files were then served from the same domain name as the application with the correct MIME type for active content and could be used to bypass the Content Security Policy. Together with other areas, where unsanitized HTML was served, this allowed persistent XSS attacks. + + + +The MIME type detection for Repository files has been removed and files are served as `application/octet-stream` which will block their execution via the Content Security Policy. + + + +Two places that could be used to abuse this vulnerability have been fixed: + + + +The Repositories module did not properly escape filenames displayed from repositories. This allowed an attacker with push access into the repository to create commits with filenames that included HTML code that was injected in the page without proper sanitation. This allowed a persisted XSS attack against all members of this project that accessed the repositories page to display a changeset where the maliciously crafted file was deleted. + + + +When a work package name contains HTML content and the work package is attached to a meeting, the work package name is rendered in the activities feed without proper sanitation. + + + +All of those vulnerabilities were reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-p423-72h4-fjvp](https://github.com/opf/openproject/security/advisories/GHSA-p423-72h4-fjvp) + + + + + + +## Bug fixes and changes + + + + +- Bugfix: Internal error saving project list (when creating new one, or renaming an existing one) \[[#72362](https://community.openproject.org/wp/72362)\] +- Bugfix: Can't create automatically managed project folder when project name contains forbidden Nextcloud characters \[[#72525](https://community.openproject.org/wp/72525)\] + + + diff --git a/docs/release-notes/17-2-0/README.md b/docs/release-notes/17-2-0/README.md index fc2917c86d8..a8a383afa0f 100644 --- a/docs/release-notes/17-2-0/README.md +++ b/docs/release-notes/17-2-0/README.md @@ -14,9 +14,6 @@ release_date: 2026-03-11 The release contains several bug fixes and we recommend updating to the newest version. In these Release Notes, we will give an overview of important feature changes. At the end, you will find a complete list of all changes and bug fixes. - - - ## Important feature changes @@ -96,7 +93,7 @@ OpenProject 17.2 introduces optional comment fields for project attributes, givi Comments are displayed and edited alongside the respective attribute on the Project overview page and follow the same permission logic as the attribute itself. Changes are tracked in the project activity, included in exports, and available via the API. By adding structured context to project metadata, this enhancement improves transparency and supports better governance and decision-making across projects and teams. -![Setting to add a comment text field to a project atttribute in OpenProject administration](openproject_release_notes_17-2-0_project_attributes_comment.png) +![Setting to add a comment text field to a project attribute in OpenProject administration](openproject_release_notes_17-2-0_project_attributes_comment.png) Read more about [project attributes in OpenProject](../../user-guide/project-home/project-attributes/). @@ -138,7 +135,7 @@ We are working on a new Jira import wizard designed to help teams migrate core p > [!IMPORTANT] > This functionality is still under active development and currently available only behind a feature flag for early testing. We’re sharing this preview to start the conversation with teams considering a move from Jira. More capabilities will follow in upcoming releases. -![Add a new confgiruration to Jira importer under OpenProject administration](openproject_release_notes_17-2-0_jira_migrator.png) +![Add a new configuration to Jira importer under OpenProject administration](openproject_release_notes_17-2-0_jira_migrator.png) To find out more [see what we are working on](https://community.openproject.org/projects/jira-migration/work_packages). @@ -157,72 +154,197 @@ Newly generated API tokens can directly be used as Bearer tokens and do not need + + +## Security fixes + + + +### CVE-2026-30234 - OpenProject BIM BCF XML Import: Path Traversal Leads to Arbitrary Local File Read (AFR) + +An authenticated project member with BCF import permissions can upload a crafted `.bcf` archive where the `` value in `markup.bcf` is manipulated to contain an absolute or traversal local path (for example: `/etc/passwd` or `../../../../etc/passwd`). + + + +During import, this untrusted `` value is used as `file.path` during attachment processing. + +As a result, local filesystem content can be read outside the intended ZIP scope. + + + +This results in an **Arbitrary File Read (AFR)** within the read permissions of the OpenProject application user. + + + +This vulnerability was reported independently by users sam91281 and DQH1 as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-q8c5-vpmm-xrxv](https://github.com/opf/openproject/security/advisories/GHSA-q8c5-vpmm-xrxv) + + + +### CVE-2026-30235 - Business Logic Error on OpenProject through hyperlinks in markdown using DOM clobbering + +This vulnerability occurs due to improper validation of OpenProject’s Markdown rendering, specifically in the hyperlink handling. This allows an attacker to inject malicious hyperlink payloads that perform DOM clobbering. DOM clobbering can crash or blank the entire page by overwriting native DOM functions with HTML elements, causing critical JavaScript calls to throw runtime errors during application initialization and halt further execution. + + + +This vulnerability was reported by user frozzipies as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-9rv2-9xv5-gpq8](https://github.com/opf/openproject/security/advisories/GHSA-9rv2-9xv5-gpq8) + + + +### CVE-2026-30236 - Users that are not project members can be used to calculate Labor Budget, leaking their global hourly rate + +When editing a project budget and planning the labor cost, it was not checked that the user that was planned in the budget is actually a project member. This exposed the user's default rate (if one was set up) to users that should only see that information for project members. + + + +Also, the endpoint that handles the pre-calculation for the frontend to display a preview of the costs, while it was being entered, did not properly validate the membership of the user as well. This also allowed to calculate costs with the default rate of non-members. + + + +This vulnerability was reported by user Thesecret2055 as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-p747-569x-3v3f](https://github.com/opf/openproject/security/advisories/GHSA-p747-569x-3v3f) + + + +### CVE-2026-30239 - Permission Check bypass on Budget deletion allows reassignment of WorkPackages into other budgets + +When budgets are deleted, the work packages that were assigned to this budget need to be moved to a different budget. This action was performed before the permission check on the delete action was executed. This allowed all users in the application to delete work package budget assignments. + + + +This vulnerability was reported by user cavid as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-gpvh-g967-g4h8](https://github.com/opf/openproject/security/advisories/GHSA-gpvh-g967-g4h8) + + + +### CVE-2026-31974 - Blind SSRF on OpenProject instance via webhooks, and through /admin/test_email via POST request leads to internal network reconnaissance + +OpenProject SMTP test endpoint (POST /admin/settings/mail\_notifications) accepts arbitrary host and port values and exhibits measurable differences in response behaviour depending on whether the target IP exists and whether the port is open. An attacker with access can use these timing and error distinctions to map internal hosts and identify which services/ports are reachable. + + + +Similarly, you can create webhooks in OpenProject and point them to arbitrary IPs, resulting in the same kind of SSRF issue which allows attackers to scan the internal network. + + + +This vulnerability was reported by user [drak3hft7](https://yeswehack.com/hunters/drak3hft7) and [adilburak](https://yeswehack.com/hunters/drak3hft7) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-9wr7-j98g-2jh3](https://github.com/opf/openproject/security/advisories/GHSA-9wr7-j98g-2jh3) + + + + + ## Bug fixes and changes -- Feature: Reusable meeting templates for meeting agendas [[#35642](https://community.openproject.org/wp/35642)] -- Feature: Primerized Backlogs list [[#57688](https://community.openproject.org/wp/57688)] -- Feature: Export relationship columns in PDF report [[#66000](https://community.openproject.org/wp/66000)] -- Feature: Overview widget for Budgets [[#66124](https://community.openproject.org/wp/66124)] -- Feature: Comment fields for project attributes [[#66343](https://community.openproject.org/wp/66343)] -- Feature: Make project description and status widget editable on Overview tab [[#67690](https://community.openproject.org/wp/67690)] -- Feature: Implement token refreshing and reduce token expiration time [[#68460](https://community.openproject.org/wp/68460)] -- Feature: Display custom field type on form [[#68524](https://community.openproject.org/wp/68524)] -- Feature: MCP Server Infrastructure and Metadata Endpoint [[#68683](https://community.openproject.org/wp/68683)] -- Feature: Integrate MCP Authentication with OpenProject OAuth2 [[#68685](https://community.openproject.org/wp/68685)] -- Feature: Provide initial set of MCP Tools [[#68686](https://community.openproject.org/wp/68686)] -- Feature: Expose OpenProject APIv3 Entities as MCP Resources [[#68689](https://community.openproject.org/wp/68689)] -- Feature: Add Admin Page for MCP Configuration [[#68690](https://community.openproject.org/wp/68690)] -- Feature: Standardized inplace edit fields based on Primer [[#68832](https://community.openproject.org/wp/68832)] -- Feature: Add enterprise banner for MCP server [[#70086](https://community.openproject.org/wp/70086)] -- Feature: Primerize Custom Field forms [[#70292](https://community.openproject.org/wp/70292)] -- Feature: Support WebP images in PDF exports [[#70333](https://community.openproject.org/wp/70333)] -- Feature: Rename status boards to kanban boards [[#70911](https://community.openproject.org/wp/70911)] -- Feature: Use autocompleters in Admin/Backlogs page [[#71069](https://community.openproject.org/wp/71069)] -- Feature: Improve Accessibility of Project Overview and Dashboard Widgets [[#71075](https://community.openproject.org/wp/71075)] -- Feature: Allow to use API Keys as Bearer tokens [[#71147](https://community.openproject.org/wp/71147)] -- Feature: Allow requiring to be logged in for external links [[#71624](https://community.openproject.org/wp/71624)] -- Feature: Primerize versions project settings [[#71641](https://community.openproject.org/wp/71641)] -- Feature: Primerize groups administration [[#71642](https://community.openproject.org/wp/71642)] -- Feature: Rename "Enable REST web service" setting [[#71886](https://community.openproject.org/wp/71886)] -- Feature: Reduce page size of MCP responses [[#71977](https://community.openproject.org/wp/71977)] -- Feature: Allow to configure MCP tool response volume [[#71978](https://community.openproject.org/wp/71978)] -- Feature: Allow authentication to MCP endpoint via session cookie [[#72253](https://community.openproject.org/wp/72253)] -- Feature: Enable Column Sorting on Versions Overview [[#72354](https://community.openproject.org/wp/72354)] -- Feature: Add "beta" label in MCP Admin settings headline [[#72511](https://community.openproject.org/wp/72511)] -- Feature: MCP Server as a bridge between OpenProject and LLMs [[#62781](https://community.openproject.org/wp/62781)] -- Bugfix: Children column on WP list cannot be expanded [[#64491](https://community.openproject.org/wp/64491)] -- Bugfix: DPA/AVV cannot be downloaded [[#67323](https://community.openproject.org/wp/67323)] -- Bugfix: BlockNote: Color for text not applied from the block side menu [[#67507](https://community.openproject.org/wp/67507)] -- Bugfix: Mobile web: When deep linking to a comment the comment is not fully scrolled into view [[#68221](https://community.openproject.org/wp/68221)] -- Bugfix: Updating the activity anchor URL without a page load does not highlight the relevant target element [[#68262](https://community.openproject.org/wp/68262)] -- Bugfix: Documents index page: pagination per page options overflow on mobile [[#68533](https://community.openproject.org/wp/68533)] -- Bugfix: Changing the filter on the activity tab with a large number of comments and slow network/compute lacks loading state while waiting for request completion [[#68878](https://community.openproject.org/wp/68878)] -- Bugfix: Flickering spec ./modules/meeting/spec/features/structured_meetings/work_package_meetings_tab_spec.rb:392 [[#68952](https://community.openproject.org/wp/68952)] -- Bugfix: Clicking work package tabs triggers page reload and flickering [[#69210](https://community.openproject.org/wp/69210)] -- Bugfix: Label for the admin document types reflects "priorities" instead of "types" in its messaging [[#69304](https://community.openproject.org/wp/69304)] -- Bugfix: Infinite SAML Seeding Loop Causing Disk Space Exhaustion [[#69339](https://community.openproject.org/wp/69339)] -- Bugfix: "Show attachments in the files tab by default" potentially overwrites the setting for existing project [[#69991](https://community.openproject.org/wp/69991)] -- Bugfix: Fix accessibility errors found by ERB Lint [[#70166](https://community.openproject.org/wp/70166)] -- Bugfix: Missing list items when using checkboxes in tables [[#70537](https://community.openproject.org/wp/70537)] -- Bugfix: Documents: when document content exceeds vertical height, the cursor does not scroll into view unless there is content typed [[#70791](https://community.openproject.org/wp/70791)] -- Bugfix: Helm-Chart: Allow user to provide service specific annotations [[#71055](https://community.openproject.org/wp/71055)] -- Bugfix: Activity tab overflows with long names [[#71106](https://community.openproject.org/wp/71106)] -- Bugfix: Multi-user custom field requires clicking twice in order to be in focus [[#71135](https://community.openproject.org/wp/71135)] -- Bugfix: Status translation issue on status widget [[#71137](https://community.openproject.org/wp/71137)] -- Bugfix: Unnecessary empty journals on dragging work packages with automatic subjects [[#71421](https://community.openproject.org/wp/71421)] -- Bugfix: Sending mails via sendmail does not work [[#71447](https://community.openproject.org/wp/71447)] -- Bugfix: Error Content-Security-Policy with Hocuspocus integration due to URL scheme misconfiguration [[#71888](https://community.openproject.org/wp/71888)] -- Bugfix: BlockNote Extension: Click on WP title opens new tab and redirects the current tab [[#71898](https://community.openproject.org/wp/71898)] -- Bugfix: Connection error on successive navigation to and from a document [[#71901](https://community.openproject.org/wp/71901)] -- Bugfix: Impossible to search for archived projects, page reverts to active projects list on its own [[#71971](https://community.openproject.org/wp/71971)] -- Bugfix: Remove presenter field/participants references in onetime templates [[#72222](https://community.openproject.org/wp/72222)] -- Bugfix: Space is too small for placeholder text in Backlogs module [[#72366](https://community.openproject.org/wp/72366)] -- Bugfix: Missing caption in new template dialog [[#72375](https://community.openproject.org/wp/72375)] -- Bugfix: Wrong wording in Enterprise on-prem support token input field [[#72459](https://community.openproject.org/wp/72459)] - +- Feature: Reusable meeting templates for meeting agendas \[[#35642](https://community.openproject.org/wp/35642)\] +- Feature: Primerized Backlogs list \[[#57688](https://community.openproject.org/wp/57688)\] +- Feature: Export relationship columns in PDF report \[[#66000](https://community.openproject.org/wp/66000)\] +- Feature: Overview widget for Budgets \[[#66124](https://community.openproject.org/wp/66124)\] +- Feature: Comment fields for project attributes \[[#66343](https://community.openproject.org/wp/66343)\] +- Feature: Make project description and status widget editable on Overview tab \[[#67690](https://community.openproject.org/wp/67690)\] +- Feature: Implement token refreshing and reduce token expiration time \[[#68460](https://community.openproject.org/wp/68460)\] +- Feature: Display custom field type on form \[[#68524](https://community.openproject.org/wp/68524)\] +- Feature: MCP Server Infrastructure and Metadata Endpoint \[[#68683](https://community.openproject.org/wp/68683)\] +- Feature: Integrate MCP Authentication with OpenProject OAuth2 \[[#68685](https://community.openproject.org/wp/68685)\] +- Feature: Provide initial set of MCP Tools \[[#68686](https://community.openproject.org/wp/68686)\] +- Feature: Expose OpenProject APIv3 Entities as MCP Resources \[[#68689](https://community.openproject.org/wp/68689)\] +- Feature: Add Admin Page for MCP Configuration \[[#68690](https://community.openproject.org/wp/68690)\] +- Feature: Standardized inplace edit fields based on Primer \[[#68832](https://community.openproject.org/wp/68832)\] +- Feature: Add enterprise banner for MCP server \[[#70086](https://community.openproject.org/wp/70086)\] +- Feature: Primerize Custom Field forms \[[#70292](https://community.openproject.org/wp/70292)\] +- Feature: Support WebP images in PDF exports \[[#70333](https://community.openproject.org/wp/70333)\] +- Feature: Rename status boards to kanban boards \[[#70911](https://community.openproject.org/wp/70911)\] +- Feature: Use autocompleters in Admin/Backlogs page \[[#71069](https://community.openproject.org/wp/71069)\] +- Feature: Improve Accessibility of Project Overview and Dashboard Widgets \[[#71075](https://community.openproject.org/wp/71075)\] +- Feature: Allow to use API Keys as Bearer tokens \[[#71147](https://community.openproject.org/wp/71147)\] +- Feature: Allow requiring to be logged in for external links \[[#71624](https://community.openproject.org/wp/71624)\] +- Feature: Primerize versions project settings \[[#71641](https://community.openproject.org/wp/71641)\] +- Feature: Primerize groups administration \[[#71642](https://community.openproject.org/wp/71642)\] +- Feature: Rename "Enable REST web service" setting \[[#71886](https://community.openproject.org/wp/71886)\] +- Feature: Reduce page size of MCP responses \[[#71977](https://community.openproject.org/wp/71977)\] +- Feature: Allow to configure MCP tool response volume \[[#71978](https://community.openproject.org/wp/71978)\] +- Feature: Allow authentication to MCP endpoint via session cookie \[[#72253](https://community.openproject.org/wp/72253)\] +- Feature: Enable Column Sorting on Versions Overview \[[#72354](https://community.openproject.org/wp/72354)\] +- Feature: Add "beta" label in MCP Admin settings headline \[[#72511](https://community.openproject.org/wp/72511)\] +- Bugfix: DPA/AVV cannot be downloaded \[[#67323](https://community.openproject.org/wp/67323)\] +- Bugfix: Score is saved as '2.0' even if user inputs '2' \[[#67670](https://community.openproject.org/wp/67670)\] +- Bugfix: Documents index page: pagination per page options overflow on mobile \[[#68533](https://community.openproject.org/wp/68533)\] +- Bugfix: Real-time collaboration admin page: two sentence paragraph is displayed on a single line \[[#69913](https://community.openproject.org/wp/69913)\] +- Bugfix: Accessibility: Primer Text Field clear button ARIA label not localized \[[#69915](https://community.openproject.org/wp/69915)\] +- Bugfix: "Show attachments in the files tab by default" potentially overwrites the setting for existing project \[[#69991](https://community.openproject.org/wp/69991)\] +- Bugfix: Activity tab overflows with long names \[[#71106](https://community.openproject.org/wp/71106)\] +- Bugfix: Multi-user custom field requires clicking twice in order to be in focus \[[#71135](https://community.openproject.org/wp/71135)\] +- Bugfix: Status translation issue on status widget \[[#71137](https://community.openproject.org/wp/71137)\] +- Bugfix: Single Date Picker does not show placeholder text \[[#71351](https://community.openproject.org/wp/71351)\] +- Bugfix: Unnecessary empty journals on dragging work packages with automatic subjects \[[#71421](https://community.openproject.org/wp/71421)\] +- Bugfix: Editor is not focused when activating edit field \[[#71863](https://community.openproject.org/wp/71863)\] +- Bugfix: Error Content-Security-Policy with Hocuspocus integration due to URL scheme misconfiguration \[[#71888](https://community.openproject.org/wp/71888)\] +- Bugfix: Trailing slash in the end of Jira host URL breaks migration \[[#71937](https://community.openproject.org/wp/71937)\] +- Bugfix: ArgumentError in HomescreenController#index \[[#71964](https://community.openproject.org/wp/71964)\] +- Bugfix: User cannot create a WP with auto generated subject \[[#72207](https://community.openproject.org/wp/72207)\] +- Bugfix: Remove presenter field/participants references in onetime templates \[[#72222](https://community.openproject.org/wp/72222)\] +- Bugfix: Titles and totals are cut off \[[#72248](https://community.openproject.org/wp/72248)\] +- Bugfix: Replace EUR with € in cost currency setting default and harmonize widgets \[[#72262](https://community.openproject.org/wp/72262)\] +- Bugfix: Overview widget is not editable if there is no existing description \[[#72361](https://community.openproject.org/wp/72361)\] +- Bugfix: Overview placeholder is wrong for users without permissions \[[#72365](https://community.openproject.org/wp/72365)\] +- Bugfix: Space is too small for placeholder text in Backlogs module \[[#72366](https://community.openproject.org/wp/72366)\] +- Bugfix: User can get edit budget permissions without view budget permissions \[[#72374](https://community.openproject.org/wp/72374)\] +- Bugfix: Missing caption in new template dialog \[[#72375](https://community.openproject.org/wp/72375)\] +- Bugfix: Defect in attachment MIME detection probably with direct uploads \[[#72452](https://community.openproject.org/wp/72452)\] +- Bugfix: Version's title is not truncated on the backlogs header \[[#72454](https://community.openproject.org/wp/72454)\] +- Bugfix: Wrong wording in Enterprise on-prem support token input field \[[#72459](https://community.openproject.org/wp/72459)\] +- Bugfix: Custom Logo not displayed in PDF export \[[#72520](https://community.openproject.org/wp/72520)\] +- Bugfix: Move behind enterprise check \[[#72539](https://community.openproject.org/wp/72539)\] +- Bugfix: Comment field not included in PDF export of PIR \[[#72541](https://community.openproject.org/wp/72541)\] +- Bugfix: Widget does not render with new currency format \[[#72553](https://community.openproject.org/wp/72553)\] +- Bugfix: Meeting templates: Update blankslate text \[[#72569](https://community.openproject.org/wp/72569)\] +- Bugfix: Backlogs: Drag and drop between shared versions does not work \[[#72655](https://community.openproject.org/wp/72655)\] +- Bugfix: Missing translation for projects name on the News index page \[[#72660](https://community.openproject.org/wp/72660)\] +- Bugfix: Trials for OP and BIM are not created \[[#72666](https://community.openproject.org/wp/72666)\] +- Bugfix: Default section of project attributes has no visibility area defined \[[#72671](https://community.openproject.org/wp/72671)\] +- Bugfix: Can not rename a meeting which was created as part of a series \[[#72674](https://community.openproject.org/wp/72674)\] +- Bugfix: WP list is blank if user adds Unit costs as a column \[[#72675](https://community.openproject.org/wp/72675)\] +- Bugfix: 'Actual costs per months' widget does not show previous 12 months \[[#72676](https://community.openproject.org/wp/72676)\] +- Bugfix: Codeblock editor appears behind new WP dialog \[[#72677](https://community.openproject.org/wp/72677)\] +- Bugfix: Refine widget blankslate text and position \[[#72681](https://community.openproject.org/wp/72681)\] +- Bugfix: WP CF of type List does not display info banner upon creation \[[#72761](https://community.openproject.org/wp/72761)\] +- Bugfix: CF is in focus even if user does not click on it \[[#72762](https://community.openproject.org/wp/72762)\] +- Bugfix: Colors in the 'Actual cost per month' graph legend and on the chart do not match if users do not have a set rate \[[#72766](https://community.openproject.org/wp/72766)\] +- Bugfix: Chart doesn't expand and Cost list is cut when costs go over budget \[[#72771](https://community.openproject.org/wp/72771)\] +- Bugfix: Jira import: Personal Access Token is not mandatory \[[#72793](https://community.openproject.org/wp/72793)\] +- Bugfix: Rephrase 'Budget by cost type' subtitle for portfolios \[[#72795](https://community.openproject.org/wp/72795)\] +- Bugfix: Budgets widget: Data from subitems is not aggregated if workspace type is not Portfolio \[[#72797](https://community.openproject.org/wp/72797)\] +- Bugfix: Jira import: previous configuration data are still visible when we go back with back button and create a new configuration \[[#72803](https://community.openproject.org/wp/72803)\] +- Bugfix: Refactor ProjectCustomFields::LoadService \[[#72823](https://community.openproject.org/wp/72823)\] +- Bugfix: Update meeting template page button \[[#72839](https://community.openproject.org/wp/72839)\] +- Bugfix: Items are not staying assigned to a meeting section on meeting template \[[#72872](https://community.openproject.org/wp/72872)\] +- Bugfix: Fix meeting template attachment text \[[#72874](https://community.openproject.org/wp/72874)\] +- Bugfix: Fix meeting template delete dialog text \[[#72875](https://community.openproject.org/wp/72875)\] +- Bugfix: Opening WP details view via menu does full page refresh \[[#72885](https://community.openproject.org/wp/72885)\] +- Bugfix: Jira import error: Couldn't find User with \[WHERE "users"."type" IN ($1, $2, $3, $4, $5) AND "users"."status" != $6 AND "users"."login" = $7\] \[[#72908](https://community.openproject.org/wp/72908)\] +- Bugfix: User is not redirected to the Template index page after deleting a template \[[#72909](https://community.openproject.org/wp/72909)\] +- Bugfix: Order of MCP tools and resources change in the table if user updates title \[[#72920](https://community.openproject.org/wp/72920)\] +- Bugfix: Backlogs: Story drag and drop does not handle errors properly \[[#72927](https://community.openproject.org/wp/72927)\] +- Bugfix: Backlogs: Backlogs are not updated with Turbo morphing \[[#72928](https://community.openproject.org/wp/72928)\] @@ -238,4 +360,4 @@ Last but not least, we are very grateful for our very engaged translation contri - [Mehmet Coşkun](https://crowdin.com/profile/mmehmet.ccoskun), for a great number of translations into Turkish. - [Liangzdz](https://crowdin.com/profile/liangzdz), for a great number of translations into Chinese Simplified. -Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! \ No newline at end of file +Would you like to help out with translations yourself? Then take a look at our [translation guide](../../contributions-guide/translate-openproject/) and find out exactly how you can contribute. It is very much appreciated! diff --git a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_budget_widget.png b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_budget_widget.png index 03d248d4e39..956bc8e1f8b 100644 Binary files a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_budget_widget.png and b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_budget_widget.png differ diff --git a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_external_links_log_in.png b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_external_links_log_in.png index fbacd8e7e33..22747db49a3 100644 Binary files a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_external_links_log_in.png and b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_external_links_log_in.png differ diff --git a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_jira_migrator.png b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_jira_migrator.png index b3f1a87ca1c..532ecd85591 100644 Binary files a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_jira_migrator.png and b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_jira_migrator.png differ diff --git a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_meetings_template.png b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_meetings_template.png index 87aa3176a59..e217ac9821d 100644 Binary files a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_meetings_template.png and b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_meetings_template.png differ diff --git a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_project_attributes_comment.png b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_project_attributes_comment.png index f864de8c7d0..165eec8ce8a 100644 Binary files a/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_project_attributes_comment.png and b/docs/release-notes/17-2-0/openproject_release_notes_17-2-0_project_attributes_comment.png differ diff --git a/docs/release-notes/17-2-0/openproject_system_guide_new_backlog.png b/docs/release-notes/17-2-0/openproject_system_guide_new_backlog.png index aa94c7b6ef9..d97db95fa40 100644 Binary files a/docs/release-notes/17-2-0/openproject_system_guide_new_backlog.png and b/docs/release-notes/17-2-0/openproject_system_guide_new_backlog.png differ diff --git a/docs/release-notes/17-2-0/openproject_system_guide_new_mcp.png b/docs/release-notes/17-2-0/openproject_system_guide_new_mcp.png index 4de3c622477..8fc77db6430 100644 Binary files a/docs/release-notes/17-2-0/openproject_system_guide_new_mcp.png and b/docs/release-notes/17-2-0/openproject_system_guide_new_mcp.png differ diff --git a/docs/release-notes/17-2-0/openproject_system_guide_pdf_export.png b/docs/release-notes/17-2-0/openproject_system_guide_pdf_export.png index da9890151d3..c2b21bda0db 100644 Binary files a/docs/release-notes/17-2-0/openproject_system_guide_pdf_export.png and b/docs/release-notes/17-2-0/openproject_system_guide_pdf_export.png differ diff --git a/docs/release-notes/17-2-0/openproject_system_guide_project_home_overview_tab_edit.png b/docs/release-notes/17-2-0/openproject_system_guide_project_home_overview_tab_edit.png index 0047c5b02c7..a3c9be4e3d6 100644 Binary files a/docs/release-notes/17-2-0/openproject_system_guide_project_home_overview_tab_edit.png and b/docs/release-notes/17-2-0/openproject_system_guide_project_home_overview_tab_edit.png differ diff --git a/docs/release-notes/17-2-1/README.md b/docs/release-notes/17-2-1/README.md new file mode 100644 index 00000000000..66f0cf45c98 --- /dev/null +++ b/docs/release-notes/17-2-1/README.md @@ -0,0 +1,98 @@ +--- +title: OpenProject 17.2.1 +sidebar_navigation: + title: 17.2.1 +release_version: 17.2.1 +release_date: 2026-03-16 +--- + + # OpenProject 17.2.1 + + Release date: 2026-03-16 + + We released OpenProject [OpenProject 17.2.1](https://community.openproject.org/versions/2283). + The release contains several bug fixes and we recommend updating to the newest version. + Below you will find a complete list of all changes and bug fixes. + + + +## Security fixes + + + +### CVE-2026-32698 - SQL Injection via Custom Field Name can be chained to Remote Code Execution + +OpenProject is vulnerable to an SQL injection attack via a custom field's name. When that custom field was used in a Cost Report, the custom field's name was injected into the SQL query without proper sanitation. This allowed an attacker to execute arbitrary SQL commands during the generation of a Cost Report.  + + + +As custom fields can only be generated by users with full administrator privileges, the attack surface is somewhat reduced. + + + +Together with another bug in the _Repositories_ module, that used the project identifier without sanitation to generate the checkout path for a git repository in the filesystem, this allowed an attacker to checkout a git repository to an arbitrarily chosen path on the server. If the checkout is done within certain paths within the OpenProject application, upon the next restart of the application, this allows the attacker to inject ruby code into the application. + + + +As the project identifier cannot be manually edited to any string containing special characters like dots or slashes, this needs to be changed via the SQL injection described above. + + + +This vulnerability was reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-jqhf-rf9x-9rhx](https://github.com/opf/openproject/security/advisories/GHSA-jqhf-rf9x-9rhx) + + + +### CVE-2026-32703 - Repository files are served with the MIME type allowing them to be used to bypass Content Security Policy + +When using the Repositories module in a project, it was possible to access the raw files via the browser with a URL like `/projects/{project}/repository/revisions/{commit_id}/raw/{file}.js.raw`. For those files, the MIME type was detected via the filename extension. For JavaScript and CSS files those files were then served from the same domain name as the application with the correct MIME type for active content and could be used to bypass the Content Security Policy. Together with other areas, where unsanitized HTML was served, this allowed persistent XSS attacks. + + + +The MIME type detection for Repository files has been removed and files are served as `application/octet-stream` which will block their execution via the Content Security Policy. + + + +Two places that could be used to abuse this vulnerability have been fixed: + + + +The Repositories module did not properly escape filenames displayed from repositories. This allowed an attacker with push access into the repository to create commits with filenames that included HTML code that was injected in the page without proper sanitation. This allowed a persisted XSS attack against all members of this project that accessed the repositories page to display a changeset where the maliciously crafted file was deleted. + + + +When a work package name contains HTML content and the work package is attached to a meeting, the work package name is rendered in the activities feed without proper sanitation. + + + +All of those vulnerabilities were reported by user [sam91281](https://yeswehack.com/hunters/sam91281) as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-p423-72h4-fjvp](https://github.com/opf/openproject/security/advisories/GHSA-p423-72h4-fjvp) + + + + + + +## Bug fixes and changes + + + + +- Bugfix: Screenshot overlaps with CKeditor tool bar when scrolling \[[#72678](https://community.openproject.org/wp/72678)\] +- Bugfix: Jira import: error when imported type is the same as on OP (with mandatory custom fields) \[[#72854](https://community.openproject.org/wp/72854)\] +- Bugfix: Nextcloud: When creating an AMPF folder fails, other folders are also not created \[[#72940](https://community.openproject.org/wp/72940)\] +- Bugfix: Send test email fails when using SMTP and TLS \[[#73099](https://community.openproject.org/wp/73099)\] +- Bugfix: curl removed from openproject/openproject:17-slim in 17.2.0 \[[#73142](https://community.openproject.org/wp/73142)\] + + + + +## Contributions +A big thanks to our Community members for reporting bugs and helping us identify and provide fixes. +This release, special thanks for reporting and finding bugs go to Martin Pfister. diff --git a/docs/release-notes/17-2-2/README.md b/docs/release-notes/17-2-2/README.md new file mode 100644 index 00000000000..7a4fe6f21e3 --- /dev/null +++ b/docs/release-notes/17-2-2/README.md @@ -0,0 +1,33 @@ +--- +title: OpenProject 17.2.2 +sidebar_navigation: + title: 17.2.2 +release_version: 17.2.2 +release_date: 2026-03-17 +--- + + # OpenProject 17.2.2 + + Release date: 2026-03-17 + + We released OpenProject [OpenProject 17.2.2](https://community.openproject.org/versions/2284). + The release contains several bug fixes and we recommend updating to the newest version. + Below you will find a complete list of all changes and bug fixes. + + + + + + + +## Bug fixes and changes + + + + +- Bugfix: Send test email fails when using SMTP and TLS \[[#73099](https://community.openproject.org/wp/73099)\] +- Bugfix: Webhook sends wrong Content-Type header \[[#73145](https://community.openproject.org/wp/73145)\] +- Bugfix: Cannot set the "Used as backlog" field in the Project Version settings. \[[#73187](https://community.openproject.org/wp/73187)\] + + + diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index c4ab1bc9afc..1f5645ff4d1 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -13,6 +13,33 @@ Stay up to date and get an overview of the new features included in the releases +## 17.2.2 + +Release date: 2026-03-17 + +[Release Notes](17-2-2/) + + +## 17.2.1 + +Release date: 2026-03-16 + +[Release Notes](17-2-1/) + + +## 17.1.3 + +Release date: 2026-03-16 + +[Release Notes](17-1-3/) + + +## 17.2.0 + +Release date: 2026-03-11 + +[Release Notes](17-2-0/) + ## 17.1.2 Release date: 2026-02-26 @@ -20,20 +47,24 @@ Release date: 2026-02-26 [Release Notes](17-1-2/) +## 17.0.6 + +Release date: 2026-03-16 + +[Release Notes](17-0-6/) + ## 17.0.5 Release date: 2026-02-26 [Release Notes](17-0-5/) - ## 17.1.1 Release date: 2026-02-18 [Release Notes](17-1-1/) - ## 17.1.0 Release date: 2026-02-11 @@ -46,24 +77,11 @@ Release date: 2026-02-18 [Release Notes](17-0-4/) - ## 17.0.3 Release date: 2026-02-06 [Release Notes](17-0-3/) -## 16.6.8 - -Release date: 2026-02-18 - -[Release Notes](16-6-8/) - - -## 16.6.7 - -Release date: 2026-02-06 - -[Release Notes](16-6-7/) ## 17.0.2 @@ -82,154 +100,12 @@ Release date: 2026-01-16 Release date: 2026-01-14 [Release Notes](17-0-0/) -## 16.6.6 - -Release date: 2026-01-27 - -[Release Notes](16-6-6/) - -## 16.6.5 - -Release date: 2026-01-16 - -[Release Notes](16-6-5/) - -## 16.6.4 - -Release date: 2026-01-08 - -[Release Notes](16-6-4/) - - -## 16.6.3 - -Release date: 2025-12-11 - -[Release Notes](16-6-3/) - - -## 16.6.2 - -Release date: 2025-12-02 - -[Release Notes](16-6-2/) - - -## 16.6.1 - -Release date: 2025-11-13 - -[Release Notes](16-6-1/) - - -## 16.6.0 - -Release date: 2025-11-05 - -[Release Notes](16-6-0/) - - -## 16.5.1 - -Release date: 2025-10-15 - -[Release Notes](16-5-1/) - - -## 16.5.0 - -Release date: 2025-10-08 - -[Release Notes](16-5-0/) - - -## 16.4.1 - -Release date: 2025-09-16 - -[Release Notes](16-4-1/) - - -## 16.4.0 - -Release date: 2025-09-10 - -[Release Notes](16-4-0/) - - -## 16.3.2 - -Release date: 2025-08-25 - -[Release Notes](16-3-2/) - - -## 16.3.1 - -Release date: 2025-08-13 - -[Release Notes](16-3-1/) - - -## 16.3.0 - -Release date: 2025-08-13 - -[Release Notes](16-3-0/) - - -## 16.2.2 - -Release date: 2025-08-07 - -[Release Notes](16-2-2/) - - -## 16.2.1 - -Release date: 2025-08-04 - -[Release Notes](16-2-1/) - - -## 16.2.0 - -Release date: 2025-07-16 - -[Release Notes](16-2-0/) - - -## 16.1.1 - -Release date: 2025-06-26 - -[Release Notes](16-1-1/) - - -## 16.1.0 - -Release date: 2025-06-18 - -[Release Notes](16-1-0/) - - -## 16.0.1 - -Release date: 2025-06-05 - -[Release Notes](16-0-1/) - - -## 16.0.0 - -Release date: 2025-05-21 - -[Release Notes](16-0-0/) ## Older versions | Version | Years | |-------------|--------------------| +| [16.x](16/) | 2025 / 2026 | | [15.x](15/) | 2024 / 2025 | | [14.x](14/) | 2024 | | [13.x](13/) | 2023 / 2024 | diff --git a/docs/security-and-privacy/statement-on-security/README.md b/docs/security-and-privacy/statement-on-security/README.md index 01632b85a44..79861ce3d82 100644 --- a/docs/security-and-privacy/statement-on-security/README.md +++ b/docs/security-and-privacy/statement-on-security/README.md @@ -66,7 +66,7 @@ Please include a description on how to reproduce the issue if possible. Our secu OpenProject is currently subject of a bug bounty program, kindly sponsored by the European Commission. Please see https://yeswehack.com/programs/openproject for more details. -Please note that OpenProject does not offer its own bug bounty program. For any security vulnerability you responsibly disclose to it, whether it's through another bug bounty porgram or through our website, we will do our best to give you the appropriate credits for responsibly disclosing a security vulnerability to us. We will gladly reference your work, name, website on every publication we do related to the security update. +Please note that OpenProject does not offer its own bug bounty program. For any security vulnerability you responsibly disclose to it, whether it's through another bug bounty program or through our website, we will do our best to give you the appropriate credits for responsibly disclosing a security vulnerability to us. We will gladly reference your work, name, website on every publication we do related to the security update. ## OpenProject security features diff --git a/docs/system-admin-guide/api-and-webhooks/openproject_system_admin_guide_api.png b/docs/system-admin-guide/api-and-webhooks/openproject_system_admin_guide_api.png index 9e6cadd7215..593e47ac2ae 100644 Binary files a/docs/system-admin-guide/api-and-webhooks/openproject_system_admin_guide_api.png and b/docs/system-admin-guide/api-and-webhooks/openproject_system_admin_guide_api.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_add.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_add.png index f80959d974c..7d10169677e 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_add.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_add.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_edit_delete.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_edit_delete.png index 0eb2d667c27..a62ec3500c5 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_edit_delete.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_edit_delete.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_example.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_example.png index 68e2404e284..7f21a350a87 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_example.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_example.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_overview.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_overview.png index 6a51841db30..c8ce5a00ecf 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_overview.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_overview.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_overview_page.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_overview_page.png index 7623e67275f..506fc39f92c 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_overview_page.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_overview_page.png differ diff --git a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_settings_page.png b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_settings_page.png index 147c14454a6..d854ea498ab 100644 Binary files a/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_settings_page.png and b/docs/system-admin-guide/attribute-help-texts/openproject_system_admin_guide_attribute_help_texts_project_settings_page.png differ diff --git a/docs/system-admin-guide/authentication/ldap-connections/ldap-group-synchronization/README.md b/docs/system-admin-guide/authentication/ldap-connections/ldap-group-synchronization/README.md index 07c33ce93c5..dc034d2406f 100644 --- a/docs/system-admin-guide/authentication/ldap-connections/ldap-group-synchronization/README.md +++ b/docs/system-admin-guide/authentication/ldap-connections/ldap-group-synchronization/README.md @@ -38,7 +38,7 @@ Synchronizing a single LDAP group allows you to connect an existing group in Ope LDAP group synchronization extends the memberships defined by administrators in an existing OpenProject group. Important things to note are: - You need to have created at least one manual group in the OpenProject administration before you continue. -- Group synchronization for this group is enabled by an administrator cerating a *synchronized LDAP group* that ties the OpenProject group to an LDAP entry. +- Group synchronization for this group is enabled by an administrator creating a *synchronized LDAP group* that ties the OpenProject group to an LDAP entry. - Only synchronized memberships will be removed from the OpenProject group. If you want to add a user outside your LDAP authentication to an OpenProject group, you can do so without the membership being affected from the group synchronization. ### Single synchronized groups diff --git a/docs/system-admin-guide/authentication/scim/README.md b/docs/system-admin-guide/authentication/scim/README.md index 1059979eb11..1018fee8bc8 100644 --- a/docs/system-admin-guide/authentication/scim/README.md +++ b/docs/system-admin-guide/authentication/scim/README.md @@ -22,29 +22,32 @@ SCIM client is a system (e.g. Keycloak with [SCIM plugin](https://github.com/mit A SCIM client sends requests to a SCIM server (in this case OpenProject), asking it to create, update, retrieve, or delete users and groups. +> [!NOTE] +> A SCIM client is able to update and delete **all users and groups** of an OpenProject instance. This not only allows you to fully centralize user management using SCIM, but also puts SCIM clients into a very privileged position inside your OpenProject instance. + To add a new SCIM client, click the **+ SCIM client** button in the upper right corner. -![A button to add a SCIM client on a SCIM clients index page under authentication settings in OpenProject administration](add_scim_1.png) +![A button to add a SCIM client on a SCIM clients index page under authentication settings in OpenProject administration](add_scim_1.png) -A configuration form for your SCIM client will open, in which you can adjust the SCIM client details. +A configuration form for your SCIM client will open, in which you can adjust the SCIM client details. ### Step 1. Enter the **Name** of your SCIM client. -![A SCIM client creation form in OpenProject administration, with the Name field highlighted and filled out](add_scim_2.png) +![A SCIM client creation form in OpenProject administration, with the Name field highlighted and filled out](add_scim_2.png) -### Step 2. Choose an **Authentication provider**. +### Step 2. Choose an **Authentication provider**. This is the service that users added by the SCIM provider will use to authenticate in OpenProject. It must have been configured before creating the SCIM client. It can be an [OIDC provider](../openid-providers/) or a [SAML provider](../saml/). - ![A SCIM client creation form in OpenProject administration, with the "Authentication provider" field highlighted and filled out](add_scim_3.png) + ![A SCIM client creation form in OpenProject administration, with the "Authentication provider" field highlighted and filled out](add_scim_3.png) -### Step 3. Choose an **Authentication method**. +### Step 3. Choose an **Authentication method**. There are three *Authentication method* options you can choose from: #### a. **Static access token** -> [!IMPORTANT] +> [!IMPORTANT] > Static access tokens are valid for period of 1 year. After that, they expire and must be replaced. This is the most commonly used authentication method for SCIM clients. In this case after clicking **Create** you get an access token that should be put to the SCIM client configuration on the other end. @@ -54,28 +57,28 @@ This is the most commonly used authentication method for SCIM clients. In this c Once you click the **Create** button, an access token will be generated. The generated token will be displayed in a pop-up dialogue form. Make sure you copy and save it. After closing the dialog, you will not see the client secret again. ![Add SCIM client. Creation form. Static access token. Copy token.](add_scim_5.png) - -Once created, a SCIM client will appear on the SCIM clients index page. + +Once created, a SCIM client will appear on the SCIM clients index page. ![Scim clients index page listing all created clients under authentication settings in OpenProject administration](openproject_system_administration_authetication_scim_index_page.png) -Click on the client name to open the detailed view, edit the information, add revoke or add tokens. You will be able to edit the client information and tokens. +Click on the client name to open the detailed view, edit the information, add revoke or add tokens. You will be able to edit the client information and tokens. SCIM client tokens can be revoked. To revoke a token click the **Revoke** icon at the far right end of the token listing. To add a new token click the **+ Token** button at the bottom of *Tokens* section. ![Add or revoke static access token on a SCIM client detailed from under administration settings in OpenProject administration](add_scim_6.png) - + Here is an example of a configuration form in Keycloak, if you use it with [SCIM plugin](https://github.com/mitodl/keycloak-scim). - + ![An example of a Keycloak configuration form to add a SCIM client for OpenProject](add_scim_10.png) - + 1. Fill in the **UI Display name**. 2. Fill in the **SCIM 2.0 endpoint**. It must be in the following format: `https:///scim_v2/` 3. Set **Endpoint content type** to `application/scim+json` 4. Set **Auth mode** to **Bearer** -5. Paste the generated static access token to **Auth password/token** +5. Paste the generated static access token to **Auth password/token** 6. Enable user and group propagation. Enable import during sync. 7. **Save** the configuration. @@ -83,17 +86,17 @@ Here is an example of a configuration form in Keycloak, if you use it with [SCIM If in [Step 3](#step-3-choose-an-authentication-method) you selected **OAuth 2.0 client credentials**, after clicking **Create** you will get client credentials of newly created [OpenProject OAuth Application](../oauth-applications/#oauth-applications). These credentials should be entered into the SCIM client configuration on the other end. The SCIM client is supposed to use the provided client credentials to obtain an access token with the `scim_v2` scope from OpenProject and then use the access token in SCIM API requests. -![Add SCIM client. Creation form. Client credentials. Generate client credentials.](add_scim_7.png) +![Add SCIM client. Creation form. Client credentials. Generate client credentials.](add_scim_7.png) -Once you click **Create**, client credentials (client ID and secret) will be generated. Make sure you copy and save these values. After closing the dialog, you will not see the client credentials again. +Once you click **Create**, client credentials (client ID and secret) will be generated. Make sure you copy and save these values. After closing the dialog, you will not see the client credentials again. -![A confirmation message that a SCIM client was created, showing client credentials to be copied in OpenProject administration](add_scim_8.png) +![A confirmation message that a SCIM client was created, showing client credentials to be copied in OpenProject administration](add_scim_8.png) #### c. **JWT from identity provider** If in [Step 3](#step-3-choose-an-authentication-method) you selected **JWT from identity provider**, you will have to specify **Subject claim** contained in the authentication JWT. -![Add SCIM client. Creation form. JWT from identity provider. Specify Subject claim.](add_scim_9.png) +![Add SCIM client. Creation form. JWT from identity provider. Specify Subject claim.](add_scim_9.png) This authentication method is intended exclusively for use with OpenID Connect setups. The SCIM client must be able to obtain a JWT from the OpenID Connect provider (e.g., Keycloak) that meets all of the following conditions: diff --git a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlog_settings.png b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlog_settings.png index 028ccb273b9..ce4f1f3a9cc 100644 Binary files a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlog_settings.png and b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlog_settings.png differ diff --git a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_select_story_types.png b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_select_story_types.png index 779432e88a6..b389bcf368d 100644 Binary files a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_select_story_types.png and b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_select_story_types.png differ diff --git a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template.png b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template.png index f6f2b02b12c..f5f8b17ebe8 100644 Binary files a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template.png and b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template.png differ diff --git a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template_in_use.png b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template_in_use.png index 19c890c8237..df1d662e9da 100644 Binary files a/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template_in_use.png and b/docs/system-admin-guide/backlogs/openproject_system_admin_guide_backlogs_wiki_template_in_use.png differ diff --git a/docs/system-admin-guide/custom-fields/open_project_system_admin_guide_custom_field_attribute_text.png b/docs/system-admin-guide/custom-fields/open_project_system_admin_guide_custom_field_attribute_text.png index 7754982e3be..d792ca82b15 100644 Binary files a/docs/system-admin-guide/custom-fields/open_project_system_admin_guide_custom_field_attribute_text.png and b/docs/system-admin-guide/custom-fields/open_project_system_admin_guide_custom_field_attribute_text.png differ diff --git a/docs/system-admin-guide/custom-fields/openproject_system_guide_hierarchy_field_add_item_button.png b/docs/system-admin-guide/custom-fields/openproject_system_guide_hierarchy_field_add_item_button.png index fe48e54fb05..3313d7ca18b 100644 Binary files a/docs/system-admin-guide/custom-fields/openproject_system_guide_hierarchy_field_add_item_button.png and b/docs/system-admin-guide/custom-fields/openproject_system_guide_hierarchy_field_add_item_button.png differ diff --git a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects.png b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects.png index 0b102bcf1b4..be112428546 100644 Binary files a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects.png and b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects.png differ diff --git a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects_search.png b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects_search.png index 4a760ba8100..1966f09a21f 100644 Binary files a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects_search.png and b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_add_to_projects_search.png differ diff --git a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_new.png b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_new.png index 01a474337f9..268f64708c3 100644 Binary files a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_new.png and b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_field_new.png differ diff --git a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_hierarchy_details_tab.png b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_hierarchy_details_tab.png index 43caf53a9c0..e0f0a8aede3 100644 Binary files a/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_hierarchy_details_tab.png and b/docs/system-admin-guide/custom-fields/openproject_system_guide_new_custom_hierarchy_details_tab.png differ diff --git a/docs/system-admin-guide/custom-fields/system-guide-custom-field-work-package.png b/docs/system-admin-guide/custom-fields/system-guide-custom-field-work-package.png index 6f68197c5c9..7a8d1691e02 100644 Binary files a/docs/system-admin-guide/custom-fields/system-guide-custom-field-work-package.png and b/docs/system-admin-guide/custom-fields/system-guide-custom-field-work-package.png differ diff --git a/docs/system-admin-guide/documents/README.md b/docs/system-admin-guide/documents/README.md index 0c0af3f821f..659ca0d5c67 100644 --- a/docs/system-admin-guide/documents/README.md +++ b/docs/system-admin-guide/documents/README.md @@ -55,7 +55,7 @@ You will see a dialogue informing you of the consequences. - If a document type is used, you will need to select a different type for reassigning - ![A warning message when deleting a used document type in OpenProject, asking to reassing documents to a different type](openproject_system_guide_documents_types_delete_message_type_used.png) + ![A warning message when deleting a used document type in OpenProject, asking to reassigning documents to a different type](openproject_system_guide_documents_types_delete_message_type_used.png) - If a document type is the last existing one, you will not be able to delete it. There must always be at least one document type configured. In this case you can create another document type first. diff --git a/docs/system-admin-guide/documents/openproject_system_guide_documents_real_time_collaboration_settings.png b/docs/system-admin-guide/documents/openproject_system_guide_documents_real_time_collaboration_settings.png index 001d46972e4..b1759d2c6d0 100644 Binary files a/docs/system-admin-guide/documents/openproject_system_guide_documents_real_time_collaboration_settings.png and b/docs/system-admin-guide/documents/openproject_system_guide_documents_real_time_collaboration_settings.png differ diff --git a/docs/system-admin-guide/files/README.md b/docs/system-admin-guide/files/README.md index 3f355995ba1..13cef4d8930 100644 --- a/docs/system-admin-guide/files/README.md +++ b/docs/system-admin-guide/files/README.md @@ -25,5 +25,5 @@ Under categories you can create and manage documentation categories in OpenProje > [!NOTE] > -> With 17.0 the *Documents* module was enhanced with live-collaboration features, resulting in a dedicated area in system adminstration. From then on documentation of Categories was moved [here](../documents). +> With 17.0 the *Documents* module was enhanced with live-collaboration features, resulting in a dedicated area in system administration. From then on documentation of Categories was moved [here](../documents). diff --git a/docs/system-admin-guide/files/external-file-storages/health-status/README.md b/docs/system-admin-guide/files/external-file-storages/health-status/README.md index 7905ff92383..6ebec39c103 100644 --- a/docs/system-admin-guide/files/external-file-storages/health-status/README.md +++ b/docs/system-admin-guide/files/external-file-storages/health-status/README.md @@ -70,12 +70,14 @@ and suggested solutions. |------------------------------------|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ERR_NC_HOST_NOT_FOUND | No Nextcloud server was found at the configured host URL. | There might be a typo or the URL has changed. | Check the configuration and enter a valid URL. | | ERR_NC_DEPENDENCY_MISSING | A required dependency is missing on the file storage. | Either the Integration OpenProject app or the Team Folders app is not enabled in Nextcloud. | Add the missing dependency to the Nextcloud server. | -| ERR_NC_DEPENDENCY_VERSION_MISMATCH | A required dependency has an outdated version. | Either the Integration OpenProject app or the Team Folders app is outdated or was not updated to the officially minimal supported version. | Update your apps to the latest version. It might be necessary to update your Nextcloud server to the latest version in order to be able to install the latest app versions. | | ERR_NC_TEAM_FOLDER_NOT_FOUND | The team folder could not be found. | The team folder used by the Integration OpenProject app was not found. This folder is usually named `OpenProject` and is owned by the group `OpenProject`. | The team folder is used only by the automatically managed project folders mode. Try to disable this option in the Nextcloud administration for the Integration OpenProject app and reenable it afterwards. | | ERR_NC_OAUTH_REQUEST_UNAUTHORIZED | The current user's token is invalid. | The token of the current user could not be used for accessing the remote file storage. | If the file storage is configure to do the *Two-Way OAuth2 authorization code flow* remove the user token from **Account settings → Access tokens** of this file storage and redo the login. If the storage is configured to use SSO login, please recheck the [SSO configuration guide](../../../integrations/nextcloud/oidc-sso/) for the settings of OpenProject and Nextcloud of your specific setup. | | ERR_NC_USERLESS_ACCESS_DENIED | The userless request was unauthorized | The configured app password is invalid. | Generate a new app password in the Nextcloud administration section of the Integration OpenProject app and copy it over to the OpenProject file storage configuration form. | +| ERR_NC_PROJECT_FOLDER_MISSING | A project folder that has been created by the AMPF synchronization job in the past could not be found anymore. | The folder might have been deleted by a Nextcloud admin or it was deleted and later a folder with the same name was recreated, but is not recognized as the original folder anymore. | This error can right now only be fixed from a Rails console. Please contact OpenProject support. | +| WRN_NC_DEPENDENCY_VERSION_MISMATCH | A required dependency has an outdated version. | Either the Integration OpenProject app or the Team Folders app is outdated or was not updated to the officially minimal supported version. | Update your apps to the latest version. It might be necessary to update your Nextcloud server to the latest version in order to be able to install the latest app versions. | | WRN_NC_OAUTH_TOKEN_MISSING | The current user has no authentication token. | The current user probably never did a successful login from OpenProject to the file storage, or the token was deleted from the account details. | Visit any work package of a project, where the current file storage is used. Click on the **Login** button in the **Files** tab. | -| WRN_NC_UNEXPECTED_CONTENT | The connection request was successful, but unexpected content was found in the team folder. | The team folder `OpenProject` might contain data, that was put there by a user, or there are remnants from projects that no longer have a valid connection in OpenProject. | Go to Nextcloud and migrate or delete the data in the OpenProject team folder, that was not created by OpenProject. Further information about the unexpected data is found in the server logs. | +| WRN_NC_UNLINKED_PROJECT_FOLDERS | Some automatically managed project folders were not yet created. | If the storage was configured for the project very recently, this can be normal and the background worker might just not have created the folder yet. If This warning remains after a longer period of time, the background synchronization may have encountered an error. | Check the AMPF sync error output on the storage's configuration page. If it shows as healthy, this warning should disappear when repeating the health checks after a few minutes. If an error is shown on the storage's configuration page, this is a likely culprit for this warning. | +| WRN_NC_UNEXPECTED_FILES | The connection request was successful, but unexpected files were found in the team folder. | The team folder `OpenProject` might contain data, that was put there by a user, or there are remnants from projects that no longer have a valid connection in OpenProject. | Go to Nextcloud and migrate or delete the data in the OpenProject team folder, that was not created by OpenProject. Further information about the unexpected data is found in the server logs. | The officially minimal supported app versions are listed in the [system admin guide](../../../../system-admin-guide/integrations/nextcloud/#required-system-versions). diff --git a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp.png b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp.png index 4de3c622477..8fc77db6430 100644 Binary files a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp.png and b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp.png differ diff --git a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp_tools.png b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp_tools.png index d724c918f31..8298368cea6 100644 Binary files a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp_tools.png and b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_mcp_tools.png differ diff --git a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_oauth_mcp.png b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_oauth_mcp.png index 455dca337a9..14689211821 100644 Binary files a/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_oauth_mcp.png and b/docs/system-admin-guide/integrations/mcp-server/openproject_system_guide_new_oauth_mcp.png differ diff --git a/docs/system-admin-guide/manage-work-packages/work-package-workflows/README.md b/docs/system-admin-guide/manage-work-packages/work-package-workflows/README.md index 2f3d6808d3b..873a2b47776 100644 --- a/docs/system-admin-guide/manage-work-packages/work-package-workflows/README.md +++ b/docs/system-admin-guide/manage-work-packages/work-package-workflows/README.md @@ -17,7 +17,7 @@ This means, a certain type of work package, e.g. a Task, can have the following To edit a workflow, first decide if you want to edit default transitions that apply to all users (depending only on the role) or for the specific cases where a user is the author or the assignee. Three tabs on top of the screen allow you to choose this: -![Tabs to select between default transitions, when the user is the author or when the user is the asignee](admin_workflow_tabs.png) +![Tabs to select between default transitions, when the user is the author or when the user is the assignee](admin_workflow_tabs.png) Once you are in the right tab: diff --git a/docs/system-admin-guide/projects/project-attributes/README.md b/docs/system-admin-guide/projects/project-attributes/README.md index be1e13d8026..af44eb31706 100644 --- a/docs/system-admin-guide/projects/project-attributes/README.md +++ b/docs/system-admin-guide/projects/project-attributes/README.md @@ -148,7 +148,7 @@ This numeric value is required and can be used in calculations — for example, [feature: calculated_values ] -**Calculated values** enable automatic computations based on formulas using numeric project attributes, including scores from Weighted item lists or even other calculated values. The computed result is displayed directly on the project overview and in the project list. It automatically updates whenever one of its source attributes (e.g., Benefit or Effort in the example below) is changed. This allows teams to calculate project scores and prioritise consistently across the portfolio. +**Calculated values** enable automatic computations based on formulas using numeric project attributes, including scores from Weighted item lists or even other calculated values. The computed result is displayed directly on the project overview and in the project list. It automatically updates whenever one of its source attributes (e.g., Benefit or Effort in the example below) is changed. This allows teams to calculate project scores and prioritize consistently across the portfolio. To set up a project attribute of the **Calculated value** type, follow the same procedure as when adding a standard project attribute and select the *Calculated value* option. Define the name, section it will appear in and the calculation formula. diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_add.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_add.png index e58a1553917..8e83809986f 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_add.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_add.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_attribute_text.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_attribute_text.png index f52ee3674fa..0e3466d915a 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_attribute_text.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_attribute_text.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_deactivate_for_project.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_deactivate_for_project.png index 39f421b41b6..248887369a4 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_deactivate_for_project.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_deactivate_for_project.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_details.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_details.png index 1f49928255e..4866145917d 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_details.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_details.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_enabled_in_projects.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_enabled_in_projects.png index 506583058f7..0b91ad23b67 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_enabled_in_projects.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_admin_guide_project_attributes_enabled_in_projects.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_calculated_value.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_calculated_value.png index 8d054e93219..11d9ad136e8 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_calculated_value.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_calculated_value.png differ diff --git a/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_new_attribute.png b/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_new_attribute.png index c474ec06a68..30ee2cfde66 100644 Binary files a/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_new_attribute.png and b/docs/system-admin-guide/projects/project-attributes/open_project_system_guide_project_attributes_new_attribute.png differ diff --git a/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links.png b/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links.png index a2aba688402..41d010bf01e 100644 Binary files a/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links.png and b/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links.png differ diff --git a/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links_warning_message.png b/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links_warning_message.png index 717da61c2ea..9f08e43b27a 100644 Binary files a/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links_warning_message.png and b/docs/system-admin-guide/system-settings/external-links/openproject_system_admin_guide_external_links_warning_message.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/README.md b/docs/system-admin-guide/users-permissions/groups/README.md index 961dabb33a4..10a86af624d 100644 --- a/docs/system-admin-guide/users-permissions/groups/README.md +++ b/docs/system-admin-guide/users-permissions/groups/README.md @@ -39,7 +39,7 @@ You will then see the detailed view of the group, including following tabs: - Users - Projects - Global roles -- Synchronised groups +- Synchronized groups ![Edit groups in OpenProject administration](openproject_system_guide_edit_new_group.png) @@ -67,7 +67,7 @@ In order to add a global role to a group, at least one global role needs to be [ ### Synchronized groups -Click the **Synchronized groups** tab to see if this group has been synchronised with groups in external identity providers like OpenID. If no synchronisation has yet been set up, this list will be empty. You can set this up in your [Authentication settings](../../authentication). +Click the **Synchronized groups** tab to see if this group has been synchronized with groups in external identity providers like OpenID. If no synchronization has yet been set up, this list will be empty. You can set this up in your [Authentication settings](../../authentication). ### Delete a group diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_group_profile.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_group_profile.png index a993d900406..a3593be25bb 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_group_profile.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_group_profile.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group.png index d6d6c29b958..6e03719b121 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_members.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_members.png index 54a8c9530fe..e00e0ed9f28 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_members.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_members.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_projects.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_projects.png index 7026b7d2b13..920d75507c2 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_projects.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_edit_new_group_add_projects.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_groups.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_groups.png index 1abe3206b0c..862b0065a6c 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_groups.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_groups.png differ diff --git a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_new_group.png b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_new_group.png index 7d1be06c432..5e40773a8ae 100644 Binary files a/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_new_group.png and b/docs/system-admin-guide/users-permissions/groups/openproject_system_guide_new_group.png differ diff --git a/docs/system-admin-guide/users-permissions/roles-permissions/README.md b/docs/system-admin-guide/users-permissions/roles-permissions/README.md index 6abdc3e285b..cbeaca62874 100644 --- a/docs/system-admin-guide/users-permissions/roles-permissions/README.md +++ b/docs/system-admin-guide/users-permissions/roles-permissions/README.md @@ -31,7 +31,7 @@ A user can have one or more roles which grant permissions on different levels. ### Global role -**Global roles** allow aministrators to delegate administrative tasks to individual users. +**Global roles** allow administrators to delegate administrative tasks to individual users. | Scope of the role | Permission examples | Customization options | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | @@ -115,7 +115,7 @@ The form shows the available global permissions which can be assigned to the new > [!TIP] > To create a subproject for an existing project the project permission "Create subprojects" is also required. -- Create portolios +- Create portfolios - Create programs diff --git a/docs/system-admin-guide/users-permissions/users/delete-user-confirmation.png b/docs/system-admin-guide/users-permissions/users/delete-user-confirmation.png index 80bbf6586cf..b5e9672fe78 100644 Binary files a/docs/system-admin-guide/users-permissions/users/delete-user-confirmation.png and b/docs/system-admin-guide/users-permissions/users/delete-user-confirmation.png differ diff --git a/docs/system-admin-guide/users-permissions/users/openproject_system_guide_delete_user.png b/docs/system-admin-guide/users-permissions/users/openproject_system_guide_delete_user.png index 7ba416b88e7..01a07653c74 100644 Binary files a/docs/system-admin-guide/users-permissions/users/openproject_system_guide_delete_user.png and b/docs/system-admin-guide/users-permissions/users/openproject_system_guide_delete_user.png differ diff --git a/docs/use-cases/meeting-management/openproject_use_cases_weekly_meetings_add_outcome.gif b/docs/use-cases/meeting-management/openproject_use_cases_weekly_meetings_add_outcome.gif index 64f3007111f..ff1fbb75c10 100644 Binary files a/docs/use-cases/meeting-management/openproject_use_cases_weekly_meetings_add_outcome.gif and b/docs/use-cases/meeting-management/openproject_use_cases_weekly_meetings_add_outcome.gif differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_gantt_charts_view.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_gantt_charts_view.png deleted file mode 100644 index b7f79432a1c..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_gantt_charts_view.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_export_options.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_export_options.png deleted file mode 100644 index 36ec8b2b023..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_export_options.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_list_button.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_list_button.png deleted file mode 100644 index bc17887c70c..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_list_button.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview.png deleted file mode 100644 index 77f53594ec3..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_filters.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_filters.png deleted file mode 100644 index 199bcb9fa19..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_filters.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_button.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_button.png deleted file mode 100644 index 3cf2dcec414..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_button.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_view_configure.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_view_configure.png deleted file mode 100644 index 8f082614650..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_projects_overview_gantt_view_configure.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report.png deleted file mode 100644 index cbead95a67e..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report_edit_mode.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report_edit_mode.png deleted file mode 100644 index 426a834f493..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_wiki_status_report_edit_mode.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_work_packages_export_icon.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolio_work_packages_export_icon.png deleted file mode 100644 index c26d657becd..00000000000 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolio_work_packages_export_icon.png and /dev/null differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters.png index 2e7941cb8f3..47d835a328b 100644 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters.png and b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters.png differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters_detailed.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters_detailed.png index 774d0ed6c0d..cc9574d36c6 100644 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters_detailed.png and b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_filters_detailed.png differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_hierarchy_examples.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_hierarchy_examples.png index d5f721d82aa..eedbcada7ee 100644 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_hierarchy_examples.png and b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_hierarchy_examples.png differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_subitems_widget.png b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_subitems_widget.png index 3ffb6d7eefd..b9b3517e3ce 100644 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_portfolios_subitems_widget.png and b/docs/use-cases/portfolio-management/openproject_use_case_portfolios_subitems_widget.png differ diff --git a/docs/use-cases/portfolio-management/openproject_use_case_select_portfolios_module.png b/docs/use-cases/portfolio-management/openproject_use_case_select_portfolios_module.png index a714c98ab90..25e080cd5a1 100644 Binary files a/docs/use-cases/portfolio-management/openproject_use_case_select_portfolios_module.png and b/docs/use-cases/portfolio-management/openproject_use_case_select_portfolios_module.png differ diff --git a/docs/use-cases/project-management-pm2-pmflex/README.md b/docs/use-cases/project-management-pm2-pmflex/README.md index 62300b33b4a..36815f2d665 100644 --- a/docs/use-cases/project-management-pm2-pmflex/README.md +++ b/docs/use-cases/project-management-pm2-pmflex/README.md @@ -86,7 +86,7 @@ Each PM² project is established as an individual OpenProject project, incorpora ### How to use project templates to quickly setup new PM² projects? -You can also use **[project templates](https://www.openproject.org/docs/user-guide/projects/project-templates)** to make it easier to create new PM² projects with the same structure, set of enabled modules or **custom work package templates**. We highly recommend using **project templates** for standardizing PM² project setup across the organization. This will also help you guide users who are new to PM² methodology. Once a new PM² project is created using a template, it can then be modified in any way in order to allow the tailoring of the methodology. +You can also use **[project templates](../../user-guide/projects/project-templates)** to make it easier to create new PM² projects with the same structure, set of enabled modules or **custom work package templates**. We highly recommend using **project templates** for standardizing PM² project setup across the organization. This will also help you guide users who are new to PM² methodology. Once a new PM² project is created using a template, it can then be modified in any way in order to allow the tailoring of the methodology. ### How to setup and manage PM² phases? @@ -132,7 +132,7 @@ OpenProject provides multiple views for managing PM² project work effectively. * Tabular display of all project artefacts and deliverables * Customizable sorting, grouping, and filtering by PM² phases or artefact types -These tables are highly customizable and can be [configured](https://www.openproject.org/docs/user-guide/work-packages/work-package-table-configuration) to show precisely the information you need. Tables can also be **sorted** (for example by id, name, start dates, project, assignee, priority), **grouped** and **filtered** to create highly precise views. They can also show nested parent-children relations in **hierarchy view**. +These tables are highly customizable and can be [configured](../../user-guide/work-packages/work-package-table-configuration) to show precisely the information you need. Tables can also be **sorted** (for example by id, name, start dates, project, assignee, priority), **grouped** and **filtered** to create highly precise views. They can also show nested parent-children relations in **hierarchy view**. To quickly access your most used table views, save these as your **favorite filters**. These will be visible to all project members. For PM² we recommend sorting all tasks per phase. With this view you can fully focus on the essential tasks within the current phase. @@ -143,7 +143,7 @@ To quickly access your most used table views, save these as your **favorite filt * Dependencies between tasks and artefacts * Critical path analysis for phase gate readiness -The [Gantt chart](https://www.openproject.org/docs/user-guide/gantt-chart) module allows you to quickly visualize planning of each phase in a timeline view that also displays [work package relations](https://www.openproject.org/docs/user-guide/work-packages/work-package-relations-hierarchies). Like table view, it can be filtered to create custom views that can be saved. +The [Gantt chart](../../user-guide/gantt-chart) module allows you to quickly visualize planning of each phase in a timeline view that also displays [work package relations](../../user-guide/work-packages/work-package-relations-hierarchies). Like table view, it can be filtered to create custom views that can be saved. ![Gantt view showing the work packages in the Planning Phase](openproject_use_case_PM2_gantt_view_planning_phase_pm2.png) @@ -179,6 +179,6 @@ PM² emphasizes **accountability, transparency, and stakeholder communication**, ## Here for you now! -OpenProject is a powerful and highly-configurable tool that can be customized to fit the needs of your PM² implementation. Beyond the basics covered in this guide, OpenProject has many additional features and modules (such as [budgets](https://www.openproject.org/docs/user-guide/budgets), [time and cost tracking](https://www.openproject.org/docs/user-guide/time-and-costs), [wiki](https://www.openproject.org/docs/user-guide/wiki) and [file storage integrations](https://www.openproject.org/docs/development/file-storage-integration)) that further enable your PM² teams to work efficiently and deliver value. +OpenProject is a powerful and highly-configurable tool that can be customized to fit the needs of your PM² implementation. Beyond the basics covered in this guide, OpenProject has many additional features and modules (such as [budgets](../../user-guide/budgets), [time and cost tracking](../../user-guide/time-and-costs), [wiki](../../user-guide/wiki) and [file storage integrations](../../development/file-storage-integration)) that further enable your PM² teams to work efficiently and deliver value. -If you have questions about how to [use](https://www.openproject.org/docs/getting-started) and [configure](https://www.openproject.org/docs/system-admin-guide) OpenProject to work for you, please [get in touch](https://www.openproject.org/contact/) or [start a free trial](https://start.openproject.com/) to see for yourself. +If you have questions about how to [use](../../getting-started) and [configure](../../system-admin-guide) OpenProject to work for you, please [get in touch](https://www.openproject.org/contact/) or [start a free trial](https://start.openproject.com/) to see for yourself. diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens.png index 6b251919955..0fb146ad9bd 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api.png index ba5150626de..9023f8181d2 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_create_new.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_create_new.png index d24e74605df..af0705d1def 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_create_new.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_create_new.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_generated.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_generated.png index 88e8d44a943..39a5688c558 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_generated.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_api_generated.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_invalid.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_invalid.png index da7f3e0d5a3..7c2aff061db 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_invalid.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_invalid.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list.png index c3ae17713f7..a3f05ab8e63 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list_with_content.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list_with_content.png index ba4f5117daa..924d3a1625d 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list_with_content.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_calendar_list_with_content.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_delete_calendar.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_delete_calendar.png index 938f84c62f2..b498eb3d195 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_delete_calendar.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_delete_calendar.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_file_storages.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_file_storages.png index ba7e077a2a0..2a4b84f8f81 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_file_storages.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_file_storages.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_meetings_delete.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_meetings_delete.png index 82494e51dab..21cd1bb21ae 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_meetings_delete.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_meetings_delete.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_oauth.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_oauth.png index da4770d6f2d..0212205fa69 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_oauth.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_oauth.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss.png index b6fbff57d67..10e0989c2b4 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_delete.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_delete.png index 66e4116d89b..27ec6b348de 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_delete.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_delete.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_new.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_new.png index 5cd7c493dff..11c7b44ef27 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_new.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_rss_new.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_button.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_button.png index 48e0c04e11e..d7bd1d54a8e 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_button.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_button.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form.png index 9786533a83e..a2402627aa0 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form.png differ diff --git a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form_confirmation.png b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form_confirmation.png index d41dee2048b..6cf694dbe4c 100644 Binary files a/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form_confirmation.png and b/docs/user-guide/account-settings/openproject_account_settings_access_tokens_subscribe_meetings_form_confirmation.png differ diff --git a/docs/user-guide/agile-boards/choose-board-type.png b/docs/user-guide/agile-boards/choose-board-type.png index de67a698e5d..2b8c272ad73 100644 Binary files a/docs/user-guide/agile-boards/choose-board-type.png and b/docs/user-guide/agile-boards/choose-board-type.png differ diff --git a/docs/user-guide/agile-boards/create-a-new-board-in-the-boards-module.png b/docs/user-guide/agile-boards/create-a-new-board-in-the-boards-module.png index ae91b4750fd..50350fa11d3 100644 Binary files a/docs/user-guide/agile-boards/create-a-new-board-in-the-boards-module.png and b/docs/user-guide/agile-boards/create-a-new-board-in-the-boards-module.png differ diff --git a/docs/user-guide/agile-boards/create-status-board.png b/docs/user-guide/agile-boards/create-status-board.png deleted file mode 100644 index 6c5a8b9cb1e..00000000000 Binary files a/docs/user-guide/agile-boards/create-status-board.png and /dev/null differ diff --git a/docs/user-guide/agile-boards/openproject_userguide_boards_kanban.png b/docs/user-guide/agile-boards/openproject_userguide_boards_kanban.png index ad9c887881d..6b5befd5c52 100644 Binary files a/docs/user-guide/agile-boards/openproject_userguide_boards_kanban.png and b/docs/user-guide/agile-boards/openproject_userguide_boards_kanban.png differ diff --git a/docs/user-guide/agile-boards/openproject_userguide_boards_overview.png b/docs/user-guide/agile-boards/openproject_userguide_boards_overview.png index 4b688a5e80c..7bde66fc5c2 100644 Binary files a/docs/user-guide/agile-boards/openproject_userguide_boards_overview.png and b/docs/user-guide/agile-boards/openproject_userguide_boards_overview.png differ diff --git a/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_column_location.png b/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_column_location.png index a82050b7d18..b3bdc481c0a 100644 Binary files a/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_column_location.png and b/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_column_location.png differ diff --git a/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_menu_option.png b/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_menu_option.png index 5f56d7758ad..9cfcab08555 100644 Binary files a/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_menu_option.png and b/docs/user-guide/backlogs-scrum/manage-sprints/openproject_user_guide_backlogs_manage_sprints_menu_option.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/17_BurndownChart2.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/17_BurndownChart2.png index 65805eed35f..a5204b49805 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/17_BurndownChart2.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/17_BurndownChart2.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs.png index 7d873d019c4..0100f26b77d 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_drag_drop.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_drag_drop.png index 8f56c2f0fc3..aad9a7b2d58 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_drag_drop.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_drag_drop.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_edit_sprint_menu.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_edit_sprint_menu.png index acbf2aceba0..f02009ff966 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_edit_sprint_menu.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_edit_sprint_menu.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story.png index 8475deed8ec..3fcbe6d46da 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_added.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_added.png index 37f3b9ff55d..14af4a2557e 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_added.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_added.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_content.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_content.png deleted file mode 100644 index 72e77234c87..00000000000 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_user_story_content.png and /dev/null differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_wp_form.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_wp_form.png index 3aaf63308cf..6d7aeaf3540 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_wp_form.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_new_wp_form.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_open_burndown_chart_option.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_open_burndown_chart_option.png index a2688fbf1d7..fefce687b54 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_open_burndown_chart_option.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_open_burndown_chart_option.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_dates_set.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_dates_set.png index 02ec3738a0a..ac6395517aa 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_dates_set.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_dates_set.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_menu_opened.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_menu_opened.png index 59a215b00a1..5ed6eb4f3d5 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_menu_opened.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_sprint_menu_opened.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_detailed_view.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_detailed_view.png index 9cb6bb83a47..38390efbd4d 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_detailed_view.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_detailed_view.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points.png index 9f7765047c8..80d08e9ba32 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points_edit.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points_edit.png index d00ae4dbbc6..7d3aa63e3e6 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points_edit.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_story_points_edit.png differ diff --git a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_wiki_menu_option.png b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_wiki_menu_option.png index 0cc5d18f315..cfe709c9cdd 100644 Binary files a/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_wiki_menu_option.png and b/docs/user-guide/backlogs-scrum/work-with-backlogs/openproject_user_guide_backlogs_wiki_menu_option.png differ diff --git a/docs/user-guide/gantt-chart/gantt-chart.gif b/docs/user-guide/gantt-chart/gantt-chart.gif index 2d194cbb486..734ba690be4 100644 Binary files a/docs/user-guide/gantt-chart/gantt-chart.gif and b/docs/user-guide/gantt-chart/gantt-chart.gif differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-print-gantt-chart.gif b/docs/user-guide/gantt-chart/openproject-user-guide-print-gantt-chart.gif index eaf40e93732..bfe443be550 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-print-gantt-chart.gif and b/docs/user-guide/gantt-chart/openproject-user-guide-print-gantt-chart.gif differ diff --git a/docs/user-guide/meetings/one-time-meetings/README.md b/docs/user-guide/meetings/one-time-meetings/README.md index cc4606210fe..700f41bd07c 100644 --- a/docs/user-guide/meetings/one-time-meetings/README.md +++ b/docs/user-guide/meetings/one-time-meetings/README.md @@ -412,7 +412,7 @@ You can download a meeting as an iCalendar event. Select the dropdown by clickin Read more about [subscribing to a calendar](../../calendar/#subscribe-to-a-calendar). -![An icon to download a meeting as an iCalendar event in OpenProject meetings moduel](openproject_userguide_meetings_download_ical.png) +![An icon to download a meeting as an iCalendar event in OpenProject meetings module](openproject_userguide_meetings_download_ical.png) Please keep in mind that downloading a meeting as an iCalendar event adds it to your calendar, but it does not keep the meeting synchronized automatically. diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_button.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_button.png index 3481c8e4f59..2092affea79 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_button.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_button.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_edit.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_edit.png index 6be9ae7f0b0..114ca41d649 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_edit.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_edit.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_form.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_form.png index 519b62d80fc..77ef21f22e8 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_form.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_existing_wp_form.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png index d7b8a8aece4..5d68791d84c 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_new_wp_form.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_new_wp_form.png index d53ed02e319..b834fa940aa 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_new_wp_form.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_agenda_outcome_new_wp_form.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_create_new_template.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_create_new_template.png index e49e274587a..e82f6f85533 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_create_new_template.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_create_new_template.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_mark_participants_attendance_button.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_mark_participants_attendance_button.png index a270c99d750..d5ab0e3b05b 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_mark_participants_attendance_button.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_mark_participants_attendance_button.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_participants_status.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_participants_status.png index 925b24fef64..502e02b27ce 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_participants_status.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_participants_status.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_send_email_invite.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_send_email_invite.png index 3f79bda64fe..0af0124e566 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_send_email_invite.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_send_email_invite.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates.png index b3a9ae900b0..ddd8f779573 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_create_new_meeting.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_create_new_meeting.png index 6c5bdeb6261..481027ff488 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_create_new_meeting.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_create_new_meeting.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete.png index 562f3d997d8..79c20dfbae8 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete_history.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete_history.png index b54551e60de..1afd821a5d4 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete_history.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_edit_delete_history.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_name_save.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_name_save.png index ecd8477d3d8..4b8035ed993 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_name_save.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_name_save.png differ diff --git a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_new_meeting.png b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_new_meeting.png index 3c6c7504604..e328157dc8c 100644 Binary files a/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_new_meeting.png and b/docs/user-guide/meetings/one-time-meetings/openproject_userguide_meetings_templates_new_meeting.png differ diff --git a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item.png b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item.png index a02b891275b..03232527c84 100644 Binary files a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item.png and b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item.png differ diff --git a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item_confirmation.png b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item_confirmation.png index 9b1e077dd36..0111f31a023 100644 Binary files a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item_confirmation.png and b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_duplicate_agenda_item_confirmation.png differ diff --git a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_move_agenda_item_confirmation.png b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_move_agenda_item_confirmation.png index 7ae0b5b6248..5279a843438 100644 Binary files a/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_move_agenda_item_confirmation.png and b/docs/user-guide/meetings/recurring-meetings/openproject_userguide_meetings_recurring_move_agenda_item_confirmation.png differ diff --git a/docs/user-guide/project-home/project-attributes/openproject_user_guide_project_overview_project_attributes_section_edit_new.png b/docs/user-guide/project-home/project-attributes/openproject_user_guide_project_overview_project_attributes_section_edit_new.png index 7d5c412d227..67cb3b22d83 100644 Binary files a/docs/user-guide/project-home/project-attributes/openproject_user_guide_project_overview_project_attributes_section_edit_new.png and b/docs/user-guide/project-home/project-attributes/openproject_user_guide_project_overview_project_attributes_section_edit_new.png differ diff --git a/docs/user-guide/project-home/project-widgets/README.md b/docs/user-guide/project-home/project-widgets/README.md index 8c319f88aab..ff83ac25e0c 100644 --- a/docs/user-guide/project-home/project-widgets/README.md +++ b/docs/user-guide/project-home/project-widgets/README.md @@ -195,11 +195,11 @@ Budgets widgets are only displayed if the following conditions are met: - At least one budget exists in the project or one of its subprojects. Some widgets may display placeholder messages if no cost data has been entered yet. - At least one work package is assigned to a budget. - The user has these necessary permissions to view the financial information: - - view_budgets - - view_cost_entries - - view_cost_rates - - view_time_entries - - view_hourly_rates + - View budgets + - View booked costs + - View cost rates + - View spent time + - View all hourly rates - The user has to have a defined hourly rate. - At least one time and/or unit costs entry is logged for the work package (the work package that is assigned to a budget). If no relevant data is available, the widgets display guidance messages. For example if **no budgets exist**, the widget encourages creating a budget. diff --git a/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_budgets_widgets.png b/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_budgets_widgets.png index 7c31550d17c..042ddc0ab70 100644 Binary files a/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_budgets_widgets.png and b/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_budgets_widgets.png differ diff --git a/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_resize_widget.gif b/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_resize_widget.gif index 7b5f709492f..2f2fda97e63 100644 Binary files a/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_resize_widget.gif and b/docs/user-guide/project-home/project-widgets/openproject_user_guide_project_overview_resize_widget.gif differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_applying_temlate.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_applying_temlate.png index a2b3d430ceb..ac2ba912408 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_applying_temlate.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_applying_temlate.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_explained.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_explained.png index a1f934e5363..dfafca8b1c9 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_explained.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_explained.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_green_checkmark.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_green_checkmark.png index bd8022fbeac..4f3aa9fbb3d 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_green_checkmark.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_green_checkmark.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_name_project.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_name_project.png index b8272b02c90..9d413838083 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_name_project.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_name_project.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_new_project.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_new_project.png index cd757e2aa21..34447401228 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_new_project.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_new_project.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_return_button.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_return_button.png index b3aa35984bf..859650a4e11 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_return_button.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_return_button.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_select_template.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_select_template.png index 74aecff6ebd..1ca36ca2421 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_select_template.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_select_template.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_success_message.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_success_message.png index 7312743f6e7..98084274b2d 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_success_message.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_success_message.png differ diff --git a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_wp_files_tab.png b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_wp_files_tab.png index 84aa1a89e20..2b287022b42 100644 Binary files a/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_wp_files_tab.png and b/docs/user-guide/projects/project-initiation-request/openproject_user_guide_project_creation_wizard_wp_files_tab.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_artifact_export.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_artifact_export.png index 282b42f2389..53c6b29646b 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_artifact_export.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_artifact_export.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_attributes.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_attributes.png index d9e8b33db18..a2ca0584435 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_attributes.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_attributes.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_disable.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_disable.png index 30876d1d73c..be5d4d02a52 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_disable.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_disable.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_name.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_name.png index dac80728177..8d8a22e570a 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_name.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_name.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_not_initiated.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_not_initiated.png index b52e2f4b057..5689078da52 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_not_initiated.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_not_initiated.png differ diff --git a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_submission.png b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_submission.png index 5ec70f685e8..441d429ddf6 100644 Binary files a/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_submission.png and b/docs/user-guide/projects/project-initiation-request/project-initiation-request-settings/openproject_userguide_project_settings_pir_request_submission.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions.png index 9cba56cb9d7..dc4e925cc31 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_close_completed.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_close_completed.png index 9c6611b0f0f..24cee93a83d 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_close_completed.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_close_completed.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_closed.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_closed.png index 9d70f7f94ff..4b0eafc1ae9 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_closed.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_closed.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_delete.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_delete.png index 1b4f06f15e3..fa39f5cc396 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_delete.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_delete.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit.png index aab4d9d3d4c..41b53878211 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit.png differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit_close_delete.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit_close_delete.png deleted file mode 100644 index b5f986f67b7..00000000000 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_edit_close_delete.png and /dev/null differ diff --git a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_new.png b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_new.png index 639819c262a..980cb7ad30e 100644 Binary files a/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_new.png and b/docs/user-guide/projects/project-settings/versions/openproject_user_guide_project_settings_work_packages_versions_new.png differ diff --git a/docs/user-guide/team-planner/README.md b/docs/user-guide/team-planner/README.md index 7b63ec68a1a..519e76d2529 100644 --- a/docs/user-guide/team-planner/README.md +++ b/docs/user-guide/team-planner/README.md @@ -79,7 +79,7 @@ When you create a new team planner, it will be empty, like so: ![An example of a newly-created empty team planner in OpenProject](openproject_user_guide_teamplanner_new_unnamed_empty.png) -The first step in setting up your team planning calendar is to add team members. To do so, click on the **+ Assignee** button then search for the team member you would like to add from the the drop-down list (1). This will add a new row to the calendar view for that team member. +The first step in setting up your team planning calendar is to add team members. To do so, click on the **+ Assignee** button then search for the team member you would like to add from the the dropdown list (1). This will add a new row to the calendar view for that team member. Repeat this step until all relevant team members are added and then save it using the floppy disk icon in the top header (2). diff --git a/docs/user-guide/time-and-costs/my-time-tracking/openproject-my-time-tracking-page.gif b/docs/user-guide/time-and-costs/my-time-tracking/openproject-my-time-tracking-page.gif index d26bb1b6238..893f22582e4 100644 Binary files a/docs/user-guide/time-and-costs/my-time-tracking/openproject-my-time-tracking-page.gif and b/docs/user-guide/time-and-costs/my-time-tracking/openproject-my-time-tracking-page.gif differ diff --git a/docs/user-guide/wiki/wiki-menu/README.md b/docs/user-guide/wiki/wiki-menu/README.md index 10373378cd1..ba6be4d3d58 100644 --- a/docs/user-guide/wiki/wiki-menu/README.md +++ b/docs/user-guide/wiki/wiki-menu/README.md @@ -25,7 +25,6 @@ To add a wiki page as a menu item to the project menu, select the **More** funct - **Do not show this wikipage in the project navigation** will NOT display a separate menu item in the project navigation. The wiki page is just displayed within the wiki module itself. - **Show as menu item in project navigation** will add a separate menu item to the project navigation. -- **Show as submenu item of ...** will display the wiki page a sub-menu item in the project navigation. 3. **Save** your changes to the wiki page menu. @@ -35,8 +34,4 @@ To add a wiki page as a menu item to the project menu, select the **More** funct ![wiki-show-menu-item](wiki-show-menu-item.png) -**Visibility** show as submenu item of project-documentation: - -![wiki-show-submenu-item](wiki-show-submenu-item.png) - The default option is **Do not show this wiki page in project navigation**. Check this option if you want to undo earlier changes and hide the wiki page from the project menu. diff --git a/docs/user-guide/wiki/wiki-menu/wiki-show-submenu-item.png b/docs/user-guide/wiki/wiki-menu/wiki-show-submenu-item.png deleted file mode 100644 index 076bd97d6e6..00000000000 Binary files a/docs/user-guide/wiki/wiki-menu/wiki-show-submenu-item.png and /dev/null differ diff --git a/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_user_guide_work_packages_meetings_tab.png b/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_user_guide_work_packages_meetings_tab.png index 0d720e30b25..7cf531c7d8f 100644 Binary files a/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_user_guide_work_packages_meetings_tab.png and b/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_user_guide_work_packages_meetings_tab.png differ diff --git a/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png b/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png index d7b8a8aece4..5d68791d84c 100644 Binary files a/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png and b/docs/user-guide/work-packages/add-work-packages-to-meetings/openproject_userguide_meetings_agenda_outcome_in_work_package.png differ diff --git a/docs/user-guide/work-packages/exporting/openproject_pdf_report_relations.png b/docs/user-guide/work-packages/exporting/openproject_pdf_report_relations.png index 4534d7e32a5..bbf19538b2f 100644 Binary files a/docs/user-guide/work-packages/exporting/openproject_pdf_report_relations.png and b/docs/user-guide/work-packages/exporting/openproject_pdf_report_relations.png differ diff --git a/docs/user-guide/work-packages/set-change-dates/openproject_user_guide_date_picker_banner_automatic_mode.png b/docs/user-guide/work-packages/set-change-dates/openproject_user_guide_date_picker_banner_automatic_mode.png index 6be62c97a4a..878a099adee 100644 Binary files a/docs/user-guide/work-packages/set-change-dates/openproject_user_guide_date_picker_banner_automatic_mode.png and b/docs/user-guide/work-packages/set-change-dates/openproject_user_guide_date_picker_banner_automatic_mode.png differ diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md new file mode 100644 index 00000000000..892d0242019 --- /dev/null +++ b/frontend/AGENTS.md @@ -0,0 +1,46 @@ +# Frontend + +## Directory Structure + +- `./src/` - Frontend code + - `./src/app/` - Legacy Angular modules/components + - `./src/stimulus/` - Stimulus controllers + - `./src/turbo/` - Turbo integration + +## Configuration Files + +- `eslint.config.mjs` - JavaScript/TypeScript linting +- `../package.json` / `./frontend/package.json` - Node.js dependencies + +## Version Requirements + +- Node: `^22.21.0` (see `package.json` engines) + +## Setup + +```bash +npm ci && cd .. # Install Node packages +``` + +## Code Style + +### JavaScript/TypeScript + +- **New development**: Use Hotwire (Turbo + Stimulus) with server-rendered HTML +- **Legacy code**: Follow ESLint rules +- Prefer TypeScript over JavaScript +- Use [Primer Design System](https://primer.style/product/) via ViewComponent + +## Linting + +```bash +# JavaScript/TypeScript +npx eslint src/ && cd .. +``` + +## Testing + +```bash +# Frontend (Jasmine/Karma) +npm test && cd .. +``` diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/frontend/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ebb79d0e894..e7abd8f5e38 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -139,8 +139,8 @@ "@angular-eslint/template-parser": "20.7.0", "@angular/language-service": "21.1.6", "@eslint/js": "^9.39.2", - "@html-eslint/eslint-plugin": "^0.57.0", - "@html-eslint/parser": "^0.57.0", + "@html-eslint/eslint-plugin": "^0.57.1", + "@html-eslint/parser": "^0.57.1", "@jsdevtools/coverage-istanbul-loader": "3.0.5", "@stylistic/eslint-plugin": "^5.7.1", "@types/codemirror": "5.60.5", @@ -185,7 +185,7 @@ "source-map-explorer": "^2.5.2", "ts-node": "~10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "^8.54.0", + "typescript-eslint": "^8.56.1", "wscat": "^6.1.0" }, "optionalDependencies": { @@ -5315,18 +5315,19 @@ } }, "node_modules/@html-eslint/eslint-plugin": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.57.0.tgz", - "integrity": "sha512-9/sjZ2KHsZmco45Z9rGySOocJ734rhjjt1ofXJve7lzzBY+t8FF7fwVp9EmcXSer+0zDUb5hGBHWbgIZ0SEnJA==", + "version": "0.57.1", + "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.57.1.tgz", + "integrity": "sha512-IDfdk3V27eebNpdXD2NLy/lnTSbUuKrro/6YJICBn/9aiXPXagNqWJB38qcSWEoxADbXfSSn17DJWcXvQTkHBg==", "dev": true, "dependencies": { "@eslint/plugin-kit": "^0.4.1", "@html-eslint/core": "^0.57.0", - "@html-eslint/parser": "^0.57.0", + "@html-eslint/parser": "^0.57.1", "@html-eslint/template-parser": "^0.57.0", "@html-eslint/template-syntax-parser": "^0.57.0", "@html-eslint/types": "^0.57.0", - "@rviscomi/capo.js": "^2.1.0" + "@rviscomi/capo.js": "^2.1.0", + "html-standard": "^0.0.13" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5335,7 +5336,7 @@ "eslint": ">=8.0.0 || ^10.0.0-0" } }, - "node_modules/@html-eslint/eslint-plugin/node_modules/@html-eslint/parser": { + "node_modules/@html-eslint/parser": { "version": "0.57.1", "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.57.1.tgz", "integrity": "sha512-nQ5vw7Os+Snjxq9hLLBak2bv502Obn77BNOWfGK2+GIrShxtGd8w1ehlKW3EB5/RQzqBk6VDK8nPfexlR3M7kg==", @@ -5348,19 +5349,6 @@ "es-html-parser": "0.3.1" } }, - "node_modules/@html-eslint/parser": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.57.0.tgz", - "integrity": "sha512-guzD7QJFM0UOGnOZco7I9WEZOBQCmXR3abt6sIhznq4x7Ws6l/KwnNo7im6r0g7/ftLTmuKnLjyNEbW8seQyMQ==", - "dev": true, - "dependencies": { - "@eslint/css-tree": "^3.6.9", - "@html-eslint/template-syntax-parser": "^0.57.0", - "@html-eslint/types": "^0.57.0", - "css-tree": "^3.1.0", - "es-html-parser": "0.3.1" - } - }, "node_modules/@html-eslint/template-parser": { "version": "0.57.0", "resolved": "https://registry.npmjs.org/@html-eslint/template-parser/-/template-parser-0.57.0.tgz", @@ -10308,15 +10296,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10326,18 +10314,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -10352,13 +10340,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10369,9 +10357,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10385,9 +10373,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10398,17 +10386,17 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -10425,13 +10413,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10441,13 +10429,25 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/utils/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/utils/node_modules/debug": { @@ -10468,27 +10468,27 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -24189,15 +24189,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", - "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", + "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.54.0", - "@typescript-eslint/parser": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0" + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -24207,21 +24207,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", - "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/type-utils": "8.54.0", - "@typescript-eslint/utils": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -24234,21 +24234,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.54.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", - "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "engines": { @@ -24259,18 +24259,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -24285,13 +24285,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -24302,9 +24302,9 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -24318,14 +24318,14 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", - "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -24337,14 +24337,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -24355,17 +24355,17 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -24382,13 +24382,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -24398,13 +24398,25 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/typescript-eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/typescript-eslint/node_modules/debug": { @@ -24425,12 +24437,12 @@ } }, "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -24446,15 +24458,15 @@ } }, "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -29129,39 +29141,25 @@ } }, "@html-eslint/eslint-plugin": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.57.0.tgz", - "integrity": "sha512-9/sjZ2KHsZmco45Z9rGySOocJ734rhjjt1ofXJve7lzzBY+t8FF7fwVp9EmcXSer+0zDUb5hGBHWbgIZ0SEnJA==", + "version": "0.57.1", + "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.57.1.tgz", + "integrity": "sha512-IDfdk3V27eebNpdXD2NLy/lnTSbUuKrro/6YJICBn/9aiXPXagNqWJB38qcSWEoxADbXfSSn17DJWcXvQTkHBg==", "dev": true, "requires": { "@eslint/plugin-kit": "^0.4.1", "@html-eslint/core": "^0.57.0", - "@html-eslint/parser": "^0.57.0", + "@html-eslint/parser": "^0.57.1", "@html-eslint/template-parser": "^0.57.0", "@html-eslint/template-syntax-parser": "^0.57.0", "@html-eslint/types": "^0.57.0", - "@rviscomi/capo.js": "^2.1.0" - }, - "dependencies": { - "@html-eslint/parser": { - "version": "0.57.1", - "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.57.1.tgz", - "integrity": "sha512-nQ5vw7Os+Snjxq9hLLBak2bv502Obn77BNOWfGK2+GIrShxtGd8w1ehlKW3EB5/RQzqBk6VDK8nPfexlR3M7kg==", - "dev": true, - "requires": { - "@eslint/css-tree": "^3.6.9", - "@html-eslint/template-syntax-parser": "^0.57.0", - "@html-eslint/types": "^0.57.0", - "css-tree": "^3.1.0", - "es-html-parser": "0.3.1" - } - } + "@rviscomi/capo.js": "^2.1.0", + "html-standard": "^0.0.13" } }, "@html-eslint/parser": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.57.0.tgz", - "integrity": "sha512-guzD7QJFM0UOGnOZco7I9WEZOBQCmXR3abt6sIhznq4x7Ws6l/KwnNo7im6r0g7/ftLTmuKnLjyNEbW8seQyMQ==", + "version": "0.57.1", + "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.57.1.tgz", + "integrity": "sha512-nQ5vw7Os+Snjxq9hLLBak2bv502Obn77BNOWfGK2+GIrShxtGd8w1ehlKW3EB5/RQzqBk6VDK8nPfexlR3M7kg==", "dev": true, "requires": { "@eslint/css-tree": "^3.6.9", @@ -32200,84 +32198,90 @@ } }, "@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "dependencies": { "@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "requires": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" } }, "@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "requires": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" } }, "@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true }, "@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "requires": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" } }, "@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "requires": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" } }, + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, "brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "requires": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" } }, "debug": { @@ -32290,18 +32294,18 @@ } }, "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true }, "minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "requires": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.2" } } } @@ -41783,126 +41787,132 @@ "dev": true }, "typescript-eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", - "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", + "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", "dev": true, "requires": { - "@typescript-eslint/eslint-plugin": "8.54.0", - "@typescript-eslint/parser": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0" + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" }, "dependencies": { "@typescript-eslint/eslint-plugin": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", - "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/type-utils": "8.54.0", - "@typescript-eslint/utils": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" } }, "@typescript-eslint/parser": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", - "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" } }, "@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "requires": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" } }, "@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "requires": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" } }, "@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true }, "@typescript-eslint/type-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", - "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "requires": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" } }, "@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "requires": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" } }, "@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "requires": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" } }, + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, "brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "requires": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" } }, "debug": { @@ -41915,9 +41925,9 @@ } }, "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true }, "ignore": { @@ -41927,12 +41937,12 @@ "dev": true }, "minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "requires": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.2" } } } diff --git a/frontend/package.json b/frontend/package.json index f0e0624b775..8ed7e4b24b7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,8 +14,8 @@ "@angular-eslint/template-parser": "20.7.0", "@angular/language-service": "21.1.6", "@eslint/js": "^9.39.2", - "@html-eslint/eslint-plugin": "^0.57.0", - "@html-eslint/parser": "^0.57.0", + "@html-eslint/eslint-plugin": "^0.57.1", + "@html-eslint/parser": "^0.57.1", "@jsdevtools/coverage-istanbul-loader": "3.0.5", "@stylistic/eslint-plugin": "^5.7.1", "@types/codemirror": "5.60.5", @@ -60,7 +60,7 @@ "source-map-explorer": "^2.5.2", "ts-node": "~10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "^8.54.0", + "typescript-eslint": "^8.56.1", "wscat": "^6.1.0" }, "dependencies": { diff --git a/frontend/src/app/shared/components/storages/file-picker-base-modal/file-picker-base-modal.component.ts b/frontend/src/app/shared/components/storages/file-picker-base-modal/file-picker-base-modal.component.ts index ca0cb105028..6bec3bbad27 100644 --- a/frontend/src/app/shared/components/storages/file-picker-base-modal/file-picker-base-modal.component.ts +++ b/frontend/src/app/shared/components/storages/file-picker-base-modal/file-picker-base-modal.component.ts @@ -173,7 +173,7 @@ export abstract class FilePickerBaseModalComponent extends OpModalComponent impl return of('/'); } - if (this.locals.projectFolderMode === 'automatic' && this.locals.projectFolderHref === null) { + if (this.locals.projectFolderMode === 'automatic' && !this.locals.projectFolderHref) { this.showAlert.next('managedFolderNotFound'); return of('/'); } diff --git a/frontend/src/global_styles/common/header/app-header.sass b/frontend/src/global_styles/common/header/app-header.sass index c93df1a4edb..789b3052e0a 100644 --- a/frontend/src/global_styles/common/header/app-header.sass +++ b/frontend/src/global_styles/common/header/app-header.sass @@ -45,6 +45,7 @@ grid-area: center justify-content: center + &--center_mobile-end @media screen and (max-width: $breakpoint-md) justify-content: flex-end diff --git a/frontend/src/global_styles/content/editor/_ckeditor.sass b/frontend/src/global_styles/content/editor/_ckeditor.sass index 7086e840bae..d9b59e95d1a 100644 --- a/frontend/src/global_styles/content/editor/_ckeditor.sass +++ b/frontend/src/global_styles/content/editor/_ckeditor.sass @@ -94,7 +94,7 @@ opce-ckeditor-augmented-textarea .op-ckeditor--attachments .document-editor__toolbar position: sticky top: 0 - z-index: 2 + z-index: 3 // Reset these styles explicitly when the editor is opened inside a Dialog, as position: sticky opens a separate stacking context. // In case the dialog has multiple editors below each other, these different context interfere and the paragraph dropdown of an editor will be behind the editor below it. diff --git a/frontend/src/stimulus/controllers/dynamic/admin/work-packages-identifier.controller.ts b/frontend/src/stimulus/controllers/dynamic/admin/work-packages-identifier.controller.ts new file mode 100644 index 00000000000..e40bff2a598 --- /dev/null +++ b/frontend/src/stimulus/controllers/dynamic/admin/work-packages-identifier.controller.ts @@ -0,0 +1,68 @@ +/* + * -- 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 { Controller } from '@hotwired/stimulus'; + +export default class WorkPackagesIdentifierController extends Controller { + static values = { + hasProblematicProjects: Boolean, + }; + + static targets = ['autofixSection', 'saveButton', 'autofixButton']; + + declare readonly hasProblematicProjectsValue:boolean; + + declare readonly autofixSectionTarget:HTMLElement; + declare readonly saveButtonTarget:HTMLButtonElement; + declare readonly autofixButtonTarget:HTMLButtonElement; + + connect() { + this.updateVisibility(); + } + + handleChange() { + this.updateVisibility(); + } + + private updateVisibility() { + const showAutofix = this.isAlphanumericSelected() && this.hasProblematicProjectsValue; + + this.autofixSectionTarget.hidden = !showAutofix; + this.saveButtonTarget.hidden = showAutofix; + this.autofixButtonTarget.hidden = !showAutofix; + } + + private isAlphanumericSelected():boolean { + const checked = this.element.querySelector( + 'input[name="settings[work_packages_identifier]"]:checked', + ); + return checked?.value === 'alphanumeric'; + } +} diff --git a/frontend/src/stimulus/controllers/poll-for-changes.controller.ts b/frontend/src/stimulus/controllers/poll-for-changes.controller.ts index 6b439f6335b..20e18ea70ca 100644 --- a/frontend/src/stimulus/controllers/poll-for-changes.controller.ts +++ b/frontend/src/stimulus/controllers/poll-for-changes.controller.ts @@ -76,7 +76,8 @@ export default class PollForChangesController extends ApplicationController { triggerTurboStream() { const url = new URL(this.urlValue, window.location.origin); - url.searchParams.set('reference', this.buildReference()); + const ref = this.buildReference(); + if (ref) url.searchParams.set('reference', ref); void fetch(url.toString()) .then(async (r) => { diff --git a/lib/open_project/events.rb b/lib/open_project/events.rb index 143cbf70163..c2e7fbb8f9b 100644 --- a/lib/open_project/events.rb +++ b/lib/open_project/events.rb @@ -80,6 +80,8 @@ module OpenProject WATCHER_ADDED = "watcher_added" WATCHER_DESTROYED = "watcher_destroyed" + MODULE_DISABLED = "module_disabled" + WORK_PACKAGE_SHARED = "work_package_shared" end end diff --git a/lib/open_project/patches/mail_smtp.rb b/lib/open_project/patches/mail_smtp.rb new file mode 100644 index 00000000000..0624129ee22 --- /dev/null +++ b/lib/open_project/patches/mail_smtp.rb @@ -0,0 +1,53 @@ +# 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. +#++ + +require "mail" + +## +# Correctly pass tls_hostname from Rails until [1] is resolved and the gem updated. +# +# [1] https://github.com/mikel/mail/issues/1660 +module OpenProject::Patches + module Mail + module SMTP + private + + def build_smtp_session + super.tap do |smtp| + smtp.tls_hostname = settings[:tls_hostname] if settings[:tls_hostname] + end + end + end + end +end + +OpenProject::Patches.patch_gem_version "mail", "2.9.0" do + Mail::SMTP.prepend OpenProject::Patches::Mail::SMTP +end diff --git a/lib/open_project/patches/mail_smtp_start_tls_auto_fix.rb b/lib/open_project/patches/mail_smtp_start_tls_auto_fix.rb deleted file mode 100644 index b747469035f..00000000000 --- a/lib/open_project/patches/mail_smtp_start_tls_auto_fix.rb +++ /dev/null @@ -1,25 +0,0 @@ -## -# This is a fix for a new SMTP bug introduced with Ruby 3. -# This can be removed once the official fix from the `mail` gem maintainers -# has been released and the gem bumped by us. -# -# Details: https://community.openproject.org/projects/openproject/work_packages/42385/activity -module OpenProject - module Patches - module MailSmtpStartTlsAutoHotfix - def build_smtp_session - super.tap do |smtp| - smtp.disable_starttls if disable_starttls? - end - end - - def disable_starttls? - settings[:enable_starttls_auto] == false && !settings[:enable_starttls] - end - end - end -end - -require "mail" - -Mail::SMTP.prepend OpenProject::Patches::MailSmtpStartTlsAutoHotfix diff --git a/lib/open_project/remove_ascii_control_characters.rb b/lib/open_project/remove_ascii_control_characters.rb new file mode 100644 index 00000000000..0e189ae6b1d --- /dev/null +++ b/lib/open_project/remove_ascii_control_characters.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module OpenProject + # Strips ASCII control characters (0x00–0x1F, 0x7F) from a string. + # Designed for use with ActiveRecord's `normalizes` API: + # + # normalizes :name, with: OpenProject::RemoveAsciiControlCharacters + # + RemoveAsciiControlCharacters = ->(value) { value.is_a?(String) ? value.gsub(/[\x00-\x1F\x7F]/, "") : value } +end diff --git a/lib/open_project/scm/adapters/git.rb b/lib/open_project/scm/adapters/git.rb index cca3094bd25..c10c09ba002 100644 --- a/lib/open_project/scm/adapters/git.rb +++ b/lib/open_project/scm/adapters/git.rb @@ -201,9 +201,14 @@ module OpenProject end def checkout_path - Pathname(OpenProject::Configuration.scm_local_checkout_path) - .join(@identifier) - .expand_path + root = Pathname(OpenProject::Configuration.scm_local_checkout_path).expand_path.to_s + path = Pathname(root).join(@identifier).expand_path.to_s + + unless path.start_with?("#{root}/") + raise ArgumentError, "Checkout path escapes the configured root directory" + end + + Pathname(path) end def checkout_uri diff --git a/lib/open_project/scm/manageable_repository.rb b/lib/open_project/scm/manageable_repository.rb index 4ed2ce65301..f5cc07db129 100644 --- a/lib/open_project/scm/manageable_repository.rb +++ b/lib/open_project/scm/manageable_repository.rb @@ -111,7 +111,14 @@ module OpenProject # Used only in the creation of a repository, at a later point # in time, it is referred to in the root_url def managed_repository_path - File.join(self.class.managed_root, repository_identifier) + root = File.expand_path(self.class.managed_root) + path = File.expand_path(File.join(root, repository_identifier)) + + unless path.start_with?("#{root}/") + raise ArgumentError, "Repository path escapes the configured managed root directory" + end + + path end ## diff --git a/lib/redmine/menu_manager/wiki_menu_helper.rb b/lib/redmine/menu_manager/wiki_menu_helper.rb index 1262b4827fa..6e85ff6d53c 100644 --- a/lib/redmine/menu_manager/wiki_menu_helper.rb +++ b/lib/redmine/menu_manager/wiki_menu_helper.rb @@ -36,10 +36,6 @@ module Redmine::MenuManager::WikiMenuHelper wiki_main_items(project_wiki).reverse_each do |main_item| Redmine::MenuManager.loose :project_menu do |menu| push_wiki_main_menu(menu, main_item, project) - - main_item.children.each do |child| - push_wiki_menu_subitem(menu, main_item, child) - end end end end @@ -60,17 +56,6 @@ module Redmine::MenuManager::WikiMenuHelper main_item.destroy end - def push_wiki_menu_subitem(menu, main_item, child) - menu.push child.menu_identifier, - { controller: "/wiki", action: "show", id: child.slug }, - caption: child.title, - html: { class: "wiki-menu--sub-item" }, - parent: main_item.menu_identifier - rescue ArgumentError => e - Rails.logger.error "Failed to add wiki item #{child.slug} to wiki menu: #{e}. Deleting it." - child.destroy - end - def default_menu_item(page) if (main_item = page.nearest_main_item) main_item diff --git a/modules/backlogs/app/components/backlogs/backlog_component.rb b/modules/backlogs/app/components/backlogs/backlog_component.rb index a25366262a3..888de7921d6 100644 --- a/modules/backlogs/app/components/backlogs/backlog_component.rb +++ b/modules/backlogs/app/components/backlogs/backlog_component.rb @@ -73,7 +73,7 @@ module Backlogs { generic_drag_and_drop_target: "container", target_container_accessor: ":scope > ul", - target_id: backlog.sprint_id, + target_id: "version:#{backlog.sprint_id}", target_allowed_drag_type: "story" } end @@ -82,7 +82,7 @@ module Backlogs { draggable_id: story.id, draggable_type: "story", - drop_url: move_backlogs_project_sprint_story_path(project, sprint, story) + drop_url: move_legacy_backlogs_project_sprint_story_path(project, sprint, story) } end end diff --git a/modules/backlogs/app/components/backlogs/sprint_component.rb b/modules/backlogs/app/components/backlogs/sprint_component.rb index 96dddd58110..19758de4839 100644 --- a/modules/backlogs/app/components/backlogs/sprint_component.rb +++ b/modules/backlogs/app/components/backlogs/sprint_component.rb @@ -76,7 +76,7 @@ module Backlogs { generic_drag_and_drop_target: "container", target_container_accessor: ":scope > ul", - target_id: sprint.id, + target_id: "sprint:#{sprint.id}", target_allowed_drag_type: "story" } end @@ -85,7 +85,7 @@ module Backlogs { draggable_id: story.id, draggable_type: "story", - drop_url: move_backlogs_project_sprint_story_path(project, sprint, story) + drop_url: move_project_sprint_story_path(project, sprint, story) } end end diff --git a/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.html.erb b/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.html.erb new file mode 100644 index 00000000000..985b7d9a585 --- /dev/null +++ b/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.html.erb @@ -0,0 +1,76 @@ +<%#-- 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. + +++#%> + +<%= + render Primer::OpenProject::PageHeader.new do |header| + header.with_title { t(:label_backlogs) } + header.with_breadcrumbs( + [{ href: project_overview_path(project), text: project.name }, + { href: project_settings_general_path(project), text: I18n.t(:label_project_settings) }, + I18n.t(:label_backlogs)] + ) + + header.with_tab_nav(label: nil) do |tab_nav| + tab_nav.with_tab( + selected: selected_tab?(:done_status), + href: project_settings_backlogs_path(project) + ) do |t| + t.with_text { t("backlogs.done_status") } + end + + if OpenProject::FeatureDecisions.scrum_projects_active? && User.current.allowed_in_project?(:share_sprint, project) + tab_nav.with_tab( + selected: selected_tab?(:sharing), + href: project_settings_backlog_sharing_path(project) + ) do |t| + t.with_text { t("backlogs.sharing") } + end + end + end + + if selected_tab == :done_status + header.with_action_menu( + menu_arguments: { anchor_align: :end }, + button_arguments: { + icon: :"kebab-horizontal", + "aria-label": t(:label_more) + } + ) do |menu| + menu.with_item( + tag: :button, + href: rebuild_positions_project_settings_backlogs_path(@project), + label: t(:"backlogs.rebuild_positions"), + form_arguments: { method: :post, data: { turbo_frame: "_top" } } + ) do |item| + item.with_leading_visual_icon(icon: :sync) + end + end + end + end +%> diff --git a/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.rb b/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.rb new file mode 100644 index 00000000000..25892dbb886 --- /dev/null +++ b/modules/backlogs/app/components/projects/settings/backlogs/settings_header_component.rb @@ -0,0 +1,54 @@ +# 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 Projects + module Settings + module Backlogs + class SettingsHeaderComponent < ApplicationComponent + include OpPrimer::ComponentHelpers + + def initialize(project:, selected_tab:) + super + + @project = project + @selected_tab = selected_tab + end + + def selected_tab?(tab_name) + selected_tab == tab_name + end + + private + + attr_reader :project, :selected_tab + end + end + end +end diff --git a/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_component.html.erb b/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_component.html.erb new file mode 100644 index 00000000000..0e5b2c1050a --- /dev/null +++ b/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_component.html.erb @@ -0,0 +1,45 @@ +<%#-- 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. + +++#%> + +<%= + render(Primer::Beta::Text.new(tag: :div, color: :muted, mb: 3)) do + I18n.t("backlogs.sharing_description") + end +%> + +<%= + settings_primer_form_with( + model: project, + url: project_settings_backlog_sharing_path(project), + method: :patch, + data: { turbo_frame: "_top", controller: "show-when-value-selected" } + ) do |f| + render(Projects::Settings::Backlogs::SharingForm.new(f)) + end +%> diff --git a/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_component.rb b/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_component.rb new file mode 100644 index 00000000000..94847d32bca --- /dev/null +++ b/modules/backlogs/app/components/projects/settings/backlogs/sharing_form_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 Projects + module Settings + module Backlogs + class SharingFormComponent < ApplicationComponent + include ApplicationHelper + include OpPrimer::ComponentHelpers + + def initialize(project:) + super + + @project = project + end + + private + + attr_reader :project + end + end + end +end diff --git a/modules/backlogs/app/contracts/projects/backlog_settings_contract.rb b/modules/backlogs/app/contracts/projects/backlog_settings_contract.rb new file mode 100644 index 00000000000..ff6ee065517 --- /dev/null +++ b/modules/backlogs/app/contracts/projects/backlog_settings_contract.rb @@ -0,0 +1,68 @@ +# 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 Projects + class BacklogSettingsContract < ::ModelContract + # The sprint_sharing setting is stored on the settings column. Hence writing + # the settings column should be allowed, but only for the sprint_sharing setting. + attribute :settings, writable: -> do + model.settings_change&.none? { it.except("sprint_sharing").any? } + end + attribute :sprint_sharing + + validate :validate_permissions + validate :validate_global_sprint_sharer_uniqueness + validates :sprint_sharing, presence: true + validates :sprint_sharing, inclusion: { in: Project::SPRINT_SHARING_MODES }, allow_blank: true + + def validate_model? = false + + protected + + def validate_permissions + unless user.allowed_in_project?(:share_sprint, model) + errors.add :base, :error_unauthorized + end + end + + def validate_global_sprint_sharer_uniqueness + if model.share_sprints_with_all_projects? && + (sharer = Project.global_sprint_sharer) && + sharer != model + + if user.allowed_in_project?(:view_project, sharer) + errors.add :sprint_sharing, :share_all_projects_already_taken, name: sharer.name + else + errors.add :sprint_sharing, :share_all_projects_already_taken_anonymous + end + end + end + end +end diff --git a/modules/backlogs/app/controllers/projects/settings/backlog_sharings_controller.rb b/modules/backlogs/app/controllers/projects/settings/backlog_sharings_controller.rb new file mode 100644 index 00000000000..dc547958a58 --- /dev/null +++ b/modules/backlogs/app/controllers/projects/settings/backlog_sharings_controller.rb @@ -0,0 +1,61 @@ +# 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. +#++ + +class Projects::Settings::BacklogSharingsController < Projects::SettingsController + menu_item :settings_backlogs + + before_action :check_scrum_projects_feature_flag + + def show; end + + def update + call = Projects::UpdateService + .new(model: @project, user: current_user, contract_class: Projects::BacklogSettingsContract) + .call(backlog_settings_params) + + if call.success? + flash[:notice] = I18n.t(:notice_successful_update) + redirect_to project_settings_backlog_sharing_path(@project) + else + flash.now[:error] = I18n.t(:notice_unsuccessful_update_with_reason, reason: call.message) + render action: :show, status: :unprocessable_entity + end + end + + private + + def check_scrum_projects_feature_flag + render_404 unless OpenProject::FeatureDecisions.scrum_projects_active? + end + + def backlog_settings_params + params.expect(project: %i[sprint_sharing]) + end +end diff --git a/modules/backlogs/app/controllers/rb_application_controller.rb b/modules/backlogs/app/controllers/rb_application_controller.rb index 83906ae31a7..5efcf887455 100644 --- a/modules/backlogs/app/controllers/rb_application_controller.rb +++ b/modules/backlogs/app/controllers/rb_application_controller.rb @@ -41,7 +41,7 @@ class RbApplicationController < ApplicationController # Loads the project to be used by the authorize filter to determine if # User.current has permission to invoke the method in question. def load_sprint_and_project - @project = Project.visible.find(params[:project_id]) + load_project # because of strong params, we want to pluck this variable out right now, # otherwise it causes issues where we are doing `attributes=`. @@ -50,6 +50,10 @@ class RbApplicationController < ApplicationController end end + def load_project + @project = Project.visible.find(params[:project_id]) + end + def check_if_plugin_is_configured settings = Setting.plugin_openproject_backlogs if settings["story_types"].blank? || settings["task_type"].blank? diff --git a/modules/backlogs/app/controllers/rb_sprints_controller.rb b/modules/backlogs/app/controllers/rb_sprints_controller.rb index 0dbbe03a5b5..2978ea374b9 100644 --- a/modules/backlogs/app/controllers/rb_sprints_controller.rb +++ b/modules/backlogs/app/controllers/rb_sprints_controller.rb @@ -176,10 +176,6 @@ class RbSprintsController < RbApplicationController load_project end - def load_project - @project = Project.visible.find(params[:project_id]) - end - def sprint_params params.expect(sprint: %i[name start_date effective_date]) end diff --git a/modules/backlogs/app/controllers/rb_stories_controller.rb b/modules/backlogs/app/controllers/rb_stories_controller.rb index 6386fccd5af..c9ab6c288b2 100644 --- a/modules/backlogs/app/controllers/rb_stories_controller.rb +++ b/modules/backlogs/app/controllers/rb_stories_controller.rb @@ -31,36 +31,48 @@ class RbStoriesController < RbApplicationController include OpTurbo::ComponentStream - before_action :load_story + NEW_SPRINT_ACTIONS = %i[move].freeze - def move # rubocop:disable Metrics/AbcSize + skip_before_action :load_sprint_and_project, only: NEW_SPRINT_ACTIONS + + before_action :legacy_load_story, except: NEW_SPRINT_ACTIONS + prepend_before_action :load_sprint, :load_project, :load_story, only: NEW_SPRINT_ACTIONS + + # Move a story from a Sprint to another Sprint or an Agile::Sprint. + def move_legacy # The update service reloads the story internally (via #move_after), # so we memoize the previous version_id before the call. version_id_was = @story.version_id - call = Stories::UpdateService - .new(user: current_user, story: @story) - .call( - attributes: { version_id: move_params[:target_id] }, - position: move_params[:position].to_i - ) - - unless call.success? - render_error_flash_message_via_turbo_stream( - message: I18n.t(:notice_unsuccessful_update_with_reason, reason: call.message) - ) + move_attributes = infer_attributes_from_target + unless move_story(move_attributes).success? return respond_with_turbo_streams(status: :unprocessable_entity) end - replace_backlog_component_via_turbo_stream(sprint: @sprint) + if target_sprint?(move_attributes) + moved_to_sprint + elsif target_version?(move_attributes) && @story.version_id != version_id_was + moved_to_version + end - if @story.version_id != version_id_was - new_sprint = @story.version.becomes(Sprint) + respond_with_turbo_streams + end - render_success_flash_message_via_turbo_stream( - message: I18n.t(:notice_successful_move, from: @sprint.name, to: new_sprint.name) - ) - replace_backlog_component_via_turbo_stream(sprint: new_sprint) + # Move a story from an Agile::Sprint to another Agile::Sprint or a Sprint. + def move + # The update service reloads the story internally (via #move_after), + # so we memoize the previous sprint_id before the call. + sprint_id_was = @story.sprint_id + + move_attributes = infer_attributes_from_target + unless move_story(move_attributes).success? + return respond_with_turbo_streams(status: :unprocessable_entity) + end + + if target_version?(move_attributes) + moved_to_version + elsif target_sprint?(move_attributes) && @story.sprint_id != sprint_id_was + moved_to_sprint end respond_with_turbo_streams @@ -85,6 +97,84 @@ class RbStoriesController < RbApplicationController private + def move_story(move_attributes) + call = update_story_with_target_and_position(attributes: move_attributes) + + if call.success? + # Update source component so that the moved story disappears + replace_typed_component_via_turbo_stream(sprint: @sprint) + else + render_error_flash_message_via_turbo_stream( + message: I18n.t(:notice_unsuccessful_update_with_reason, reason: call.message) + ) + end + + call + end + + def update_story_with_target_and_position(attributes:) + Stories::UpdateService + .new(user: current_user, story: @story) + .call( + attributes:, + position: move_params[:position].to_i + ) + end + + def replace_typed_component_via_turbo_stream(sprint:) + if sprint.is_a?(Agile::Sprint) + replace_sprint_component_via_turbo_stream(sprint:) + else + replace_backlog_component_via_turbo_stream(sprint:) + end + end + + def moved_to_version + moved_to(new_sprint: @story.version.becomes(Sprint)) + end + + def moved_to_sprint + moved_to(new_sprint: @story.sprint.becomes(Agile::Sprint)) + end + + def moved_to(new_sprint:) + render_success_flash_message_via_turbo_stream( + message: I18n.t(:notice_successful_move, from: @sprint.name, to: new_sprint.name) + ) + + # Update the target component so that the moved story shows up + replace_typed_component_via_turbo_stream(sprint: new_sprint) + end + + def infer_attributes_from_target + target_type, target_id = move_params[:target_id].split(":") + + case target_type + when "version" + { version_id: target_id, sprint_id: nil } + when "sprint" + # If the story is assigned to a version, we will only nullify the version + # if it is used as a backlog. We will keep a "regular" version reference. + # Otherwise, moving a story to a sprint would delete it from any version it is + # assigned to. + if @story.version&.used_as_backlog? + { version_id: nil, sprint_id: target_id } + else + { sprint_id: target_id } + end + else + raise ArgumentError, "target_type must include one of: version, sprint." + end + end + + def target_version?(move_attributes) + move_attributes[:version_id].present? + end + + def target_sprint?(move_attributes) + move_attributes[:sprint_id].present? + end + def replace_backlog_component_via_turbo_stream(sprint:) @backlog = Backlog.for(sprint:, project: @project) replace_via_turbo_stream( @@ -93,10 +183,22 @@ class RbStoriesController < RbApplicationController ) end - def load_story + def replace_sprint_component_via_turbo_stream(sprint:) + replace_via_turbo_stream(component: Backlogs::SprintComponent.new(sprint: sprint)) + end + + def legacy_load_story @story = Story.visible.find(params[:id]) end + def load_story + @story = WorkPackage.visible.find(params[:id]) + end + + def load_sprint + @sprint = Agile::Sprint.for_project(@project).visible.find(params[:sprint_id]) + end + def move_params params.require(%i[position target_id]) params.permit(:position, :target_id) diff --git a/modules/backlogs/app/forms/projects/settings/backlogs/sharing_form.rb b/modules/backlogs/app/forms/projects/settings/backlogs/sharing_form.rb new file mode 100644 index 00000000000..38eac5f43c5 --- /dev/null +++ b/modules/backlogs/app/forms/projects/settings/backlogs/sharing_form.rb @@ -0,0 +1,123 @@ +# 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 Projects + module Settings + module Backlogs + class SharingForm < ApplicationForm + form do |sharing_form| + # TODO: Remove this hidden field, once the `radio_button_group` supports rendering + # the hidden empty field. + # The purpose of the hidden field is to ensure we submit the `sprint_sharing` field + # even if no radio button is chosen. Otherwise, the submitted form will not include + # the field at all and the save request will return success when in fact no setting + # is saved. + # Ideally the hidden field should automatically be rendered by the `radio_button_group` + # helper, similar to how the `collection_radio_buttons` rails helper does. + sharing_form.hidden(name: :sprint_sharing, value: "") + + sharing_form.radio_button_group( + name: :sprint_sharing, + label: I18n.t("projects.settings.backlog_sharing.sprint_sharing") + ) do |group| + Project::SPRINT_SHARING_MODES.each do |option| + group.radio_button( + label: sharing_option_text(option, :label), + value: option, + checked: checked?(option), + disabled: disabled?(option), + caption: caption_for(option), + data: { "show-when-value-selected-target": "cause" } + ) + end + end + + sharing_form.html_content { banner_for(Project::SHARE_SUBPROJECTS, type: :info) } + sharing_form.html_content { banner_for(Project::RECEIVE_SHARED, type: :warning) } + + sharing_form.submit( + name: :submit, + label: I18n.t("button_save"), + scheme: :primary + ) + end + + private + + def checked?(option) + option == model.sprint_sharing + end + + def disabled?(option) + option == Project::SHARE_ALL_PROJECTS && share_all_projects_disabled? + end + + def sharing_option_text(option, key, **) + I18n.t("projects.settings.backlog_sharing.options.#{option}.#{key}", **) + end + + def caption_for(option) + if disabled?(option) + if User.current.allowed_in_project?(:view_project, global_sprint_sharer) + sharing_option_text(option, :disabled_caption, name: global_sprint_sharer.name) + else + sharing_option_text(option, :disabled_caption_anonymous) + end + else + sharing_option_text(option, :caption) + end + end + + def share_all_projects_disabled? + global_sprint_sharer && global_sprint_sharer != model + end + + def global_sprint_sharer + @global_sprint_sharer ||= Project.global_sprint_sharer + end + + def banner_for(option, type: :info) + banner_arguments = + type == :warning ? { scheme: :warning } : { icon: :info } + + render(Primer::BaseComponent.new( + tag: :div, + hidden: model.sprint_sharing != option, + data: { value: option, "show-when-value-selected-target": "effect" } + )) do + render(Primer::Alpha::Banner.new(**banner_arguments)) do + sharing_option_text(option, type) + end + end + end + end + end + end +end diff --git a/modules/backlogs/app/models/agile/sprint.rb b/modules/backlogs/app/models/agile/sprint.rb index 8905ffd709d..cef4d7f6f34 100644 --- a/modules/backlogs/app/models/agile/sprint.rb +++ b/modules/backlogs/app/models/agile/sprint.rb @@ -35,17 +35,15 @@ module Agile class Sprint < ApplicationRecord self.table_name = "sprints" + include ::Scopes::Scoped + belongs_to :project has_many :work_packages, dependent: :nullify - scope :for_project, ->(project) { where(project:) } - scope :not_completed, -> { !completed } - scope :order_by_date, -> do - order(arel_table[:start_date].asc.nulls_last, - arel_table[:finish_date].asc.nulls_last) - end - # FIXME: replace this stub with a meaningful implementation. - scope :visible, -> { all } + scopes :for_project, + :not_completed, + :order_by_date, + :visible enum :status, { @@ -56,16 +54,6 @@ module Agile default: "in_planning", validate: true - enum :sharing, - { - none: "none", - descendants: "descendants", - system: "system" - }, - default: "none", - prefix: :sharing_with, - validate: true - validates :name, presence: true validates :project, presence: true validates :start_date, presence: true @@ -76,9 +64,6 @@ module Agile validate :validate_only_one_active_sprint_per_project - # TODO: validate sharing is set to an allowed value, e.g. only admins may share systemwide (#71374, #71253) - # TODO: implement sharing logic once it has been defined (#71374) - def date_range_set? start_date? && finish_date? end diff --git a/modules/backlogs/app/models/agile/sprints/scopes/for_project.rb b/modules/backlogs/app/models/agile/sprints/scopes/for_project.rb new file mode 100644 index 00000000000..1b0a1c65d72 --- /dev/null +++ b/modules/backlogs/app/models/agile/sprints/scopes/for_project.rb @@ -0,0 +1,44 @@ +# 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 Agile::Sprints::Scopes::ForProject + extend ActiveSupport::Concern + + class_methods do + def for_project(project) + # Ideally the project.work_packages scope would be used, but unfortunately + # it has some extra includes that are not necessary in this case. + from_work_packages = WorkPackage.where(project:).where.not(sprint_id: nil) + + where(project: project.sprint_source) + .or(where(id: from_work_packages.select(:sprint_id))) + end + end +end diff --git a/modules/backlogs/app/models/agile/sprints/scopes/not_completed.rb b/modules/backlogs/app/models/agile/sprints/scopes/not_completed.rb new file mode 100644 index 00000000000..2e68e7f1230 --- /dev/null +++ b/modules/backlogs/app/models/agile/sprints/scopes/not_completed.rb @@ -0,0 +1,37 @@ +# 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 Agile::Sprints::Scopes::NotCompleted + extend ActiveSupport::Concern + + def not_completed # rubocop:disable Naming/PredicateMethod + !completed + end +end diff --git a/modules/backlogs/app/models/agile/sprints/scopes/order_by_date.rb b/modules/backlogs/app/models/agile/sprints/scopes/order_by_date.rb new file mode 100644 index 00000000000..b6aed82b9a1 --- /dev/null +++ b/modules/backlogs/app/models/agile/sprints/scopes/order_by_date.rb @@ -0,0 +1,40 @@ +# 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 Agile::Sprints::Scopes::OrderByDate + extend ActiveSupport::Concern + + class_methods do + def order_by_date + order(arel_table[:start_date].asc.nulls_last, + arel_table[:finish_date].asc.nulls_last) + end + end +end diff --git a/modules/backlogs/app/models/agile/sprints/scopes/visible.rb b/modules/backlogs/app/models/agile/sprints/scopes/visible.rb new file mode 100644 index 00000000000..b9d214d8680 --- /dev/null +++ b/modules/backlogs/app/models/agile/sprints/scopes/visible.rb @@ -0,0 +1,38 @@ +# 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 Agile::Sprints::Scopes::Visible + extend ActiveSupport::Concern + + class_methods do + # FIXME: replace this stub with a meaningful implementation. + def visible = all + end +end diff --git a/modules/backlogs/app/models/projects/scopes/not_sharing_sprints.rb b/modules/backlogs/app/models/projects/scopes/not_sharing_sprints.rb new file mode 100644 index 00000000000..38fab4571bd --- /dev/null +++ b/modules/backlogs/app/models/projects/scopes/not_sharing_sprints.rb @@ -0,0 +1,41 @@ +# 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 Projects::Scopes::NotSharingSprints + extend ActiveSupport::Concern + + class_methods do + def not_sharing_sprints + with_settings(sprint_sharing: Projects::SprintSharing::NO_SHARING) + .or(with_settings(sprint_sharing: "")) + .or(with_settings(sprint_sharing: nil)) + end + end +end diff --git a/modules/backlogs/app/models/projects/scopes/receive_shared_sprints.rb b/modules/backlogs/app/models/projects/scopes/receive_shared_sprints.rb new file mode 100644 index 00000000000..0e023d90da1 --- /dev/null +++ b/modules/backlogs/app/models/projects/scopes/receive_shared_sprints.rb @@ -0,0 +1,39 @@ +# 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 Projects::Scopes::ReceiveSharedSprints + extend ActiveSupport::Concern + + class_methods do + def receive_shared_sprints + with_settings(sprint_sharing: Projects::SprintSharing::RECEIVE_SHARED) + end + end +end diff --git a/modules/backlogs/app/models/projects/scopes/share_sprints_with_all_projects.rb b/modules/backlogs/app/models/projects/scopes/share_sprints_with_all_projects.rb new file mode 100644 index 00000000000..c0c1eb8503b --- /dev/null +++ b/modules/backlogs/app/models/projects/scopes/share_sprints_with_all_projects.rb @@ -0,0 +1,39 @@ +# 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 Projects::Scopes::ShareSprintsWithAllProjects + extend ActiveSupport::Concern + + class_methods do + def share_sprints_with_all_projects + with_settings(sprint_sharing: Projects::SprintSharing::SHARE_ALL_PROJECTS) + end + end +end diff --git a/modules/backlogs/app/models/projects/scopes/share_sprints_with_subprojects.rb b/modules/backlogs/app/models/projects/scopes/share_sprints_with_subprojects.rb new file mode 100644 index 00000000000..c4dce1be4c8 --- /dev/null +++ b/modules/backlogs/app/models/projects/scopes/share_sprints_with_subprojects.rb @@ -0,0 +1,39 @@ +# 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 Projects::Scopes::ShareSprintsWithSubprojects + extend ActiveSupport::Concern + + class_methods do + def share_sprints_with_subprojects + with_settings(sprint_sharing: Projects::SprintSharing::SHARE_SUBPROJECTS) + end + end +end diff --git a/modules/backlogs/app/models/projects/sprint_sharing.rb b/modules/backlogs/app/models/projects/sprint_sharing.rb new file mode 100644 index 00000000000..547c28808e1 --- /dev/null +++ b/modules/backlogs/app/models/projects/sprint_sharing.rb @@ -0,0 +1,108 @@ +# 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 Projects::SprintSharing + extend ActiveSupport::Concern + + NO_SHARING = "no_sharing" + SHARE_ALL_PROJECTS = "share_all_projects" + SHARE_SUBPROJECTS = "share_subprojects" + RECEIVE_SHARED = "receive_shared" + + SPRINT_SHARING_MODES = [NO_SHARING, SHARE_ALL_PROJECTS, SHARE_SUBPROJECTS, RECEIVE_SHARED].freeze + + included do + store_attribute :settings, :sprint_sharing, :string + + scopes :share_sprints_with_all_projects, + :share_sprints_with_subprojects, + :receive_shared_sprints, + :not_sharing_sprints + end + + class_methods do + def global_sprint_sharer + global_sprint_sharer_relation.first + end + + def global_sprint_sharer_relation + share_sprints_with_all_projects.active.limit(1) + end + end + + # `default:` cannot be reliably used on the store_attribute declaration, + # see config/initializers/store_attribute.rb for more details. + def sprint_sharing + super || NO_SHARING + end + + def share_sprints_with_all_projects? + sprint_sharing == SHARE_ALL_PROJECTS + end + + def share_sprints_with_subprojects? + sprint_sharing == SHARE_SUBPROJECTS + end + + def receive_shared_sprints? + sprint_sharing == RECEIVE_SHARED + end + + def not_sharing_sprints? + sprint_sharing == NO_SHARING + end + + def not_sharing_sprints! + return if not_sharing_sprints? + + update_column(:settings, settings.merge("sprint_sharing" => NO_SHARING)) + end + + def sprint_source + # Senders and non-sharing projects only see their own sprints. + # Receivers see external sprints from the closest ancestor sharing + # subprojects, falling back to the global sharer. + if receive_shared_sprints? + closest_sharing_ancestor_or_global_sharer + else + self.class.where(id:) + end + end + + private + + def closest_sharing_ancestor_or_global_sharer + closest_ancestor = ancestors.share_sprints_with_subprojects.reorder(lft: :desc).limit(1) + + self.class + .where(id: closest_ancestor).limit(1) # Both sides of `or` must be structurally identical + .or(self.class.global_sprint_sharer_relation.where.not(closest_ancestor.arel.exists)) + end +end diff --git a/modules/backlogs/app/services/sprints/set_attributes_service.rb b/modules/backlogs/app/services/sprints/set_attributes_service.rb index 22625e0b759..2ed6d5974c2 100644 --- a/modules/backlogs/app/services/sprints/set_attributes_service.rb +++ b/modules/backlogs/app/services/sprints/set_attributes_service.rb @@ -41,16 +41,15 @@ module Sprints def set_default_attributes(_params) set_sprint_name - set_status_and_sharing + set_default_status end def set_sprint_name model.name ||= sprint_name_from_predecessor end - def set_status_and_sharing + def set_default_status model.status ||= "in_planning" - model.sharing ||= "none" end def next_name_in_succession(predecessor) diff --git a/modules/backlogs/app/views/projects/settings/backlog_sharings/show.html.erb b/modules/backlogs/app/views/projects/settings/backlog_sharings/show.html.erb new file mode 100644 index 00000000000..9bd54844005 --- /dev/null +++ b/modules/backlogs/app/views/projects/settings/backlog_sharings/show.html.erb @@ -0,0 +1,39 @@ +<%#-- 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. + +++#%> + +<%= turbo_frame_tag "backlogs-settings" do %> + <%= render( + Projects::Settings::Backlogs::SettingsHeaderComponent.new( + project: @project, + selected_tab: :sharing + ) + ) %> + + <%= render(Projects::Settings::Backlogs::SharingFormComponent.new(project: @project)) %> +<% end %> diff --git a/modules/backlogs/app/views/projects/settings/backlogs/show.html.erb b/modules/backlogs/app/views/projects/settings/backlogs/show.html.erb index 11ac6fb8e62..9b6c15a85f3 100644 --- a/modules/backlogs/app/views/projects/settings/backlogs/show.html.erb +++ b/modules/backlogs/app/views/projects/settings/backlogs/show.html.erb @@ -27,41 +27,22 @@ See COPYRIGHT and LICENSE files for more details. ++#%> -<%= - render Primer::OpenProject::PageHeader.new do |header| - header.with_title { t(:label_backlogs) } +<%= turbo_frame_tag "backlogs-settings" do %> + <%= render( + Projects::Settings::Backlogs::SettingsHeaderComponent.new( + project: @project, + selected_tab: :done_status + ) + ) %> - header.with_breadcrumbs( - [{ href: project_overview_path(@project), text: @project.name }, - { href: project_settings_general_path(@project), text: I18n.t(:label_project_settings) }, - t(:label_backlogs)] - ) - - header.with_action_menu( - menu_arguments: { anchor_align: :end }, - button_arguments: { - icon: :"kebab-horizontal", - "aria-label": t(:label_more) - } - ) do |menu| - menu.with_item( - tag: :button, - href: rebuild_positions_project_settings_backlogs_path(@project), - label: t(:"backlogs.rebuild_positions"), - form_arguments: { method: :post } - ) do |item| - item.with_leading_visual_icon(icon: :sync) - end - end - end -%> - -<%= - settings_primer_form_with( - url: project_settings_backlogs_path(@project), - model: @project, - method: :patch - ) do |f| -%> - <%= render Projects::Settings::BacklogsSettingsForm.new(f) %> + <%= + settings_primer_form_with( + url: project_settings_backlogs_path(@project), + model: @project, + method: :patch, + data: { turbo_frame: "_top" } + ) do |f| + %> + <%= render Projects::Settings::BacklogsSettingsForm.new(f) %> + <% end %> <% end %> diff --git a/modules/backlogs/config/locales/crowdin/af.yml b/modules/backlogs/config/locales/crowdin/af.yml index 8f5d854a324..1e362abd74c 100644 --- a/modules/backlogs/config/locales/crowdin/af.yml +++ b/modules/backlogs/config/locales/crowdin/af.yml @@ -31,6 +31,8 @@ af: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ af: backlogs_work_package_type: "Agterstand tipe" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ af: column_width: "Column width" definition_of_done: "Definisie van Gedoen" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Belemmering" label_versions_default_fold_state: "Wys weergawe gevou" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ af: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Agterstandes" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ar.yml b/modules/backlogs/config/locales/crowdin/ar.yml index 1de0218f19a..e2de45637d6 100644 --- a/modules/backlogs/config/locales/crowdin/ar.yml +++ b/modules/backlogs/config/locales/crowdin/ar.yml @@ -31,6 +31,8 @@ ar: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ar: backlogs_work_package_type: "نوع الأعمال المتراكمة غير المنجزة" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ar: column_width: "Column width" definition_of_done: "تعريف ما تم" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "عائق" label_versions_default_fold_state: "إظهار الإصدارات مطوية" caption_versions_default_fold_state: "" @@ -166,6 +176,27 @@ ar: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "الأعمال المتراكمة غير المنجزة" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/az.yml b/modules/backlogs/config/locales/crowdin/az.yml index 6e7aea2b54f..5279a18085e 100644 --- a/modules/backlogs/config/locales/crowdin/az.yml +++ b/modules/backlogs/config/locales/crowdin/az.yml @@ -31,6 +31,8 @@ az: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ az: backlogs_work_package_type: "" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ az: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ az: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/be.yml b/modules/backlogs/config/locales/crowdin/be.yml index 771b833a2dc..c80bdab0446 100644 --- a/modules/backlogs/config/locales/crowdin/be.yml +++ b/modules/backlogs/config/locales/crowdin/be.yml @@ -31,6 +31,8 @@ be: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ be: backlogs_work_package_type: "Тып бэклогу" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ be: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -162,6 +172,27 @@ be: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/bg.yml b/modules/backlogs/config/locales/crowdin/bg.yml index f653c939045..1ec8a64ba55 100644 --- a/modules/backlogs/config/locales/crowdin/bg.yml +++ b/modules/backlogs/config/locales/crowdin/bg.yml @@ -31,6 +31,8 @@ bg: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ bg: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ bg: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Препядствие" label_versions_default_fold_state: "Показване на сгънати версиите " caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ bg: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Назад" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ca.yml b/modules/backlogs/config/locales/crowdin/ca.yml index c7253773dba..b88ca17f7e3 100644 --- a/modules/backlogs/config/locales/crowdin/ca.yml +++ b/modules/backlogs/config/locales/crowdin/ca.yml @@ -31,6 +31,8 @@ ca: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ca: backlogs_work_package_type: "Tipus de backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ca: column_width: "Column width" definition_of_done: "Definició de fet" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Mostra les versions contretes" caption_versions_default_fold_state: "Les versions no s'expandiran per defecte quan es visualitzin els registres enrere. Cada un ha d'ampliar-se manualment." @@ -158,6 +168,27 @@ ca: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ckb-IR.yml b/modules/backlogs/config/locales/crowdin/ckb-IR.yml index 60450ebe853..19639bd81e4 100644 --- a/modules/backlogs/config/locales/crowdin/ckb-IR.yml +++ b/modules/backlogs/config/locales/crowdin/ckb-IR.yml @@ -31,6 +31,8 @@ ckb-IR: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ckb-IR: backlogs_work_package_type: "جۆری Backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ckb-IR: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ ckb-IR: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/cs.yml b/modules/backlogs/config/locales/crowdin/cs.yml index de225baae06..1ec2ddc71ff 100644 --- a/modules/backlogs/config/locales/crowdin/cs.yml +++ b/modules/backlogs/config/locales/crowdin/cs.yml @@ -31,6 +31,8 @@ cs: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Doba trvání sprintu" work_package: @@ -39,6 +41,11 @@ cs: backlogs_work_package_type: "Typ nevyřízené položky" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ cs: column_width: "Column width" definition_of_done: "Definice dokončena" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: " Verze zobrazit srolovaně" caption_versions_default_fold_state: "Verze se při prohlížení nevyřízených žádostí ve výchozím nastavení nerozbalují. Každou z nich je třeba rozbalit ručně." @@ -162,6 +172,27 @@ cs: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Nevyřízené položky" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/da.yml b/modules/backlogs/config/locales/crowdin/da.yml index d29bad1355a..25c50c99587 100644 --- a/modules/backlogs/config/locales/crowdin/da.yml +++ b/modules/backlogs/config/locales/crowdin/da.yml @@ -31,6 +31,8 @@ da: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ da: backlogs_work_package_type: "Backlog-type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ da: column_width: "Column width" definition_of_done: "Definition af Udført" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Hindring" label_versions_default_fold_state: "Vis versioner sammenfoldet" caption_versions_default_fold_state: "Versioner vil ikke blive udvidet som standard, når man ser på backlogs. Hver enkelt version skal udvides manuelt." @@ -158,6 +168,27 @@ da: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/de.yml b/modules/backlogs/config/locales/crowdin/de.yml index f2e91491024..7f354321296 100644 --- a/modules/backlogs/config/locales/crowdin/de.yml +++ b/modules/backlogs/config/locales/crowdin/de.yml @@ -31,6 +31,8 @@ de: goal: "Sprint-Ziel" name: "Sprint-Name" sharing: "Teilen" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint-Dauer" work_package: @@ -39,6 +41,11 @@ de: backlogs_work_package_type: "Backlog Typ" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ de: column_width: "Spaltenbreite" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Hindernis" label_versions_default_fold_state: "Versionen eingeklappt anzeigen" caption_versions_default_fold_state: "Versionen werden beim Anzeigen des Backlogs standardmäßig nicht aufgeklappt. Sie müssen manuell geöffnet werden." @@ -158,6 +168,27 @@ de: permission_start_complete_sprint: "Sprint starten/abschließen" permission_view_sprints: "Sprints ansehen" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Keine Burndown-Daten verfügbar" diff --git a/modules/backlogs/config/locales/crowdin/el.yml b/modules/backlogs/config/locales/crowdin/el.yml index 0d1a7eac949..a1770cd1ae8 100644 --- a/modules/backlogs/config/locales/crowdin/el.yml +++ b/modules/backlogs/config/locales/crowdin/el.yml @@ -31,6 +31,8 @@ el: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ el: backlogs_work_package_type: "Τύπος backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ el: column_width: "Column width" definition_of_done: "Ορισμός των Ολοκληρωμένων" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Εμπόδιο" label_versions_default_fold_state: "Εμφάνιση συμπτυγμένων εκδόσεων" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ el: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/eo.yml b/modules/backlogs/config/locales/crowdin/eo.yml index 82f8ebbb1c3..6a9fcac0830 100644 --- a/modules/backlogs/config/locales/crowdin/eo.yml +++ b/modules/backlogs/config/locales/crowdin/eo.yml @@ -31,6 +31,8 @@ eo: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ eo: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ eo: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ eo: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/es.yml b/modules/backlogs/config/locales/crowdin/es.yml index 09b6a6aef4f..4acfd170279 100644 --- a/modules/backlogs/config/locales/crowdin/es.yml +++ b/modules/backlogs/config/locales/crowdin/es.yml @@ -31,6 +31,8 @@ es: goal: "Objetivo del sprint" name: "Nombre del sprint" sharing: "Uso compartido" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Duración del sprint" work_package: @@ -39,6 +41,11 @@ es: backlogs_work_package_type: "Tipo de Backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ es: column_width: "Ancho de columna" definition_of_done: "Criterio de Aceptación" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impedimento" label_versions_default_fold_state: "Mostrar versiones colapsadas" caption_versions_default_fold_state: "Las versiones no se expandirán por defecto al visualizar los trabajos pendientes. Cada una deberá expandirse manualmente." @@ -158,6 +168,27 @@ es: permission_start_complete_sprint: "Iniciar/completar sprint" permission_view_sprints: "Ver sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No hay datos de trabajo pendiente disponibles" diff --git a/modules/backlogs/config/locales/crowdin/et.yml b/modules/backlogs/config/locales/crowdin/et.yml index 7c7d3d3daa6..40e46393441 100644 --- a/modules/backlogs/config/locales/crowdin/et.yml +++ b/modules/backlogs/config/locales/crowdin/et.yml @@ -31,6 +31,8 @@ et: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ et: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ et: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ et: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/eu.yml b/modules/backlogs/config/locales/crowdin/eu.yml index 30e0af5f5cb..fab65bd9e43 100644 --- a/modules/backlogs/config/locales/crowdin/eu.yml +++ b/modules/backlogs/config/locales/crowdin/eu.yml @@ -31,6 +31,8 @@ eu: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ eu: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ eu: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ eu: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/fa.yml b/modules/backlogs/config/locales/crowdin/fa.yml index 510a1c9685b..6b038e250a1 100644 --- a/modules/backlogs/config/locales/crowdin/fa.yml +++ b/modules/backlogs/config/locales/crowdin/fa.yml @@ -31,6 +31,8 @@ fa: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "مدت زمان اسپرینت" work_package: @@ -39,6 +41,11 @@ fa: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ fa: column_width: "عرض ستون" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "در هنگام مشاهده backlog ها، نسخه‌ها به صورت پیش‌فرض بازنخواهندشد. هر کدام باید به صورت دستی باز شوند." @@ -158,6 +168,27 @@ fa: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "وظایف" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/fi.yml b/modules/backlogs/config/locales/crowdin/fi.yml index 853ef47c81f..7139bf3ee61 100644 --- a/modules/backlogs/config/locales/crowdin/fi.yml +++ b/modules/backlogs/config/locales/crowdin/fi.yml @@ -31,6 +31,8 @@ fi: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ fi: backlogs_work_package_type: "Työjonon tyyppi" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ fi: column_width: "Column width" definition_of_done: "Valmiin määritelmä" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Este" label_versions_default_fold_state: "Näytä versiot ryhmiteltyinä" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ fi: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Työjonot" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/fil.yml b/modules/backlogs/config/locales/crowdin/fil.yml index eaa59519e54..2ef0247f2c6 100644 --- a/modules/backlogs/config/locales/crowdin/fil.yml +++ b/modules/backlogs/config/locales/crowdin/fil.yml @@ -31,6 +31,8 @@ fil: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ fil: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ fil: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ fil: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/fr.yml b/modules/backlogs/config/locales/crowdin/fr.yml index eb04e9ebdb1..14b3d5ce931 100644 --- a/modules/backlogs/config/locales/crowdin/fr.yml +++ b/modules/backlogs/config/locales/crowdin/fr.yml @@ -31,6 +31,8 @@ fr: goal: "Objectif du sprint" name: "Nom du sprint" sharing: "Partage" + project: + sprint_sharing: "Partage de sprint" sprint: duration: "Durée du sprint" work_package: @@ -39,6 +41,11 @@ fr: backlogs_work_package_type: "Type de backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "ne peut pas être défini car le projet \"%{name}\" est déjà partagé avec tous les projets." + share_all_projects_already_taken_anonymous: "ne peut pas être défini parce qu'un autre projet est déjà partagé avec tous les projets." work_package: attributes: blocks_ids: @@ -56,7 +63,10 @@ fr: any: "tout" column_width: "Largeur de colonne" definition_of_done: "Définition de Fait" - definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + definition_of_done_caption: "Les work packages ayant ces statuts sont traités comme terminés dans les vues du carnet de commandes et dans les rapports." + done_status: "État terminé" + sharing_description: "Ce projet peut soit partager ses propres sprints, soit recevoir des sprints partagés, soit gérer les sprints de manière indépendante (sans partage)." + sharing: "Partage" impediment: "Obstacle" label_versions_default_fold_state: "Afficher les versions de manière repliée" caption_versions_default_fold_state: "Les versions ne seront pas développées par défaut lors de l'affichage des backlogs. Chacune devra être développée manuellement." @@ -158,6 +168,27 @@ fr: permission_start_complete_sprint: "Commencer/terminer le sprint" permission_view_sprints: "Voir les sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Ne pas partager" + caption: "Les sprints créés dans ce projet ne seront disponibles et visibles que pour ce projet. Ils ne seront pas non plus visibles par les sous-projets." + receive_shared: + label: "Recevoir des sprints partagés" + caption: "Ce projet ne peut utiliser que des sprints partagés par d'autres projets." + warning: "Ce projet ne peut utiliser que des sprints partagés par d'autres projets. Les sprints inutilisés créés dans ce projet par le passé ne seront plus visibles." + share_all_projects: + label: "Tous les projets" + caption: "Les sprints créés dans ce projet seront disponibles pour tous les projets de cette instance. Si vous sélectionnez cette option, les sprints ne seront plus disponibles pour les autres projets." + disabled_caption: "L'option n'est pas disponible car le projet \"%{name}\" est actuellement partagé avec tous les projets et seul un projet peut le faire." + disabled_caption_anonymous: "Option non disponible car un autre projet est actuellement en train de partager avec tous les projets et seul un projet peut le faire." + share_subprojects: + label: "Sous-projets" + caption: "Les sprints créés dans ce projet seront disponibles pour tous les sous-projets du projet en cours." + info: "Le partage d'un sprint entraîne le partage du nom, du statut et des dates de début et de fin dans tous les projets. Ceux-ci ne peuvent pas être modifiés dans les projets qui reçoivent et utilisent ces sprints." + sprint_sharing: Partager les sprints rb_burndown_charts: show: blankslate_title: "Aucune donnée disponible sur le burndown" diff --git a/modules/backlogs/config/locales/crowdin/he.yml b/modules/backlogs/config/locales/crowdin/he.yml index 31015e32fb7..f06acdb71fa 100644 --- a/modules/backlogs/config/locales/crowdin/he.yml +++ b/modules/backlogs/config/locales/crowdin/he.yml @@ -31,6 +31,8 @@ he: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ he: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ he: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -162,6 +172,27 @@ he: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/hi.yml b/modules/backlogs/config/locales/crowdin/hi.yml index c4d105746f4..cfe9fafe806 100644 --- a/modules/backlogs/config/locales/crowdin/hi.yml +++ b/modules/backlogs/config/locales/crowdin/hi.yml @@ -31,6 +31,8 @@ hi: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ hi: backlogs_work_package_type: "बैकलॉग प्रकार" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ hi: column_width: "Column width" definition_of_done: "पूर्ण की परिभाषा" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "बाधा" label_versions_default_fold_state: "मुड़े हुए संस्करण दिखाएं" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ hi: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/hr.yml b/modules/backlogs/config/locales/crowdin/hr.yml index f4318fddb9e..2d0f59ea3d7 100644 --- a/modules/backlogs/config/locales/crowdin/hr.yml +++ b/modules/backlogs/config/locales/crowdin/hr.yml @@ -31,6 +31,8 @@ hr: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ hr: backlogs_work_package_type: "Backlog tip" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ hr: column_width: "Column width" definition_of_done: "Definicija učinjenog" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Teškoće" label_versions_default_fold_state: "Prikaži prikupljene verzije" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -160,6 +170,27 @@ hr: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/hu.yml b/modules/backlogs/config/locales/crowdin/hu.yml index 2bbdd49a147..1162b326881 100644 --- a/modules/backlogs/config/locales/crowdin/hu.yml +++ b/modules/backlogs/config/locales/crowdin/hu.yml @@ -31,6 +31,8 @@ hu: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ hu: backlogs_work_package_type: "Backlog típus" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ hu: column_width: "Column width" definition_of_done: "A \"Kész\" meghatározása" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Akadály" label_versions_default_fold_state: "Összecsukott verziók mutatása" caption_versions_default_fold_state: "A verziók alapértelmezés szerint nem lesznek kibontva a várólista (backlog) megtekintésekor. Mindegyiket manuálisan kell kibontani." @@ -158,6 +168,27 @@ hu: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/id.yml b/modules/backlogs/config/locales/crowdin/id.yml index 2f03ef740e4..0358278d122 100644 --- a/modules/backlogs/config/locales/crowdin/id.yml +++ b/modules/backlogs/config/locales/crowdin/id.yml @@ -31,6 +31,8 @@ id: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ id: backlogs_work_package_type: "Jenis jaminan tersimpan" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ id: column_width: "Column width" definition_of_done: "Definisi Selesai" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Halangan" label_versions_default_fold_state: "Tampilkan versi terlipat" caption_versions_default_fold_state: "Versi tidak akan diperluas secara default saat melihat daftar tugas yang tertunda. Setiap versi harus diperluas secara manual." @@ -156,6 +166,27 @@ id: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/it.yml b/modules/backlogs/config/locales/crowdin/it.yml index 92bda374c47..09199d2219e 100644 --- a/modules/backlogs/config/locales/crowdin/it.yml +++ b/modules/backlogs/config/locales/crowdin/it.yml @@ -31,6 +31,8 @@ it: goal: "Obiettivo dello sprint" name: "Nome dello sprint" sharing: "Condivisione" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Durata dello sprint" work_package: @@ -39,6 +41,11 @@ it: backlogs_work_package_type: "Tipo di backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ it: column_width: "Larghezza della colonna" definition_of_done: "Definizione di fatto" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impedimento" label_versions_default_fold_state: "Espandi le versioni" caption_versions_default_fold_state: "Le versioni non verranno espanse per impostazione predefinita durante la visualizzazione dei backlog. Ogni versione deve essere espansa manualmente." @@ -158,6 +168,27 @@ it: permission_start_complete_sprint: "Iniziare/completa lo sprint" permission_view_sprints: "Visualizza gli sprint" project_module_backlogs: "Backlog" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Non sono disponibili dati di burndown" diff --git a/modules/backlogs/config/locales/crowdin/ja.yml b/modules/backlogs/config/locales/crowdin/ja.yml index 4eb545ca810..ed559ad21e0 100644 --- a/modules/backlogs/config/locales/crowdin/ja.yml +++ b/modules/backlogs/config/locales/crowdin/ja.yml @@ -31,6 +31,8 @@ ja: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ja: backlogs_work_package_type: "バックログの種類" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ja: column_width: "Column width" definition_of_done: "「終了」の定義" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "障害事項" label_versions_default_fold_state: "バージョンを折り畳んで表示" caption_versions_default_fold_state: "バックログを表示する場合、デフォルトではバージョンは展開されません。各バージョンは手動で展開する必要があります。" @@ -156,6 +166,27 @@ ja: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "バックログ" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ka.yml b/modules/backlogs/config/locales/crowdin/ka.yml index 800f0ec5014..a29561c677e 100644 --- a/modules/backlogs/config/locales/crowdin/ka.yml +++ b/modules/backlogs/config/locales/crowdin/ka.yml @@ -31,6 +31,8 @@ ka: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ka: backlogs_work_package_type: "ჩამორჩენის ტიპი" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ka: column_width: "Column width" definition_of_done: "დასრულების აღწერა" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "წინააღმდეგობა" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ ka: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "შეუსრულებელი ამოცანები" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/kk.yml b/modules/backlogs/config/locales/crowdin/kk.yml index 8a82b88509c..cd93e23a720 100644 --- a/modules/backlogs/config/locales/crowdin/kk.yml +++ b/modules/backlogs/config/locales/crowdin/kk.yml @@ -31,6 +31,8 @@ kk: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ kk: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ kk: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ kk: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ko.yml b/modules/backlogs/config/locales/crowdin/ko.yml index 4b2ee8833fb..57af32fb81a 100644 --- a/modules/backlogs/config/locales/crowdin/ko.yml +++ b/modules/backlogs/config/locales/crowdin/ko.yml @@ -31,6 +31,8 @@ ko: goal: "스프린트 목표" name: "스프린트 이름" sharing: "공유" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "스프린트 기간" work_package: @@ -39,6 +41,11 @@ ko: backlogs_work_package_type: "백로그 유형" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ko: column_width: "열 너비" definition_of_done: "완료 정의" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "제한" label_versions_default_fold_state: "접힌 버전 표시" caption_versions_default_fold_state: "백로그를 볼 때 버전은 기본적으로 확장되지 않습니다. 각 버전을 수동으로 확장해야 합니다." @@ -156,6 +166,27 @@ ko: permission_start_complete_sprint: "스프린트 시작/완료" permission_view_sprints: "스프린트 보기" project_module_backlogs: "백로그" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "사용 가능한 번다운 데이터 없음" diff --git a/modules/backlogs/config/locales/crowdin/lt.yml b/modules/backlogs/config/locales/crowdin/lt.yml index af7ad730f97..4ccb602b9fa 100644 --- a/modules/backlogs/config/locales/crowdin/lt.yml +++ b/modules/backlogs/config/locales/crowdin/lt.yml @@ -31,6 +31,8 @@ lt: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ lt: backlogs_work_package_type: "Darbų sąrašo tipas" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ lt: column_width: "Column width" definition_of_done: "Pabaigimo apibrėžimas" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Kliūtis" label_versions_default_fold_state: "Rodyti suskleistas versijas" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -162,6 +172,27 @@ lt: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Darbų sąrašai" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/lv.yml b/modules/backlogs/config/locales/crowdin/lv.yml index c4ae62c40ed..6109d4099ee 100644 --- a/modules/backlogs/config/locales/crowdin/lv.yml +++ b/modules/backlogs/config/locales/crowdin/lv.yml @@ -31,6 +31,8 @@ lv: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ lv: backlogs_work_package_type: "Produkta darbu krātuves tips" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ lv: column_width: "Column width" definition_of_done: "Pabeigtības definīcija" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Šķēršļi" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -160,6 +170,27 @@ lv: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Darbu krātuve" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/mn.yml b/modules/backlogs/config/locales/crowdin/mn.yml index 4b9ae429fe0..34332e35397 100644 --- a/modules/backlogs/config/locales/crowdin/mn.yml +++ b/modules/backlogs/config/locales/crowdin/mn.yml @@ -31,6 +31,8 @@ mn: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ mn: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ mn: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ mn: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ms.yml b/modules/backlogs/config/locales/crowdin/ms.yml index d93c45c1701..d17ec5b7404 100644 --- a/modules/backlogs/config/locales/crowdin/ms.yml +++ b/modules/backlogs/config/locales/crowdin/ms.yml @@ -31,6 +31,8 @@ ms: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ms: backlogs_work_package_type: "Jenis tunggakan kerja" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ms: column_width: "Column width" definition_of_done: "Definisi Selesai" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Halangan" label_versions_default_fold_state: "Paparkan versi dilipat" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -156,6 +166,27 @@ ms: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Tunggakan" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ne.yml b/modules/backlogs/config/locales/crowdin/ne.yml index 6e6a574c935..da2c8ce48bd 100644 --- a/modules/backlogs/config/locales/crowdin/ne.yml +++ b/modules/backlogs/config/locales/crowdin/ne.yml @@ -31,6 +31,8 @@ ne: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ne: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ne: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ ne: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/nl.yml b/modules/backlogs/config/locales/crowdin/nl.yml index 0fbb1ed4317..11907683026 100644 --- a/modules/backlogs/config/locales/crowdin/nl.yml +++ b/modules/backlogs/config/locales/crowdin/nl.yml @@ -31,6 +31,8 @@ nl: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ nl: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ nl: column_width: "Column width" definition_of_done: "Definitie van Klaar" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Belemmering" label_versions_default_fold_state: "Laat versies samengevouwen zien" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ nl: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/no.yml b/modules/backlogs/config/locales/crowdin/no.yml index feb3aa9b1be..03a46a7a196 100644 --- a/modules/backlogs/config/locales/crowdin/no.yml +++ b/modules/backlogs/config/locales/crowdin/no.yml @@ -31,6 +31,8 @@ goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ backlogs_work_package_type: "Forsinkelser type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ column_width: "Column width" definition_of_done: "Definisjon av ferdig" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Hinder" label_versions_default_fold_state: "Vis versjoner kollapset" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Forsinkelser" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/pl.yml b/modules/backlogs/config/locales/crowdin/pl.yml index a389daa6760..cd0b8696e42 100644 --- a/modules/backlogs/config/locales/crowdin/pl.yml +++ b/modules/backlogs/config/locales/crowdin/pl.yml @@ -31,6 +31,8 @@ pl: goal: "Cel sprintu" name: "Nazwa sprintu" sharing: "Udostępnianie" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Czas trwania sprintu" work_package: @@ -39,6 +41,11 @@ pl: backlogs_work_package_type: "Typ backlogu" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ pl: column_width: "Szerokość kolumny" definition_of_done: "Definicja Zrobione" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Przeszkoda" label_versions_default_fold_state: "Pokaż zwinięte wersje" caption_versions_default_fold_state: "Wersje nie będą domyślnie rozwijane podczas przeglądania backlogów. Każdą z nich należy rozwinąć ręcznie." @@ -162,6 +172,27 @@ pl: permission_start_complete_sprint: "Rozpocznij/ukończ sprint" permission_view_sprints: "Wyświetl sprinty" project_module_backlogs: "Backlogi" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Brak dostępnych danych spalania" diff --git a/modules/backlogs/config/locales/crowdin/pt-BR.yml b/modules/backlogs/config/locales/crowdin/pt-BR.yml index 55fdce0fae2..6178178d0eb 100644 --- a/modules/backlogs/config/locales/crowdin/pt-BR.yml +++ b/modules/backlogs/config/locales/crowdin/pt-BR.yml @@ -31,6 +31,8 @@ pt-BR: goal: "Objetivo da sprint" name: "Nome da sprint" sharing: "Compartilhamento" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Duração da sprint" work_package: @@ -39,6 +41,11 @@ pt-BR: backlogs_work_package_type: "Tipo de backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ pt-BR: column_width: "Largura da coluna" definition_of_done: "Definição de pronto" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impedimento" label_versions_default_fold_state: "Mostrar versões em modo fechado" caption_versions_default_fold_state: "As versões não serão expandidas por padrão ao visualizar backlogs. Cada uma deve ser expandida manualmente." @@ -158,6 +168,27 @@ pt-BR: permission_start_complete_sprint: "Iniciar/concluir sprint" permission_view_sprints: "Ver sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Nenhum dado de burndown disponível" diff --git a/modules/backlogs/config/locales/crowdin/pt-PT.yml b/modules/backlogs/config/locales/crowdin/pt-PT.yml index 4f37f5ce94d..377207d9045 100644 --- a/modules/backlogs/config/locales/crowdin/pt-PT.yml +++ b/modules/backlogs/config/locales/crowdin/pt-PT.yml @@ -31,6 +31,8 @@ pt-PT: goal: "Objetivo do sprint" name: "Nome do sprint" sharing: "Partilhar" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Duração do sprint" work_package: @@ -39,6 +41,11 @@ pt-PT: backlogs_work_package_type: "Tipo de backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ pt-PT: column_width: "Largura da coluna" definition_of_done: "Definição de feito" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impedimento" label_versions_default_fold_state: "Mostrar versões dobradas" caption_versions_default_fold_state: "Versões não serão expandidas por predefinição quando visualizar os backlogs. Cada uma tem de ser expandida manualmente." @@ -158,6 +168,27 @@ pt-PT: permission_start_complete_sprint: "Iniciar/completar sprint" permission_view_sprints: "Ver sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Não há dados de burndown disponíveis" diff --git a/modules/backlogs/config/locales/crowdin/ro.yml b/modules/backlogs/config/locales/crowdin/ro.yml index 22597abf6e8..c569e875c4b 100644 --- a/modules/backlogs/config/locales/crowdin/ro.yml +++ b/modules/backlogs/config/locales/crowdin/ro.yml @@ -31,6 +31,8 @@ ro: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ ro: backlogs_work_package_type: "Tip restanță" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ ro: column_width: "Column width" definition_of_done: "Procent realizat" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Afișare versiuni complete" caption_versions_default_fold_state: "Versiunile nu vor fi extinse în mod implicit la vizualizarea restanțelor. Fiecare versiune trebuie să fie extinsă manual." @@ -160,6 +170,27 @@ ro: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Restanțe" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/ru.yml b/modules/backlogs/config/locales/crowdin/ru.yml index 01134c1718d..d719dcc6ca2 100644 --- a/modules/backlogs/config/locales/crowdin/ru.yml +++ b/modules/backlogs/config/locales/crowdin/ru.yml @@ -31,6 +31,8 @@ ru: goal: "Цель спринта" name: "Название спринта" sharing: "Совместное использование" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Продолжительность спринта" work_package: @@ -39,6 +41,11 @@ ru: backlogs_work_package_type: "Тип невыполненной работы" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -56,7 +63,10 @@ ru: any: "любой" column_width: "Ширина столбца" definition_of_done: "Определение термина \"Завершено\"" - definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + definition_of_done_caption: "Пакеты работ с такими статусами рассматриваются как завершенные в представлениях бэклога и отчетах." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Препятствие" label_versions_default_fold_state: "Показать свернутые версии" caption_versions_default_fold_state: "Версии не будут разворачиваться по умолчанию при просмотре бэклогов. Каждая версия должна быть развернута вручную." @@ -162,6 +172,27 @@ ru: permission_start_complete_sprint: "Начать/завершить спринт" permission_view_sprints: "Просмотр спринтов" project_module_backlogs: "Бэклоги" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Спринты, созданные в этом проекте, будут доступны и видны только в этом проекте. Они также не будут видны подпроектам." + receive_shared: + label: "Receive shared sprints" + caption: "Этот проект может использовать только спринты, совместно используемые другими проектами." + warning: "Этот проект может использовать только общие спринты других проектов. Неиспользуемые спринты, созданные в этом проекте в прошлом, больше не будут видны." + share_all_projects: + label: "Все проекты" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Подпроекты" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Нет сводных данных" diff --git a/modules/backlogs/config/locales/crowdin/rw.yml b/modules/backlogs/config/locales/crowdin/rw.yml index c2dbd4ef227..377e44fc915 100644 --- a/modules/backlogs/config/locales/crowdin/rw.yml +++ b/modules/backlogs/config/locales/crowdin/rw.yml @@ -31,6 +31,8 @@ rw: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ rw: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ rw: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ rw: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/si.yml b/modules/backlogs/config/locales/crowdin/si.yml index 4af952f455c..cef2feee69e 100644 --- a/modules/backlogs/config/locales/crowdin/si.yml +++ b/modules/backlogs/config/locales/crowdin/si.yml @@ -31,6 +31,8 @@ si: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ si: backlogs_work_package_type: "බැක්ලොග් වර්ගය" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ si: column_width: "Column width" definition_of_done: "සිදු කරන ලද අර්ථ දැක්වීම" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "බාධාවන්" label_versions_default_fold_state: "නවනු අනුවාද පෙන්වන්න" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ si: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "බැක්ලොග්ස්" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/sk.yml b/modules/backlogs/config/locales/crowdin/sk.yml index 5e384c812fd..867697ba38d 100644 --- a/modules/backlogs/config/locales/crowdin/sk.yml +++ b/modules/backlogs/config/locales/crowdin/sk.yml @@ -31,6 +31,8 @@ sk: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Trvanie šprintu" work_package: @@ -39,6 +41,11 @@ sk: backlogs_work_package_type: "Typ oneskorenia" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ sk: column_width: "Šírka stĺpca" definition_of_done: "Definícia pojmu Hotovo" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Prekážka" label_versions_default_fold_state: "Zobrazenie zložených verzií" caption_versions_default_fold_state: "Verzie sa pri prezeraní nevybavených dokumentov nebudú predvolene rozbaľovať. Každú z nich je potrebné rozbaliť manuálne." @@ -162,6 +172,27 @@ sk: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/sl.yml b/modules/backlogs/config/locales/crowdin/sl.yml index 953cff09d89..5fafed62682 100644 --- a/modules/backlogs/config/locales/crowdin/sl.yml +++ b/modules/backlogs/config/locales/crowdin/sl.yml @@ -31,6 +31,8 @@ sl: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ sl: backlogs_work_package_type: "Tip opravila na čakanju" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ sl: column_width: "Column width" definition_of_done: "Opredelitev opravljenega" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Ovira" label_versions_default_fold_state: "Pokaži različice zložene" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -162,6 +172,27 @@ sl: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Zaostanki" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/sr.yml b/modules/backlogs/config/locales/crowdin/sr.yml index dc9391b8e13..f849101982e 100644 --- a/modules/backlogs/config/locales/crowdin/sr.yml +++ b/modules/backlogs/config/locales/crowdin/sr.yml @@ -31,6 +31,8 @@ sr: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ sr: backlogs_work_package_type: "Tip backlog-a" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ sr: column_width: "Column width" definition_of_done: "Definicija završetka" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Smetnja" label_versions_default_fold_state: "Prikaži verzije skupljene" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -160,6 +170,27 @@ sr: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/sv.yml b/modules/backlogs/config/locales/crowdin/sv.yml index afef125bbc1..fb3fc262b39 100644 --- a/modules/backlogs/config/locales/crowdin/sv.yml +++ b/modules/backlogs/config/locales/crowdin/sv.yml @@ -31,6 +31,8 @@ sv: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ sv: backlogs_work_package_type: "Typ av backlogg" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ sv: column_width: "Column width" definition_of_done: "Definition av klart" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Hinder" label_versions_default_fold_state: "Visa ihopfällda versioner" caption_versions_default_fold_state: "Versioner kommer inte att utökas som standard när du visar backloggar. Var och en måste utökas manuellt." @@ -158,6 +168,27 @@ sv: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backloggar" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/th.yml b/modules/backlogs/config/locales/crowdin/th.yml index e8c928d448f..089c7feccb0 100644 --- a/modules/backlogs/config/locales/crowdin/th.yml +++ b/modules/backlogs/config/locales/crowdin/th.yml @@ -31,6 +31,8 @@ th: goal: "เป้าหมายสปริ๊นต์" name: "ชื่อสปรินต์" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "ระยะเวลาการสปรินต์" work_package: @@ -39,6 +41,11 @@ th: backlogs_work_package_type: "ประเภทงานค้าง" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ th: column_width: "ความกว้างของคอลัมน์" definition_of_done: "นิยามของคำว่าเสร็จสิ้น" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "รายการอุปสรรค" label_versions_default_fold_state: "แสดงเวอร์ชันที่พับอยู่" caption_versions_default_fold_state: "เวอร์ชันจะถูกพับไว้เป็นค่าเริ่มต้น กรุณาคลิกเพื่อขยายดูทีละรายการ" @@ -156,6 +166,27 @@ th: permission_start_complete_sprint: "เริ่มต้น/เสร็จสิ้นสปรินท์" permission_view_sprints: "ดูสปรินท์" project_module_backlogs: "รายการงานคงค้าง" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "ไม่มีข้อมูลกราฟติดตามงาน (Burndown)" diff --git a/modules/backlogs/config/locales/crowdin/tr.yml b/modules/backlogs/config/locales/crowdin/tr.yml index d0e5ff7103a..6e2ee977b0d 100644 --- a/modules/backlogs/config/locales/crowdin/tr.yml +++ b/modules/backlogs/config/locales/crowdin/tr.yml @@ -31,6 +31,8 @@ tr: goal: "Sprint goal" name: "Sprint name" sharing: "Paylaşım" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint süresi" work_package: @@ -39,6 +41,11 @@ tr: backlogs_work_package_type: "Bekleme listesi türü" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ tr: column_width: "Sütun genişliği" definition_of_done: "Bitti Tanımı" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Engel" label_versions_default_fold_state: "Katlanmış sürümleri göster" caption_versions_default_fold_state: "Birikmiş işler görüntülenirken sürümler öntanımlı olarak genişletilmeyecektir. Her birinin ayrı ayrı genişletilmesi gerekir." @@ -158,6 +168,27 @@ tr: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "İş listesi" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Burndown verisi yok" diff --git a/modules/backlogs/config/locales/crowdin/uk.yml b/modules/backlogs/config/locales/crowdin/uk.yml index 395ef98c388..5cf85e3fc10 100644 --- a/modules/backlogs/config/locales/crowdin/uk.yml +++ b/modules/backlogs/config/locales/crowdin/uk.yml @@ -31,6 +31,8 @@ uk: goal: "Ціль спринту" name: "Ім’я спринту" sharing: "Надання доступу" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Тривалість спринту" work_package: @@ -39,6 +41,11 @@ uk: backlogs_work_package_type: "Тип Backlog-у" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ uk: column_width: "Ширина стовпця" definition_of_done: "Визначення завершено" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Перешкода" label_versions_default_fold_state: "Показати складені версії" caption_versions_default_fold_state: "Версії не розгортатимуться за замовчуванням при перегляді невиконаних завдань. Кожну версію потрібно розгортати вручну." @@ -162,6 +172,27 @@ uk: permission_start_complete_sprint: "Початок/завершення спринтів" permission_view_sprints: "Перегляд спринтів" project_module_backlogs: "Невиконані завдання" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "Немає даних про згорання завдань" diff --git a/modules/backlogs/config/locales/crowdin/uz.yml b/modules/backlogs/config/locales/crowdin/uz.yml index 90ca537e08a..4b5d038b3f7 100644 --- a/modules/backlogs/config/locales/crowdin/uz.yml +++ b/modules/backlogs/config/locales/crowdin/uz.yml @@ -31,6 +31,8 @@ uz: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ uz: backlogs_work_package_type: "Backlog type" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ uz: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -158,6 +168,27 @@ uz: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/vi.yml b/modules/backlogs/config/locales/crowdin/vi.yml index 55ee9ba1d3f..681c24b2418 100644 --- a/modules/backlogs/config/locales/crowdin/vi.yml +++ b/modules/backlogs/config/locales/crowdin/vi.yml @@ -31,6 +31,8 @@ vi: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -39,6 +41,11 @@ vi: backlogs_work_package_type: "Loại Backlog" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ vi: column_width: "Column width" definition_of_done: "Định nghĩa về Hoàn thành" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Trở ngại" label_versions_default_fold_state: "Hiển thị các phiên bản \n" caption_versions_default_fold_state: "Các phiên bản sẽ không được mở rộng theo mặc định khi xem hồ sơ tồn đọng. Mỗi cái phải được mở rộng bằng tay." @@ -156,6 +166,27 @@ vi: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "tồn đọng" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/locales/crowdin/zh-CN.yml b/modules/backlogs/config/locales/crowdin/zh-CN.yml index 4e72f220e5c..ae92da0c00c 100644 --- a/modules/backlogs/config/locales/crowdin/zh-CN.yml +++ b/modules/backlogs/config/locales/crowdin/zh-CN.yml @@ -31,6 +31,8 @@ zh-CN: goal: "冲刺目标" name: "冲刺名称" sharing: "共享" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "冲刺持续时间" work_package: @@ -39,6 +41,11 @@ zh-CN: backlogs_work_package_type: "待办清单类型" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ zh-CN: column_width: "列宽" definition_of_done: "完成的定义" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "障碍" label_versions_default_fold_state: "显示已折叠的版本" caption_versions_default_fold_state: "查看积压工作时,默认情况下不会展开版本。每个版本都必须手动展开。" @@ -156,6 +166,27 @@ zh-CN: permission_start_complete_sprint: "开始/完成冲刺" permission_view_sprints: "查看冲刺" project_module_backlogs: "待办清单" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "没有可用的燃尽数据" diff --git a/modules/backlogs/config/locales/crowdin/zh-TW.yml b/modules/backlogs/config/locales/crowdin/zh-TW.yml index f183a8b675f..483f6689f6b 100644 --- a/modules/backlogs/config/locales/crowdin/zh-TW.yml +++ b/modules/backlogs/config/locales/crowdin/zh-TW.yml @@ -31,6 +31,8 @@ zh-TW: goal: "Sprint goal" name: "Sprint name" sharing: "分享" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "衝刺時間" work_package: @@ -39,6 +41,11 @@ zh-TW: backlogs_work_package_type: "待辦事項類型" errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -57,6 +64,9 @@ zh-TW: column_width: "欄寬" definition_of_done: "定義" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "阻礙" label_versions_default_fold_state: "顯示精簡版本" caption_versions_default_fold_state: "檢視待辦清單時,版本預設不會展開,需手動逐一展開。" @@ -156,6 +166,27 @@ zh-TW: permission_start_complete_sprint: "Start/complete sprint" permission_view_sprints: "View sprints" project_module_backlogs: "待辦事項" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "沒有可用的燃盡圖資料" diff --git a/modules/backlogs/config/locales/en.yml b/modules/backlogs/config/locales/en.yml index 3d26e704927..ef130788c11 100644 --- a/modules/backlogs/config/locales/en.yml +++ b/modules/backlogs/config/locales/en.yml @@ -40,6 +40,8 @@ en: goal: "Sprint goal" name: "Sprint name" sharing: "Sharing" + project: + sprint_sharing: "Sprint sharing" sprint: duration: "Sprint duration" work_package: @@ -49,6 +51,11 @@ en: errors: models: + project: + attributes: + sprint_sharing: + share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects." + share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects." work_package: attributes: blocks_ids: @@ -70,6 +77,9 @@ en: column_width: "Column width" definition_of_done: "Definition of Done" definition_of_done_caption: "Work packages with these statuses are treated as completed in backlog views and reporting." + done_status: "Done status" + sharing_description: "This project can either share its own sprints, receive shared sprints or handle sprints independently (no sharing)." + sharing: "Sharing" impediment: "Impediment" label_versions_default_fold_state: "Show versions folded" caption_versions_default_fold_state: "Versions will not be expanded by default when viewing backlogs. Each one has to be manually expanded." @@ -187,6 +197,27 @@ en: project_module_backlogs: "Backlogs" + projects: + settings: + backlog_sharing: + options: + no_sharing: + label: "Don't share" + caption: "Sprints created in this project will only be available and visible to this project. They will also not be visible to subprojects." + receive_shared: + label: "Receive shared sprints" + caption: "This project can only use sprints shared by other projects." + warning: "This project can only use sprints shared by other projects. Unused sprints created in this project in the past, will no longer be visible." + share_all_projects: + label: "All projects" + caption: "Sprints created in this project will be available to all projects in this instance. If you select this option, it will no longer be available to other projects." + disabled_caption: "Option not available since project \"%{name}\" is currently sharing with all projects and only one project can do this." + disabled_caption_anonymous: "Option not available since another project is currently sharing with all projects and only one project can do this." + share_subprojects: + label: "Subprojects" + caption: "Sprints created in this project will be available to all subprojects of the current project." + info: "Sharing a sprint will share the name, status and the start and finish dates in all projects. These cannot be modified in projects that receive and use these sprints." + sprint_sharing: Share sprints rb_burndown_charts: show: blankslate_title: "No burndown data available" diff --git a/modules/backlogs/config/routes.rb b/modules/backlogs/config/routes.rb index 25c9eb65019..f4a3e0436d5 100644 --- a/modules/backlogs/config/routes.rb +++ b/modules/backlogs/config/routes.rb @@ -40,6 +40,12 @@ Rails.application.routes.draw do get :edit_dialog put :update_agile_sprint end + + resources :stories, controller: :rb_stories, only: [] do + member do + put :move + end + end end end @@ -71,7 +77,7 @@ Rails.application.routes.draw do resources :stories, controller: :rb_stories, only: [] do member do - put :move + put :move_legacy post :reorder end end @@ -88,6 +94,8 @@ Rails.application.routes.draw do scope "projects/:project_id", as: "project", module: "projects" do namespace "settings" do + resource :backlog_sharing, only: %i[show update] + resource :backlogs, only: %i[show update] do member do post "rebuild_positions" => "backlogs#rebuild_positions" diff --git a/modules/backlogs/db/migrate/20260227143618_remove_sharing_from_sprints.rb b/modules/backlogs/db/migrate/20260227143618_remove_sharing_from_sprints.rb new file mode 100644 index 00000000000..2f70e7b6ed4 --- /dev/null +++ b/modules/backlogs/db/migrate/20260227143618_remove_sharing_from_sprints.rb @@ -0,0 +1,35 @@ +# 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. +#++ + +class RemoveSharingFromSprints < ActiveRecord::Migration[8.1] + def change + remove_column :sprints, :sharing, :string, null: false, default: "none" + end +end diff --git a/modules/backlogs/db/migrate/20260305175656_add_index_to_projects_sprint_sharing_settings.rb b/modules/backlogs/db/migrate/20260305175656_add_index_to_projects_sprint_sharing_settings.rb new file mode 100644 index 00000000000..108c65cd1c1 --- /dev/null +++ b/modules/backlogs/db/migrate/20260305175656_add_index_to_projects_sprint_sharing_settings.rb @@ -0,0 +1,38 @@ +# 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. +#++ + +class AddIndexToProjectsSprintSharingSettings < ActiveRecord::Migration[8.1] + def change + add_index :projects, + "(settings->'sprint_sharing')", + using: :gin, + name: "index_projects_settings_sprint_sharing" + end +end diff --git a/modules/backlogs/lib/open_project/backlogs/engine.rb b/modules/backlogs/lib/open_project/backlogs/engine.rb index f259da89eeb..e9b0daef535 100644 --- a/modules/backlogs/lib/open_project/backlogs/engine.rb +++ b/modules/backlogs/lib/open_project/backlogs/engine.rb @@ -100,13 +100,13 @@ module OpenProject::Backlogs visible: -> { OpenProject::FeatureDecisions.scrum_projects_active? } permission :manage_sprint_items, - { rb_stories: %i[move reorder] }, + { rb_stories: %i[move move_legacy reorder] }, permissible_on: :project, require: :member, dependencies: :view_sprints permission :share_sprint, - {}, + { "projects/settings/backlog_sharings": %i[show update] }, permissible_on: :project, require: :member, dependencies: :create_sprints, @@ -185,6 +185,21 @@ module OpenProject::Backlogs OpenProject::Backlogs::Hooks::UserSettingsHook end + initializer "openproject_backlogs.event_subscriptions" do + Rails.application.config.after_initialize do + OpenProject::Notifications.subscribe(OpenProject::Events::MODULE_DISABLED) do |payload| + disabled_module = payload[:disabled_module] + next unless disabled_module.name == "backlogs" + + disabled_module.project.not_sharing_sprints! + end + + OpenProject::Notifications.subscribe(OpenProject::Events::PROJECT_ARCHIVED) do |payload| + payload[:project].not_sharing_sprints! + end + end + end + config.to_prepare do ::Type.add_constraint :position, ->(type, project: nil) do if project.present? diff --git a/modules/backlogs/lib/open_project/backlogs/patches/project_patch.rb b/modules/backlogs/lib/open_project/backlogs/patches/project_patch.rb index f63de9c4b45..9ddee562a10 100644 --- a/modules/backlogs/lib/open_project/backlogs/patches/project_patch.rb +++ b/modules/backlogs/lib/open_project/backlogs/patches/project_patch.rb @@ -29,26 +29,23 @@ #++ module OpenProject::Backlogs::Patches::ProjectPatch - def self.included(base) - base.class_eval do - has_and_belongs_to_many :done_statuses, join_table: :done_statuses_for_project, class_name: "::Status" - has_many :sprints, class_name: "Agile::Sprint", dependent: :destroy + extend ActiveSupport::Concern + include Projects::SprintSharing - include InstanceMethods - end + included do + has_and_belongs_to_many :done_statuses, join_table: :done_statuses_for_project, class_name: "::Status" + has_many :sprints, class_name: "Agile::Sprint", dependent: :destroy end - module InstanceMethods - def rebuild_positions - return unless backlogs_enabled? + def rebuild_positions + return unless backlogs_enabled? - shared_versions.each { |v| v.rebuild_story_positions(self) } - nil - end + shared_versions.each { |v| v.rebuild_story_positions(self) } + nil + end - def backlogs_enabled? - module_enabled? "backlogs" - end + def backlogs_enabled? + module_enabled? "backlogs" end end diff --git a/modules/backlogs/lib/open_project/backlogs/patches/version_patch.rb b/modules/backlogs/lib/open_project/backlogs/patches/version_patch.rb index 2730388c184..0adb1ee5ad3 100644 --- a/modules/backlogs/lib/open_project/backlogs/patches/version_patch.rb +++ b/modules/backlogs/lib/open_project/backlogs/patches/version_patch.rb @@ -37,6 +37,14 @@ module OpenProject::Backlogs::Patches::VersionPatch end module InstanceMethods + def used_as_backlog?(project = self.project) + return false unless project.backlogs_enabled? + + settings = version_settings&.where(project:)&.first + + !!settings&.display_right? + end + def rebuild_story_positions(project = self.project) return unless project.backlogs_enabled? diff --git a/modules/backlogs/spec/components/backlogs/backlog_component_spec.rb b/modules/backlogs/spec/components/backlogs/backlog_component_spec.rb index 4a9e1ccb2bb..a963c3dcf30 100644 --- a/modules/backlogs/spec/components/backlogs/backlog_component_spec.rb +++ b/modules/backlogs/spec/components/backlogs/backlog_component_spec.rb @@ -119,7 +119,7 @@ RSpec.describe Backlogs::BacklogComponent, type: :component do box = page.find(".Box") 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.id.to_s) + expect(box["data-target-id"]).to eq("version:#{sprint.id}") expect(box["data-target-allowed-drag-type"]).to eq("story") end @@ -129,7 +129,7 @@ RSpec.describe Backlogs::BacklogComponent, type: :component do story_row = page.find(".Box-row[id='story_#{story1.id}']") expect(story_row["data-draggable-id"]).to eq(story1.id.to_s) expect(story_row["data-draggable-type"]).to eq("story") - expect(story_row["data-drop-url"]).to end_with(move_backlogs_project_sprint_story_path(project, sprint, story1)) + expect(story_row["data-drop-url"]).to end_with(move_legacy_backlogs_project_sprint_story_path(project, sprint, story1)) end it "renders story rows with proper classes" do diff --git a/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb b/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb index 9eb127060ed..bc56e0db62e 100644 --- a/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb +++ b/modules/backlogs/spec/components/backlogs/sprint_component_spec.rb @@ -116,7 +116,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do box = page.find(".Box") 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.id.to_s) + expect(box["data-target-id"]).to eq("sprint:#{sprint.id}") expect(box["data-target-allowed-drag-type"]).to eq("story") end @@ -126,7 +126,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do story_row = page.find(".Box-row[id='work_package_#{story1.id}']") expect(story_row["data-draggable-id"]).to eq(story1.id.to_s) expect(story_row["data-draggable-type"]).to eq("story") - expect(story_row["data-drop-url"]).to end_with(move_backlogs_project_sprint_story_path(project, sprint, story1)) + expect(story_row["data-drop-url"]).to end_with(move_project_sprint_story_path(project, sprint, story1)) end it "renders story rows with proper classes" do diff --git a/modules/backlogs/spec/contracts/projects/backlog_settings_contract_spec.rb b/modules/backlogs/spec/contracts/projects/backlog_settings_contract_spec.rb new file mode 100644 index 00000000000..510289290d1 --- /dev/null +++ b/modules/backlogs/spec/contracts/projects/backlog_settings_contract_spec.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +require "spec_helper" +require "contracts/shared/model_contract_shared_context" + +RSpec.describe Projects::BacklogSettingsContract, type: :model do + include_context "ModelContract shared context" + + let(:current_user) { build_stubbed(:user) } + let(:project) { create(:project) } + let(:permissions) { %i(share_sprint) } + + subject(:contract) { described_class.new(project, current_user) } + + before do + mock_permissions_for(current_user) do |mock| + mock.allow_in_project(*permissions, project:) + mock.allow_in_project(*other_permissions, project: other_project) if defined?(other_project) + end + end + + it "is expected to be a subclass of ModelContract" do + expect(described_class).to be < ModelContract + end + + describe "validations" do + it_behaves_like "contract is valid" + + it { expect(subject).to validate_presence_of(:sprint_sharing) } + + it do + expect(subject) + .to validate_inclusion_of(:sprint_sharing).in_array(Project::SPRINT_SHARING_MODES) + end + + # This spec of explicitly setting sprint_sharing to empty is required because the + # simple presence validation spec is not sufficient to catch certain corner cases. + # For example, when the sprint_sharing getter is overriden to provide a default value, + # and the user submits an empty value, the contract should be invalid. + context "when sprint_sharing is empty" do + before { project.sprint_sharing = "" } + + it_behaves_like "contract is invalid", sprint_sharing: :blank + end + + describe "permissions" do + context "when user can share sprint" do + let(:permissions) { %i(share_sprint) } + + it_behaves_like "contract is valid" + end + + context "when user cannot share sprint" do + let(:permissions) { [] } + + it_behaves_like "contract user is unauthorized" + end + end + + describe "#validate_global_sprint_sharer_uniqueness" do + before do + project.sprint_sharing = "share_all_projects" + end + + context "when no other project shares with all projects" do + it_behaves_like "contract is valid" + end + + context "when the project already has share_all_projects" do + let(:project) { create(:project, sprint_sharing: "share_all_projects") } + + it_behaves_like "contract is valid" + end + + context "when another project already shares with all projects" do + let!(:other_project) { create(:project, sprint_sharing: "share_all_projects") } + let(:other_permissions) { %i(view_project) } + + it_behaves_like "contract is invalid", sprint_sharing: :share_all_projects_already_taken + + context "when sprint_sharing is set to Share subprojects" do + before { project.sprint_sharing = "share_subprojects" } + + it_behaves_like "contract is valid" + end + + context "when the other project is archived" do + let!(:other_project) { create(:project, :archived, sprint_sharing: "share_all_projects") } + + it_behaves_like "contract is valid" + end + + context "when the current user cannot see the other project" do + let(:other_permissions) { [] } + + it_behaves_like "contract is invalid", sprint_sharing: :share_all_projects_already_taken_anonymous + end + end + end + end + + describe "#writable_attributes" do + it "only allows sprint_sharing to be written" do + expect(contract.writable_attributes).to include("sprint_sharing") + expect(contract.writable_attributes).not_to include("settings") + expect(contract.writable_attributes).not_to include("deactivate_work_package_attachments") + end + + context "when sprint_sharing is the only changed setting" do + before { project.sprint_sharing = "share_subprojects" } + + it "includes the settings column too" do + expect(contract.writable_attributes).to include("settings") + end + + it_behaves_like "contract is valid" + end + + context "when other settings keys are also changed" do + before do + project.sprint_sharing = "share_subprojects" + project.deactivate_work_package_attachments = true + end + + it "excludes the settings column" do + expect(contract.writable_attributes).not_to include("settings") + end + + it_behaves_like "contract is invalid", settings: :error_readonly + end + end +end diff --git a/modules/backlogs/spec/contracts/sprints/create_contract_spec.rb b/modules/backlogs/spec/contracts/sprints/create_contract_spec.rb index 35828129040..f542fac55b7 100644 --- a/modules/backlogs/spec/contracts/sprints/create_contract_spec.rb +++ b/modules/backlogs/spec/contracts/sprints/create_contract_spec.rb @@ -41,14 +41,12 @@ RSpec.describe Sprints::CreateContract do project:, start_date: sprint_start_date, finish_date: sprint_finish_date, - status: sprint_status, - sharing: sprint_sharing) + status: sprint_status) end let(:sprint_name) { "Sprint 1" } let(:sprint_start_date) { Time.zone.today } let(:sprint_finish_date) { Time.zone.today + 14.days } let(:sprint_status) { "in_planning" } - let(:sprint_sharing) { "none" } let(:permissions) { [:create_sprints] } subject(:contract) { described_class.new(sprint, user) } diff --git a/modules/backlogs/spec/controllers/projects/settings/backlog_sharings_controller_spec.rb b/modules/backlogs/spec/controllers/projects/settings/backlog_sharings_controller_spec.rb new file mode 100644 index 00000000000..100e317df11 --- /dev/null +++ b/modules/backlogs/spec/controllers/projects/settings/backlog_sharings_controller_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Projects::Settings::BacklogSharingsController, with_flag: { scrum_projects: true } do + shared_let(:user) { create(:admin) } + + current_user { user } + + before do + visible_relation = instance_double(ActiveRecord::Relation) + allow(Project).to receive(:visible).and_return(visible_relation) + allow(visible_relation).to receive(:find).with(project.identifier).and_return(project) + end + + describe "PATCH #update" do + let(:project) { build_stubbed(:project, sprint_sharing: "no_sharing") } + let(:service_result) { ServiceResult.success(result: project) } + let(:update_service) { instance_double(Projects::UpdateService, call: service_result) } + + before do + allow(Projects::UpdateService) + .to receive(:new) + .with(model: project, user:, contract_class: Projects::BacklogSettingsContract) + .and_return(update_service) + + patch :update, params: { project_id: project.identifier, project: project_params } + end + + context "when service call succeeds" do + let(:project_params) { { sprint_sharing: "share_subprojects", name: "must_be_ignored" } } + + it "updates sprint sharing and redirects to show", :aggregate_failures do + expect(update_service).to have_received(:call).with( + ActionController::Parameters.new("sprint_sharing" => "share_subprojects").permit! + ) + expect(response).to redirect_to(project_settings_backlog_sharing_path(project)) + expect(flash[:notice]).to include I18n.t(:notice_successful_update) + end + end + + context "when service call fails" do + let(:service_result) { ServiceResult.failure(result: project, message: "invalid setting") } + let(:project_params) { { sprint_sharing: "invalid_option" } } + + it "renders show with an error", :aggregate_failures do + expect(response).to have_http_status(:unprocessable_entity) + expect(response).to render_template("projects/settings/backlog_sharings/show") + expect(flash[:error]).to eq I18n.t(:notice_unsuccessful_update_with_reason, reason: "invalid setting") + end + end + end + + context "when scrum_projects feature flag is inactive", with_flag: { scrum_projects: false } do + let(:project) { build_stubbed(:project) } + + it "returns 404 for show" do + get :show, params: { project_id: project.identifier } + + expect(response).to have_http_status(:not_found) + end + + it "returns 404 for update" do + patch :update, params: { project_id: project.identifier, project: { sprint_sharing: "no_sharing" } } + + expect(response).to have_http_status(:not_found) + end + end +end diff --git a/modules/backlogs/spec/controllers/rb_stories_controller_spec.rb b/modules/backlogs/spec/controllers/rb_stories_controller_spec.rb index dd59a5b2903..6fd8581ca2c 100644 --- a/modules/backlogs/spec/controllers/rb_stories_controller_spec.rb +++ b/modules/backlogs/spec/controllers/rb_stories_controller_spec.rb @@ -33,43 +33,65 @@ require "rails_helper" RSpec.describe RbStoriesController do shared_let(:type_feature) { create(:type_feature) } shared_let(:type_task) { create(:type_task) } - shared_let(:user) { create(:admin) } + current_user { user } + let(:user) { create(:admin) } let(:project) { create(:project) } - let(:status) { create(:status, name: "status 1", is_default: true) } - let(:sprint) { create(:sprint, project:) } - let(:story) { create(:story, status:, version: sprint, project:) } + let(:status) { create(:status, name: "status 1", is_default: true) } + let(:version_sprint) { create(:sprint, project:) } + let(:story) { create(:story, status:, version: version_sprint, project:) } + + # Via this setting, version_sprint is used as backlog: + let!(:version_setting) { create(:version_setting, version: version_sprint, project:, display: VersionSetting::DISPLAY_RIGHT) } before do allow(Setting) .to receive(:plugin_openproject_backlogs) - .and_return({ "story_types" => [type_feature.id], "task_type" => type_task.id }) + .and_return({ "story_types" => [type_feature.id], "task_type" => type_task.id }) end - describe "PUT #move" do + describe "PUT #move_legacy" do + context "with a user lacking project permission" do + let(:user) { create(:user) } + + it "responds with 403" do + put :move_legacy, params: { + project_id: project.id, + sprint_id: version_sprint.id, + id: story.id, + target_id: "foo", + position: 1 + }, + format: :turbo_stream + + expect(response).not_to be_successful + expect(response).to have_http_status :not_found + end + end + context "with a version from the same project" do - let(:other_sprint) { create(:sprint, name: "Sprint 2", project:) } + let(:other_version_sprint) { create(:sprint, name: "Sprint 2", project:) } it "responds with success", :aggregate_failures do - put :move, params: { - project_id: project.id, - sprint_id: sprint.id, - id: story.id, - target_id: other_sprint.id, - position: 1 - }, - format: :turbo_stream + put :move_legacy, params: { + project_id: project.id, + sprint_id: version_sprint.id, + id: story.id, + target_id: "version:#{other_version_sprint.id}", + position: 1 + }, + format: :turbo_stream expect(response).to be_successful expect(response).to have_http_status :ok - expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{sprint.id}" - expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{other_sprint.id}" - assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{sprint.id}"][method="morph"]) - assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{other_sprint.id}"][method="morph"]) + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{other_version_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{version_sprint.id}"][method="morph"]) + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{other_version_sprint.id}"][method="morph"]) # rubocop:disable Layout/LineLength expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" expect(assigns(:project)).to eq(project) - expect(assigns(:sprint)).to eq(sprint) + expect(assigns(:sprint)).to eq(version_sprint) expect(assigns(:story)).to eq(story) expect(assigns(:backlog)).to be_a(Backlog) end @@ -77,35 +99,64 @@ RSpec.describe RbStoriesController do context "with a version from another project" do let(:other_project) { create(:project) } - let(:other_sprint) { create(:sprint, name: "Sprint 2", project: other_project, sharing: "system") } - let(:story) { create(:story, status:, version: other_sprint, project:) } + let(:other_version_sprint) { create(:sprint, name: "Sprint 2", project: other_project, sharing: "system") } + let(:story) { create(:story, status:, version: other_version_sprint, project:) } it "responds with success", :aggregate_failures do - put :move, params: { - project_id: project.id, - sprint_id: other_sprint.id, - id: story.id, - target_id: sprint.id, - position: 1 - }, - format: :turbo_stream + put :move_legacy, params: { + project_id: project.id, + sprint_id: other_version_sprint.id, + id: story.id, + target_id: "version:#{version_sprint.id}", + position: 1 + }, + format: :turbo_stream expect(response).to be_successful expect(response).to have_http_status :ok - expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{other_sprint.id}" - expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{sprint.id}" - assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{other_sprint.id}"][method="morph"]) - assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{sprint.id}"][method="morph"]) + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{other_version_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{other_version_sprint.id}"][method="morph"]) # rubocop:disable Layout/LineLength + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{version_sprint.id}"][method="morph"]) expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" expect(assigns(:project)).to eq(project) - expect(assigns(:sprint)).to eq(other_sprint) + expect(assigns(:sprint)).to eq(other_version_sprint) expect(assigns(:story)).to eq(story) expect(assigns(:backlog)).to be_a(Backlog) end end + context "with an Agile::Sprint as target" do + let(:agile_sprint) { create(:agile_sprint, name: "Agile Sprint 1", project:) } + + it "responds with success and moves story to Agile::Sprint, removing the association to the version", :aggregate_failures do + put :move_legacy, params: { + project_id: project.id, + sprint_id: version_sprint.id, + id: story.id, + target_id: "sprint:#{agile_sprint.id}", + position: 1 + }, + format: :turbo_stream + + expect(response).to be_successful + expect(response).to have_http_status :ok + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{version_sprint.id}"][method="morph"]) + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"]) + expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" + expect(assigns(:project)).to eq(project) + expect(assigns(:sprint)).to eq(version_sprint) + expect(assigns(:story)).to eq(story) + + # It will remove the association to the version since the version is used as backlog: + expect(story.reload.version).to be_nil + end + end + context "when service call fails" do - let(:other_sprint) { create(:sprint, name: "Sprint 2", project:) } + let(:other_version_sprint) { create(:sprint, name: "Sprint 2", project:) } let(:service_result) { ServiceResult.failure(message: "Something went wrong") } before do @@ -117,33 +168,33 @@ RSpec.describe RbStoriesController do end it "renders an error flash with 422", :aggregate_failures do - put :move, params: { - project_id: project.id, - sprint_id: sprint.id, - id: story.id, - target_id: other_sprint.id, - position: 1 - }, - format: :turbo_stream + put :move_legacy, params: { + project_id: project.id, + sprint_id: version_sprint.id, + id: story.id, + target_id: "version:#{other_version_sprint.id}", + position: 1 + }, + format: :turbo_stream expect(response).to have_http_status :unprocessable_entity expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" - expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{sprint.id}" + expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" end end end describe "POST #reorder" do it "responds with success", :aggregate_failures do - post :reorder, params: { project_id: project.id, sprint_id: sprint.id, id: story.id, direction: "highest" }, + post :reorder, params: { project_id: project.id, sprint_id: version_sprint.id, id: story.id, direction: "highest" }, format: :turbo_stream expect(response).to be_successful expect(response).to have_http_status :ok - expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{sprint.id}" - assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{sprint.id}"][method="morph"]) + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{version_sprint.id}"][method="morph"]) expect(assigns(:project)).to eq(project) - expect(assigns(:sprint)).to eq(sprint) + expect(assigns(:sprint)).to eq(version_sprint) expect(assigns(:story)).to eq(story) expect(assigns(:backlog)).to be_a(Backlog) end @@ -160,12 +211,127 @@ RSpec.describe RbStoriesController do end it "renders an error flash with 422", :aggregate_failures do - post :reorder, params: { project_id: project.id, sprint_id: sprint.id, id: story.id, direction: "highest" }, + post :reorder, params: { project_id: project.id, sprint_id: version_sprint.id, id: story.id, direction: "highest" }, format: :turbo_stream expect(response).to have_http_status :unprocessable_entity expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" - expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{sprint.id}" + expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + end + end + end + + describe "PUT #move" do + let(:agile_sprint) { create(:agile_sprint, name: "Agile Sprint 1", project:) } + let(:story_in_agile_sprint) { create(:work_package, status:, sprint: agile_sprint, project:) } + + context "with another Agile::Sprint as target" do + let(:other_agile_sprint) { create(:agile_sprint, name: "Agile Sprint 2", project:) } + + it "responds with success and moves story to another Agile::Sprint", :aggregate_failures do + put :move, params: { + project_id: project.id, + sprint_id: agile_sprint.id, + id: story_in_agile_sprint.id, + target_id: "sprint:#{other_agile_sprint.id}", + position: 1 + }, + format: :turbo_stream + + expect(response).to be_successful + expect(response).to have_http_status :ok + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{other_agile_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"]) + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{other_agile_sprint.id}"]) + expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" + expect(assigns(:project)).to eq(project) + expect(assigns(:sprint)).to eq(agile_sprint) + expect(assigns(:story)).to eq(story_in_agile_sprint) + end + + context "when the story has a version that is not used as backlog" do + let(:story_in_agile_sprint) { create(:work_package, status:, sprint: agile_sprint, version: version_sprint, project:) } + # Via this setting, version_sprint is NOT used as backlog: + let!(:version_setting) { create(:version_setting, version: version_sprint, project:, display: VersionSetting::DISPLAY_NONE) } + + it "responds with success and moves story to Agile::Sprint, keeping the version", :aggregate_failures do + put :move, params: { + project_id: project.id, + sprint_id: agile_sprint.id, + id: story_in_agile_sprint.id, + target_id: "sprint:#{other_agile_sprint.id}", + position: 1 + }, + format: :turbo_stream + + expect(response).to be_successful + expect(response).to have_http_status :ok + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{other_agile_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"]) + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{other_agile_sprint.id}"]) + expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" + expect(assigns(:project)).to eq(project) + expect(assigns(:sprint)).to eq(agile_sprint) + expect(assigns(:story)).to eq(story_in_agile_sprint) + + # It will preserve the version since it is not used as backlog/sprint. + expect(story_in_agile_sprint.reload.version).to eq(version_sprint) + end + end + end + + context "with a Sprint (Version) as target" do + it "responds with success and moves story to Sprint", :aggregate_failures do + put :move, params: { + project_id: project.id, + sprint_id: agile_sprint.id, + id: story_in_agile_sprint.id, + target_id: "version:#{version_sprint.id}", + position: 1 + }, + format: :turbo_stream + + expect(response).to be_successful + expect(response).to have_http_status :ok + expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}" + expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlog-component-#{version_sprint.id}" + assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"]) + assert_select %(turbo-stream[action="replace"][target="backlogs-backlog-component-#{version_sprint.id}"][method="morph"]) + expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" + expect(assigns(:project)).to eq(project) + expect(assigns(:sprint)).to eq(agile_sprint) + expect(assigns(:story)).to eq(story_in_agile_sprint) + expect(assigns(:backlog)).to be_a(Backlog) + end + end + + context "when service call fails" do + let(:other_agile_sprint) { create(:agile_sprint, name: "Agile Sprint 2", project:) } + let(:service_result) { ServiceResult.failure(message: "Something went wrong") } + + before do + update_service = instance_double(Stories::UpdateService, call: service_result) + + allow(Stories::UpdateService) + .to receive(:new) + .and_return(update_service) + end + + it "renders an error flash with 422", :aggregate_failures do + put :move, params: { + project_id: project.id, + sprint_id: agile_sprint.id, + id: story_in_agile_sprint.id, + target_id: "sprint:#{other_agile_sprint.id}", + position: 1 + }, + format: :turbo_stream + + expect(response).to have_http_status :unprocessable_entity + expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component" + expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}" end end end diff --git a/modules/backlogs/spec/features/projects/settings/backlog_sharing_settings_spec.rb b/modules/backlogs/spec/features/projects/settings/backlog_sharing_settings_spec.rb new file mode 100644 index 00000000000..33ad5f37a6b --- /dev/null +++ b/modules/backlogs/spec/features/projects/settings/backlog_sharing_settings_spec.rb @@ -0,0 +1,157 @@ +# 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. +#++ + +require "rails_helper" + +RSpec.describe "Backlogs project settings sprint sharing", :js, with_flag: { scrum_projects: true } do + let(:project) { create(:project) } + let(:permissions) { %i[create_sprints share_sprint select_done_statuses] } + + let(:current_user) do + create(:user, member_with_permissions: { project => permissions }) + end + + before do + login_as current_user + end + + context "with share_sprint permission" do + it "displays and stores sprint sharing settings" do + visit project_settings_backlog_sharing_path(project) + + expect(page).to have_link( + "Sharing", + href: project_settings_backlog_sharing_path(project) + ) + + # all radio buttons are present with no_sharing checked by default + expect(page).to have_checked_field("Don't share") + expect(page).to have_unchecked_field("All projects") + expect(page).to have_unchecked_field("Subprojects") + expect(page).to have_unchecked_field("Receive shared sprints") + + # no banners visible by default + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + + # selecting share_subprojects shows its info banner + choose("Subprojects") + expect(page).to have_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + + # selecting receive_shared shows its warning banner + choose("Receive shared sprints") + expect(page).to have_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + + # persists receive_shared + click_button I18n.t("button_save") + + expect_and_dismiss_flash(type: :success, message: I18n.t(:notice_successful_update)) + expect(page).to have_checked_field("Receive shared sprints") + expect(project.reload.sprint_sharing).to eq("receive_shared") + + # keeps the banner visible after persisting + expect(page).to have_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + + # selecting no_sharing hides all banners + choose("Don't share") + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + + # persists no_sharing + click_button I18n.t("button_save") + + expect_and_dismiss_flash(type: :success, message: I18n.t(:notice_successful_update)) + expect(page).to have_checked_field("Don't share") + expect(project.reload.sprint_sharing).to eq("no_sharing") + + # keeps the banner hidden after persisting + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.share_subprojects.info")) + expect(page).to have_no_text(I18n.t("projects.settings.backlog_sharing.options.receive_shared.warning")) + end + + context "when another project already shares with all projects" do + let!(:other_project) { create(:project, name: "Sharer Project", sprint_sharing: "share_all_projects") } + + it "disables the all projects option with an explanation" do + visit project_settings_backlog_sharing_path(project) + + expect(page).to have_field("All projects", disabled: true) + expect(page).to have_text( + I18n.t("projects.settings.backlog_sharing.options.share_all_projects.disabled_caption_anonymous") + ) + end + + context "when the current user cannot see the other project" do + let!(:other_project) { create(:project, public: false, name: "Sharer Project", sprint_sharing: "share_all_projects") } + + it "disables the all projects option without revealing the project name" do + visit project_settings_backlog_sharing_path(project) + + expect(page).to have_field("All projects", disabled: true) + expect(page).to have_text( + I18n.t("projects.settings.backlog_sharing.options.share_all_projects.disabled_caption_anonymous") + ) + expect(page).to have_no_text("Sharer Project") + end + end + end + end + + context "without share_sprint permission" do + let(:permissions) { %i[create_sprints select_done_statuses] } + + it "does not show the sharing tab and forbids direct route access" do + visit project_settings_backlogs_path(project) + + expect(page).to have_heading(I18n.t(:label_backlogs)) + expect(page).to have_no_link(I18n.t("backlogs.sharing")) + + visit project_settings_backlog_sharing_path(project) + + expect(page).to have_text(I18n.t(:notice_not_authorized)) + end + end + + context "when scrum_projects feature flag is inactive", with_flag: { scrum_projects: false } do + it "does not show the sharing tab and returns 404 on direct access" do + visit project_settings_backlogs_path(project) + + expect(page).to have_heading(I18n.t(:label_backlogs)) + expect(page).to have_no_link(I18n.t("backlogs.sharing")) + + visit project_settings_backlog_sharing_path(project) + + expect(page).to have_text(I18n.t(:notice_file_not_found)) + end + end +end diff --git a/modules/backlogs/spec/lib/open_project/backlogs/event_subscriptions_spec.rb b/modules/backlogs/spec/lib/open_project/backlogs/event_subscriptions_spec.rb new file mode 100644 index 00000000000..54a863d0a40 --- /dev/null +++ b/modules/backlogs/spec/lib/open_project/backlogs/event_subscriptions_spec.rb @@ -0,0 +1,89 @@ +# 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. +#++ + +require "spec_helper" + +RSpec.describe OpenProject::Notifications, "backlogs event subscriptions" do # rubocop:disable RSpec/SpecFilePathFormat + describe "MODULE_DISABLED" do + subject do + described_class.send( + OpenProject::Events::MODULE_DISABLED, + disabled_module: + ) + end + + Projects::SprintSharing::SPRINT_SHARING_MODES.each do |sharing_mode| + context "when the backlogs module is disabled on a project with #{sharing_mode}" do + let(:project) { create(:project, sprint_sharing: sharing_mode) } + let(:disabled_module) { instance_double(EnabledModule, name: "backlogs", project:) } + + it "sets sprint sharing to no_sharing" do + subject + + expect(project.reload.sprint_sharing).to eq(Projects::SprintSharing::NO_SHARING) + end + end + end + + context "when a different module is disabled" do + let(:project) do + create(:project, sprint_sharing: Projects::SprintSharing::SHARE_ALL_PROJECTS) + end + let(:disabled_module) { instance_double(EnabledModule, name: "wiki", project:) } + + it "does not reset sprint sharing" do + subject + + expect(project.reload.sprint_sharing).to eq(Projects::SprintSharing::SHARE_ALL_PROJECTS) + end + end + end + + describe "PROJECT_ARCHIVED" do + subject do + described_class.send( + OpenProject::Events::PROJECT_ARCHIVED, + project: + ) + end + + Projects::SprintSharing::SPRINT_SHARING_MODES.each do |sharing_mode| + context "when a project with #{sharing_mode} is archived" do + let(:project) { create(:project, sprint_sharing: sharing_mode) } + + it "sets sprint sharing to no_sharing" do + subject + + expect(project.reload.sprint_sharing).to eq(Projects::SprintSharing::NO_SHARING) + end + end + end + end +end diff --git a/modules/backlogs/spec/models/agile/sprint_spec.rb b/modules/backlogs/spec/models/agile/sprint_spec.rb index 8aef9d36833..5ce79972dea 100644 --- a/modules/backlogs/spec/models/agile/sprint_spec.rb +++ b/modules/backlogs/spec/models/agile/sprint_spec.rb @@ -46,7 +46,6 @@ RSpec.describe Agile::Sprint do it { is_expected.to validate_presence_of(:finish_date) } it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_inclusion_of(:status).in_array(described_class.statuses.keys) } - it { is_expected.to validate_inclusion_of(:sharing).in_array(described_class.sharings.keys) } it "validates finish_date is after or equal to start_date" do sprint.finish_date = sprint.start_date - 1.day @@ -113,14 +112,6 @@ RSpec.describe Agile::Sprint do it "status defaults to in_planning" do expect(sprint).to be_in_planning end - - it "has sharing enum with correct values" do - expect(described_class.sharings.keys).to contain_exactly("none", "descendants", "system") - end - - it "sharing defaults to none" do - expect(sprint).to be_sharing_with_none - end end describe "associations" do diff --git a/modules/backlogs/spec/models/agile/sprints/scopes/for_project_spec.rb b/modules/backlogs/spec/models/agile/sprints/scopes/for_project_spec.rb new file mode 100644 index 00000000000..bd45f4578ae --- /dev/null +++ b/modules/backlogs/spec/models/agile/sprints/scopes/for_project_spec.rb @@ -0,0 +1,191 @@ +# 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. +#++ + +require "spec_helper" + +RSpec.describe Agile::Sprints::Scopes::ForProject do + let(:sprint_sharing) { "no_sharing" } + let(:project) { create(:project, sprint_sharing:) } + let(:global_sharer) { create(:project, sprint_sharing: "share_all_projects") } + let(:other_project) { create(:project) } + let!(:sprint_in_project) { create(:agile_sprint, project:) } + let!(:global_sprint) { create(:agile_sprint, project: global_sharer) } + let!(:sprint_in_other_project) { create(:agile_sprint, project: other_project) } + + shared_examples "executes a single SQL query" do + it "resolves for_project in a single query" do + expect { Agile::Sprint.for_project(project).load }.to have_a_query_limit(1) + end + end + + describe ".for_project" do + context "when project does not receive sprints (no_sharing)" do + let(:sprint_sharing) { "no_sharing" } + + it_behaves_like "executes a single SQL query" + + context "and there are no work package assignments" do + it "returns only the project's own sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project) + end + end + + context "and the project has a work package assigned to a sprint from another project" do + let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) } + let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) } + + it "returns both the own sprint and the sprint assigned via work package" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint) + end + + context "when the cross-project sprint is completed" do + let!(:completed_sprint) { create(:agile_sprint, project: other_project, status: "completed") } + let!(:work_package) { create(:work_package, project:, sprint: completed_sprint) } + + it "returns the completed sprint among the sprints" do + expect(Agile::Sprint.for_project(project)).to include(completed_sprint) + end + end + end + end + + context "when project is a sender (share_subprojects)" do + let(:sprint_sharing) { "share_subprojects" } + + it_behaves_like "executes a single SQL query" + + context "and there are no work package assignments" do + it "returns only the project's own sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project) + end + end + + context "and a work package in the project is assigned to a sprint from another project" do + let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) } + let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) } + + it "returns both the own sprint and the cross-project sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint) + end + end + end + + context "when project is a sender (share_all_projects)" do + let(:sprint_sharing) { "share_all_projects" } + + it_behaves_like "executes a single SQL query" + + context "and there are no work package assignments" do + it "returns only the project's own sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project) + end + end + + context "and a work package in the project is assigned to a sprint from another project" do + let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) } + let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) } + + it "returns both the own sprint and the cross-project sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint) + end + end + end + + context "when project receives shared sprints" do + let(:sprint_sharing) { "receive_shared" } + + it_behaves_like "executes a single SQL query" + + context "and there is only a global sharer" do + it "returns only the sprints shared from the global sharer project" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint) + end + + context "and a work package is assigned to the project's own sprint" do + let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) } + + it "returns both the global shared sprint and the project's own sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_project) + end + end + + context "and a work package is assigned to the shared sprint from the global sharer" do + let!(:work_package) { create(:work_package, project:, sprint: global_sprint) } + + it "returns the shared sprint only once" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint) + end + end + + context "and a work package is assigned to a sprint from an unrelated project" do + let!(:work_package) { create(:work_package, project:, sprint: sprint_in_other_project) } + + it "returns the global shared sprint and the unrelated project's sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_other_project) + end + end + end + + context "and there is a subproject-sharing ancestor" do + let(:subproject_sharer) { create(:project, sprint_sharing: "share_subprojects") } + let(:project) { create(:project, parent: subproject_sharer, sprint_sharing:) } + let!(:subproject_sprint) { create(:agile_sprint, project: subproject_sharer) } + + it "returns only the sprints shared from the closest subproject-sharing ancestor" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint) + end + + context "and a work package is assigned to the project's own sprint" do + let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) } + + it "returns both the ancestor's shared sprint and the project's own sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint, sprint_in_project) + end + end + + context "and a work package is assigned to the ancestor's shared sprint" do + let!(:work_package) { create(:work_package, project:, sprint: subproject_sprint) } + + it "returns the ancestor's shared sprint only once" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint) + end + end + + context "and a work package is assigned to a sprint from the global sharer" do + let!(:work_package) { create(:work_package, project:, sprint: global_sprint) } + + it "returns both the ancestor's shared sprint and the global sharer's sprint" do + expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint, global_sprint) + end + end + end + end + end +end diff --git a/modules/backlogs/spec/models/projects/scopes_spec.rb b/modules/backlogs/spec/models/projects/scopes_spec.rb new file mode 100644 index 00000000000..79a57256972 --- /dev/null +++ b/modules/backlogs/spec/models/projects/scopes_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Projects::Scopes, "scopes" do + shared_let(:project_without_settings) { create(:project, sprint_sharing: nil) } + shared_let(:project_with_empty_settings) { create(:project, sprint_sharing: "") } + shared_let(:no_sharing_project) { create(:project, sprint_sharing: "no_sharing") } + shared_let(:all_projects_sharer) { create(:project, sprint_sharing: "share_all_projects") } + shared_let(:subprojects_sharer) { create(:project, sprint_sharing: "share_subprojects") } + shared_let(:receiver) { create(:project, sprint_sharing: "receive_shared") } + + describe ".share_sprints_with_all_projects" do + it "returns projects that share with all projects" do + expect(Project.share_sprints_with_all_projects).to contain_exactly(all_projects_sharer) + end + end + + describe ".share_sprints_with_subprojects" do + it "returns projects that share with subprojects" do + expect(Project.share_sprints_with_subprojects).to contain_exactly(subprojects_sharer) + end + end + + describe ".receive_shared_sprints" do + it "returns projects that receive shared sprints" do + expect(Project.receive_shared_sprints).to contain_exactly(receiver) + end + end + + describe ".not_sharing_sprints" do + it "returns projects with no sharing" do + expect(Project.not_sharing_sprints).to contain_exactly( + project_without_settings, + project_with_empty_settings, + no_sharing_project + ) + end + end +end diff --git a/modules/backlogs/spec/models/projects/sprint_sharing_spec.rb b/modules/backlogs/spec/models/projects/sprint_sharing_spec.rb new file mode 100644 index 00000000000..bc4a85cb3ae --- /dev/null +++ b/modules/backlogs/spec/models/projects/sprint_sharing_spec.rb @@ -0,0 +1,207 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Projects::SprintSharing do + let(:sprint_sharing) { "no_sharing" } + let(:active) { true } + let!(:project) { create(:project, sprint_sharing:, active:) } + + describe "SPRINT_SHARING_MODES" do + it "defines all supported sprint sharing options" do + expect(described_class::SPRINT_SHARING_MODES).to match_array( + %w[share_all_projects share_subprojects no_sharing receive_shared] + ) + end + + it "is exposed on Project" do + expect(Project::SPRINT_SHARING_MODES).to eq(described_class::SPRINT_SHARING_MODES) + end + end + + describe "#sprint_sharing" do + let(:sprint_sharing) { nil } + + it "defaults to no_sharing" do + expect(project.sprint_sharing).to eq("no_sharing") + end + + it "persists configured values" do + project.update!(sprint_sharing: "share_subprojects") + + expect(project.reload.sprint_sharing).to eq("share_subprojects") + end + end + + describe "predicate methods" do + it "#share_sprints_with_all_projects? returns true when sharing with all projects" do + project.sprint_sharing = "share_all_projects" + expect(project).to be_share_sprints_with_all_projects + end + + it "#share_sprints_with_subprojects? returns true when sharing with subprojects" do + project.sprint_sharing = "share_subprojects" + expect(project).to be_share_sprints_with_subprojects + end + + it "#receive_shared_sprints? returns true when receiving shared sprints" do + project.sprint_sharing = "receive_shared" + expect(project).to be_receive_shared_sprints + end + + it "#not_sharing_sprints? returns true when not sharing (default)" do + expect(project).to be_not_sharing_sprints + end + + it "predicates return false for non-matching values" do + project.sprint_sharing = "share_subprojects" + + expect(project).not_to be_share_sprints_with_all_projects + expect(project).not_to be_receive_shared_sprints + expect(project).not_to be_not_sharing_sprints + end + end + + describe "#not_sharing_sprints!" do + context "when the project is already set to no_sharing" do + let(:sprint_sharing) { "no_sharing" } + + it "does not update the database" do + allow(project).to receive(:update_column) + + subject + + expect(project).not_to have_received(:update_column) + end + end + + context "when the project has an active sharing mode" do + let(:sprint_sharing) { "share_all_projects" } + + it "resets sprint_sharing to no_sharing" do + project.not_sharing_sprints! + + expect(project.reload.sprint_sharing).to eq("no_sharing") + end + end + end + + describe ".global_sprint_sharer" do + context "when no project shares with all projects" do + let(:sprint_sharing) { "no_sharing" } + + it "returns nil" do + expect(Project.global_sprint_sharer).to be_nil + end + end + + context "when a project shares with all projects" do + let(:sprint_sharing) { "share_all_projects" } + + it "returns that project" do + expect(Project.global_sprint_sharer).to eq(project) + end + end + + context "when the sharing project is archived" do + let(:sprint_sharing) { "share_all_projects" } + let(:active) { false } + + it "returns nil" do + expect(Project.global_sprint_sharer).to be_nil + end + end + end + + describe "#sprint_source" do + let(:global_sprint_sharing) { "share_all_projects" } + let(:root_sprint_sharing) { "share_subprojects" } + let(:parent_sprint_sharing) { "share_subprojects" } + let(:project_sprint_sharing) { "receive_shared" } + + let!(:global_sharer) { create(:project, sprint_sharing: global_sprint_sharing) } + let!(:root_project) { create(:project, sprint_sharing: root_sprint_sharing) } + let!(:parent_project) { create(:project, parent: root_project, sprint_sharing: parent_sprint_sharing) } + let!(:project) { create(:project, parent: parent_project, sprint_sharing: project_sprint_sharing) } + + # Projects that should not be returned + shared_let(:other_project) { create(:project, sprint_sharing: "share_subprojects") } + shared_let(:archived_global_sharer) { create(:project, :archived, sprint_sharing: "share_all_projects") } + + shared_examples "returns the project itself" do + it "returns only itself" do + expect(project.sprint_source).to contain_exactly(project) + end + end + + shared_examples "executes a single SQL query" do + it "resolves sprint_source in a single query" do + expect { project.sprint_source.load }.to have_a_query_limit(1) + end + end + + context "when sprint_sharing is no_sharing (default)" do + let(:project_sprint_sharing) { "no_sharing" } + + it_behaves_like "returns the project itself" + it_behaves_like "executes a single SQL query" + end + + context "when sprint_sharing is share_subprojects" do + let(:project_sprint_sharing) { "share_subprojects" } + + it_behaves_like "returns the project itself" + it_behaves_like "executes a single SQL query" + end + + context "when sprint_sharing is share_all_projects" do + let(:global_sprint_sharing) { "no_sharing" } + let(:root_sprint_sharing) { "share_subprojects" } + let(:parent_sprint_sharing) { "share_subprojects" } + let(:project_sprint_sharing) { "share_all_projects" } + + it_behaves_like "returns the project itself" + it_behaves_like "executes a single SQL query" + end + + context "when sprint_sharing is receive_shared" do + let(:project_sprint_sharing) { "receive_shared" } + + context "with only a global sharer" do + let(:global_sprint_sharing) { "share_all_projects" } + let(:root_sprint_sharing) { "no_sharing" } + let(:parent_sprint_sharing) { "no_sharing" } + + it "returns only the global sharer" do + expect(project.sprint_source).to contain_exactly(global_sharer) + end + + it_behaves_like "executes a single SQL query" + end + + context "with a global sharer and both ancestors sharing subprojects" do + let(:global_sprint_sharing) { "share_all_projects" } + let(:root_sprint_sharing) { "share_subprojects" } + let(:parent_sprint_sharing) { "share_subprojects" } + + it "returns only the closest sharing ancestor" do + expect(project.sprint_source).to contain_exactly(parent_project) + end + + it_behaves_like "executes a single SQL query" + end + + context "with no sharing sources" do + let(:global_sprint_sharing) { "no_sharing" } + let(:root_sprint_sharing) { "no_sharing" } + let(:parent_sprint_sharing) { "no_sharing" } + + it "returns an empty scope" do + expect(project.sprint_source).to be_empty + end + + it_behaves_like "executes a single SQL query" + end + end + end +end diff --git a/modules/backlogs/spec/models/version_spec.rb b/modules/backlogs/spec/models/version_spec.rb index bbaa95de5ce..46435be8a20 100644 --- a/modules/backlogs/spec/models/version_spec.rb +++ b/modules/backlogs/spec/models/version_spec.rb @@ -31,6 +31,95 @@ require "spec_helper" RSpec.describe Version do it { is_expected.to have_many :version_settings } + describe "#used_as_backlog?" do + let(:project) { create(:project) } + let(:version) { create(:version, project:) } + + context "when backlogs is not enabled" do + before do + project.enabled_module_names = project.enabled_module_names - ["backlogs"] + end + + it "returns false" do + expect(version.used_as_backlog?(project)).to be false + end + end + + context "when backlogs is enabled" do + before do + project.enabled_module_names = project.enabled_module_names + ["backlogs"] + end + + context "when no version_settings exist" do + it "returns false" do + expect(version.used_as_backlog?(project)).to be false + end + end + + context "when version_settings exist with display_right" do + before do + create(:version_setting, version:, project:, display: VersionSetting::DISPLAY_RIGHT) + end + + it "returns true" do + expect(version.used_as_backlog?(project)).to be true + end + end + + context "when version_settings exist with display_left" do + before do + create(:version_setting, version:, project:, display: VersionSetting::DISPLAY_LEFT) + end + + it "returns false" do + expect(version.used_as_backlog?(project)).to be false + end + end + + context "when version_settings exist with display_none" do + before do + create(:version_setting, version:, project:, display: VersionSetting::DISPLAY_NONE) + end + + it "returns false" do + expect(version.used_as_backlog?(project)).to be false + end + end + + context "when multiple version_settings exist for different projects" do + let(:other_project) { create(:project) } + + before do + project.enabled_module_names = project.enabled_module_names + ["backlogs"] + other_project.enabled_module_names = other_project.enabled_module_names + ["backlogs"] + create(:version_setting, version:, project:, display: VersionSetting::DISPLAY_RIGHT) + create(:version_setting, version:, project: other_project, display: VersionSetting::DISPLAY_LEFT) + end + + it "returns true for the project with display_right" do + expect(version.used_as_backlog?(project)).to be true + end + + it "returns false for the project with display_left" do + expect(version.used_as_backlog?(other_project)).to be false + end + end + + context "when project parameter is not provided" do + context "and version has a project" do + before do + project.enabled_module_names = project.enabled_module_names + ["backlogs"] + create(:version_setting, version:, project:, display: VersionSetting::DISPLAY_RIGHT) + end + + it "uses the version's project" do + expect(version.used_as_backlog?).to be true + end + end + end + end + end + describe "rebuild positions" do def build_work_package(options = {}) build(:work_package, options.reverse_merge(version_id: version.id, diff --git a/modules/backlogs/spec/routing/rb_stories_routing_spec.rb b/modules/backlogs/spec/routing/rb_stories_routing_spec.rb index d0af15bece9..e484c850e36 100644 --- a/modules/backlogs/spec/routing/rb_stories_routing_spec.rb +++ b/modules/backlogs/spec/routing/rb_stories_routing_spec.rb @@ -30,6 +30,16 @@ require "spec_helper" RSpec.describe RbStoriesController do describe "routing" do + it { + expect(put("/projects/project_42/sprints/21/stories/85/move_legacy")).to route_to( + controller: "rb_stories", + action: "move_legacy", + project_id: "project_42", + sprint_id: "21", + id: "85" + ) + } + it { expect(put("/projects/project_42/sprints/21/stories/85/move")).to route_to( controller: "rb_stories", diff --git a/modules/backlogs/spec/services/sprints/set_attributes_service_spec.rb b/modules/backlogs/spec/services/sprints/set_attributes_service_spec.rb index f08152ad0e8..8ef4e349dfa 100644 --- a/modules/backlogs/spec/services/sprints/set_attributes_service_spec.rb +++ b/modules/backlogs/spec/services/sprints/set_attributes_service_spec.rb @@ -138,12 +138,6 @@ RSpec.describe Sprints::SetAttributesService, type: :model do expect(sprint.status).to eq("in_planning") end - it "sets default sharing to none" do - service_call - - expect(sprint.sharing).to eq("none") - end - context "when status is already set" do let(:sprint) { Agile::Sprint.new(status: "active") } @@ -153,16 +147,6 @@ RSpec.describe Sprints::SetAttributesService, type: :model do expect(sprint.status).to eq("active") end end - - context "when sharing is already set" do - let(:sprint) { Agile::Sprint.new(sharing: "descendants") } - - it "does not override the existing sharing" do - service_call - - expect(sprint.sharing).to eq("descendants") - end - end end end diff --git a/modules/budgets/config/locales/crowdin/cs.yml b/modules/budgets/config/locales/crowdin/cs.yml index 765bb62a1c2..c3ec09e6661 100644 --- a/modules/budgets/config/locales/crowdin/cs.yml +++ b/modules/budgets/config/locales/crowdin/cs.yml @@ -71,9 +71,9 @@ cs: total_actual_costs: "Total actual costs" total_planned_budget: "Total planned budget" budget_by_cost_type: - title: "Budget by cost type" + title: "Rozpočet podle typu nákladů" blankslate: - heading: "Start project controlling" + heading: "Zahájit projektový controlling" description: "Get an overview of your budgets and costs to efficiently track the health status of your project" blankslate_zero: heading: "Budget details missing" diff --git a/modules/budgets/config/locales/crowdin/ru.yml b/modules/budgets/config/locales/crowdin/ru.yml index a9ca6fc08c1..605e3cd5a26 100644 --- a/modules/budgets/config/locales/crowdin/ru.yml +++ b/modules/budgets/config/locales/crowdin/ru.yml @@ -89,12 +89,12 @@ ru: other: "Данные, собранные из %{count} бюджетов, включены в этот проект и его подпроекты." program: zero: "Нет данных о бюджете." - one: "Data aggregated from %{count} budget included in this program and its subitems." - other: "Data aggregated from %{count} budgets included in this program and its subitems." + one: "Данные, собранные из %{count} бюджета, включены в эту программу и её подпрограммы." + other: "Данные, собранные из %{count} бюджетов, включены в эту программу и её подпрограммы." portfolio: - zero: "No budget data." - one: "Data aggregated from %{count} budget included in this portfolio and its subitems." - other: "Data aggregated from %{count} budgets included in this portfolio and its subitems." + zero: "Нет данных о бюджете." + one: "Данные, собранные из %{count} бюджета, включены в этот портфель и его подпункты." + other: "Данные, собранные из %{count} бюджетов, включены в этот портфель и его подпункты." view_details: "Посмотреть детали бюджета" events: budget: "Бюджет изменен" diff --git a/modules/costs/config/locales/crowdin/cs.yml b/modules/costs/config/locales/crowdin/cs.yml index 85d249a63ce..139bd7778c9 100644 --- a/modules/costs/config/locales/crowdin/cs.yml +++ b/modules/costs/config/locales/crowdin/cs.yml @@ -31,9 +31,9 @@ cs: spent: "Strávený čas" spent_on: "Datum" logged_by: "Zadáno" - entity: Přihlášen - entity_id: Přihlášen - entity_gid: Přihlášen + entity: Přihlášen + entity_id: Přihlášen + entity_gid: Přihlášen cost_type: unit: "Název jednotky" unit_plural: "Název Pluralizované jednotky" @@ -61,9 +61,9 @@ cs: start_time: Čas zahájení end_time: Čas dokončení time: Čas - entity: Přihlášen - entity_id: Přihlášen - entity_gid: Přihlášen + entity: Přihlášen + entity_id: Přihlášen + entity_gid: Přihlášen models: time_entry: one: "Vstup času" @@ -242,8 +242,8 @@ cs: actual_costs: title: "Actual costs by month" blankslate: - heading: "Start tracking your time and costs" - description: "Get an overview of your costs and logged time to monitor progress of your project. Make sure that work packages are associated with the correct budget." + heading: "Začněte sledovat svůj čas a náklady" + description: "Získejte přehled o vašich nákladech a zalogovaném čase pro sledování průběhu vašeho projektu. Ujistěte se, že pracovní balíčky jsou přiřazeny ke správnému rozpočtu." action: "Log time" view_details: "View actual costs details" ee: diff --git a/modules/costs/config/locales/crowdin/de.yml b/modules/costs/config/locales/crowdin/de.yml index f4ab9eb9320..8d9d9183c51 100644 --- a/modules/costs/config/locales/crowdin/de.yml +++ b/modules/costs/config/locales/crowdin/de.yml @@ -197,7 +197,7 @@ de: permission_log_costs: "Stückkosten buchen" permission_log_own_costs: "Eigene Stückkosten buchen" permission_view_cost_entries: "Gebuchte Kosten ansehen" - permission_view_cost_rates: "Anzeigen von Stückpreisen" + permission_view_cost_rates: "Stückkosten ansehen" permission_view_hourly_rates: "Alle Stundensätze ansehen" permission_view_own_cost_entries: "Eigene gebuchte Kosten ansehen" permission_view_own_hourly_rate: "Eigene Stundensätze ansehen" diff --git a/modules/documents/config/locales/crowdin/cs.yml b/modules/documents/config/locales/crowdin/cs.yml index 3fe467eb53a..0151e949282 100644 --- a/modules/documents/config/locales/crowdin/cs.yml +++ b/modules/documents/config/locales/crowdin/cs.yml @@ -78,7 +78,7 @@ cs: description: "The connection to the real-time text collaboration server has been restored." tabs: "Document tabs" index_page: - name: "Název:" + name: "Název" type: "Typ" updated_at: "Last edited" label_legacy: "Legacy" diff --git a/modules/grids/config/locales/crowdin/cs.yml b/modules/grids/config/locales/crowdin/cs.yml index 6bc4da8bcac..e9165943e7d 100644 --- a/modules/grids/config/locales/crowdin/cs.yml +++ b/modules/grids/config/locales/crowdin/cs.yml @@ -5,12 +5,12 @@ cs: empty: "This widget is currently empty." not_available: "This widget is not available." subitems: - title: "Subitems" + title: "Dílčí položky" no_results: "There are no visible children." view_all_subitems: "View all subitems" - button_text: "Subitem" + button_text: "Dílčí položky" members: - title: "Members" + title: "Členové" no_results: "Žádní viditelní členové." view_all_members: "Zobrazit všechny členy" show_members_count: "Show all %{count} members" diff --git a/modules/grids/config/locales/crowdin/js-cs.yml b/modules/grids/config/locales/crowdin/js-cs.yml index a24501fd1df..5f2d3fd11c2 100644 --- a/modules/grids/config/locales/crowdin/js-cs.yml +++ b/modules/grids/config/locales/crowdin/js-cs.yml @@ -29,7 +29,7 @@ cs: finished: 'Dokončeno' discontinued: 'Zrušeno' subprojects: - title: 'Subitems' + title: 'Dílčí položky' project_favorites: title: 'Oblíbené projekty' no_results: 'Momentálně nemáte žádné oblíbené projekty. Klikněte na ikonu hvězdičky v nástěnce projektu pro přidání jednoho do oblíbených.' diff --git a/modules/meeting/config/locales/crowdin/cs.yml b/modules/meeting/config/locales/crowdin/cs.yml index a335c7f279e..9b7169ccdb0 100644 --- a/modules/meeting/config/locales/crowdin/cs.yml +++ b/modules/meeting/config/locales/crowdin/cs.yml @@ -221,7 +221,7 @@ cs: text: template: "Tito účastníci budou automaticky pozváni na všechna budoucí zasedání po jejich vytvoření." manage_participants: "Search for and add project members as participants to this meeting." - search_for_members: "Search for project members" + search_for_members: "Vyhledávání členů projektu" blankslate: heading: "Nikdo tu není" description: "There are no participants yet." diff --git a/modules/meeting/config/locales/crowdin/fr.yml b/modules/meeting/config/locales/crowdin/fr.yml index 3409978e1d7..c296d40bbb4 100644 --- a/modules/meeting/config/locales/crowdin/fr.yml +++ b/modules/meeting/config/locales/crowdin/fr.yml @@ -85,7 +85,7 @@ fr: models: recurring_meeting: "Réunion récurrente" meeting: "Réunion ponctuelle" - meeting_agenda_item: "" + meeting_agenda_item: "Point d'ordre du jour" meeting_agenda: "Ordre du jour" meeting_section: "Section" token/ical_meeting: diff --git a/modules/meeting/config/locales/crowdin/ru.yml b/modules/meeting/config/locales/crowdin/ru.yml index ab2052d8fb7..3d54f2873fa 100644 --- a/modules/meeting/config/locales/crowdin/ru.yml +++ b/modules/meeting/config/locales/crowdin/ru.yml @@ -63,7 +63,7 @@ ru: end_date: "Дате окончания" iterations: "События" recurring_meeting_interim_response: - start_time: "Start time" + start_time: "Время начала" meeting_participant: invited: "Приглашённые" attended: "Участвовал" @@ -76,7 +76,7 @@ ru: section_not_belong_to_meeting: "Раздел не принадлежит к одному и тому же совещанию." user_invalid: "не является действительным участником." recurring_meeting_interim_response: - not_an_occurrence: "is not a valid occurrence time for this recurring meeting" + not_an_occurrence: "не является допустимым временем повторения совещания" recurring_meeting: must_cover_existing_meetings: one: "В серии есть одно открытое совещание, которое не включено в новый график. Измените график, чтобы включить все существующие совещания." @@ -206,7 +206,7 @@ ru: label_start_date: "Дата начала" label_subscribe_icalendar: "Подписаться на календарь" caption_meeting_template_select: "Выберите шаблон для автоматического копирования его повестки дня" - caption_template_project_select: "Please select the project in which to create this meeting template" + caption_template_project_select: "Пожалуйста, выберите проект, в котором будет создан этот шаблон совещания" meeting: participants: label: @@ -226,8 +226,8 @@ ru: heading: "Нет участников" description: "Пока нет участников." attachments: - onetime_template: "These attached files will be included in all future meetings using this template." - series_template: "These attached files will be included in all future meetings in the series." + onetime_template: "Эти прикрепленные файлы будут включены во все последующие совещания, проводимые по этому шаблону." + series_template: "Эти прикрепленные файлы будут включены во все последующие совещания этой серии." text: "Прикрепленные файлы доступны всем участникам совещания. Вы также можете перенести их в примечания к пунктам повестки дня." copy: title: "Копировать совещание %{title}" @@ -259,9 +259,9 @@ ru: header: "Отменено: совещание '%{title}'" header_occurrence: "Отменено: событие совещания '%{title}'" header_series: "Отменено: серия совещаний '%{title}'" - summary_occurrence: "An occurrence of '%{title}' has been cancelled by %{actor}, or you have been removed as a participant" - summary_series: "Meeting series '%{title}' has been cancelled by %{actor}, or you have been removed as a participant" - summary: "'%{title}' has been cancelled by %{actor}, or you have been removed as a participant" + summary_occurrence: "Начало '%{title}' было отменено %{actor}, или вы были удалены из списка участников" + summary_series: "Серия совещаний '%{title}' была отменена %{actor}, или вы были удалены из списка участников" + summary: "'%{title}' было отменено %{actor}, или вы были удалены из списка участников" date_time: "Запланированная дата/время" participant_added: header: "Совещание '%{title}' - участник добавлен" @@ -275,7 +275,7 @@ ru: summary_series: "%{actor} удалил %{participant} из серии совещаний '%{title}'" ended: header_series: "Завершено: Серия совещаний '%{title}'" - summary_series: "Meeting series '%{title}' has been ended by %{actor}" + summary_series: "Серия совещаний '%{title}' была завершена %{actor}" updated: header: "Встреча '%{title}' была обновлена" summary: "Совещание '%{title}' было обновлено пользователем %{actor}" @@ -304,7 +304,7 @@ ru: title: "Удалить шаблон" heading: "Удалить этот шаблон?" confirmation_message_html: > - This action is not reversible. Please proceed with caution. Existing meetings that were created using this template will not be affected. + Это действие не обратимо. Пожалуйста, действуйте с осторожностью. Существующие совещания, созданные с помощью этого шаблона, не будут затронуты. occurrence: title: "Отменить это событие" heading: "Отменить это событие?" @@ -570,8 +570,8 @@ ru: label_agenda_item_move_up: "Вверх" label_agenda_item_move_down: "Вниз" label_agenda_item_duplicate: "Дубликат" - label_agenda_item_duplicate_in_next: "Duplicate in next meeting" - label_agenda_item_duplicate_in_next_title: "Duplicate in next meeting?" + label_agenda_item_duplicate_in_next: "Продублировать в следующее совещание" + label_agenda_item_duplicate_in_next_title: "Продублировать в следующее совещание?" label_agenda_item_add_notes: "Добавить заметки" label_agenda_item_add_outcome: "Добавить итог" label_agenda_item_work_package_add: "Добавить пакет работ" @@ -632,7 +632,7 @@ ru: text_meeting_draft_banner: "В настоящее время Вы находитесь в режиме черновика. Это совещание не будет рассылать никаких обновлений календаря или приглашений, даже если Вы измените детали совещания или добавите/удалите участников." text_onetime_meeting_template_banner: "В данный момент Вы редактируете шаблон совещания. Вы можете использовать этот шаблон для создания одноразовых совещаний с заранее определенной повесткой дня. Изменения не повлияют на уже созданные совещания." text_onetime_meeting_template_empty_heading: "Этот шаблон совещания пуст" - text_onetime_meeting_template_empty_description: "Add agenda items, sections and attachments here. They will be included in every meeting created using this template." + text_onetime_meeting_template_empty_description: "Добавьте сюда пункты повестки дня, разделы и вложения. Они будут включены в каждое совещание, созданное с помощью этого шаблона." text_exit_draft_mode_dialog_title: "Открыть это совещание и разослать приглашения?" text_exit_draft_mode_dialog_subtitle: "Вы не можете вернуться в режим черновика после того, как запланировали совещание." text_exit_draft_mode_dialog_template_title: "Открыть первое совещание из этой серии?" diff --git a/modules/meeting/lib/open_project/journal_formatter/meeting_work_package_id.rb b/modules/meeting/lib/open_project/journal_formatter/meeting_work_package_id.rb index 0edb7cc83f5..e8622bd6f13 100644 --- a/modules/meeting/lib/open_project/journal_formatter/meeting_work_package_id.rb +++ b/modules/meeting/lib/open_project/journal_formatter/meeting_work_package_id.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH @@ -44,8 +45,8 @@ class OpenProject::JournalFormatter::MeetingWorkPackageId < JournalFormatter::Ba old = visible(values.first) I18n.t(:"activity.item.meeting_agenda_item.work_package.updated#{html}", - value: new ? new.name : I18n.t(:label_agenda_item_undisclosed_wp, id: values.last), - old_value: old ? old.name : I18n.t(:label_agenda_item_undisclosed_wp, id: values.first)) + value: new ? h(new.name) : I18n.t(:label_agenda_item_undisclosed_wp, id: values.last), + old_value: old ? h(old.name) : I18n.t(:label_agenda_item_undisclosed_wp, id: values.first)) end def visible(work_package_id) diff --git a/modules/meeting/spec/features/meeting_backlogs_spec.rb b/modules/meeting/spec/features/meeting_backlogs_spec.rb index 88e22a76eea..be53398bb00 100644 --- a/modules/meeting/spec/features/meeting_backlogs_spec.rb +++ b/modules/meeting/spec/features/meeting_backlogs_spec.rb @@ -247,14 +247,6 @@ RSpec.describe "Meeting Backlogs", :js do end describe "for meeting series" do - before_all do - travel_to(Date.new(2024, 12, 1)) - end - - after(:all) do # rubocop:disable RSpec/BeforeAfterAll - travel_back - end - shared_let(:recurring_meeting) do create :recurring_meeting, project:, @@ -276,6 +268,10 @@ RSpec.describe "Meeting Backlogs", :js do RecurringMeetings::InitNextOccurrenceJob.perform_now(recurring_meeting, next_occurrence_time) end + after do + travel_back + end + describe "backlog visibility" do context "when the meeting is 'open'" do it "is expanded" do diff --git a/modules/meeting/spec/features/meetings_index_spec.rb b/modules/meeting/spec/features/meetings_index_spec.rb index fae6aaaa574..88c1b3d81a6 100644 --- a/modules/meeting/spec/features/meetings_index_spec.rb +++ b/modules/meeting/spec/features/meetings_index_spec.rb @@ -32,6 +32,12 @@ require "spec_helper" require_relative "../support/pages/meetings/index" RSpec.describe "Meetings", "Index", :js do + shared_let(:business_day_at_noon) { Time.zone.local(2025, 1, 8, 12, 0, 0) } + + after do + travel_back + end + # The order the Projects are created in is important. By naming `project` alphanumerically # after `other_project`, we can ensure that subsequent specs that assert sorting is # correct for the right reasons (sorting by Project name and not id) @@ -55,14 +61,14 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project:, title: "Awesome meeting today!", - start_time: Time.current) + start_time: business_day_at_noon - 5.minutes) end shared_let(:tomorrows_meeting) do create(:meeting, :author_participates, project:, title: "Awesome meeting tomorrow!", - start_time: 1.day.from_now, + start_time: business_day_at_noon + 1.day, duration: 2.0, location: "no-protocol.com") end @@ -71,7 +77,7 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project:, title: "Boring meeting without a location!", - start_time: 1.day.from_now, + start_time: business_day_at_noon + 1.day + 5.minutes, location: "") end shared_let(:meeting_with_malicious_location) do @@ -79,7 +85,7 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project:, title: "Sneaky meeting!", - start_time: 1.day.from_now, + start_time: business_day_at_noon + 1.day + 10.minutes, location: "") end shared_let(:yesterdays_meeting) do @@ -87,7 +93,7 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project:, title: "Awesome meeting yesterday!", - start_time: 1.day.ago) + start_time: business_day_at_noon - 1.day) end shared_let(:other_project_meeting) do @@ -95,7 +101,7 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project: other_project, title: "Awesome other project meeting!", - start_time: 2.days.from_now, + start_time: business_day_at_noon + 2.days, duration: 2.0, location: "not-a-url") end @@ -104,7 +110,7 @@ RSpec.describe "Meetings", "Index", :js do :author_participates, project:, title: "Awesome ongoing meeting!", - start_time: 30.minutes.ago) + start_time: business_day_at_noon - 30.minutes) end def setup_meeting_involvement @@ -120,6 +126,7 @@ RSpec.describe "Meetings", "Index", :js do end before do + travel_to(business_day_at_noon) login_as user end diff --git a/modules/meeting/spec/features/move_to_section_spec.rb b/modules/meeting/spec/features/move_to_section_spec.rb index df2317e5133..64690b0f88a 100644 --- a/modules/meeting/spec/features/move_to_section_spec.rb +++ b/modules/meeting/spec/features/move_to_section_spec.rb @@ -52,6 +52,10 @@ RSpec.describe "Move agenda items to section", :js do login_as current_user end + after do + travel_back + end + describe "for one-time meetings" do shared_let(:meeting) do create :meeting, diff --git a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_create_spec.rb b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_create_spec.rb index 81287ee636c..e91d16f84e6 100644 --- a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_create_spec.rb +++ b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_create_spec.rb @@ -74,6 +74,10 @@ RSpec.describe "Recurring meetings creation", travel_to(Date.new(2024, 12, 1)) end + after do + travel_back + end + context "with a user with permissions" do it "can create a recurring meeting" do login_as current_user diff --git a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_crud_spec.rb b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_crud_spec.rb index a95a70bc171..b91732cfafb 100644 --- a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_crud_spec.rb +++ b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_crud_spec.rb @@ -38,14 +38,6 @@ RSpec.describe "Recurring meetings CRUD", :js do include Components::Autocompleter::NgSelectAutocompleteHelpers - before_all do - travel_to(Date.new(2024, 12, 1)) - end - - after(:all) do # rubocop:disable RSpec/BeforeAfterAll - travel_back - end - shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) } shared_let(:user) do create :user, @@ -85,6 +77,10 @@ RSpec.describe "Recurring meetings CRUD", RecurringMeetings::InitNextOccurrenceJob.perform_now(meeting, meeting.first_occurrence.to_time) end + after do + travel_back + end + it "can delete a recurring meeting from the show page and return to the index page" do show_page.visit! diff --git a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_global_crud_spec.rb b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_global_crud_spec.rb index 6f03deb0517..010ae29a69b 100644 --- a/modules/meeting/spec/features/recurring_meetings/recurring_meeting_global_crud_spec.rb +++ b/modules/meeting/spec/features/recurring_meetings/recurring_meeting_global_crud_spec.rb @@ -37,14 +37,6 @@ require_relative "../../support/pages/meetings/index" RSpec.describe "Recurring meetings global CRUD", :js do include Components::Autocompleter::NgSelectAutocompleteHelpers - before_all do - travel_to(Date.new(2024, 12, 1)) - end - - after(:all) do # rubocop:disable RSpec/BeforeAfterAll - travel_back - end - shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) } shared_let(:user) do create :user, @@ -84,6 +76,10 @@ RSpec.describe "Recurring meetings global CRUD", :js do RecurringMeetings::InitNextOccurrenceJob.perform_now(meeting, meeting.first_occurrence.to_time) end + after do + travel_back + end + it "can delete a recurring meeting from the show page and return to the index page" do show_page.visit! diff --git a/modules/meeting/spec/features/structured_meetings/structured_meeting_update_flash_spec.rb b/modules/meeting/spec/features/structured_meetings/structured_meeting_update_flash_spec.rb index 5bb68fe2392..77eb0ccf0f8 100644 --- a/modules/meeting/spec/features/structured_meetings/structured_meeting_update_flash_spec.rb +++ b/modules/meeting/spec/features/structured_meetings/structured_meeting_update_flash_spec.rb @@ -193,14 +193,6 @@ RSpec.describe "Meetings CRUD", end context "for meeting series, across the same occurrence" do - before_all do - travel_to(Date.new(2024, 12, 1)) - end - - after(:all) do # rubocop:disable RSpec/BeforeAfterAll - travel_back - end - let(:recurring_meeting) do create :recurring_meeting, project:, @@ -222,6 +214,10 @@ RSpec.describe "Meetings CRUD", RecurringMeetings::InitNextOccurrenceJob.perform_now(recurring_meeting, first_occurrence_time) end + after do + travel_back + end + it_behaves_like "no flash appears when interacting with backlog in multiple windows" end diff --git a/modules/meeting/spec/lib/open_project/journal_formatter/meeting_work_package_id_spec.rb b/modules/meeting/spec/lib/open_project/journal_formatter/meeting_work_package_id_spec.rb new file mode 100644 index 00000000000..05984fb0fb2 --- /dev/null +++ b/modules/meeting/spec/lib/open_project/journal_formatter/meeting_work_package_id_spec.rb @@ -0,0 +1,99 @@ +# 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. +#++ + +require "spec_helper" + +RSpec.describe OpenProject::JournalFormatter::MeetingWorkPackageId do + let(:instance) { described_class.new(build_stubbed(:journal)) } + + let(:project) { create(:project) } + let(:old_work_package) { create(:work_package, project:, subject: "Old task") } + let(:new_work_package) { create(:work_package, project:, subject: "New task") } + + describe "#render" do + context "when both work packages are visible" do + before do + allow(WorkPackage).to receive(:visible).and_return(WorkPackage.where(id: [old_work_package.id, new_work_package.id])) + end + + it "renders work package names in HTML mode" do + result = instance.render("work_package_id", [old_work_package.id, new_work_package.id], html: true) + + expect(result).to include("Old task") + expect(result).to include("New task") + end + + it "renders work package names in plain text mode" do + result = instance.render("work_package_id", [old_work_package.id, new_work_package.id], html: false) + + expect(result).to include("Old task") + expect(result).to include("New task") + end + end + + context "when work packages are not visible" do + before do + allow(WorkPackage).to receive(:visible).and_return(WorkPackage.none) + end + + it "renders undisclosed work package text with the ID" do + result = instance.render("work_package_id", [old_work_package.id, new_work_package.id], html: true) + + expect(result).to include(old_work_package.id.to_s) + expect(result).to include(new_work_package.id.to_s) + expect(result).not_to include("Old task") + expect(result).not_to include("New task") + end + end + + context "when work package names contain HTML" do + let(:old_work_package) { create(:work_package, project:, subject: "Safe task") } + let(:new_work_package) { create(:work_package, project:, subject: "") } + + before do + allow(WorkPackage).to receive(:visible).and_return(WorkPackage.where(id: [old_work_package.id, new_work_package.id])) + end + + it "escapes HTML in work package names" do + result = instance.render("work_package_id", [old_work_package.id, new_work_package.id], html: true) + + expect(result).not_to include(" %i(view_meetings create_meetings) }) end + let(:business_day_at_noon) { Time.zone.parse("2025-01-08T12:00:00Z") } let(:instance) { described_class.new(user:) } let(:service_result) { subject } let(:series) { service_result.result } @@ -42,6 +43,14 @@ RSpec.describe RecurringMeetings::CreateService, "integration", type: :model do subject { instance.call(**params) } + before do + travel_to(business_day_at_noon) + end + + after do + travel_back + end + shared_examples "creates the series" do it "creates the series and template" do expect(service_result).to be_success diff --git a/modules/reporting/app/models/cost_query/custom_field_mixin.rb b/modules/reporting/app/models/cost_query/custom_field_mixin.rb index 9eedfdc55b8..d101ae75461 100644 --- a/modules/reporting/app/models/cost_query/custom_field_mixin.rb +++ b/modules/reporting/app/models/cost_query/custom_field_mixin.rb @@ -113,7 +113,7 @@ module CostQuery::CustomFieldMixin custom_options_table = CustomOption.table_name <<-SQL - -- BEGIN Custom Field Join: #{db_field} + -- BEGIN Custom Field Join: cf_#{field.id} LEFT OUTER JOIN ( SELECT co.id AS #{db_field}, @@ -129,16 +129,16 @@ module CostQuery::CustomFieldMixin AND #{db_field}.custom_field_id = #{field.id} AND #{db_field}.customized_id = entries.entity_id - -- END Custom Field Join: #{db_field} + -- END Custom Field Join: cf_#{field.id} SQL end def default_join_table(field) - <<-SQL % [CustomValue.table_name, table_name, field.id, field.name, SQL_TYPES[field.field_format]] - -- BEGIN Custom Field Join: "%4$s" + <<-SQL % [CustomValue.table_name, table_name, field.id, SQL_TYPES[field.field_format]] + -- BEGIN Custom Field Join: cf_%3$d LEFT OUTER JOIN ( \tSELECT - \t\tCAST(value AS %5$s) AS %2$s, + \t\tCAST(value AS %4$s) AS %2$s, \t\tcustomized_type, \t\tcustom_field_id, \t\tcustomized_id @@ -148,7 +148,7 @@ module CostQuery::CustomFieldMixin ON %2$s.customized_type = 'WorkPackage' AND %2$s.custom_field_id = %3$d AND %2$s.customized_id = entries.entity_id - -- END Custom Field Join: "%4$s" + -- END Custom Field Join: cf_%3$d SQL end diff --git a/modules/reporting/spec/models/cost_query/custom_field_mixin_spec.rb b/modules/reporting/spec/models/cost_query/custom_field_mixin_spec.rb new file mode 100644 index 00000000000..9023483bcbd --- /dev/null +++ b/modules/reporting/spec/models/cost_query/custom_field_mixin_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require_relative "../../spec_helper" + +RSpec.describe CostQuery::CustomFieldMixin, :reporting_query_helper do + minimal_query + + let!(:project) { create(:project_with_types) } + let!(:user) { create(:admin) } + + describe "#default_join_table" do + let!(:custom_field) do + create(:wp_custom_field, :string, name: "Robert'); DROP TABLE Students;-- Roberts") + end + + before do + CostQuery::Cache.reset! + CostQuery::Filter::CustomFieldEntries.all + end + + after do + CostQuery::Cache.reset! + CostQuery::Filter::CustomFieldEntries.reset! + end + + it "uses field.id in the SQL comment and does not include the field name" do + query.filter custom_field.attribute_name, operator: "=", value: "test" + sql = query.sql_statement.to_s + + expect(sql).to include("-- BEGIN Custom Field Join: cf_#{custom_field.id}") + expect(sql).to include("-- END Custom Field Join: cf_#{custom_field.id}") + expect(sql).not_to include("DROP TABLE students") + expect(sql).to include("CAST(value AS varchar)") + end + end +end diff --git a/modules/storages/app/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator.rb b/modules/storages/app/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator.rb index f93515ea20f..75daf1b9368 100644 --- a/modules/storages/app/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator.rb +++ b/modules/storages/app/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator.rb @@ -40,13 +40,21 @@ module Storages def validate register_checks( - :team_folder_app, :files_request, :userless_access, :team_folder_presence, :team_folder_contents + :team_folder_app, + :files_request, + :userless_access, + :team_folder_presence, + :project_folders_linked, + :project_folders_exist, + :team_folder_contents ) team_folder_app_checks files_request_failed_with_unknown_error userless_access_denied team_folder_not_found + project_folders_linked + project_folders_exist with_unexpected_content end @@ -66,7 +74,7 @@ module Storages if capabilities.group_folder_disabled? fail_check(:team_folder_app, :nc_dependency_missing, context: { dependency: }) elsif capabilities.group_folder_version < required_version - fail_check(:team_folder_app, :nc_dependency_version_mismatch, context: { dependency: }) + warn_check(:team_folder_app, :nc_dependency_version_mismatch, context: { dependency: }) else pass_check(:team_folder_app) end @@ -92,12 +100,33 @@ module Storages pass_check(:files_request) end + def project_folders_linked + ampf_project_storages = @storage.project_storages.active.automatic + expected = ampf_project_storages.count + actual = ampf_project_storages.with_project_folder.count + return pass_check(:project_folders_linked) if actual == expected + + warn_check(:project_folders_linked, :nc_unlinked_project_folders, context: { actual:, expected: }) + end + + def project_folders_exist + @storage.project_storages.active.automatic.with_project_folder.each do |project_storage| + next if existing_folder_ids.include?(project_storage.project_folder_id) + + return fail_check( + :project_folders_exist, :nc_project_folder_missing, context: { project: project_storage.project.name } + ) + end + + pass_check(:project_folders_exist) + end + def with_unexpected_content unexpected_files = files.value!.reject { managed_project_folder_ids.include?(it.id) } return pass_check(:team_folder_contents) if unexpected_files.empty? log_extraneous_files(unexpected_files) - warn_check(:team_folder_contents, :nc_unexpected_content) + warn_check(:team_folder_contents, :nc_unexpected_files, context: { sample: unexpected_files.sample.name }) end def log_extraneous_files(unexpected_files) @@ -121,6 +150,10 @@ module Storages end end + def existing_folder_ids + @existing_folder_ids ||= files.value!.all_folders.to_set(&:id) + end + def noop = Input::Strategy.build(key: :noop) def nextcloud_dependencies diff --git a/modules/storages/app/components/storages/admin/side_panel/health_notifications_component.html.erb b/modules/storages/app/components/storages/admin/side_panel/health_notifications_component.html.erb index f0272abe837..0e9592207f0 100644 --- a/modules/storages/app/components/storages/admin/side_panel/health_notifications_component.html.erb +++ b/modules/storages/app/components/storages/admin/side_panel/health_notifications_component.html.erb @@ -36,7 +36,7 @@ See COPYRIGHT and LICENSE files for more details. notifications_container.with_row do concat( render(Primer::Beta::Text.new(pr: 2, test_selector: "storage-health-checked-at")) do - I18n.t("storages.health.checked", datetime: helpers.format_time(@storage.health_checked_at)) + I18n.t("storages.health.synced", datetime: helpers.format_time(@storage.health_checked_at)) end ) diff --git a/modules/storages/app/services/storages/nextcloud_managed_folder_create_service.rb b/modules/storages/app/services/storages/nextcloud_managed_folder_create_service.rb index dbcd1814f40..099db7e1258 100644 --- a/modules/storages/app/services/storages/nextcloud_managed_folder_create_service.rb +++ b/modules/storages/app/services/storages/nextcloud_managed_folder_create_service.rb @@ -101,16 +101,14 @@ module Storages @project_storages.includes(:project).find_each do |project_storage| folder_id = project_storage.project_folder_id - result = case id_folder_map[folder_id] - when nil - create_remote_folder(project_storage) - when project_storage.managed_project_folder_path.chop - Success() - else - rename_folder(folder_id, project_storage.managed_project_folder_name) - end - - result.or { return Failure() } + case id_folder_map[folder_id] + when nil + create_remote_folder(project_storage) + when project_storage.managed_project_folder_path.chop + Success() + else + rename_folder(folder_id, project_storage.managed_project_folder_name) + end end Success(:setup_folders) diff --git a/modules/storages/config/locales/crowdin/af.yml b/modules/storages/config/locales/crowdin/af.yml index a3e1eae664d..b28bb59ee62 100644 --- a/modules/storages/config/locales/crowdin/af.yml +++ b/modules/storages/config/locales/crowdin/af.yml @@ -279,6 +279,8 @@ af: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ af: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ af: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ar.yml b/modules/storages/config/locales/crowdin/ar.yml index 35136372029..748f12662da 100644 --- a/modules/storages/config/locales/crowdin/ar.yml +++ b/modules/storages/config/locales/crowdin/ar.yml @@ -279,6 +279,8 @@ ar: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -330,8 +332,10 @@ ar: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -380,6 +384,7 @@ ar: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/az.yml b/modules/storages/config/locales/crowdin/az.yml index 837192548b5..99a1caa5947 100644 --- a/modules/storages/config/locales/crowdin/az.yml +++ b/modules/storages/config/locales/crowdin/az.yml @@ -279,6 +279,8 @@ az: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ az: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ az: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/be.yml b/modules/storages/config/locales/crowdin/be.yml index e5b4ae686bc..8bd71dbceb2 100644 --- a/modules/storages/config/locales/crowdin/be.yml +++ b/modules/storages/config/locales/crowdin/be.yml @@ -279,6 +279,8 @@ be: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ be: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ be: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/bg.yml b/modules/storages/config/locales/crowdin/bg.yml index f776454f834..1f7e130df70 100644 --- a/modules/storages/config/locales/crowdin/bg.yml +++ b/modules/storages/config/locales/crowdin/bg.yml @@ -279,6 +279,8 @@ bg: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ bg: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ bg: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ca.yml b/modules/storages/config/locales/crowdin/ca.yml index 73998b14972..a06891cbc2e 100644 --- a/modules/storages/config/locales/crowdin/ca.yml +++ b/modules/storages/config/locales/crowdin/ca.yml @@ -279,6 +279,8 @@ ca: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ ca: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ ca: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ckb-IR.yml b/modules/storages/config/locales/crowdin/ckb-IR.yml index 8ac9d49712f..813a87713e2 100644 --- a/modules/storages/config/locales/crowdin/ckb-IR.yml +++ b/modules/storages/config/locales/crowdin/ckb-IR.yml @@ -279,6 +279,8 @@ ckb-IR: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ ckb-IR: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ ckb-IR: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/cs.yml b/modules/storages/config/locales/crowdin/cs.yml index 4b8eb5d866e..052866f7691 100644 --- a/modules/storages/config/locales/crowdin/cs.yml +++ b/modules/storages/config/locales/crowdin/cs.yml @@ -279,6 +279,8 @@ cs: drive_contents: Drive content files_request: Fetching team folder files header: Automaticky spravované projektové složky + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ cs: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Nakonfigurované heslo aplikace je neplatné. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ cs: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/da.yml b/modules/storages/config/locales/crowdin/da.yml index e95ef9f15e2..90153e877a4 100644 --- a/modules/storages/config/locales/crowdin/da.yml +++ b/modules/storages/config/locales/crowdin/da.yml @@ -279,6 +279,8 @@ da: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ da: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ da: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/de.yml b/modules/storages/config/locales/crowdin/de.yml index 7abfc15b703..52a0cf0a924 100644 --- a/modules/storages/config/locales/crowdin/de.yml +++ b/modules/storages/config/locales/crowdin/de.yml @@ -279,6 +279,8 @@ de: drive_contents: Speicherinhalt files_request: Teamordnerdateien werden abgerufen header: Automatisch verwaltete Projektordner + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Abhängigkeit: Teamordner' team_folder_contents: Inhalt des Teamordners team_folder_presence: Teamordner existiert @@ -322,8 +324,10 @@ de: nc_oauth_request_not_found: Der Endpunkt für den Abruf des aktuell verbundenen Benutzers wurde nicht gefunden. Bitte überprüfen Sie die Serverprotokolle für weitere Informationen. nc_oauth_request_unauthorized: Der aktuelle Benutzer ist nicht berechtigt, auf den Remote-Datei-Speicher zuzugreifen. Bitte überprüfen Sie die Server-Protokolle für weitere Informationen. nc_oauth_token_missing: OpenProject kann die Kommunikation auf Benutzerebene mit Nextcloud nicht testen, da der Benutzer sein Nextcloud Konto noch nicht verknüpft hat. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Der Teamordner konnte nicht gefunden werden. - nc_unexpected_content: Unerwarteter Inhalt im verwalteten Teamordner gefunden. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Das konfigurierte App-Passwort ist ungültig. not_configured: Die Verbindung konnte nicht validiert werden. Bitte schließen Sie zuerst die Konfiguration ab. od_client_cant_delete_folder: Der Client hat Probleme beim Löschen von Ordnern. Bitte überprüfen Sie die Setup-Dokumentation für Ihren Speicher. @@ -372,6 +376,7 @@ de: failure: Einige Überprüfungen sind fehlgeschlagen und das System funktioniert nicht wie erwartet. success: Alle Verbindungen und Systeme funktionieren wie erwartet. warning: Einige Überprüfungen ergaben eine Warnung. Dies kann zu unerwartetem Verhalten führen. + synced: 'Zuletzt aktualisiert: %{datetime}' title: Gesundheitsstatusbericht health_email_notifications: description_disabled: Administrator:innen erhalten keine E-Mail-Updates, wenn es wichtige Änderungen gibt. diff --git a/modules/storages/config/locales/crowdin/el.yml b/modules/storages/config/locales/crowdin/el.yml index 1204fd9f2d1..12b2669b557 100644 --- a/modules/storages/config/locales/crowdin/el.yml +++ b/modules/storages/config/locales/crowdin/el.yml @@ -279,6 +279,8 @@ el: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ el: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ el: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/eo.yml b/modules/storages/config/locales/crowdin/eo.yml index b14e36bc75d..6f0ad947e98 100644 --- a/modules/storages/config/locales/crowdin/eo.yml +++ b/modules/storages/config/locales/crowdin/eo.yml @@ -279,6 +279,8 @@ eo: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ eo: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ eo: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/es.yml b/modules/storages/config/locales/crowdin/es.yml index 8e66eb7b4ce..5d8e0c2e60b 100644 --- a/modules/storages/config/locales/crowdin/es.yml +++ b/modules/storages/config/locales/crowdin/es.yml @@ -279,6 +279,8 @@ es: drive_contents: Contenido de la unidad files_request: Obteniendo archivos de carpetas de equipo header: Carpetas de proyecto gestionadas automáticamente + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependencia: Carpetas de equipo' team_folder_contents: Contenido de la carpeta de equipo team_folder_presence: La carpeta del equipo existe @@ -322,8 +324,10 @@ es: nc_oauth_request_not_found: No se ha encontrado el terminal para obtener el usuario actualmente conectado. Consulte los registros del servidor para obtener más información. nc_oauth_request_unauthorized: El usuario actual no está autorizado a acceder al almacenamiento remoto de archivos. Consulte los registros del servidor para obtener más información. nc_oauth_token_missing: OpenProject no puede probar la comunicación a nivel de usuario con Nextcloud, ya que el usuario aún no ha vinculado su cuenta de Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: No se ha podido encontrar la carpeta del equipo. - nc_unexpected_content: Se ha encontrado contenido inesperado en la carpeta del equipo gestionada. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: La contraseña configurada de la aplicación no es válida. not_configured: No se ha podido validar la conexión. Por favor, termine primero la configuración. od_client_cant_delete_folder: El cliente tiene problemas para eliminar carpetas. Consulte la documentación de configuración de su almacenamiento. @@ -372,6 +376,7 @@ es: failure: Algunas comprobaciones han fallado y el sistema no funciona como se esperaba. success: Todas las conexiones y sistemas funcionan según lo previsto. warning: Algunas comprobaciones devolvieron una advertencia. Esto puede dar lugar a un comportamiento inesperado. + synced: 'Last sync: %{datetime}' title: Informe de estado de salud health_email_notifications: description_disabled: Los administradores no recibirán actualizaciones por correo electrónico cuando haya actualizaciones importantes. diff --git a/modules/storages/config/locales/crowdin/et.yml b/modules/storages/config/locales/crowdin/et.yml index 9f55d41dffc..04e14a57ece 100644 --- a/modules/storages/config/locales/crowdin/et.yml +++ b/modules/storages/config/locales/crowdin/et.yml @@ -279,6 +279,8 @@ et: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ et: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ et: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/eu.yml b/modules/storages/config/locales/crowdin/eu.yml index 2d727afd2cb..71b214592a8 100644 --- a/modules/storages/config/locales/crowdin/eu.yml +++ b/modules/storages/config/locales/crowdin/eu.yml @@ -279,6 +279,8 @@ eu: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ eu: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ eu: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/fa.yml b/modules/storages/config/locales/crowdin/fa.yml index 7b258d9059c..345e54afedd 100644 --- a/modules/storages/config/locales/crowdin/fa.yml +++ b/modules/storages/config/locales/crowdin/fa.yml @@ -279,6 +279,8 @@ fa: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ fa: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ fa: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/fi.yml b/modules/storages/config/locales/crowdin/fi.yml index aff63ffd958..d03517b3564 100644 --- a/modules/storages/config/locales/crowdin/fi.yml +++ b/modules/storages/config/locales/crowdin/fi.yml @@ -279,6 +279,8 @@ fi: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ fi: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ fi: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/fil.yml b/modules/storages/config/locales/crowdin/fil.yml index 260e7617dc2..e4313441255 100644 --- a/modules/storages/config/locales/crowdin/fil.yml +++ b/modules/storages/config/locales/crowdin/fil.yml @@ -279,6 +279,8 @@ fil: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ fil: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ fil: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/fr.yml b/modules/storages/config/locales/crowdin/fr.yml index d858daae69b..0bd06148587 100644 --- a/modules/storages/config/locales/crowdin/fr.yml +++ b/modules/storages/config/locales/crowdin/fr.yml @@ -279,6 +279,8 @@ fr: drive_contents: Contenu du lecteur files_request: Récupération des fichiers du dossier de l'équipe header: Dossiers de projets gérés automatiquement + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dépendance : dossiers d''équipe' team_folder_contents: Contenu du dossier de l'équipe team_folder_presence: Le dossier de l'équipe existe @@ -322,8 +324,10 @@ fr: nc_oauth_request_not_found: Le point de terminaison pour récupérer l'utilisateur actuellement connecté n'a pas été trouvé. Veuillez vérifier les journaux du serveur pour obtenir plus d'informations. nc_oauth_request_unauthorized: L'utilisateur actuel n'est pas autorisé à accéder à l'espace de stockage de fichiers distant. Veuillez consulter les journaux du serveur pour obtenir plus d'informations. nc_oauth_token_missing: OpenProject ne peut pas tester la communication au niveau utilisateur avec Nextcloud, car l'utilisateur n'a pas encore lié son compte Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Le dossier de l'équipe est introuvable. - nc_unexpected_content: Contenu inattendu trouvé dans le dossier d'équipe géré. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Le mot de passe de l'application configurée n'est pas valide. not_configured: La connexion n'a pas pu être validée. Veuillez d'abord terminer la configuration. od_client_cant_delete_folder: Le client rencontre des difficultés pour supprimer des dossiers. Veuillez consulter la documentation d'installation de votre espace de stockage. @@ -372,6 +376,7 @@ fr: failure: Certaines vérifications ont échoué et le système ne fonctionne pas comme prévu. success: Toutes les connexions et les systèmes fonctionnent comme prévu. warning: Certaines vérifications ont renvoyé un avertissement. Cela peut entraîner un comportement inattendu. + synced: 'Dernière synchronisation : %{datetime}' title: Rapport sur l'état de santé health_email_notifications: description_disabled: Les administrateurs ne recevront pas de mises à jour par e-mail lors des mises à jour importantes. diff --git a/modules/storages/config/locales/crowdin/he.yml b/modules/storages/config/locales/crowdin/he.yml index bdcb7832e4e..ef759a21e2d 100644 --- a/modules/storages/config/locales/crowdin/he.yml +++ b/modules/storages/config/locales/crowdin/he.yml @@ -279,6 +279,8 @@ he: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ he: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ he: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/hi.yml b/modules/storages/config/locales/crowdin/hi.yml index 48343bc1d5b..297c71b0cc3 100644 --- a/modules/storages/config/locales/crowdin/hi.yml +++ b/modules/storages/config/locales/crowdin/hi.yml @@ -279,6 +279,8 @@ hi: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ hi: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ hi: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/hr.yml b/modules/storages/config/locales/crowdin/hr.yml index 5b26f9ccc46..f10343005e9 100644 --- a/modules/storages/config/locales/crowdin/hr.yml +++ b/modules/storages/config/locales/crowdin/hr.yml @@ -279,6 +279,8 @@ hr: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -324,8 +326,10 @@ hr: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -374,6 +378,7 @@ hr: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/hu.yml b/modules/storages/config/locales/crowdin/hu.yml index f46bc6960d2..45366821369 100644 --- a/modules/storages/config/locales/crowdin/hu.yml +++ b/modules/storages/config/locales/crowdin/hu.yml @@ -279,6 +279,8 @@ hu: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ hu: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ hu: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/id.yml b/modules/storages/config/locales/crowdin/id.yml index d2ed1045168..41a4cd5d2b9 100644 --- a/modules/storages/config/locales/crowdin/id.yml +++ b/modules/storages/config/locales/crowdin/id.yml @@ -279,6 +279,8 @@ id: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -320,8 +322,10 @@ id: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -370,6 +374,7 @@ id: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/it.yml b/modules/storages/config/locales/crowdin/it.yml index 93567eeaa53..a8d4059080f 100644 --- a/modules/storages/config/locales/crowdin/it.yml +++ b/modules/storages/config/locales/crowdin/it.yml @@ -279,6 +279,8 @@ it: drive_contents: Contenuto dell'unità files_request: Recupero dei file delle cartelle di team header: Cartelle di progetto gestite automaticamente + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dipendenza: Cartelle di team' team_folder_contents: Contenuto della cartella di team team_folder_presence: La cartella di team esiste @@ -322,8 +324,10 @@ it: nc_oauth_request_not_found: L'endpoint per recuperare l'utente attualmente connesso non è stato trovato. Per ulteriori informazioni, consulta i log del server. nc_oauth_request_unauthorized: L'utente attuale non è autorizzato ad accedere all'archivio file remoto. Per ulteriori informazioni, consulta i log del server. nc_oauth_token_missing: OpenProject non può testare la comunicazione a livello utente con Nextcloud poiché l'utente non ha ancora collegato il proprio account Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Impossibile trovare la cartella di team. - nc_unexpected_content: Contenuto inatteso trovato nella cartella di team gestita. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: La password dell'app configurata non è valida. not_configured: Non è stato possibile verificare la connessione. Prima è necessario completare la configurazione. od_client_cant_delete_folder: Il cliente riscontra problemi con l'eliminazione delle cartelle. Consulta la documentazione di configurazione del tuo archivio. @@ -372,6 +376,7 @@ it: failure: Alcuni controlli non sono riusciti e il sistema non funziona come previsto. success: Tutte le connessioni e i sistemi funzionano come previsto. warning: Alcuni controlli hanno restituito un avviso. Questo può causare comportamenti imprevisti. + synced: 'Last sync: %{datetime}' title: Report sullo stato di salute health_email_notifications: description_disabled: Gli amministratori non riceveranno aggiornamenti via email quando ci sono aggiornamenti importanti. diff --git a/modules/storages/config/locales/crowdin/ja.yml b/modules/storages/config/locales/crowdin/ja.yml index 4708d197140..3b9839f81ab 100644 --- a/modules/storages/config/locales/crowdin/ja.yml +++ b/modules/storages/config/locales/crowdin/ja.yml @@ -279,6 +279,8 @@ ja: drive_contents: Drive content files_request: Fetching team folder files header: 自動的に管理されるプロジェクトフォルダ + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -320,8 +322,10 @@ ja: nc_oauth_request_not_found: 現在接続しているユーザーを取得するエンドポイントが見つかりませんでした。詳細については、サーバーのログを確認してください。 nc_oauth_request_unauthorized: 現在のユーザーにはリモートファイルストレージにアクセスする権限がありません。サーバーのログを確認してください。 nc_oauth_token_missing: OpenProject は、Nextcloudアカウントへのリンクがまだないため、Nextcloudとのユーザーレベルの通信をテストできません。 + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: 設定されているアプリのパスワードが無効です。 not_configured: 接続を検証できませんでした。先に設定を完了してください。 od_client_cant_delete_folder: クライアントがフォルダを削除できません。ストレージのセットアップドキュメントを確認してください。 @@ -370,6 +374,7 @@ ja: failure: いくつかのチェックに失敗し、システムが期待どおりに動作しません。 success: すべての接続とシステムは期待どおりに動作しています。 warning: いくつかのチェックが警告を返しました。これは予期しない動作につながる可能性があります。 + synced: 'Last sync: %{datetime}' title: 健康状態レポート health_email_notifications: description_disabled: 管理者は、重要なアップデートがあった場合、メールでアップデートを受け取ることはできません。 diff --git a/modules/storages/config/locales/crowdin/ka.yml b/modules/storages/config/locales/crowdin/ka.yml index c883721ba5a..c5fbcf72786 100644 --- a/modules/storages/config/locales/crowdin/ka.yml +++ b/modules/storages/config/locales/crowdin/ka.yml @@ -279,6 +279,8 @@ ka: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ ka: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ ka: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/kk.yml b/modules/storages/config/locales/crowdin/kk.yml index 531e32cca16..44e49d37233 100644 --- a/modules/storages/config/locales/crowdin/kk.yml +++ b/modules/storages/config/locales/crowdin/kk.yml @@ -279,6 +279,8 @@ kk: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ kk: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ kk: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ko.yml b/modules/storages/config/locales/crowdin/ko.yml index 3f79855017b..5740e8dfe55 100644 --- a/modules/storages/config/locales/crowdin/ko.yml +++ b/modules/storages/config/locales/crowdin/ko.yml @@ -279,6 +279,8 @@ ko: drive_contents: 드라이브 콘텐츠 files_request: 팀 폴더 파일 가져오기 header: 자동으로 관리되는 프로젝트 폴더 + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: '종속성: 팀 폴더' team_folder_contents: 팀 폴더 콘텐츠 team_folder_presence: 팀 폴더가 존재합니다 @@ -320,8 +322,10 @@ ko: nc_oauth_request_not_found: 현재 연결된 사용자를 가져올 엔드포인트를 찾을 수 없습니다. 자세한 내용은 서버 로그를 확인하세요. nc_oauth_request_unauthorized: 현재 사용자는 원격 파일 저장소에 액세스할 수 있는 권한이 없습니다. 자세한 내용은 서버 로그를 확인하세요. nc_oauth_token_missing: 사용자가 아직 Nextcloud 계정을 링크하지 않았기 때문에 OpenProject가 Nextcloud와의 사용자 수준 통신을 테스트할 수 없습니다. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: 팀 폴더를 찾을 수 없습니다. - nc_unexpected_content: 관리되는 팀 폴더에서 예기치 않은 콘텐츠가 발견되었습니다. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: 구성된 앱 암호가 잘못되었습니다. not_configured: 연결에 대한 유효성 검사를 할 수 없습니다. 먼저 구성을 완료하세요. od_client_cant_delete_folder: 클라이언트에서 폴더를 삭제하는 중에 문제가 발생했습니다. 저장소에 대한 설정 설명서를 확인하세요. @@ -370,6 +374,7 @@ ko: failure: 일부 검사가 실패하여 시스템이 예상대로 작동되지 않습니다. success: 모든 연결과 시스템이 예상대로 작동 중입니다. warning: 일부 검사에서 경고가 반환되었습니다. 이로 인해 예상치 못한 동작이 발생할 수 있습니다. + synced: 'Last sync: %{datetime}' title: 상태 보고서 health_email_notifications: description_disabled: 중요 업데이트가 있을 때 관리자에게 이메일로 업데이트가 전송되지 않습니다. diff --git a/modules/storages/config/locales/crowdin/lt.yml b/modules/storages/config/locales/crowdin/lt.yml index 2e3b9618829..8d2fffc5287 100644 --- a/modules/storages/config/locales/crowdin/lt.yml +++ b/modules/storages/config/locales/crowdin/lt.yml @@ -279,6 +279,8 @@ lt: drive_contents: Drive content files_request: Fetching team folder files header: Automatiškai valdomi projekto aplankai + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ lt: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ lt: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/lv.yml b/modules/storages/config/locales/crowdin/lv.yml index 093dec25b5c..df157562a29 100644 --- a/modules/storages/config/locales/crowdin/lv.yml +++ b/modules/storages/config/locales/crowdin/lv.yml @@ -279,6 +279,8 @@ lv: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -324,8 +326,10 @@ lv: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -374,6 +378,7 @@ lv: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/mn.yml b/modules/storages/config/locales/crowdin/mn.yml index 48e64819cfd..500878f5d56 100644 --- a/modules/storages/config/locales/crowdin/mn.yml +++ b/modules/storages/config/locales/crowdin/mn.yml @@ -279,6 +279,8 @@ mn: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ mn: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ mn: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ms.yml b/modules/storages/config/locales/crowdin/ms.yml index e1eee9dc10f..07c68083cb2 100644 --- a/modules/storages/config/locales/crowdin/ms.yml +++ b/modules/storages/config/locales/crowdin/ms.yml @@ -279,6 +279,8 @@ ms: drive_contents: Drive content files_request: Fetching team folder files header: Folder projek yang dikendalikan secara automatik + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -320,8 +322,10 @@ ms: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Kata laluan apl yang dikonfigurasikan adalah tidak sah. not_configured: Sambungan tidak dapat disahkan. Sila selesaikan konfigurasi dahulu. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -370,6 +374,7 @@ ms: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ne.yml b/modules/storages/config/locales/crowdin/ne.yml index 94d3120d062..12e1b811827 100644 --- a/modules/storages/config/locales/crowdin/ne.yml +++ b/modules/storages/config/locales/crowdin/ne.yml @@ -279,6 +279,8 @@ ne: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ ne: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ ne: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/nl.yml b/modules/storages/config/locales/crowdin/nl.yml index 3b6609aea4f..53118fc8189 100644 --- a/modules/storages/config/locales/crowdin/nl.yml +++ b/modules/storages/config/locales/crowdin/nl.yml @@ -279,6 +279,8 @@ nl: drive_contents: Drive content files_request: Fetching team folder files header: Automatisch beheerde projectmappen + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ nl: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: De verbinding kon niet gevalideerd worden. Voltooi eerst de configuratie. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ nl: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/no.yml b/modules/storages/config/locales/crowdin/no.yml index d661f246c74..d36b1352d19 100644 --- a/modules/storages/config/locales/crowdin/no.yml +++ b/modules/storages/config/locales/crowdin/no.yml @@ -279,6 +279,8 @@ drive_contents: Drive content files_request: Fetching team folder files header: Automatisk administrerte prosjektmapper + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/pl.yml b/modules/storages/config/locales/crowdin/pl.yml index 340b15a72d4..85cc52c569b 100644 --- a/modules/storages/config/locales/crowdin/pl.yml +++ b/modules/storages/config/locales/crowdin/pl.yml @@ -279,6 +279,8 @@ pl: drive_contents: Zawartość dysku files_request: Pobieranie plików folderu zespołu header: Automatycznie zarządzane foldery projektu + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Zależność: foldery zespołów' team_folder_contents: Zawartość folderu zespołu team_folder_presence: Folder zespołu istnieje @@ -326,8 +328,10 @@ pl: nc_oauth_request_not_found: Nie znaleziono punktu końcowego, z którego można pobrać informacje o aktualnie połączonym użytkowniku. Aby uzyskać więcej informacji, sprawdź dzienniki serwera. nc_oauth_request_unauthorized: Bieżący użytkownik nie ma uprawnień dostępu do zdalnego magazynu plików. Aby uzyskać więcej informacji, sprawdź dzienniki serwera. nc_oauth_token_missing: Aplikacja OpenProject nie może przetestować komunikacji z usługą Nextcloud na poziomie użytkownika, ponieważ użytkownik nie powiązał jeszcze swojego konta Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Nie można znaleźć folderu zespołu. - nc_unexpected_content: W folderze zarządzanego zespołu znaleziono nieoczekiwaną zawartość. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Skonfigurowane hasło aplikacji jest nieprawidłowe. not_configured: Nie można zweryfikować połączenia. Najpierw zakończ konfigurację. od_client_cant_delete_folder: Klient ma problemy z usunięciem folderów. Sprawdź dokumentację konfiguracji swojej pamięci masowej. @@ -376,6 +380,7 @@ pl: failure: Niektóre kontrole nie powiodły się i system nie działa zgodnie z oczekiwaniami. success: Wszystkie połączenia i systemy działają zgodnie z oczekiwaniami. warning: Niektóre kontrole zwróciły ostrzeżenie. Może to prowadzić do nieoczekiwanego sposobu działania. + synced: 'Last sync: %{datetime}' title: Raport o stanie health_email_notifications: description_disabled: Administratorzy nie będą otrzymywać aktualizacji pocztą elektroniczną, gdy pojawią się ważne aktualizacje. diff --git a/modules/storages/config/locales/crowdin/pt-BR.yml b/modules/storages/config/locales/crowdin/pt-BR.yml index 89796811996..c23f5735a9b 100644 --- a/modules/storages/config/locales/crowdin/pt-BR.yml +++ b/modules/storages/config/locales/crowdin/pt-BR.yml @@ -279,6 +279,8 @@ pt-BR: drive_contents: Conteúdo da unidade files_request: Buscando arquivos da pasta da equipe header: Pastas de projeto gerenciadas automaticamente + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependência: Pastas da equipe' team_folder_contents: Conteúdo da pasta da equipe team_folder_presence: A pasta da equipe existe @@ -322,8 +324,10 @@ pt-BR: nc_oauth_request_not_found: O endpoint para recuperar o usuário conectado não foi encontrado. Verifique os logs do servidor para mais detalhes. nc_oauth_request_unauthorized: O usuário atual não está autorizado a acessar o armazenamento remoto de arquivos. Verifique os logs do servidor para mais informações. nc_oauth_token_missing: O OpenProject não pode testar a comunicação do usuário com o Nextcloud, pois a conta do Nextcloud ainda não foi vinculada. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: A pasta da equipe não pôde ser localizada. - nc_unexpected_content: Conteúdo inesperado encontrado na pasta da equipe gerenciado. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: A senha configurada do aplicativo não é válida. not_configured: A conexão não pôde ser validada. Conclua a configuração primeiro. od_client_cant_delete_folder: O cliente está com dificuldades para excluir pastas. Verifique a documentação de configuração do seu armazenamento. @@ -372,6 +376,7 @@ pt-BR: failure: Alguns testes não passaram e o sistema não está funcionando corretamente. success: Todas as conexões e sistemas estão operando normalmente. warning: Alguns testes retornaram um alerta. Isso pode causar comportamentos inesperados. + synced: 'Last sync: %{datetime}' title: Relatório de status de integridade health_email_notifications: description_disabled: Os administradores não receberão atualizações por e-mail quando houver atualizações importantes. diff --git a/modules/storages/config/locales/crowdin/pt-PT.yml b/modules/storages/config/locales/crowdin/pt-PT.yml index c19fcc03323..e6c2356933a 100644 --- a/modules/storages/config/locales/crowdin/pt-PT.yml +++ b/modules/storages/config/locales/crowdin/pt-PT.yml @@ -279,6 +279,8 @@ pt-PT: drive_contents: Conteúdo da unidade files_request: A obter ficheiros da pasta de equipa header: Pastas do projeto geridas automaticamente + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependência: Pastas de equipa' team_folder_contents: Conteúdo da pasta de equipa team_folder_presence: A pasta de equipa existe @@ -322,8 +324,10 @@ pt-PT: nc_oauth_request_not_found: O terminal para o utilizador com sessão iniciada não foi encontrado. Consulte os registos do servidor para mais informações. nc_oauth_request_unauthorized: O utilizador atual não está autorizado a aceder ao armazenamento de ficheiros remoto. Verifique os registos do servidor para mais informações. nc_oauth_token_missing: O OpenProject não pode testar a comunicação de nível de utilizador com o Nextcloud uma vez que o utilizador ainda não associou a sua conta Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Não foi possível encontrar a pasta de equipa. - nc_unexpected_content: Conteúdo inesperado encontrado na pasta de equipa gerida. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: A palavra-passe da aplicação configurada é inválida. not_configured: Não foi possível validar a ligação.Termine, primeiro, a configuração. od_client_cant_delete_folder: O cliente está a ter problemas a eliminar pastas. Consulte a documentação de configuração para o seu armazenamento. @@ -372,6 +376,7 @@ pt-PT: failure: Algumas verificações não foram aprovadas e o sistema não funciona como esperado. success: Todas as ligações e sistemas estão a funcionar como esperado. warning: Algumas verificações foram devolvidas com um aviso. Isso pode resultar num comportamento inesperado. + synced: 'Last sync: %{datetime}' title: Relatório de estado de saúde health_email_notifications: description_disabled: Os administradores não receberão atualizações por e-mail quando houver atualizações importantes. diff --git a/modules/storages/config/locales/crowdin/ro.yml b/modules/storages/config/locales/crowdin/ro.yml index 80cff04813f..f28909c0e97 100644 --- a/modules/storages/config/locales/crowdin/ro.yml +++ b/modules/storages/config/locales/crowdin/ro.yml @@ -279,6 +279,8 @@ ro: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -324,8 +326,10 @@ ro: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: Utilizatorul curent nu este autorizat să acceseze spațiul de stocare de la distanță. Te rog să verifici jurnalele serverului pentru informații suplimentare. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -374,6 +378,7 @@ ro: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Raport privind starea de sănătate health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/ru.yml b/modules/storages/config/locales/crowdin/ru.yml index 1cc7b7c77f9..7e8a96aecee 100644 --- a/modules/storages/config/locales/crowdin/ru.yml +++ b/modules/storages/config/locales/crowdin/ru.yml @@ -279,6 +279,8 @@ ru: drive_contents: Содержимое диска files_request: Получение файлов папки команды header: Автоматически управляемые папки проекта + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Зависимость: папки команды' team_folder_contents: Содержимое папки команды team_folder_presence: Папка команды существует @@ -326,8 +328,10 @@ ru: nc_oauth_request_not_found: Конечная точка для получения данных о текущем подключенном пользователе не найдена. Пожалуйста, проверьте журналы сервера для получения дополнительной информации. nc_oauth_request_unauthorized: Текущий пользователь не авторизован для доступа к удаленному файловому хранилищу. Пожалуйста, проверьте журналы сервера для получения дополнительной информации. nc_oauth_token_missing: OpenProject не может протестировать пользовательскую связь с Nextcloud, так как пользователь еще не связал свою учетную запись Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Папка команды не найдена. - nc_unexpected_content: Непредвиденное содержимое найдено в папке команды. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Указанный пароль приложения неверен. not_configured: Соединение не удалось подтвердить. Пожалуйста, сначала завершите настройку. od_client_cant_delete_folder: У клиента возникли проблемы с удалением папок. Пожалуйста, проверьте документацию по конфигурации для вашего хранилища. @@ -376,6 +380,7 @@ ru: failure: Некоторые проверки не удались, и система работает не так, как ожидалось. success: Все соединения и системы работают, как и ожидалось. warning: Некоторые проверки вернули предупреждение. Это может привести к неожиданному поведению. + synced: 'Last sync: %{datetime}' title: Отчёт о состоянии хранилища health_email_notifications: description_disabled: Администраторы не будут получать обновления по электронной почте, когда выходят важные обновления. diff --git a/modules/storages/config/locales/crowdin/rw.yml b/modules/storages/config/locales/crowdin/rw.yml index 77291057820..1ec973eee78 100644 --- a/modules/storages/config/locales/crowdin/rw.yml +++ b/modules/storages/config/locales/crowdin/rw.yml @@ -279,6 +279,8 @@ rw: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ rw: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ rw: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/si.yml b/modules/storages/config/locales/crowdin/si.yml index 921673d4932..daca008ee39 100644 --- a/modules/storages/config/locales/crowdin/si.yml +++ b/modules/storages/config/locales/crowdin/si.yml @@ -279,6 +279,8 @@ si: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ si: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ si: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/sk.yml b/modules/storages/config/locales/crowdin/sk.yml index d5a202cefc8..f3d4b5a32ab 100644 --- a/modules/storages/config/locales/crowdin/sk.yml +++ b/modules/storages/config/locales/crowdin/sk.yml @@ -279,6 +279,8 @@ sk: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ sk: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ sk: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/sl.yml b/modules/storages/config/locales/crowdin/sl.yml index 1e5c6b58768..1b460882ece 100644 --- a/modules/storages/config/locales/crowdin/sl.yml +++ b/modules/storages/config/locales/crowdin/sl.yml @@ -279,6 +279,8 @@ sl: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -326,8 +328,10 @@ sl: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -376,6 +380,7 @@ sl: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/sr.yml b/modules/storages/config/locales/crowdin/sr.yml index 8976b18ec45..304c7d4510e 100644 --- a/modules/storages/config/locales/crowdin/sr.yml +++ b/modules/storages/config/locales/crowdin/sr.yml @@ -279,6 +279,8 @@ sr: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -324,8 +326,10 @@ sr: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -374,6 +378,7 @@ sr: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/sv.yml b/modules/storages/config/locales/crowdin/sv.yml index 20189052160..fa3373bca6d 100644 --- a/modules/storages/config/locales/crowdin/sv.yml +++ b/modules/storages/config/locales/crowdin/sv.yml @@ -279,6 +279,8 @@ sv: drive_contents: Diskinnehåll files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ sv: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ sv: failure: Vissa kontroller misslyckades och systemet fungerar inte som förväntat. success: Alla anslutningar och system fungerar som förväntat. warning: Vissa kontroller gav tillbaka en varning. Detta kan leda till oväntat beteende. + synced: 'Last sync: %{datetime}' title: Rapport om hälsostatus health_email_notifications: description_disabled: Administratörer kommer inte att få uppdateringar via e-post när det finns viktiga uppdateringar. diff --git a/modules/storages/config/locales/crowdin/th.yml b/modules/storages/config/locales/crowdin/th.yml index e8840da033c..87735d3236c 100644 --- a/modules/storages/config/locales/crowdin/th.yml +++ b/modules/storages/config/locales/crowdin/th.yml @@ -279,6 +279,8 @@ th: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -320,8 +322,10 @@ th: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -370,6 +374,7 @@ th: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/tr.yml b/modules/storages/config/locales/crowdin/tr.yml index ec1eb6a9f7f..723f543f3c3 100644 --- a/modules/storages/config/locales/crowdin/tr.yml +++ b/modules/storages/config/locales/crowdin/tr.yml @@ -279,6 +279,8 @@ tr: drive_contents: Sücürü içeriği files_request: Takım klasöründeki dosyaları getir header: Otomatik olarak yönetilen proje klasörleri + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Bağımlılık: Ekip Klasörleri' team_folder_contents: Ekip klasörü içeriği team_folder_presence: Ekip klasörü mevcut @@ -322,8 +324,10 @@ tr: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Ekip klasörü bulunamadı. - nc_unexpected_content: Yönetilen ekip klasöründe beklenmeyen içerik bulundu. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Yapılandırılan uygulama parolası geçersiz. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ tr: failure: Bazı kontroller başarısız oldu ve sistem beklendiği gibi çalışmıyor. success: Tüm bağlantılar ve sistemler beklendiği gibi çalışıyor. warning: Bazı kontroller bir uyarı döndürdü. Bu beklenmedik davranışlara yol açabilir. + synced: 'Last sync: %{datetime}' title: Sağlık durumu raporu health_email_notifications: description_disabled: Önemli güncellemeler olduğunda yöneticiler e-posta ile güncelleme almayacaktır. diff --git a/modules/storages/config/locales/crowdin/uk.yml b/modules/storages/config/locales/crowdin/uk.yml index 9a8cd28b187..8a7822561e2 100644 --- a/modules/storages/config/locales/crowdin/uk.yml +++ b/modules/storages/config/locales/crowdin/uk.yml @@ -279,6 +279,8 @@ uk: drive_contents: Вміст диска files_request: Отримання файлів із папок команди header: Папки проєкту з автоматичним керуванням + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Залежність: папки команди' team_folder_contents: Вміст папки команди team_folder_presence: Папка команди існує @@ -326,8 +328,10 @@ uk: nc_oauth_request_not_found: Кінцеву точку для отримання підключеного зараз користувача не знайдено. Щоб дізнатися більше, перевірте журнали сервера. nc_oauth_request_unauthorized: Поточний користувач не має дозволу на доступ до віддаленого файлового сховища. Щоб дізнатися більше, перевірте журнали сервера. nc_oauth_token_missing: OpenProject не може перевірити з’єднання на рівні користувача з Nextcloud, оскільки користувач досі не зв’язав свій обліковий запис Nextcloud. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Папку команди не знайдено. - nc_unexpected_content: У папці керованої команди знайдено неочікуваний вміст. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Налаштований пароль застосунку недійсний. not_configured: Не вдалося перевірити підключення. Спочатку налаштуйте конфігурацію. od_client_cant_delete_folder: Клієнту не вдалося видалити папки. Ознайомтеся з документацією щодо конфігурації для свого сховища. @@ -376,6 +380,7 @@ uk: failure: Деякі перевірки не пройдено, і система працює неналежним чином. success: Усі підключення й системи працють належним чином. warning: Деякі перевірки завершилися з попередженням. Це може призвести до неочікуваної поведінки. + synced: 'Last sync: %{datetime}' title: Звіт про стан справності health_email_notifications: description_disabled: Адміністратори не отримуватимуть електронні листи про важливі оновлення. diff --git a/modules/storages/config/locales/crowdin/uz.yml b/modules/storages/config/locales/crowdin/uz.yml index e9dd7686422..4eae84ecff5 100644 --- a/modules/storages/config/locales/crowdin/uz.yml +++ b/modules/storages/config/locales/crowdin/uz.yml @@ -279,6 +279,8 @@ uz: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -322,8 +324,10 @@ uz: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -372,6 +376,7 @@ uz: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/config/locales/crowdin/vi.yml b/modules/storages/config/locales/crowdin/vi.yml index 215249d05c8..597521e54c3 100644 --- a/modules/storages/config/locales/crowdin/vi.yml +++ b/modules/storages/config/locales/crowdin/vi.yml @@ -279,6 +279,8 @@ vi: drive_contents: Nội dung ổ đĩa files_request: Tải xuống các tệp trong thư mục của nhóm header: Thư mục dự án được quản lý tự động + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Phụ thuộc: Thư mục nhóm' team_folder_contents: Nội dung thư mục của nhóm team_folder_presence: Thư mục nhóm đã tồn tại @@ -320,8 +322,10 @@ vi: nc_oauth_request_not_found: Không tìm thấy điểm cuối để tìm nạp người dùng hiện được kết nối. Vui lòng kiểm tra nhật ký máy chủ để biết thêm thông tin. nc_oauth_request_unauthorized: Người dùng hiện tại không được phép truy cập vào bộ lưu trữ tệp từ xa. Vui lòng kiểm tra nhật ký máy chủ để biết thêm thông tin. nc_oauth_token_missing: OpenProject không thể kiểm tra giao tiếp ở cấp độ người dùng với Nextcloud vì người dùng chưa liên kết tài khoản Nextcloud của họ. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: Thư mục nhóm không thể được tìm thấy. - nc_unexpected_content: Nội dung không mong đợi được tìm thấy trong thư mục của nhóm được quản lý. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: Mật khẩu ứng dụng đã định cấu hình không hợp lệ. not_configured: Kết nối không thể được xác nhận. Vui lòng hoàn tất cấu hình trước. od_client_cant_delete_folder: Máy khách đang gặp sự cố khi xóa các thư mục. Vui lòng kiểm tra tài liệu thiết lập cho bộ nhớ của bạn. @@ -370,6 +374,7 @@ vi: failure: Một số lần kiểm tra không thành công và hệ thống không hoạt động như mong đợi. success: Tất cả các kết nối và hệ thống đều hoạt động như mong đợi. warning: Một số kiểm tra trả lại một cảnh báo. Điều này có thể dẫn đến hành vi không mong muốn. + synced: 'Last sync: %{datetime}' title: Báo cáo tình trạng sức khoẻ health_email_notifications: description_disabled: Quản trị viên sẽ không nhận được thông tin cập nhật qua email khi có thông tin cập nhật quan trọng. diff --git a/modules/storages/config/locales/crowdin/zh-CN.yml b/modules/storages/config/locales/crowdin/zh-CN.yml index e227630b5e2..3f3410abbab 100644 --- a/modules/storages/config/locales/crowdin/zh-CN.yml +++ b/modules/storages/config/locales/crowdin/zh-CN.yml @@ -279,6 +279,8 @@ zh-CN: drive_contents: 驱动器内容 files_request: 正在获取团队文件夹文件 header: 自动托管的项目文件夹 + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: '依赖关系:团队文件夹' team_folder_contents: 团队文件夹内容 team_folder_presence: 团队文件夹已存在 @@ -320,8 +322,10 @@ zh-CN: nc_oauth_request_not_found: 未找到获取当前连接用户的端点。请检查服务器日志以获取更多信息。 nc_oauth_request_unauthorized: 当前用户无权访问远程文件存储。请检查服务器日志以获取更多信息。 nc_oauth_token_missing: OpenProject 无法测试用户与 Nextcloud 之间的通信,因为用户尚未链接他们的 Nextcloud 帐户。 + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: 找不到该团队文件夹。 - nc_unexpected_content: 在受管理的团队文件夹中找到非预期内容。 + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: 已配置的应用密码无效。 not_configured: 无法验证连接。请先完成配置。 od_client_cant_delete_folder: 客户端在删除文件夹时遇到问题。请检查您的存储的设置文档。 @@ -370,6 +374,7 @@ zh-CN: failure: 有些检查失败,系统无法按预期运行。 success: 所有连接和系统都按预期运行。 warning: 某些检查返回了警告。这可能导致异常行为。 + synced: 'Last sync: %{datetime}' title: 健康状况报告 health_email_notifications: description_disabled: 当有重要更新时,管理员将不会通过电子邮件收到更新提醒。 diff --git a/modules/storages/config/locales/crowdin/zh-TW.yml b/modules/storages/config/locales/crowdin/zh-TW.yml index c2e5cb16b0f..78788b4ad73 100644 --- a/modules/storages/config/locales/crowdin/zh-TW.yml +++ b/modules/storages/config/locales/crowdin/zh-TW.yml @@ -279,6 +279,8 @@ zh-TW: drive_contents: 磁碟內容 files_request: 擷取團隊資料夾檔案 header: 自動管理的專案資料夾 + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: '依賴性:團隊文件夾' team_folder_contents: 團隊資料夾內容 team_folder_presence: 團隊資料夾存在 @@ -320,8 +322,10 @@ zh-TW: nc_oauth_request_not_found: 無法找到取得目前連線使用者的端點。請檢查伺服器日誌以取得更多資訊。 nc_oauth_request_unauthorized: 當前使用者未獲授權存取遠端檔案儲存空間。請檢查伺服器日誌以取得進一步資訊。 nc_oauth_token_missing: OpenProject 無法測試與 Nextcloud 的用戶級連線,因為沒有當前用戶的令牌(Token)。 + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: 找不到團隊資料夾。 - nc_unexpected_content: 在管理的團隊資料夾中發現意外內容。 + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: 設定的應用程式密碼無效。 not_configured: 連線無法驗證。請先完成設定。 od_client_cant_delete_folder: 用戶刪除資料夾失敗,請檢查儲存空間的文件設定。 @@ -370,6 +374,7 @@ zh-TW: failure: 部分檢查失敗,系統無法如預期運作。 success: 所有連線與系統均如預期運作。 warning: 某些檢查返回警告,可能會引發預期外的行為。 + synced: 'Last sync: %{datetime}' title: 健康狀況報告 health_email_notifications: description_disabled: 當有重要更新時,管理員將不會透過電子郵件收到更新。 diff --git a/modules/storages/config/locales/en.yml b/modules/storages/config/locales/en.yml index 495e3d32266..aa907a61bfc 100644 --- a/modules/storages/config/locales/en.yml +++ b/modules/storages/config/locales/en.yml @@ -280,6 +280,8 @@ en: drive_contents: Drive content files_request: Fetching team folder files header: Automatically managed project folders + project_folders_exist: Project folders exist + project_folders_linked: Project folders linked team_folder_app: 'Dependency: Team Folders' team_folder_contents: Team folder content team_folder_presence: Team folder exists @@ -323,8 +325,10 @@ en: nc_oauth_request_not_found: The endpoint to fetch the currently connected user was not found. Please check the server logs for further information. nc_oauth_request_unauthorized: The current user isn't authorized to access the remote file storage. Please check the server logs for further information. nc_oauth_token_missing: OpenProject cannot test the user level communication with Nextcloud as the user did not yet link their Nextcloud account. + nc_project_folder_missing: The previously created project folder for project "%{project}" could not be found. nc_team_folder_not_found: The team folder could not be found. - nc_unexpected_content: Unexpected content found in the managed team folder. + nc_unexpected_files: 'Unexpected files found in the managed team folder. For example: %{sample}' + nc_unlinked_project_folders: Not all project folders have been created yet (%{actual} / %{expected}). This can indicate errors during the AMPF background synchronization. nc_userless_access_denied: The configured app password is invalid. not_configured: The connection could not be validated. Please finish configuration first. od_client_cant_delete_folder: The client is having trouble deleting folders. Please check the setup documentation for your storage. @@ -373,6 +377,7 @@ en: failure: Some checks failed and the system does not work as expected. success: All connections and systems are working as expected. warning: Some checks returned a warning. This can lead to unexpected behaviour. + synced: 'Last sync: %{datetime}' title: Health status report health_email_notifications: description_disabled: Admins will not receive updates by email when there are important updates. diff --git a/modules/storages/spec/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator_spec.rb b/modules/storages/spec/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator_spec.rb index b74411e0d55..bb307442214 100644 --- a/modules/storages/spec/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator_spec.rb +++ b/modules/storages/spec/common/storages/adapters/providers/nextcloud/validators/ampf_configuration_validator_spec.rb @@ -45,9 +45,14 @@ module Storages let(:files_response) do Success(Results::StorageFileCollection.new( - files: [Results::StorageFile.new(id: project_folder_id, - name: project_storage.managed_project_folder_name)], - parent: Results::StorageFile.new(id: "root", name: "root"), + files: [ + Results::StorageFile.new( + id: project_folder_id, + name: project_storage.managed_project_folder_name, + mime_type: "application/x-op-directory" + ) + ], + parent: Results::StorageFile.new(id: "root", name: "root", mime_type: "application/x-op-directory"), ancestors: [] )) end @@ -87,7 +92,7 @@ module Storages allow(subject).to receive(:nextcloud_dependencies).and_return(absurd_version) results = validator.call - expect(results[:team_folder_app]).to be_a_failure + expect(results[:team_folder_app]).to be_a_warning expect(results[:team_folder_app].code).to eq(:nc_dependency_version_mismatch) expect(results[:team_folder_app].context[:dependency]).to eq("Team Folders") end @@ -108,7 +113,7 @@ module Storages results = validator.call states = results.tally - expect(states).to eq({ success: 2, failure: 1, skipped: 2 }) + expect(states).to eq({ success: 2, failure: 1, skipped: 4 }) expect(results[:userless_access]).to be_failure expect(results[:userless_access].code).to eq(:nc_userless_access_denied) end @@ -144,10 +149,14 @@ module Storages let(:files_response) do Success(Results::StorageFileCollection.new( files: [ - Results::StorageFile.new(id: project_folder_id, name: "I am your father"), + Results::StorageFile.new( + id: project_folder_id, + name: "I am your father", + mime_type: "application/x-op-directory" + ), Results::StorageFile.new(id: "noooooooooo", name: "testimony_of_luke_skywalker.md") ], - parent: Results::StorageFile.new(id: "root", name: "root"), + parent: Results::StorageFile.new(id: "root", name: "root", mime_type: "application/x-op-directory"), ancestors: [] )) end @@ -156,7 +165,43 @@ module Storages results = validator.call expect(results[:team_folder_contents]).to be_a_warning - expect(results[:team_folder_contents].code).to eq(:nc_unexpected_content) + expect(results[:team_folder_contents].code).to eq(:nc_unexpected_files) + end + end + + context "if the files request does not return a project folder" do + let(:files_response) do + Success(Results::StorageFileCollection.new( + files: [ + Results::StorageFile.new( + id: "13#{project_folder_id}37", + name: project_storage.managed_project_folder_name, # name matches, but ID is different + mime_type: "application/x-op-directory" + ) + ], + parent: Results::StorageFile.new(id: "root", name: "root", mime_type: "application/x-op-directory"), + ancestors: [] + )) + end + + it "shows a failure about a missing project folder" do + results = validator.call + + expect(results[:project_folders_exist]).to be_a_failure + expect(results[:project_folders_exist].code).to eq(:nc_project_folder_missing) + end + end + + context "when an AMPF project storage has no project folder yet" do + let!(:project_storage_two) do + create(:project_storage, :as_automatically_managed, project_folder_id: "", storage:, project: create(:project)) + end + + it "warns the user about a missing project folder link" do + results = validator.call + + expect(results[:project_folders_linked]).to be_a_warning + expect(results[:project_folders_linked].code).to eq(:nc_unlinked_project_folders) end end diff --git a/modules/storages/spec/components/storages/admin/side_panel/health_notifications_component_spec.rb b/modules/storages/spec/components/storages/admin/side_panel/health_notifications_component_spec.rb index 7cf678a7f50..c3dba9cb762 100644 --- a/modules/storages/spec/components/storages/admin/side_panel/health_notifications_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/side_panel/health_notifications_component_spec.rb @@ -58,7 +58,7 @@ RSpec.describe Storages::Admin::SidePanel::HealthNotificationsComponent, type: : it "shows a healthy status" do expect(page).to have_test_selector("storage-health-status", text: "Healthy") - expect(page).to have_test_selector("storage-health-checked-at", text: "Last check: 11/28/2023 01:02 AM") + expect(page).to have_test_selector("storage-health-checked-at", text: "Last sync: 11/28/2023 01:02 AM") end end diff --git a/modules/storages/spec/services/storages/nextcloud_managed_folder_create_service_spec.rb b/modules/storages/spec/services/storages/nextcloud_managed_folder_create_service_spec.rb index b021a82ed74..ff0f92e9dfd 100644 --- a/modules/storages/spec/services/storages/nextcloud_managed_folder_create_service_spec.rb +++ b/modules/storages/spec/services/storages/nextcloud_managed_folder_create_service_spec.rb @@ -278,7 +278,7 @@ module Storages folder_name: project_storage.managed_project_folder_path, parent_location: "/")) ensure - delete_folder(already_existing_folder.id) + delete_folder(already_existing_folder.id) if already_existing_folder end it "logs the occurrence", vcr: "nextcloud/sync_service_creation_fail" do @@ -292,7 +292,7 @@ module Storages parent_location: "/", data: { body: String, status: 405 }) ensure - delete_folder(already_existing_folder.id) + delete_folder(already_existing_folder.id) if already_existing_folder end end end diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/sync_service_creation_fail.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/sync_service_creation_fail.yml index 4bd712809a2..d70db279126 100644 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/sync_service_creation_fail.yml +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/sync_service_creation_fail.yml @@ -7,14 +7,14 @@ http_interactions: encoding: US-ASCII string: '' headers: - Authorization: - - Basic User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic response: status: code: 201 @@ -25,36 +25,43 @@ http_interactions: Content-Type: - text/html; charset=UTF-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:32 GMT Oc-Fileid: - - 00000662ocxxq957y92g + - 00002024ocm4e2tlfbl8 Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=6a4dc7084fa34a1711338f7f745464b6; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=K37QVOPW03YQiLauKSCZ5bzqy2sAwGsWIjAladNMAPdbEUycG2mYyY48mNviGLBO4X%2FKYR9XS8soFfzG1hKY3iKgFLBPgf8ixPiF%2FwOWDIWessD0Dc0fcuR7jhG8XLl4; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=6a4dc7084fa34a1711338f7f745464b6; + - ocm4e2tlfbl8=9ced57dc382a1937105a796dc48373d5; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=xCM7H1MPWHUQ9svGpIX1ENOTuqDxba4cJ73gorZMeCAoNliMGazf8GlztbkkXzle25p1INDVq7uBRlwr%2Fh1uAzTo9%2Fh6eKfX8Eznks4WhGd2nQiQGD%2FBZ%2BfgpgfIpmFI; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=9ced57dc382a1937105a796dc48373d5; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=6a4dc7084fa34a1711338f7f745464b6; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=6a4dc7084fa34a1711338f7f745464b6; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=3b15dffb9b1fc55521d02f47ab6a7911; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=9ced57dc382a1937105a796dc48373d5; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=9ced57dc382a1937105a796dc48373d5; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=bc4ea7c8496f66a2a04f25e6626c8945; path=/; secure; HttpOnly; SameSite=Lax X-Content-Type-Options: - nosniff X-Debug-Token: - - TKED0ckv35pd0eMqME69 + - cIxk9DlRUtUzULVYTFr5 X-Frame-Options: - SAMEORIGIN X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Request-Id: - - TKED0ckv35pd0eMqME69 + - cIxk9DlRUtUzULVYTFr5 X-Robots-Tag: - noindex, nofollow X-Xss-Protection: @@ -64,7 +71,7 @@ http_interactions: body: encoding: UTF-8 string: '' - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: method: propfind uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%5BSample%5D%20Project%20Name%20%7C%20Ehuu%20(-273) @@ -76,26 +83,27 @@ http_interactions: + headers: - Authorization: - - Basic - Depth: - - '1' User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic + Depth: + - '1' Content-Type: - application/xml; charset=utf-8 Content-Length: - - '229' + - '253' response: status: code: 207 @@ -108,51 +116,58 @@ http_interactions: Content-Type: - application/xml; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:33 GMT Dav: - 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, - nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar + nc-paginate, nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=1efaad59ce5f6f27b82899def8495a31; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=0cI%2FAzxfTeFPoI7SkSsfloFTyFgmEEqDzBHWdBwHqsAnbPYJ8npvS6PwARoA0Wt8NoLocl6vTNTPbkNL5fWKAgX10MKdf32S3GB5%2BqDZHdYeAzJtywr5i6n7p6DZFZdQ; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=1efaad59ce5f6f27b82899def8495a31; + - ocm4e2tlfbl8=c1eb0e209a2fedfca200a48a31413926; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=4WwizmCytpd4ANmUKDZnXMWnhA8%2FDuZQEuyiBnSaG3MmfbiVvhxELrIfvpv7lHaQQlo90Kn5yHdNdytpdmRjzfdsOwRvO45VY6oeTdwGUk6Eahc6ov8XmuerVt5PT61o; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=c1eb0e209a2fedfca200a48a31413926; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=1efaad59ce5f6f27b82899def8495a31; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=1efaad59ce5f6f27b82899def8495a31; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=c20f161bb9618d09e940914a6f72b9c1; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=c1eb0e209a2fedfca200a48a31413926; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=c1eb0e209a2fedfca200a48a31413926; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=219456568949b1d9803eb65e97da6fa8; path=/; secure; HttpOnly; SameSite=Lax Vary: - Brief,Prefer X-Content-Type-Options: - nosniff X-Debug-Token: - - mRZbsL7FCXqJOt8WKx71 + - 59xncmhYi4onMNRQPUHG X-Frame-Options: - SAMEORIGIN X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Request-Id: - - mRZbsL7FCXqJOt8WKx71 + - 59xncmhYi4onMNRQPUHG X-Robots-Tag: - noindex, nofollow X-Xss-Protection: - 1; mode=block Content-Length: - - '360' + - '388' body: encoding: UTF-8 string: | - /remote.php/dav/files/OpenProject/OpenProject/%5bSample%5d%20Project%20Name%20%7c%20Ehuu%20(-273)/6620Tue, 21 Jan 2025 17:09:16 GMTRMGDNVCKOpenProjectHTTP/1.1 200 OK - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + /remote.php/dav/files/OpenProject/OpenProject/%5bSample%5d%20Project%20Name%20%7c%20Ehuu%20(-273)/20240Thu, 12 Mar 2026 07:59:33 GMTRMGDNVCKOpenProjectHTTP/1.1 200 OKHTTP/1.1 404 Not Found + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: method: propfind uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject @@ -167,16 +182,16 @@ http_interactions: headers: - Authorization: - - Basic - Depth: - - '1' User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic + Depth: + - '1' Content-Type: - application/xml; charset=utf-8 Content-Length: @@ -193,68 +208,75 @@ http_interactions: Content-Type: - application/xml; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:33 GMT Dav: - 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, - nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar + nc-paginate, nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=08e94660fca905807cab1390b0a1c934; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=fUkxnNLKCGS9E8%2Fc%2BnBM%2F1hcqdng1h304r%2FNDeKHynYjMAvDonyVO6H%2FoYFUxr2WoBJViv6W%2Bfa2TnRUp019FAKNHGEXK03tSFoabUUjvapeX%2BykK7D28etDGyyq12UV; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=08e94660fca905807cab1390b0a1c934; + - ocm4e2tlfbl8=710a8cadf1143561287817e5f46c0c1a; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=%2B6RHdJ3uVMbvZUVgCUwVZfERvhs5hYVJgh3Zy3SbxYLIJ99fAzKllEstSVWwOpD9ANoW5ufPgvJvor5I8%2FGJGQ6Se1T9%2FSz1ONGeI1FvojWeP4lpYxdLTVz5GoYHo1gg; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=710a8cadf1143561287817e5f46c0c1a; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=08e94660fca905807cab1390b0a1c934; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=08e94660fca905807cab1390b0a1c934; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=f60c91114e2d165346c8c9b70a133816; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=710a8cadf1143561287817e5f46c0c1a; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=710a8cadf1143561287817e5f46c0c1a; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a8e383cd826be279aee92cde73e76122; path=/; secure; HttpOnly; SameSite=Lax Vary: - Brief,Prefer X-Content-Type-Options: - nosniff X-Debug-Token: - - yBFwfleC9ZbljVcYBw7g + - LmNdBdUGBgzQwwu72rlF X-Frame-Options: - SAMEORIGIN X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Request-Id: - - yBFwfleC9ZbljVcYBw7g + - LmNdBdUGBgzQwwu72rlF X-Robots-Tag: - noindex, nofollow X-Xss-Protection: - 1; mode=block Content-Length: - - '466' + - '735' body: encoding: UTF-8 string: | - /remote.php/dav/files/OpenProject/OpenProject/103groupOpenProjectOpenProject311userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/Demo%20project%20(1)/180groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/%5bdev%5d%20Empty%20(3)/181groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/Projectify%20(8)/204groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/%5bSample%5d%20Project%20Name%20%7c%20Ehuu%20(-273)/662HTTP/1.1 200 OKHTTP/1.1 404 Not Found - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + /remote.php/dav/files/OpenProject/OpenProject/219groupOpenProjectOpenProject311userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/BLubb_%20I%20did%20it%20again%21%20(9)/1699groupOpenProjectOpenProject310user43ec7cf16becca5aeb0268d604d8577930d6904cb0d8b56799fb514a910c52b9Keycloak Admin3131userOpenProjectOpenProject3131useradminKeycloak Admin3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/Demo%20project%20(1)/2022groupOpenProjectOpenProject310user43ec7cf16becca5aeb0268d604d8577930d6904cb0d8b56799fb514a910c52b9Keycloak Admin3131userOpenProjectOpenProject3131useradminKeycloak Admin3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/Private%20Wurst%20(8)/1600groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/Scrum%20project%20(2)/2023groupOpenProjectOpenProject310user43ec7cf16becca5aeb0268d604d8577930d6904cb0d8b56799fb514a910c52b9Keycloak Admin3131userOpenProjectOpenProject3131useradminKeycloak Admin3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/%5bSample%5d%20Project%20Name%20%7c%20Ehuu%20(-273)/2024HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/dav/files/OpenProject/OpenProject/%5bdev%5d%20Custom%20fields%20(7)/1014groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/%5bdev%5d%20Work%20package%20sharing%20(4)/686groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/bar.txt1888groupOpenProjectOpenProject310userOpenProjectOpenProject3131HTTP/1.1 200 OK/remote.php/dav/files/OpenProject/OpenProject/existing-sub-folder%20(3187)/1920groupOpenProjectOpenProject310user43ec7cf16becca5aeb0268d604d8577930d6904cb0d8b56799fb514a910c52b9Keycloak Admin3131userOpenProjectOpenProject3131useradminKeycloak Admin3131HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: method: get - uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/103 + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/219 body: encoding: US-ASCII string: '' headers: - Authorization: - - Basic - Ocs-Apirequest: - - 'true' + User-Agent: + - OpenProject 17.2.1 HTTPX Client Accept: - application/json - User-Agent: - - httpx.rb/1.4.0 Accept-Encoding: - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' response: status: code: 200 @@ -269,7 +291,7 @@ http_interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:33 GMT Feature-Policy: - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none' @@ -278,15 +300,22 @@ http_interactions: Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=11debc91718deb3262ad1be585e1c9bc; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=J4kItkpIeE83mfet%2FwRBlIRv3eviW27uajC%2B0KeL%2B5u6lvcJbq1kTPybpnJnldDDAufgdKB%2BR8wIlhY7BfnDXQMsk9x7NjQ76Sgd6e0XXzt%2FcTow5xLMLQ83iBj9KhOg; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=11debc91718deb3262ad1be585e1c9bc; + - ocm4e2tlfbl8=21f5a25792585ce3d8a62e1c7a60bd88; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=rszWoVwbyy%2F%2BZWJS5AoEFwQn%2FC0n82uv7GJz5ujVK6hO1kId31zP3SzOxdKgWJUmobzcZNbDRQt8W2yEUNUxWzHQSnc5Z6HIAynAUCCU%2BCVbiTzf3iBkIg8wCgELGAlF; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=21f5a25792585ce3d8a62e1c7a60bd88; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=11debc91718deb3262ad1be585e1c9bc; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=11debc91718deb3262ad1be585e1c9bc; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=1a7d4c8f29f0c3f4e90abcac3fc820f0; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=21f5a25792585ce3d8a62e1c7a60bd88; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=21f5a25792585ce3d8a62e1c7a60bd88; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=d8956ae8abc2eb6ec2e111eebab80561; path=/; secure; HttpOnly; SameSite=Lax X-Content-Type-Options: - nosniff @@ -295,9 +324,9 @@ http_interactions: X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Request-Id: - - BivQOQFKIC2m8IfSs2c8 + - wFG3z5i9a5J458SLzo2n X-Robots-Tag: - noindex, nofollow X-Xss-Protection: @@ -306,8 +335,8 @@ http_interactions: - '251' body: encoding: UTF-8 - string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":103,"name":"OpenProject","mtime":1737479356,"ctime":0,"mimetype":"application\/x-op-directory","size":90335,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":null,"modifier_id":null,"dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/"}}}' - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":219,"name":"OpenProject","mtime":1773302373,"ctime":0,"mimetype":"application\/x-op-directory","size":259868,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":null,"modifier_id":null,"dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: method: proppatch uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject @@ -336,14 +365,14 @@ http_interactions: headers: - Authorization: - - Basic User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic Content-Type: - application/xml; charset=utf-8 Content-Length: @@ -358,36 +387,43 @@ http_interactions: Content-Type: - application/xml; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:33 GMT Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=97e948ccc8c4f318b9f4c52631d31ba7; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=XDlYwKiczit1OtQACBXsc3bnFR6nky%2F7mNTzVL4q204aRsDDGlIeNguLKacGYB71CjkaCf%2F9jzpmJ2AeJkQITPlt6mpFVp7Kw3nLRvjKvqA555q7ZLXVbmdE64nEllzt; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=97e948ccc8c4f318b9f4c52631d31ba7; + - ocm4e2tlfbl8=a3f3758caa98839522ccb69e91fe23f3; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=%2B74YzZ1nUU5j%2BbtRZyIJ1xSGN3xruXQjmc9Qgoxu%2BPv7iHSOWiHhgkDDrPnWGj4995zoRhc8iYq8odHWEY5bLVgQ1GbNyfhEcIdRLN1Ic%2BeR8QhpP1EkvT2SDBaj8KT3; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a3f3758caa98839522ccb69e91fe23f3; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=97e948ccc8c4f318b9f4c52631d31ba7; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=97e948ccc8c4f318b9f4c52631d31ba7; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=9a2083955ef2dcfc1ee7eb7a33c89ba9; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=a3f3758caa98839522ccb69e91fe23f3; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=a3f3758caa98839522ccb69e91fe23f3; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a174236fba2b66de5e35afabde5d26fd; path=/; secure; HttpOnly; SameSite=Lax Vary: - Brief,Prefer X-Content-Type-Options: - nosniff X-Debug-Token: - - yn94gj7cWhPnFyK6VCFB + - FlswueZOBawCUfczOirF X-Frame-Options: - SAMEORIGIN X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Request-Id: - - yn94gj7cWhPnFyK6VCFB + - FlswueZOBawCUfczOirF X-Robots-Tag: - noindex, nofollow X-Xss-Protection: @@ -399,7 +435,7 @@ http_interactions: string: | /remote.php/dav/files/OpenProject/OpenProjectHTTP/1.1 200 OK - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: method: mkcol uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%5BSample%5D%20Project%20Name%20%7C%20Ehuu%20(-273) @@ -407,14 +443,14 @@ http_interactions: encoding: US-ASCII string: '' headers: - Authorization: - - Basic User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic response: status: code: 405 @@ -423,28 +459,32 @@ http_interactions: Allow: - OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT Content-Security-Policy: - - 'default-src ''none'';base-uri ''none'';manifest-src ''self'';script-src ''self'';style-src - ''self'' ''unsafe-inline'';img-src ''self'' data: blob:;font-src ''self'' - data:;connect-src ''self'';media-src ''self'';frame-ancestors ''self'';form-action - ''self''' + - default-src 'none'; Content-Type: - application/xml; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:16 GMT + - Thu, 12 Mar 2026 07:59:33 GMT Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=a393e3b443d6cc63f8470e99442c1533; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=YuPjF7DG5KsyccDA%2BYh7VvFnJL0kAD69KIyGhoCpHFEJlKY8TAupPbXzmPfUR%2BSSmULVPB2fic4crIatoAQy9yo4xV6PQvwjRcLOApcRgkky6N9ciqMtQWo9Y4B%2BS0ac; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=a393e3b443d6cc63f8470e99442c1533; + - ocm4e2tlfbl8=dca2ee9c13e963dd64e42acb2b7b0e5c; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=2MlvNoS8M2FrXpR%2Fbg5PD39zsJPWIWMlDTPI4rpXaaYW4o5gpsYZsUwZoNLaARzPI7pH4F9iisbNLpTtH6gky2sr76lbh29iRqsOyrkToI4mpFoXEU%2BvMe%2F4MUzCPzbM; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=dca2ee9c13e963dd64e42acb2b7b0e5c; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=a393e3b443d6cc63f8470e99442c1533; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=a393e3b443d6cc63f8470e99442c1533; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=cae1c899dcfb6f0f525fab54a4d3f2a5; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=dca2ee9c13e963dd64e42acb2b7b0e5c; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=dca2ee9c13e963dd64e42acb2b7b0e5c; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=8c353f2258e687a59c52dd75c1151410; path=/; secure; HttpOnly; SameSite=Lax X-Content-Type-Options: - nosniff @@ -453,64 +493,2005 @@ http_interactions: X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Robots-Tag: - noindex, nofollow X-Xss-Protection: - 1; mode=block Content-Length: - - '526' + - '247' body: encoding: UTF-8 - string: "\n\n\tInternal Server Error\n\t\n\t\tThe - server was unable to complete your request.\t\tIf this happens again, please - send the technical details below to the server administrator.\t\tMore details - can be found in the server log.\t\t\t\n\n\t\n\t\t127.0.0.1\n\t\tZnsznBmdibTtOyF59aPG\n\n\t\t\n\n" - recorded_at: Tue, 21 Jan 2025 17:09:16 GMT + string: | + + + Sabre\DAV\Exception\MethodNotAllowed + The resource you tried to create already exists + + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT - request: - method: delete - uri: https://nextcloud.local/remote.php/dav/files/OpenProject/662 + method: mkcol + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%3C=o=%3E%20%7C%20%22Jedi%22%20Project%20Folder%20%7C%7C%7C%20(-273) body: encoding: US-ASCII string: '' headers: - Authorization: - - Basic User-Agent: - - httpx.rb/1.4.0 + - OpenProject 17.2.1 HTTPX Client Accept: - "*/*" Accept-Encoding: - gzip, deflate + Authorization: + - Basic + response: + status: + code: 201 + message: Created + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - text/html; charset=UTF-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Oc-Fileid: + - 00002025ocm4e2tlfbl8 + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=06400f32d8e644956782ad8115898825; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=BXr9ZRO%2FhPBH0Dgsd0msHCNNc9vXlJpUDVTg0UR%2FMKdtFoBpw4NYQW8B%2BX3rWWDSODXfvrEssWj4M3lnF9AbL22g0XjgIo%2BmoN05VVhwj8G%2BxrrtsXdeQ8ub0dWXjvOx; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=06400f32d8e644956782ad8115898825; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=06400f32d8e644956782ad8115898825; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=06400f32d8e644956782ad8115898825; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=360df0003e3bbf26db44067771cca1ee; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - GIcSc7skB4De39Dhkbt4 + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - GIcSc7skB4De39Dhkbt4 + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '0' + body: + encoding: UTF-8 + string: '' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: propfind + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%3C=o=%3E%20%7C%20%22Jedi%22%20Project%20Folder%20%7C%7C%7C%20(-273) + body: + encoding: UTF-8 + string: | + + + + + + + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Depth: + - '1' + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '253' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Dav: + - 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, + nc-paginate, nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=ad52bb04ea6549c5067328d592044c0f; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=7FutK1ov2KC9TYkDLd3VRHvGCTvdiiYCtIkRmTSd%2BKuG6i8ZAJuGYPi4veFzamut%2F7HdNtIAoooKMEujV%2FU1UiVpRMwT%2B7kHtHFyrN291zImxQ%2BBnsOlQLhOfGdB%2F4E3; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=ad52bb04ea6549c5067328d592044c0f; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=ad52bb04ea6549c5067328d592044c0f; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=ad52bb04ea6549c5067328d592044c0f; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=88c2e78a9f8923040c23eaf267acfe98; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - 2M7pi1bEyVN7IzqQ1wGl + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 2M7pi1bEyVN7IzqQ1wGl + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '395' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/%3c%3do%3d%3e%20%7c%20%22Jedi%22%20Project%20Folder%20%7c%7c%7c%20(-273)/20250Thu, 12 Mar 2026 07:59:33 GMTRMGDNVCKOpenProjectHTTP/1.1 200 OKHTTP/1.1 404 Not Found + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: mkcol + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/PUBLIC%20PROJECT%20(-273) + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + response: + status: + code: 201 + message: Created + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - text/html; charset=UTF-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Oc-Fileid: + - 00002026ocm4e2tlfbl8 + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=864dc144f901216197a2be2ceb1397f1; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=XkJEawEyNEtEf1KmwPLFbMDv5004W0d0z%2FDa%2Fbhk7173LQEovfNAzgqnGqU6gmcnCMBBWOFmeR8LZPooCZMv%2BZ5blrg6n%2BfPUb9qD2hd9z4tfGnUDYf5SAh7Em4x%2FaOo; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=864dc144f901216197a2be2ceb1397f1; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=864dc144f901216197a2be2ceb1397f1; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=864dc144f901216197a2be2ceb1397f1; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=f636ecf98e673fe4c46f695662363c50; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - RBBIXP3IkIAFezWyrwRB + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - RBBIXP3IkIAFezWyrwRB + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '0' + body: + encoding: UTF-8 + string: '' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: propfind + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/PUBLIC%20PROJECT%20(-273) + body: + encoding: UTF-8 + string: | + + + + + + + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Depth: + - '1' + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '253' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Dav: + - 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, + nc-paginate, nextcloud-checksum-update, nc-calendar-search, nc-enable-birthday-calendar + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=ae3fb85d610379029598dc679079afea; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=MCPgSCJAhJ6bwApDjoJeIezXr7%2BYJrZ9uVrrB4L%2FSs%2BfUuz6HWOFgP1ddqFszNInVMFImiS24EFZjOPV2j5thgXsdu7W%2BoWacMhToWv1lQnIcrz65PMYhRYItk06gjS1; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=ae3fb85d610379029598dc679079afea; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=ae3fb85d610379029598dc679079afea; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=ae3fb85d610379029598dc679079afea; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=96d322dfe4ba3e25a2b3d19283fb4ee7; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - sqrLJJquBXdjpntUR89i + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - sqrLJJquBXdjpntUR89i + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '374' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/PUBLIC%20PROJECT%20(-273)/20260Thu, 12 Mar 2026 07:59:33 GMTRMGDNVCKOpenProjectHTTP/1.1 200 OKHTTP/1.1 404 Not Found + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/1699 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=e29cb9c9e076e14a9626ef5c72eedebc; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=u2m7xJChcHj5kHtFUmekyS2i3Dyk4PLNX6FCsQYlttg83fhpREBIfZ5eEpeJQKQ0sQaI%2F7ixRL2DbC0swozpP63yhsePtSM5udNK0sOCdyGTK6g4L4GA9pDlHnNEhVha; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=e29cb9c9e076e14a9626ef5c72eedebc; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=e29cb9c9e076e14a9626ef5c72eedebc; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=e29cb9c9e076e14a9626ef5c72eedebc; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=73f586101095b763b0cd915bad37f5a4; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - FiUhuUHKRAFNqafWBC5n + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '279' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":1699,"name":"BLubb_ + I did it again! (9)","mtime":1764161544,"ctime":0,"mimetype":"application\/x-op-directory","size":259818,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/BLubb_ + I did it again! (9)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/BLubb_%20I%20did%20it%20again!%20(9) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=0c08c793f8d54d094b27f500faa44c55; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=oF%2BQUkFCYC1pfIyFqIxuZWNsBS9iHFlrtwWeITdGaWtToV64xVt0aWejssT7soWywbVGEqJGxQnhqM9sjElLqLVxHUMSZoeHW2DXuft7jgnhD7PUPEwlBIIaEcz2vbkw; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=0c08c793f8d54d094b27f500faa44c55; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=0c08c793f8d54d094b27f500faa44c55; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=0c08c793f8d54d094b27f500faa44c55; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=c774c5915f1041e3cc7d3abcccf9435e; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - 7lxAkWbz4R8MCCUNJ30c + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 7lxAkWbz4R8MCCUNJ30c + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '389' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/BLubb_%20I%20did%20it%20again%21%20(9)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/2022 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=6cbfb2a750c57c72a30199d3b224715b; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=HOY7OEB%2FvCt6Mh%2FCmMdRvtJGy0a6uhLXKNcsBLc2gg8esc92JQCzp44DmBJyJfRva0z3ze%2Fwu6QfoRJidPq6AEhU4rKKRtMUVwkG0vxvPEGUQHUAI3snv%2Fv%2BQ5p%2BKbID; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=6cbfb2a750c57c72a30199d3b224715b; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=6cbfb2a750c57c72a30199d3b224715b; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=6cbfb2a750c57c72a30199d3b224715b; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=eaf7d0644c1505b343546930c6265a32; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - aiyJxa8ZCGP8JFWNICCn + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '259' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":2022,"name":"Demo + project (1)","mtime":1772121760,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/Demo + project (1)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/Demo%20project%20(1) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=e4a765505da9c9fd95fb5cf2311619e6; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=WQgyjfID8AYQVgWX4LotDdZmoZsCsWwl%2BgF0nvlsTj%2Fm%2F43jjWDPyrcGiOILqcteiFWUoPB5v8%2BM8eKObqADrbbVePhTcHmdOK0oQLF7weXsxdWFWTWYEJ7ZMEZOe6H0; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=e4a765505da9c9fd95fb5cf2311619e6; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=e4a765505da9c9fd95fb5cf2311619e6; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=e4a765505da9c9fd95fb5cf2311619e6; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=2751ebfe0d97a216e13e8ab58c83ba72; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - FNpwPERaBmHcmEEKeQyv + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - FNpwPERaBmHcmEEKeQyv + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '371' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/Demo%20project%20(1)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/1600 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=d72d5172796066ddf037ef1b2dd02486; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=o7I4XGvtM4ROxM0%2F%2FeP7wLDy07a2pyI7jUzqlrYXLviaEQ5kgSa8zBPZExNBvTbgJ4V0GM1MCcdRsLYA6a96WBqfJ%2F6l11yOk99U0U2%2Fshl61aHC%2FTWosIeWhULWZrEP; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=d72d5172796066ddf037ef1b2dd02486; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=d72d5172796066ddf037ef1b2dd02486; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=d72d5172796066ddf037ef1b2dd02486; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=0aec1934bfd4a1c821e593deb6f6ee60; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - gA7P5CfRHTzc7j2uFegE + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '264' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":1600,"name":"Private + Wurst (8)","mtime":1744191648,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/Private + Wurst (8)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/Private%20Wurst%20(8) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=91975b0c98f6001b9381cf24bea9843c; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=ASkBL%2B8WjrLoouodz3Y7LnKyxzLkKtq9EfY0ok9Z%2BirQ%2FCLO1dthqZOpHkK4iYLFITlhXS9KoHSXktTfI%2BgU05GbxyNea8tX2iKFxpyY2a6vd1pTmqA%2FGt3Eb1941DiV; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=91975b0c98f6001b9381cf24bea9843c; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=91975b0c98f6001b9381cf24bea9843c; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=91975b0c98f6001b9381cf24bea9843c; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=1b0f2f7a974f028d2ebb65ff68f21493; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - UB51GuiCr1c1Dktt7pGn + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - UB51GuiCr1c1Dktt7pGn + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '372' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/Private%20Wurst%20(8)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/2023 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=d1f480d2e8c36f6a3d6f6ec718d86592; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=7JzhEXsKuZ4rIqHkttq2CSk%2F00TpGYvLis3YQ9pxE825bkFbF%2FyGo%2FKAFwD3UEo2834wO8cP29IptOoyAxsD4cWKRq72WJKKguazR5Ue9rAxWGHn6nu1adDtyNB4KBVM; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=d1f480d2e8c36f6a3d6f6ec718d86592; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=d1f480d2e8c36f6a3d6f6ec718d86592; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=d1f480d2e8c36f6a3d6f6ec718d86592; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=0be49dae5b316df1dd38abfc33e33032; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - QUw2H4stQ4XiTdEkxE6i + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '261' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":2023,"name":"Scrum + project (2)","mtime":1772121761,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/Scrum + project (2)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/Scrum%20project%20(2) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=8e2be2e586d949c1274d8c0248a613a0; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=8YqCELa1iCwupVmYygSTUrBfzKJ1Mn%2FoUhb8yEbXZCz6WoVRxJB9QxNcd8pnboT2cIVtTEL6C05YduY2osswkfvxzOQk7fG%2F%2BRAnABIhMPhGZZPCR78wm77j%2BFTdB48U; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=8e2be2e586d949c1274d8c0248a613a0; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=8e2be2e586d949c1274d8c0248a613a0; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=8e2be2e586d949c1274d8c0248a613a0; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=af33e8afc64da403920b33e05792c9b8; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - 3oQtaXuKHSpbH9YXUMKl + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 3oQtaXuKHSpbH9YXUMKl + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '372' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/Scrum%20project%20(2)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:33 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/2024 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:33 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=39a19f83f81bf9879e6b03974a29b2f4; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=HDRZJ2cAIYmbcj3rgWOaNEtAZyqHYouiMSM1N3R1g%2B7vDUWpMiLJ%2B2tCFfNYCKTmIzNuQUhMUgfpdXFF%2Bw8eD7D2YzoEwyOsgC9eLaIq741k%2BoPk6qsGYXSYlr5fsVUz; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=39a19f83f81bf9879e6b03974a29b2f4; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=39a19f83f81bf9879e6b03974a29b2f4; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=39a19f83f81bf9879e6b03974a29b2f4; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=0047820ce9f21abe32dddfe48f76f48c; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 84jnV9fjT1tOplHjzPzV + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '277' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":2024,"name":"[Sample] + Project Name | Ehuu (-273)","mtime":1773302373,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/[Sample] + Project Name | Ehuu (-273)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%5BSample%5D%20Project%20Name%20%7C%20Ehuu%20(-273) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=1643140ed0c0471df86e51317f44fa36; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=oiDRKbldar4AZY2RkDMBgNzp%2F5bCyq1J%2BoGn4ujnrwufdJY5YoakJi9KzGTArYEwW6FgIeHcEgg3d%2BSaiUi2rlKvKJ6PJncTFLridhAHoMd5e1eZJ0qccRWFpDOo7p08; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=1643140ed0c0471df86e51317f44fa36; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=1643140ed0c0471df86e51317f44fa36; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=1643140ed0c0471df86e51317f44fa36; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=3f4e758e4bd8e9f943a26ba1d816aac2; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - wthSYgHjaKIKu6m4HjgI + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - wthSYgHjaKIKu6m4HjgI + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '402' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/%5bSample%5d%20Project%20Name%20%7c%20Ehuu%20(-273)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/1014 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=e2d76857150f364c6007f641baab7267; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=neqPX1xlfhowqrlT1TlEPXXw6IWXLdIAYhlRcICgP9YO0x2z7mZjuUJF%2BnQPPnaNz2l4x%2B%2FMSE3eo4CSL%2B0IRIeFZFeqXNs88Gnup8o%2B7pxxTyIIdtIOY08duNLHCQxO; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=e2d76857150f364c6007f641baab7267; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=e2d76857150f364c6007f641baab7267; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=e2d76857150f364c6007f641baab7267; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=3337555f8b468426ec9d7ab04d0f97d6; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 1dkhN67eHhwlaI7PhB5h + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '269' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":1014,"name":"[dev] + Custom fields (7)","mtime":1744031052,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/[dev] + Custom fields (7)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%5Bdev%5D%20Custom%20fields%20(7) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=ec40127a9937b2ca4b2b149878b1b388; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=r8xz2sbIQBSt3CNrB%2B65jZP7aJumI0xuOo1fq4e8C16%2Bu1pfPI4exHlfYmg6SiKFHjtZCizjSNWpNWjJT5OH31TQYg1Wj3fw3y4NMs%2F5JEFkfh2nJdX8FPmcEHmMXWt%2F; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=ec40127a9937b2ca4b2b149878b1b388; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=ec40127a9937b2ca4b2b149878b1b388; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=ec40127a9937b2ca4b2b149878b1b388; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a6661bf5fbb802d851dffe2009ec3ef5; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - qVgiG56VQujdhrhdrxcl + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - qVgiG56VQujdhrhdrxcl + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '384' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/%5bdev%5d%20Custom%20fields%20(7)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/686 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=7b96728063f3d126a554dad6ce91362e; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=orxEY2oj%2FuT92%2FL%2FH%2BlFr3lVfgFSzJo%2BR0uNBmWx0QcQ3J5n40xIsRh%2F1UhNXpiwilyuZ2fIgLN003zbnlNzFaZnlfEWnHCt%2FKMXpbpiZHqhOqe9FPNtpKPl7HBdlaBu; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=7b96728063f3d126a554dad6ce91362e; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=7b96728063f3d126a554dad6ce91362e; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=7b96728063f3d126a554dad6ce91362e; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=d07fe68d26275bafd84d9ce2e2210ca8; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - tYkPqw050ZlvU3VkeWzG + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '279' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":686,"name":"[dev] + Work package sharing (4)","mtime":1741613426,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":null,"modifier_id":null,"dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/[dev] + Work package sharing (4)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%5Bdev%5D%20Work%20package%20sharing%20(4) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=09c34ddac680bed6d6e27b3edd36da76; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=HnBVpwWx47FQs%2FjIUDIGTSQH2ot1HHk6yI52kpQS5h0a9fhPmXrpTYcwsVhpsSoUc4uplGqK35iSpEuhDEfJ%2FqYaRF7PqI%2FfJoQFtcGSRAI2vanCg4FebLVes16mJnk3; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=09c34ddac680bed6d6e27b3edd36da76; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=09c34ddac680bed6d6e27b3edd36da76; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=09c34ddac680bed6d6e27b3edd36da76; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=7eb6dfcf61d7c0b26eafcf4cf6961a28; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - bMqEawQJhnDC0rIzB6I0 + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - bMqEawQJhnDC0rIzB6I0 + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '393' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/%5bdev%5d%20Work%20package%20sharing%20(4)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/1888 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=39c642b1ec345511d391d10a19b879bc; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=RVv5mw6%2BHuVZoXqgOU5dDMBSC2QXT0a7pvFyeUPt2CKZAzfux5crBOrXXMeeuwU4JK53sOBhXKW8TfLYctbb0l8BGAMd6BIBvEny6nUliUoSrVHXuGdBkHwSMnxAfLE%2B; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=39c642b1ec345511d391d10a19b879bc; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=39c642b1ec345511d391d10a19b879bc; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=39c642b1ec345511d391d10a19b879bc; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=7240c9a244f9d8047b4daf152b71a605; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 91l0kbh3eHM1CD5ABBiB + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '242' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":1888,"name":"bar.txt","mtime":1763389765,"ctime":0,"mimetype":"text\/plain","size":50,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVW","path":"files\/OpenProject\/bar.txt"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/bar.txt + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=a3b956120e685cb8dd2c699a529dd1ad; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=kLG6RyiUI8by3hu%2FzYhFBlFKonOLfZKVsyP8QCG4mVHbRGq7tU1ZdC16Hzb6eLX3yIvwxjCeIqn4lMjhCdPpmCYz0zi0gx6HLm7uYkB9F2uZcem%2FWVsTt7G%2Fa1UxsPL6; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a3b956120e685cb8dd2c699a529dd1ad; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=a3b956120e685cb8dd2c699a529dd1ad; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=a3b956120e685cb8dd2c699a529dd1ad; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=e38c53bbb8591301b1e8f3bf0fc76c3b; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - vGVijXv8MQso1vYS17K8 + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - vGVijXv8MQso1vYS17K8 + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '358' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/bar.txtHTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/1920 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Ocs-Apirequest: + - 'true' + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=a2e0668c11f190fe4391e24f3e190a0f; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=GypCmVi%2BoXoaq6JiL0R8sTBGnmXzPQvipF0PUM5H1np2S2Xlgwsq%2FiUTLe2cc04fE7vNRFUugJvz2uJZBPrIjB3oCkQIdZ%2BItmE9PxcFHCtIn%2F696DyCQa6JvGVbSJQk; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a2e0668c11f190fe4391e24f3e190a0f; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=a2e0668c11f190fe4391e24f3e190a0f; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=a2e0668c11f190fe4391e24f3e190a0f; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=1308a913675d8cdc56aa4205ea46f830; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - kVpLx4Go7eSDSwqRGVy8 + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '272' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":1920,"name":"existing-sub-folder + (3187)","mtime":1763390954,"ctime":0,"mimetype":"application\/x-op-directory","size":0,"owner_name":"OpenProject","owner_id":"OpenProject","modifier_name":"OpenProject","modifier_id":"OpenProject","dav_permissions":"RMGDNVCK","path":"files\/OpenProject\/existing-sub-folder + (3187)\/"}}}' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: proppatch + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/existing-sub-folder%20(3187) + body: + encoding: UTF-8 + string: | + + + + + + + group + OpenProject + 31 + 0 + + + user + OpenProject + 31 + 31 + + + + + + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + Content-Type: + - application/xml; charset=utf-8 + Content-Length: + - '696' + response: + status: + code: 207 + message: Multi-Status + headers: + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=11f20375e4aa5d0e8249ed14fe27775a; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=aje%2F%2Fjn40F0dxeJqKb3N7me7Q69I%2B0cO66fwEumDyzOoXGFGOLwoK1C%2BhgyKXAbizdMpF6Czi5YarLidCsZB5lpRO8JYvesIAxB3OoQyXRmIGH7EnEWhfbXFLUAlYSe3; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=11f20375e4aa5d0e8249ed14fe27775a; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=11f20375e4aa5d0e8249ed14fe27775a; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=11f20375e4aa5d0e8249ed14fe27775a; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=a2dd31fca15244324fa7b8b1d5a66b51; + path=/; secure; HttpOnly; SameSite=Lax + Vary: + - Brief,Prefer + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - XtFGhqW3lkVPbKjjXVqW + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - XtFGhqW3lkVPbKjjXVqW + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '379' + body: + encoding: UTF-8 + string: | + + /remote.php/dav/files/OpenProject/OpenProject/existing-sub-folder%20(3187)HTTP/1.1 200 OK + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: delete + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/2024 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic response: status: code: 404 message: Not Found headers: Content-Security-Policy: - - 'default-src ''none'';base-uri ''none'';manifest-src ''self'';script-src ''self'';style-src - ''self'' ''unsafe-inline'';img-src ''self'' data: blob:;font-src ''self'' - data:;connect-src ''self'';media-src ''self'';frame-ancestors ''self'';form-action - ''self''' + - default-src 'none'; Content-Type: - application/xml; charset=utf-8 Date: - - Tue, 21 Jan 2025 17:09:17 GMT + - Thu, 12 Mar 2026 07:59:34 GMT Referrer-Policy: - no-referrer Server: - Apache/2.4.62 (Debian) Set-Cookie: - - ocxxq957y92g=9f6873750380bffdd52522d28334d1ad; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=gMfF9P1bCfLoHSNzOftrl8SJ2rWt9YqlLSbiTw5otbCWalTFbeqvTeGShLgbQun8GAq9VdQKUA2KDUAZBptUA8AMAAA%2F91p%2BRySXp%2B7CV%2FJGfX0s4AMNyOSDBS1yGYdn; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=9f6873750380bffdd52522d28334d1ad; + - ocm4e2tlfbl8=061677067108881750cca99b1a3c1e08; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=UMaFFZGAR%2BZEIoNHiPYAD6WIRNNdpkg3BfSXcp38kJyNMzcqJO3QaqVsHBEKlCgcZAuh76jF5FlUfGgq1AIzuZ%2FZB6osyAWHb%2BmzeG8Aq2H816sdSgCrxRvU7mLyXNe2; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=061677067108881750cca99b1a3c1e08; path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocxxq957y92g=9f6873750380bffdd52522d28334d1ad; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=9f6873750380bffdd52522d28334d1ad; - path=/; secure; HttpOnly; SameSite=Lax, ocxxq957y92g=676848016351f98c4973b04bde9fd2bb; + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=061677067108881750cca99b1a3c1e08; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=061677067108881750cca99b1a3c1e08; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=9c05506887fb1cf5c6e95e6b0fc5226e; path=/; secure; HttpOnly; SameSite=Lax X-Content-Type-Options: - nosniff @@ -519,19 +2500,152 @@ http_interactions: X-Permitted-Cross-Domain-Policies: - none X-Powered-By: - - PHP/8.2.27 + - PHP/8.3.20 X-Robots-Tag: - noindex, nofollow X-Xss-Protection: - 1; mode=block Content-Length: - - '526' + - '234' body: encoding: UTF-8 - string: "\n\n\tInternal Server Error\n\t\n\t\tThe - server was unable to complete your request.\t\tIf this happens again, please - send the technical details below to the server administrator.\t\tMore details - can be found in the server log.\t\t\t\n\n\t\n\t\t127.0.0.1\n\t\tBt1BeMzgW1PoRryqdlUO\n\n\t\t\n\n" - recorded_at: Tue, 21 Jan 2025 17:09:17 GMT -recorded_with: VCR 6.3.1 + string: | + + + Sabre\DAV\Exception\NotFound + File with name //2024 could not be located + + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: delete + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/%3C=o=%3E%20%7C%20%22Jedi%22%20Project%20Folder%20%7C%7C%7C%20(-273) + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + response: + status: + code: 204 + message: No Content + headers: + Content-Security-Policy: + - default-src 'none'; + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=9de3cb6489d45d91407eeaac1e21e27b; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=PLdO616Ow25uU6QW%2B8WEqbLulIfHcCev8eWVN5jReCJQYBH3lvJ74xBbrZwWo0J73%2B7aiVd%2BIZX6Jz0%2FicNVhC3uAR6ZbUSSk%2FquYhQ77h6%2FYwv2PMQ6vc2GxWzY0sLF; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=9de3cb6489d45d91407eeaac1e21e27b; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=9de3cb6489d45d91407eeaac1e21e27b; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=9de3cb6489d45d91407eeaac1e21e27b; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=e8e08c874f9c19dc7a4789a1e786e8aa; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - YJ65kCfi5AOG3eErSaLz + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - YJ65kCfi5AOG3eErSaLz + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + body: + encoding: UTF-8 + string: '' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +- request: + method: delete + uri: https://nextcloud.local/remote.php/dav/files/OpenProject/OpenProject/PUBLIC%20PROJECT%20(-273) + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.2.1 HTTPX Client + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Authorization: + - Basic + response: + status: + code: 204 + message: No Content + headers: + Content-Security-Policy: + - default-src 'none'; + Date: + - Thu, 12 Mar 2026 07:59:34 GMT + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.62 (Debian) + Set-Cookie: + - ocm4e2tlfbl8=af7ef8edc182ab6f4a204d77227520e1; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=jApRfqeEHgpL61LvwwLSFWVuVb44ElTbt0EYjMje%2F30OgS2l8NCXCuCqsJ3%2FnLCNcatthKwPSqNxwWtnzs6ymUqu6g7bBXHgNhceRU1ny2Fa%2BbvipVC0o6clbhCbzn0q; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=af7ef8edc182ab6f4a204d77227520e1; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocm4e2tlfbl8=af7ef8edc182ab6f4a204d77227520e1; + path=/; secure; HttpOnly; SameSite=Lax, nc_username=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_token=deleted; expires=Thu, + 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_session_id=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; secure; HttpOnly, nc_username=deleted; + expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly, + nc_token=deleted; expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0; path=/; + secure; HttpOnly, nc_session_id=deleted; expires=Thu, 01 Jan 1970 00:00:01 + GMT; Max-Age=0; path=/; secure; HttpOnly, ocm4e2tlfbl8=af7ef8edc182ab6f4a204d77227520e1; + path=/; secure; HttpOnly; SameSite=Lax, ocm4e2tlfbl8=2c0a86ade58f4c46a4a1416e672c5a34; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Debug-Token: + - 1DYeAJoFSCbOdYmNb1OQ + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.3.20 + X-Request-Id: + - 1DYeAJoFSCbOdYmNb1OQ + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + body: + encoding: UTF-8 + string: '' + recorded_at: Thu, 12 Mar 2026 07:59:34 GMT +recorded_with: VCR 6.4.0 diff --git a/modules/webhooks/app/workers/represented_webhook_job.rb b/modules/webhooks/app/workers/represented_webhook_job.rb index a89fcf0feb8..1325fe71771 100644 --- a/modules/webhooks/app/workers/represented_webhook_job.rb +++ b/modules/webhooks/app/workers/represented_webhook_job.rb @@ -61,8 +61,8 @@ class RepresentedWebhookJob < WebhookJob def request_headers { - content_type: "application/json", - accept: "application/json" + "Content-Type": "application/json", + Accept: "application/json" } end diff --git a/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb b/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb index 04b0d8366b6..a0a5dce1ad2 100644 --- a/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb @@ -42,7 +42,7 @@ RSpec.describe AttachmentWebhookJob, :webmock, type: :job do let(:stubbed_url) { request_url } let(:request_headers) do - { content_type: "application/json", accept: "application/json" } + { "Content-Type": "application/json", Accept: "application/json" } end let(:response_code) { 200 } diff --git a/modules/webhooks/spec/workers/project_webhook_job_spec.rb b/modules/webhooks/spec/workers/project_webhook_job_spec.rb index 5bfc2864c65..6b89510bdc0 100644 --- a/modules/webhooks/spec/workers/project_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/project_webhook_job_spec.rb @@ -42,7 +42,7 @@ RSpec.describe ProjectWebhookJob, :webmock, type: :job do let(:stubbed_url) { request_url } let(:request_headers) do - { content_type: "application/json", accept: "application/json" } + { "Content-Type": "application/json", Accept: "application/json" } end let(:response_code) { 200 } diff --git a/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb b/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb index affb68d46a8..17304244085 100644 --- a/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb @@ -43,7 +43,7 @@ RSpec.describe TimeEntryWebhookJob, :webmock, type: :job do let(:stubbed_url) { request_url } let(:request_headers) do - { content_type: "application/json", accept: "application/json" } + { "Content-Type": "application/json", Accept: "application/json" } end let(:response_code) { 200 } diff --git a/modules/webhooks/spec/workers/work_package_comment_webhook_job_spec.rb b/modules/webhooks/spec/workers/work_package_comment_webhook_job_spec.rb index 843c9cd4bcd..8a97a093c87 100644 --- a/modules/webhooks/spec/workers/work_package_comment_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/work_package_comment_webhook_job_spec.rb @@ -43,7 +43,7 @@ RSpec.describe WorkPackageCommentWebhookJob, :webmock, type: :model do let(:stubbed_url) { request_url } let(:request_headers) do - { content_type: "application/json", accept: "application/json" } + { "Content-Type": "application/json", Accept: "application/json" } end let(:response_code) { 200 } diff --git a/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb b/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb index 40c6eff15af..664d0515c9c 100644 --- a/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb @@ -46,7 +46,7 @@ RSpec.describe WorkPackageWebhookJob, :webmock, type: :model do let(:stubbed_url) { request_url } let(:request_headers) do - { content_type: "application/json", accept: "application/json" } + { "Content-Type": "application/json", Accept: "application/json" } end let(:response_code) { 200 } diff --git a/modules/wikis/README.md b/modules/wikis/README.md new file mode 100644 index 00000000000..2be37cd302b --- /dev/null +++ b/modules/wikis/README.md @@ -0,0 +1,7 @@ +# OpenProject Wikis Plugin + +FIXME Add description and check issue tracker link below + +## Issue Tracker + +https://community.openproject.org/projects/wikis/work_packages diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml new file mode 100644 index 00000000000..efc34c0e46a --- /dev/null +++ b/modules/wikis/config/locales/en.yml @@ -0,0 +1,7 @@ +--- +en: + activerecord: + attributes: {} + errors: {} + models: {} + wikis: {} diff --git a/modules/wikis/lib/open_project/wikis.rb b/modules/wikis/lib/open_project/wikis.rb new file mode 100644 index 00000000000..d647a267736 --- /dev/null +++ b/modules/wikis/lib/open_project/wikis.rb @@ -0,0 +1,36 @@ +# 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. +#++ + +require "open_project/wikis/engine" + +module OpenProject + module Wikis + end +end diff --git a/modules/wikis/lib/open_project/wikis/engine.rb b/modules/wikis/lib/open_project/wikis/engine.rb new file mode 100644 index 00000000000..c01586c0670 --- /dev/null +++ b/modules/wikis/lib/open_project/wikis/engine.rb @@ -0,0 +1,45 @@ +# 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. +#++ + +# Prevent load-order problems in case openproject-plugins is listed after a plugin in the Gemfile +# or not at all +require "open_project/plugins" + +module OpenProject::Wikis + class Engine < ::Rails::Engine + engine_name :openproject_wikis + + include OpenProject::Plugins::ActsAsOpEngine + + register "openproject-wikis", + author_url: "https://openproject.org", + requires_openproject: ">= 17.0.0" + end +end diff --git a/modules/wikis/lib/openproject-wikis.rb b/modules/wikis/lib/openproject-wikis.rb new file mode 100644 index 00000000000..adbe05a548f --- /dev/null +++ b/modules/wikis/lib/openproject-wikis.rb @@ -0,0 +1,31 @@ +# 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. +#++ + +require "open_project/wikis" diff --git a/modules/wikis/openproject-wikis.gemspec b/modules/wikis/openproject-wikis.gemspec new file mode 100644 index 00000000000..f6ef7db7d07 --- /dev/null +++ b/modules/wikis/openproject-wikis.gemspec @@ -0,0 +1,44 @@ +# 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. +#++ + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "openproject-wikis" + s.version = "1.0.0" + + s.authors = "OpenProject GmbH" + s.email = "info@openproject.org" + s.summary = "OpenProject Wikis" + s.description = "Allows linking work packages to pages in wikis, such as XWiki or the internal OpenProject wiki." + s.license = "GPLv3" + + s.files = Dir["{app,config,db,lib}/**/*"] + %w(CHANGELOG.md README.md) + s.metadata["rubygems_mfa_required"] = "true" +end diff --git a/package-lock.json b/package-lock.json index cd5b9d00cbb..451db8f1fe3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2428,11 +2428,10 @@ } }, "node_modules/undici": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", - "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.17" } diff --git a/publiccode.yml b/publiccode.yml index b9f451ed7cc..a4c4f9261bf 100644 --- a/publiccode.yml +++ b/publiccode.yml @@ -7,8 +7,8 @@ name: OpenProject applicationSuite: openDesk url: 'https://github.com/opf/openproject' roadmap: 'https://www.openproject.org/roadmap' -releaseDate: '2026-02-26' -softwareVersion: '17.1.2' +releaseDate: '2026-03-17' +softwareVersion: '17.2.2' developmentStatus: stable softwareType: standalone/web logo: 'publiccode_logo.svg' diff --git a/script/github_pr_errors b/script/github_pr_errors index 82f9abc693d..fcfb79f81bc 100755 --- a/script/github_pr_errors +++ b/script/github_pr_errors @@ -17,14 +17,14 @@ require "yaml" require "httpx" require "cgi" +require_relative "support/github_actions_failures" + GITHUB_API_OPENPROJECT_PREFIX = "https://api.github.com/repos/opf/openproject" GITHUB_HTML_OPENPROJECT_PREFIX = "https://github.com/opf/openproject" RAILS_ROOT = Pathname.new(__dir__).dirname EXCLUDED_JOB_NAMES = %w[eslint rubocop].freeze -if !ENV["GITHUB_USERNAME"] - raise "Missing GITHUB_USERNAME env" -elsif !ENV["GITHUB_TOKEN"] +if !ENV["GITHUB_TOKEN"] raise "Missing GITHUB_TOKEN env, go to https://github.com/settings/tokens and create one with 'repo' access" end @@ -179,8 +179,9 @@ end def http HTTPX .plugin(:follow_redirects) - .plugin(:basic_auth) - .basic_auth(ENV.fetch("GITHUB_USERNAME"), ENV.fetch("GITHUB_TOKEN")) + .with_headers( + "Authorization" => "Bearer #{ENV.fetch('GITHUB_TOKEN')}" + ) end def get_http(path) @@ -337,170 +338,6 @@ Report = Data.define( end end -class Error - attr_accessor :location, :page_html, :page_screenshot, :tests_group, :loading_error -end - -# rubocop:disable Layout/LineLength -# Looks like this in the job log: -# Process 28: TEST_ENV_NUMBER=28 RUBYOPT=-I/usr/local/bundle/bundler/gems/turbo_tests-3148ae6c3482/lib -r/usr/local/bundle/gems/bundler-2.5.23/lib/bundler/setup -W0 RSPEC_SILENCE_FILTER_ANNOUNCEMENTS=1 /usr/local/bundle/gems/bundler-2.5.23/exe/bundle exec rspec --seed 52674 --format TurboTests::JsonRowsFormatter --out tmp/test-pipes/subprocess-28 --format ParallelTests::RSpec::RuntimeLogger --out spec/support/turbo_runtime_features.log spec/features/api_docs/index_spec.rb spec/features/custom_fields/reorder_options_spec.rb spec/features/projects/projects_portfolio_spec.rb spec/features/projects/template_spec.rb spec/features/versions/edit_spec.rb spec/features/work_packages/details/markdown/description_editor_spec.rb spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb spec/features/work_packages/table/invalid_query_spec.rb spec/features/work_packages/tabs/activity_revisions_spec.rb -# rubocop:enable Layout/LineLength -class TestsGroup - attr_accessor :test_env_number, :seed, :files - - def initialize - @files = [] - end - - def include_error?(error) - return false if error.location.nil? - - files.any? { |file| error.location.include?(file) } - end - - def inspect - "#<#{self.class} @test_env_number=#{test_env_number} @seed=#{seed} (#{files.count} files)>" - end -end - -class JobErrorsFinder - SPEC_FAILURES_PATTERN = %r{^\S+ rspec (\S+) #.+$} - SPEC_LOADING_ERRORS_PATTERN = %r{^\S+ An error occurred while loading (\S+)\.\r?$} - SCREENSHOT_PATTERN = /\{"message":"Screenshot captured for failed feature test"[^\n]+$/ - TESTS_GROUP_PATTERN = /Process \d+: TEST_ENV_NUMBER=\d+ [^\n]+$/ - BRANCH_MERGE_PATTERN = /Merge \w{40} into (\w{40})$/ - - attr_reader :failures_explanation, :merge_branch_sha - - def self.scan_logs(report, logs) - finder = new - logs.each do |log| - finder.scan_log(log) - end - report.with( - errors: finder.errors, - failures_explanation: finder.failures_explanation, - merge_branch_sha: finder.merge_branch_sha - ) - end - - def scan_log(log) - find_failures(log) - find_failures_explanation(log) - find_loading_errors(log) - find_screenshots(log) - find_tests_groups(log) - find_merge_branch_info(log) - end - - def errors - @errors.values - end - - protected - - def initialize - @errors = {} - end - - def create_error(location) - return if location.nil? - - error = Error.new - error.location = location - @errors[location] ||= error - end - - def with_matching_error(location: nil, id: nil) - error = @errors[id] || @errors[location] - yield error if error && block_given? - error - end - - def find_failures(log) - log.scan(SPEC_FAILURES_PATTERN) - .flatten - .uniq - .sort - .each do |rerun_location| - create_error(rerun_location) - end - end - - def find_failures_explanation(log) - explanations = [] - log.split("\n").each do |line| - if line.end_with?("Failures:") .. line.end_with?("Failed examples:") - explanations << line - end - end - explanations.map! { it[29..] } # Remove leading timestamp (like "2024-02-05T08:37:54.5175930Z") - explanations.reject! do |line| - line == "Failures:" || - line == "Failed examples:" || - line.include?("gems/rspec-retry-") || - line.include?("gems/webmock-") - end - @failures_explanation = explanations.join("\n") - end - - def find_loading_errors(log) - log.scan(SPEC_LOADING_ERRORS_PATTERN) - .flatten - .uniq - .sort - .each do |location| - error = create_error(location) - error.loading_error = true - end - end - - def find_screenshots(log) - log.scan(SCREENSHOT_PATTERN) - .map { JSON.parse it } - .each do |screenshot_info| - id = screenshot_info["test_id"] - location = screenshot_info["test_location"] - with_matching_error(location:, id:) do |error| - error.page_html = screenshot_info["html"] - error.page_screenshot = screenshot_info["image"] - end - end - end - - def find_tests_groups(log) - tests_groups = log - .scan(TESTS_GROUP_PATTERN) - .flatten - .map { build_tests_group_from_command(it) } - - errors.each do |error| - error.tests_group = tests_groups.find { it.include_error?(error) } - end - end - - def find_merge_branch_info(log) - merge_branch_sha = log.scan(BRANCH_MERGE_PATTERN).flatten.first - @merge_branch_sha = merge_branch_sha if merge_branch_sha - end - - def build_tests_group_from_command(line) - tests_group = TestsGroup.new - parts = line.split - while parts.any? - case part = parts.shift - when /^TEST_ENV_NUMBER=/ - tests_group.test_env_number = part.delete_prefix("TEST_ENV_NUMBER=") - when "--seed" - tests_group.seed = parts.shift - when /_spec.rb$/ - tests_group.files << part - end - end - tests_group - end -end - class Formatter def initialize(compact: false) @compact = compact @@ -798,7 +635,12 @@ formatter = Formatter.new(compact: Options.compact) report = get_failed_jobs_logs(report, formatter) -report = JobErrorsFinder.scan_logs(report, report.failed_job_logs) +scan_result = GithubActionsFailures::JobErrorsFinder.scan_logs(report.failed_job_logs) +report = report.with( + errors: scan_result.errors, + failures_explanation: scan_result.failures_explanation, + merge_branch_sha: scan_result.merge_branch_sha +) case report.run_status when "completed" diff --git a/script/report_out_of_hours_ci_failures b/script/report_out_of_hours_ci_failures new file mode 100755 index 00000000000..afd2ff9bea2 --- /dev/null +++ b/script/report_out_of_hours_ci_failures @@ -0,0 +1,371 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "rubygems" +require "bundler" +Bundler.setup(:default, :development) + +require "json" +require "optparse" +require "pathname" +require "time" +require "yaml" +require "httpx" +require "active_support/all" + +require_relative "support/github_actions_failures" + +GITHUB_API_OPENPROJECT_PREFIX = "https://api.github.com/repos/opf/openproject" +RAILS_ROOT = Pathname.new(__dir__).dirname +TEST_WORKFLOW_FILE = "test-core.yml" +PRIMARY_BRANCH_PATTERN = /\A(?:dev|release\/.+)\z/ +TEST_STEP_NAMES = ["Unit tests", "Feature tests"].freeze +DEFAULT_TIMEZONE = "Europe/Berlin" +DEFAULT_LOOKBACK_DAYS = 30 + +module OutOfHoursCiFailures + RunSummary = Data.define(:run_id, :run_number, :html_url, :head_branch, :event, :created_at, :failed_steps, :errors) + SpecSummary = Data.define( + :location, + :test_types, + :out_of_hours_count, + :in_hours_count, + :branches, + :first_seen_at, + :last_seen_at, + :out_of_hours_runs, + :in_hours_runs, + :classification + ) + + class Options + DEFAULTS = { + days: DEFAULT_LOOKBACK_DAYS, + include_pr_runs: false, + json: false, + timezone: DEFAULT_TIMEZONE, + workflow: TEST_WORKFLOW_FILE + }.freeze + + class << self + # rubocop:disable Metrics/AbcSize + def parse!(argv) + options = DEFAULTS.dup + + OptionParser.new do |parser| + parser.banner = "Usage: script/report_out_of_hours_ci_failures [options]" + + parser.on("--days DAYS", Integer, "Look back this many days (default: #{DEFAULT_LOOKBACK_DAYS})") do |value| + options[:days] = value + end + + parser.on("--include-pr-runs", "Include pull_request runs in the report") do + options[:include_pr_runs] = true + end + + parser.on("--json", "Output JSON instead of a table") do + options[:json] = true + end + + parser.on( + "--timezone NAME", + "Timezone for the in-hours/out-of-hours classification (default: #{DEFAULT_TIMEZONE})" + ) do |value| + options[:timezone] = value + end + + parser.on("--workflow FILE", "Workflow file name to inspect (default: #{TEST_WORKFLOW_FILE})") do |value| + options[:workflow] = value + end + + parser.on("-h", "--help", "Print this help") do + puts parser + exit + end + end.parse!(argv) + + options + end + # rubocop:enable Metrics/AbcSize + end + end + + class GithubClient + def initialize(cache_dir:) + @cache_dir = cache_dir + end + + def workflow_runs(workflow_file:, page:) + get_json("actions/workflows/#{workflow_file}/runs?status=completed&per_page=100&page=#{page}") + end + + def jobs(run_id) + get_json("actions/runs/#{run_id}/jobs") + end + + def log(job_id) + cached("job_#{job_id}.log") do + get_http("actions/jobs/#{job_id}/logs") + end + end + + private + + def http + @http ||= HTTPX + .plugin(:follow_redirects) + .with_headers( + "Authorization" => "Bearer #{ENV.fetch('GITHUB_TOKEN')}" + ) + end + + def github_url(path) + path.start_with?("http") ? path : "#{GITHUB_API_OPENPROJECT_PREFIX}/#{path}" + end + + def get_http(path) + response = http.get(github_url(path)) + response.raise_for_status + response.to_s + end + + def get_json(path) + JSON.parse(get_http(path)) + rescue HTTPX::HTTPError => e + body = e.response.json + raise "#{body['message']} (see #{body['documentation_url']})" + end + + def cached(name) + path = @cache_dir.join(name) + return path.read if path.file? + + content = yield + path.dirname.mkpath + path.write(content) + content + end + end + + class ReportBuilder + def initialize(options:, client:) + @options = options + @client = client + @timezone = ActiveSupport::TimeZone[options[:timezone]] || raise("Unknown timezone #{options[:timezone]}") + @since = Time.current - options[:days].days + end + + # rubocop:disable Metrics/AbcSize + def build + spec_runs = Hash.new { |hash, key| hash[key] = [] } + + each_relevant_run do |workflow_run, failed_jobs| + logs = failed_jobs.map { |job| @client.log(job.fetch("id")) } + scan_result = GithubActionsFailures::JobErrorsFinder.scan_logs(logs) + next if scan_result.errors.empty? + + failed_steps = failed_jobs.flat_map { failing_test_steps(it) }.uniq.sort + summary = RunSummary.new( + run_id: workflow_run.fetch("id"), + run_number: workflow_run.fetch("run_number"), + html_url: workflow_run.fetch("html_url"), + head_branch: workflow_run.fetch("head_branch"), + event: workflow_run.fetch("event"), + created_at: parse_time(workflow_run.fetch("created_at")), + failed_steps:, + errors: scan_result.errors.map(&:location).sort + ) + + summary.errors.each do |location| + spec_runs[location] << summary + end + end + + spec_runs + .sort_by { |location, _| location } + .map { |location, runs| summarize(location, runs) } + .sort_by { |summary| [-summary.out_of_hours_count, -summary.in_hours_count, summary.location] } + end + # rubocop:enable Metrics/AbcSize + + private + + # rubocop:disable Metrics/AbcSize + def each_relevant_run + page = 1 + done = false + + loop do + response = @client.workflow_runs(workflow_file: @options[:workflow], page:) + runs = response.fetch("workflow_runs") + break if runs.empty? + + runs.each do |workflow_run| + created_at = parse_time(workflow_run.fetch("created_at")) + if created_at < @since + done = true + break + end + + next unless include_run?(workflow_run) + + jobs = @client.jobs(workflow_run.fetch("id")).fetch("jobs") + failed_jobs = jobs.select { test_job_failure?(it) } + next if failed_jobs.empty? + + yield workflow_run, failed_jobs + end + + page += 1 + break if done + end + end + # rubocop:enable Metrics/AbcSize + + def include_run?(workflow_run) + branch = workflow_run.fetch("head_branch") + return false unless branch.match?(PRIMARY_BRANCH_PATTERN) || @options[:include_pr_runs] + return false if workflow_run.fetch("event") == "pull_request" && !@options[:include_pr_runs] + + true + end + + def test_job_failure?(job) + job.fetch("conclusion") == "failure" && failing_test_steps(job).any? + end + + def failing_test_steps(job) + job + .fetch("steps") + .filter_map { |step| step["name"] if step["conclusion"] == "failure" && TEST_STEP_NAMES.include?(step["name"]) } + end + + # rubocop:disable Metrics/AbcSize + def summarize(location, runs) + out_of_hours_runs, in_hours_runs = runs.partition { out_of_hours?(it.created_at) } + branches = runs.map(&:head_branch).uniq.sort + test_types = runs.flat_map(&:failed_steps).uniq.sort + + SpecSummary.new( + location:, + test_types:, + out_of_hours_count: out_of_hours_runs.count, + in_hours_count: in_hours_runs.count, + branches:, + first_seen_at: runs.min_by(&:created_at).created_at, + last_seen_at: runs.max_by(&:created_at).created_at, + out_of_hours_runs: out_of_hours_runs.map(&:html_url), + in_hours_runs: in_hours_runs.map(&:html_url), + classification: classify(out_of_hours_runs:, in_hours_runs:, branches:) + ) + end + # rubocop:enable Metrics/AbcSize + + def classify(out_of_hours_runs:, in_hours_runs:, branches:) + total = out_of_hours_runs.count + in_hours_runs.count + return "needs manual review" if total < 2 + return "likely regression" if branches.one? + return "likely datetime-sensitive" if in_hours_runs.empty? + + ratio = out_of_hours_runs.count.to_f / total + return "likely datetime-sensitive" if ratio >= 0.75 && branches.many? + + "likely generic flaky" + end + + def out_of_hours?(time) + local = time.in_time_zone(@timezone) + local.saturday? || local.sunday? || local.hour < 9 || local.hour >= 18 + end + + def parse_time(value) + Time.iso8601(value) + end + end + + class Formatter + def initialize(timezone:) + @timezone = timezone + end + + def print(spec_summaries, json: false) + json ? print_json(spec_summaries) : print_table(spec_summaries) + end + + private + + # rubocop:disable Metrics/AbcSize + def print_json(spec_summaries) + puts JSON.pretty_generate( + spec_summaries.map do |summary| + { + location: summary.location, + test_types: summary.test_types, + out_of_hours_count: summary.out_of_hours_count, + in_hours_count: summary.in_hours_count, + branches: summary.branches, + first_seen_at: summary.first_seen_at.in_time_zone(@timezone).iso8601, + last_seen_at: summary.last_seen_at.in_time_zone(@timezone).iso8601, + classification: summary.classification, + out_of_hours_runs: summary.out_of_hours_runs, + in_hours_runs: summary.in_hours_runs + } + end + ) + end + # rubocop:enable Metrics/AbcSize + + # rubocop:disable Metrics/AbcSize + def print_table(spec_summaries) + puts [ + "Classification".ljust(26), + "OOH".rjust(3), + "IN".rjust(3), + "Type".ljust(16), + "Branches".ljust(18), + "First seen".ljust(17), + "Last seen".ljust(17), + "Spec" + ].join(" ") + + spec_summaries.each do |summary| + puts [ + summary.classification.ljust(26), + summary.out_of_hours_count.to_s.rjust(3), + summary.in_hours_count.to_s.rjust(3), + summary.test_types.join(",").ljust(16), + truncate(summary.branches.join(","), 18).ljust(18), + summary.first_seen_at.in_time_zone(@timezone).strftime("%F %H:%M"), + summary.last_seen_at.in_time_zone(@timezone).strftime("%F %H:%M"), + summary.location + ].join(" ") + end + end + # rubocop:enable Metrics/AbcSize + + def truncate(value, length) + return value if value.length <= length + + "#{value[0, length - 3]}..." + end + end +end + +if $PROGRAM_NAME == __FILE__ + if !ENV["GITHUB_TOKEN"] + raise "Missing GITHUB_TOKEN env, go to https://github.com/settings/tokens and create one with 'repo' access" + end + + # workaround an openssl 3.6.0 issue + # https://github.com/ruby/openssl/issues/949#issuecomment-3367944960 + s = OpenSSL::X509::Store.new.tap(&:set_default_paths) + OpenSSL::SSL::SSLContext.send(:remove_const, :DEFAULT_CERT_STORE) rescue nil # rubocop:disable Style/RescueModifier + OpenSSL::SSL::SSLContext.const_set(:DEFAULT_CERT_STORE, s.freeze) + + options = OutOfHoursCiFailures::Options.parse!(ARGV) + client = OutOfHoursCiFailures::GithubClient.new(cache_dir: RAILS_ROOT.join("tmp/report_out_of_hours_ci_failures")) + builder = OutOfHoursCiFailures::ReportBuilder.new(options:, client:) + formatter = OutOfHoursCiFailures::Formatter.new(timezone: options[:timezone]) + + formatter.print(builder.build, json: options[:json]) +end diff --git a/script/support/github_actions_failures.rb b/script/support/github_actions_failures.rb new file mode 100644 index 00000000000..f6407a3be6f --- /dev/null +++ b/script/support/github_actions_failures.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +require "json" + +module GithubActionsFailures + Result = Data.define(:errors, :failures_explanation, :merge_branch_sha) + + class Error + attr_accessor :location, :page_html, :page_screenshot, :tests_group, :loading_error + end + + class TestsGroup + attr_accessor :test_env_number, :seed, :files + + def initialize + @files = [] + end + + def include_error?(error) + return false if error.location.nil? + + files.any? { |file| error.location.include?(file) } + end + + def inspect + "#<#{self.class} @test_env_number=#{test_env_number} @seed=#{seed} (#{files.count} files)>" + end + end + + class JobErrorsFinder + SPEC_FAILURES_PATTERN = %r{^\S+ rspec (\S+) #.+$} + SPEC_LOADING_ERRORS_PATTERN = %r{^\S+ An error occurred while loading (\S+)\.\r?$} + SCREENSHOT_PATTERN = /\{"message":"Screenshot captured for failed feature test"[^\n]+$/ + # Looks like this in the job log: + # rubocop:disable Layout/LineLength + # Process 28: TEST_ENV_NUMBER=28 RUBYOPT=-I/usr/local/bundle/bundler/gems/turbo_tests-3148ae6c3482/lib -r/usr/local/bundle/gems/bundler-2.5.23/lib/bundler/setup -W0 RSPEC_SILENCE_FILTER_ANNOUNCEMENTS=1 /usr/local/bundle/gems/bundler-2.5.23/exe/bundle exec rspec --seed 52674 --format TurboTests::JsonRowsFormatter --out tmp/test-pipes/subprocess-28 --format ParallelTests::RSpec::RuntimeLogger --out spec/support/turbo_runtime_features.log spec/features/api_docs/index_spec.rb spec/features/custom_fields/reorder_options_spec.rb spec/features/projects/projects_portfolio_spec.rb spec/features/projects/template_spec.rb spec/features/versions/edit_spec.rb spec/features/work_packages/details/markdown/description_editor_spec.rb spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb spec/features/work_packages/table/invalid_query_spec.rb spec/features/work_packages/tabs/activity_revisions_spec.rb + # rubocop:enable Layout/LineLength + TESTS_GROUP_PATTERN = /Process \d+: TEST_ENV_NUMBER=\d+ [^\n]+$/ + BRANCH_MERGE_PATTERN = /Merge \w{40} into (\w{40})$/ + + def self.scan_logs(logs) + finder = new + logs.each do |log| + finder.scan_log(log) + end + + Result.new( + errors: finder.errors, + failures_explanation: finder.failures_explanation, + merge_branch_sha: finder.merge_branch_sha + ) + end + + attr_reader :failures_explanation, :merge_branch_sha + + def scan_log(log) + find_failures(log) + find_failures_explanation(log) + find_loading_errors(log) + find_screenshots(log) + find_tests_groups(log) + find_merge_branch_info(log) + end + + def errors + @errors.values + end + + private + + def initialize + @errors = {} + end + + def create_error(location) + return if location.nil? + + error = Error.new + error.location = location + @errors[location] ||= error + end + + def with_matching_error(location: nil, id: nil) + error = @errors[id] || @errors[location] + yield error if error && block_given? + error + end + + def find_failures(log) + log.scan(SPEC_FAILURES_PATTERN) + .flatten + .uniq + .sort + .each do |rerun_location| + create_error(rerun_location) + end + end + + def find_failures_explanation(log) + explanations = [] + log.split("\n").each do |line| + if line.end_with?("Failures:") .. line.end_with?("Failed examples:") + explanations << line + end + end + explanations.map! { it[29..] } # Remove leading GitHub Actions log timestamp (e.g. "2024-02-05T08:37:54.5175930Z ") + explanations.reject! do |line| + line == "Failures:" || + line == "Failed examples:" || + line.include?("gems/rspec-retry-") || + line.include?("gems/webmock-") + end + @failures_explanation = explanations.join("\n") + end + + def find_loading_errors(log) + log.scan(SPEC_LOADING_ERRORS_PATTERN) + .flatten + .uniq + .sort + .each do |location| + error = create_error(location) + error.loading_error = true + end + end + + def find_screenshots(log) + log.scan(SCREENSHOT_PATTERN) + .map { JSON.parse(it) } + .each do |screenshot_info| + id = screenshot_info["test_id"] + location = screenshot_info["test_location"] + with_matching_error(location:, id:) do |error| + error.page_html = screenshot_info["html"] + error.page_screenshot = screenshot_info["image"] + end + end + end + + def find_tests_groups(log) + tests_groups = log + .scan(TESTS_GROUP_PATTERN) + .flatten + .map { build_tests_group_from_command(it) } + + errors.each do |error| + error.tests_group = tests_groups.find { it.include_error?(error) } + end + end + + def find_merge_branch_info(log) + merge_branch_sha = log.scan(BRANCH_MERGE_PATTERN).flatten.first + @merge_branch_sha = merge_branch_sha if merge_branch_sha + end + + def build_tests_group_from_command(line) + tests_group = TestsGroup.new + parts = line.split + while parts.any? + case part = parts.shift + when /^TEST_ENV_NUMBER=/ + tests_group.test_env_number = part.delete_prefix("TEST_ENV_NUMBER=") + when "--seed" + tests_group.seed = parts.shift + when /_spec.rb$/ + tests_group.files << part + end + end + tests_group + end + end +end diff --git a/spec/AGENTS.md b/spec/AGENTS.md new file mode 100644 index 00000000000..f5fd6ce1e62 --- /dev/null +++ b/spec/AGENTS.md @@ -0,0 +1,32 @@ +# Spec + +## Directory Structure + +- `spec/features/` - System/feature tests (Capybara) +- `spec/models/` - Model unit tests +- `spec/requests/` - API/integration tests +- `spec/services/` - Service tests + +## Running Tests + +```bash +# Backend (RSpec) - prefer specific tests over running all +bundle exec rspec spec/models/user_spec.rb # Single file +bundle exec rspec spec/models/user_spec.rb:42 # Single line +bundle exec rspec spec/features # Directory +RAILS_ENV=test ./bin/rails parallel:spec # Parallel execution +``` + +### Docker + +```bash +bin/compose rspec spec/models/user_spec.rb # Run specific tests in backend-test container +bin/compose exec backend bundle exec rspec # Run tests directly in backend container +``` + +## Debugging CI Failures + +```bash +./script/github_pr_errors | xargs bundle exec rspec # Run failed tests from CI +./script/bulk_run_rspec spec/path/to/flaky_spec.rb # Run tests multiple times +``` diff --git a/spec/CLAUDE.md b/spec/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/spec/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/spec/components/portfolios/details_component_spec.rb b/spec/components/portfolios/details_component_spec.rb index e8a0a74dfd9..31fea1f7d66 100644 --- a/spec/components/portfolios/details_component_spec.rb +++ b/spec/components/portfolios/details_component_spec.rb @@ -38,6 +38,7 @@ RSpec.describe Portfolios::DetailsComponent, type: :component do render_inline(described_class.new(...)) end + let(:reference_time) { Time.zone.local(2025, 2, 1, 12, 0, 0) } let(:user) { create(:admin) } let(:status_code_a) { "on_track" } let(:status_code_b) { "at_risk" } @@ -51,6 +52,8 @@ RSpec.describe Portfolios::DetailsComponent, type: :component do end before do + travel_to(reference_time) + create(:program, parent: portfolio, status_code: status_code_a).tap do |program_a| create(:project, parent: program_a, status_code: status_code_a).tap do |project_a| create(:project, parent: project_a, status_code: status_code_b) @@ -69,6 +72,10 @@ RSpec.describe Portfolios::DetailsComponent, type: :component do def portfolio.favorited?; false; end end + after do + travel_back + end + shared_examples "having a description and last update time" do it { expect(subject).to have_text(portfolio.description) } diff --git a/spec/components/work_packages/admin/settings/identifier_autofix_section_component_spec.rb b/spec/components/work_packages/admin/settings/identifier_autofix_section_component_spec.rb new file mode 100644 index 00000000000..b42137f4876 --- /dev/null +++ b/spec/components/work_packages/admin/settings/identifier_autofix_section_component_spec.rb @@ -0,0 +1,162 @@ +# 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. +#++ + +require "rails_helper" + +RSpec.describe WorkPackages::Admin::Settings::IdentifierAutofixSectionComponent, type: :component do + include OpenProject::StaticRouting::UrlHelpers + + def build_entry(name:, identifier:, handle:, error_reason:) + project = instance_double(Project, name:, id: rand(1..9999), to_param: identifier) + { + project:, + current_identifier: identifier, + suggested_identifier: handle, + error_reason: + } + end + + let(:entry_special_chars) do + build_entry(name: "Flight Planning", identifier: "flight-planning", handle: "FP", error_reason: :special_characters) + end + let(:entry_too_long) do + build_entry(name: "Very Long Name Project", identifier: "verylongnameproject", handle: "VLNP", error_reason: :too_long) + end + + subject(:component) { described_class.new(projects_data: projects_data) } + + context "with fewer than 5 projects" do + let(:projects_data) { [entry_special_chars, entry_too_long] } + + it "renders all entries without a footer" do + render_inline(component) + expect(page).to have_text("Flight Planning") + expect(page).to have_text("Very Long Name Project") + expect(page).to have_no_text("more project") + end + + it "shows the previous identifier" do + render_inline(component) + expect(page).to have_text("flight-planning") + expect(page).to have_text("verylongnameproject") + end + + it "shows the suggested handle" do + render_inline(component) + expect(page).to have_text("FP") + expect(page).to have_text("VLNP") + end + + it "shows a realistic example work package ID" do + render_inline(component) + # Numbers are deterministic from the identifier's byte sum. + expect(page).to have_text("FP-151") # "FP".bytes.sum % 500 + 1 = 151 + expect(page).to have_text("VLNP-321") # "VLNP".bytes.sum % 500 + 1 = 321 + end + + it "shows the special characters error caption" do + render_inline(component) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.autofix_preview.error_special_characters")) + end + + it "shows the too long error caption" do + render_inline(component) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.autofix_preview.error_too_long")) + end + + it "renders the warning banner with the total project count" do + render_inline(component) + expect(page).to have_text( + I18n.t( + "admin.settings.work_packages_identifier.banner.existing_identifiers_notice", + project_count: 2 + ) + ) + end + end + + context "with exactly 5 projects" do + let(:projects_data) do + Array.new(5) do |i| + build_entry(name: "Project #{i}", identifier: "proj-#{i}", handle: "P#{i}", error_reason: :special_characters) + end + end + + it "renders all 5 entries without a footer" do + render_inline(component) + expect(page).to have_no_text("more project") + end + end + + context "with more than 5 projects" do + let(:projects_data) do + Array.new(8) do |i| + build_entry(name: "Project #{i}", identifier: "proj-#{i}", handle: "P#{i}X", error_reason: :special_characters) + end + end + + it "renders only the first 5 entries" do + render_inline(component) + expect(page).to have_text("Project 0") + expect(page).to have_text("Project 4") + expect(page).to have_no_text("Project 5") + end + + it "shows a footer with the remaining count" do + render_inline(component) + expect(page).to have_text("3 more projects") + end + end + + context "with exactly 6 projects" do + let(:projects_data) do + Array.new(6) do |i| + build_entry(name: "Project #{i}", identifier: "proj-#{i}", handle: "P#{i}X", error_reason: :special_characters) + end + end + + it "shows '1 more project' (singular)" do + render_inline(component) + expect(page).to have_text("1 more project") + end + end + + context "with column headers" do + let(:projects_data) { [entry_special_chars] } + + it "renders all four column headers" do + render_inline(component) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.box_header.label_project")) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.box_header.label_previous_identifier")) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.box_header.label_autofixed_suggestion")) + expect(page).to have_text(I18n.t("admin.settings.work_packages_identifier.box_header.label_example_work_package_id")) + end + end +end diff --git a/spec/components/work_packages/admin/settings/identifier_settings_form_component_spec.rb b/spec/components/work_packages/admin/settings/identifier_settings_form_component_spec.rb new file mode 100644 index 00000000000..372dab0e168 --- /dev/null +++ b/spec/components/work_packages/admin/settings/identifier_settings_form_component_spec.rb @@ -0,0 +1,162 @@ +# 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. +#++ + +require "rails_helper" + +RSpec.describe WorkPackages::Admin::Settings::IdentifierSettingsFormComponent, type: :component do + subject(:component) { described_class.new(state:) } + + let(:empty_result) do + WorkPackages::IdentifierAutofix::PreviewQuery::Result.new(projects_data: [], total_count: 0) + end + + def render_component(component) + with_controller_class(Admin::Settings::WorkPackagesIdentifierController) do + with_request_url("/admin/settings/work_packages_identifier") do + render_inline(component) + end + end + end + + before do + preview_stub = instance_double(WorkPackages::IdentifierAutofix::PreviewQuery, call: empty_result) + allow(WorkPackages::IdentifierAutofix::PreviewQuery).to receive(:new).and_return(preview_stub) + end + + context "when state is :change_in_progress" do + let(:state) { :change_in_progress } + + it "renders the in-progress spinner message" do + render_component(component) + expect(page).to have_text("Project identifiers are currently being updated to project-based alphanumerical identifiers.") + end + + it "does not render the success banner" do + render_component(component) + expect(page).to have_no_text("Successfully updated work package identifier format.") + end + + it "renders the radio buttons as disabled" do + render_component(component) + expect(page).to have_field("Instance-wide numerical sequence (default)", disabled: true) + expect(page).to have_field("Project-based alphanumerical identifiers", disabled: true) + end + + it "does not render the save or autofix buttons" do + render_component(component) + expect(page).to have_no_button("Save") + expect(page).to have_no_link("Autofix and save") + end + + it "does not call PreviewQuery" do + render_component(component) + expect(WorkPackages::IdentifierAutofix::PreviewQuery).not_to have_received(:new) + end + end + + context "when state is :completed" do + let(:state) { :completed } + + it "renders the success banner" do + render_component(component) + expect(page).to have_text("Successfully updated work package identifier format.") + end + + it "does not render the in-progress spinner message" do + render_component(component) + expect(page).to have_no_text("Project identifiers are currently being updated to project-based alphanumerical identifiers.") + end + + it "renders the radio buttons as enabled" do + render_component(component) + expect(page).to have_field("Instance-wide numerical sequence (default)", disabled: false) + expect(page).to have_field("Project-based alphanumerical identifiers", disabled: false) + end + + it "does not call PreviewQuery" do + render_component(component) + expect(WorkPackages::IdentifierAutofix::PreviewQuery).not_to have_received(:new) + end + end + + context "when state is :edit" do + let(:state) { :edit } + + it "calls PreviewQuery" do + render_component(component) + expect(WorkPackages::IdentifierAutofix::PreviewQuery).to have_received(:new).once + end + + it "renders the save button" do + render_component(component) + expect(page).to have_button("Save") + end + + it "does not render in-progress or success content" do + render_component(component) + expect(page).to have_no_text("Project identifiers are currently being updated to project-based alphanumerical identifiers.") + expect(page).to have_no_text("Successfully updated work package identifier format.") + end + + context "with problematic projects and alphanumeric setting", + with_settings: { work_packages_identifier: "alphanumeric" } do + let(:project) { instance_double(Project, name: "Bad Project", id: 1, to_param: "bad-proj") } + let(:problematic_result) do + WorkPackages::IdentifierAutofix::PreviewQuery::Result.new( + projects_data: [ + { project:, current_identifier: "bad-proj", suggested_identifier: "BP", error_reason: :special_characters } + ], + total_count: 1 + ) + end + + before do + stub = instance_double(WorkPackages::IdentifierAutofix::PreviewQuery, call: problematic_result) + allow(WorkPackages::IdentifierAutofix::PreviewQuery).to receive(:new).and_return(stub) + end + + it "hides the plain save button" do + render_component(component) + expect(page).to have_no_button("Save") + end + + it "renders the autofix button" do + render_component(component) + expect(page).to have_link("Autofix and save") + end + end + end + + context "when an unknown state is given" do + it "raises ArgumentError" do + expect { described_class.new(state: :bogus) }.to raise_error(ArgumentError, /Unknown state/) + end + end +end diff --git a/spec/controllers/admin_controller_spec.rb b/spec/controllers/admin_controller_spec.rb index 7c48017aa1b..fa567885466 100644 --- a/spec/controllers/admin_controller_spec.rb +++ b/spec/controllers/admin_controller_spec.rb @@ -143,7 +143,7 @@ RSpec.describe AdminController do it "redirects back, showing an error" do expect(response).to redirect_to admin_settings_mail_notifications_path - expect(flash[:error]).to match /OPENPROJECT_SSRF_PROTECTION_ALLOWLIST/ + expect(flash[:error]).to match /OPENPROJECT_SSRF_PROTECTION_IP_ALLOWLIST/ end end diff --git a/spec/controllers/projects_settings_menu_controller_spec.rb b/spec/controllers/projects_settings_menu_controller_spec.rb index 4154892b372..c6a7bbde3ca 100644 --- a/spec/controllers/projects_settings_menu_controller_spec.rb +++ b/spec/controllers/projects_settings_menu_controller_spec.rb @@ -105,8 +105,6 @@ RSpec.describe Projects::Settings::ModulesController, "menu" do it_behaves_like "renders the modules show page" it_behaves_like "has selector", "#main-menu a.wiki-example-menu-item" - - it_behaves_like "has selector", "#main-menu a.wiki-sub-menu-item" end end diff --git a/spec/controllers/repositories_controller_spec.rb b/spec/controllers/repositories_controller_spec.rb index 844ee2aab82..01267fdeac2 100644 --- a/spec/controllers/repositories_controller_spec.rb +++ b/spec/controllers/repositories_controller_spec.rb @@ -287,6 +287,18 @@ RSpec.describe RepositoriesController do end end + describe "#entry" do + let(:permissions) { [:browse_repository] } + + it "serves raw files as application/octet-stream attachment" do + get :entry, params: { project_id: project.identifier, repo_path: "subversion_test/textfile.txt", format: "raw" } + + expect(response).to be_successful + expect(response.headers["Content-Type"]).to eq("application/octet-stream") + expect(response.headers["Content-Disposition"]).to match(/attachment/) + end + end + describe "checkout path" do render_views diff --git a/spec/features/admin/settings/work_packages_identifier_spec.rb b/spec/features/admin/settings/work_packages_identifier_spec.rb new file mode 100644 index 00000000000..792455a4993 --- /dev/null +++ b/spec/features/admin/settings/work_packages_identifier_spec.rb @@ -0,0 +1,128 @@ +# 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. +#++ + +require "spec_helper" + +RSpec.describe "Work packages identifier admin settings", :js do + shared_let(:admin) { create(:admin) } + + before do + with_flags(semantic_work_package_ids: true) + login_as(admin) + end + + let(:settings_path) { "/admin/settings/work_packages_identifier" } + + def visit_settings + visit settings_path + # Wait for the radio group legend to confirm the page has loaded + expect(page).to have_css("legend", text: "Work package identifier", wait: 10) + end + + context "when no projects have problematic identifiers" do + it "saves the setting without showing a dialog" do + visit_settings + + click_button "Save" + + expect(page).to have_current_path(settings_path) + expect(page).to have_no_dialog + end + end + + context "when a project has a problematic identifier" do + shared_let(:project) { create(:project, identifier: "bad-id", name: "Bad Project") } + + context "when saving with the current numeric setting" do + it "saves without showing the confirmation dialog" do + visit_settings + + # The autofix section is hidden when numeric is selected + expect(page).to have_css( + "[data-admin--work-packages-identifier-target=autofixSection][hidden]", + visible: :all + ) + click_button "Save" + + expect(page).to have_current_path(settings_path) + expect(page).to have_no_dialog + end + end + + context "when switching to alphanumeric" do + before do + visit_settings + choose "Project-based alphanumerical identifiers" + end + + it "shows the autofix section after selecting alphanumeric" do + expect(page).to have_css( + "[data-admin--work-packages-identifier-target=autofixSection]:not([hidden])", + visible: :visible + ) + end + + it "opens the confirmation dialog when 'Autofix and save' is clicked" do + click_on "Autofix and save" + + expect(page).to have_dialog "Change work package identifiers" + end + + it "shows the dialog heading and checkbox" do + click_on "Autofix and save" + + within_dialog "Change work package identifiers" do + expect(page).to have_text("Enable project-based work package IDs?") + expect(page).to have_field( + "I understand that this will permanently change all work package IDs", + type: :checkbox + ) + end + end + + it "enables the confirm button only after checking the checkbox" do + click_on "Autofix and save" + + within "[role=alertdialog]" do + expect(page).to have_button("Change identifiers", disabled: true) + + check "I understand that this will permanently change all work package IDs" + + expect(page).to have_button("Change identifiers", disabled: false) + end + end + + it "hides the plain Save button when autofix section is visible" do + expect(page).to have_no_button("Save") + expect(page).to have_link("Autofix and save") + end + end + end +end diff --git a/spec/features/menu_items/wiki_menu_item_spec.rb b/spec/features/menu_items/wiki_menu_item_spec.rb index be9d357814a..dad3558d3ff 100644 --- a/spec/features/menu_items/wiki_menu_item_spec.rb +++ b/spec/features/menu_items/wiki_menu_item_spec.rb @@ -64,11 +64,11 @@ RSpec.describe "Wiki menu items", # Create two items with identical slugs (one with space, which is removed) let(:item1) do MenuItems::WikiMenuItem.new(navigatable_id: wiki.id, - parent: parent_menu, title: "Item 1", name: "slug") + parent: nil, title: "Item 1", name: "slug ") end let(:item2) do MenuItems::WikiMenuItem.new(navigatable_id: wiki.id, - parent: parent_menu, title: "Item 2", name: "slug ") + parent: nil, title: "Item 2", name: "slug") end it "one is invalid and deleted during visit" do @@ -114,38 +114,27 @@ RSpec.describe "Wiki menu items", expect(page) .to have_current_path(project_wiki_path(project, wiki_page)) - # modifying the menu item to a different name and to be a subpage + # modifying the menu item to a different name page.find_test_selector("wiki-more-dropdown-menu").click page.find_test_selector("wiki-configure-menu-action-menu-item").click wait_for_network_idle fill_in "Name of menu item", with: "Custom page name" - choose "Show as submenu item of" - - select other_wiki_page.slug, from: "parent_wiki_menu_item" click_link_or_button "Save" wait_for_network_idle - # the other page is now the main heading + # the custom name is used as the main heading expect(page) - .to have_css(".main-menu--children-menu-header", text: other_wiki_page.title) + .to have_css(".main-menu--children-menu-header", text: "Custom page name") - expect(page) - .to have_css(".wiki-menu--sub-item", text: "Custom page name") - - find(".wiki-menu--sub-item", text: "Custom page name").click - wait_for_network_idle - - expect(page) - .to have_current_path(project_wiki_path(project, wiki_page)) - - # the submenu item is not visible on top level + # the item is visible on top level + visit(project_wiki_path(project, wiki_page)) find(".main-menu--arrow-left-to-project").click expect(page) - .to have_no_css(".main-item-wrapper", text: "Custom page name") + .to have_css(".main-item-wrapper", text: "Custom page name") # deleting the page will remove the menu item visit project_wiki_path(project, wiki_page) diff --git a/spec/features/notifications/notification_center/notification_center_date_alert_mention_spec.rb b/spec/features/notifications/notification_center/notification_center_date_alert_mention_spec.rb index 496eebf61b7..94dac8faead 100644 --- a/spec/features/notifications/notification_center/notification_center_date_alert_mention_spec.rb +++ b/spec/features/notifications/notification_center/notification_center_date_alert_mention_spec.rb @@ -12,9 +12,9 @@ RSpec.describe "Notification center date alert and mention", create(:user, member_with_permissions: { project => %w[view_work_packages] }) end - shared_let(:work_package) { create(:work_package, project:, due_date: 1.day.ago) } - - shared_let(:notification_mention) do + let(:reference_time) { Time.zone.local(2025, 1, 8, 12, 0, 0) } + let(:work_package) { create(:work_package, project:, due_date: 1.day.ago.to_date) } + let!(:notification_mention) do create(:notification, reason: :mentioned, recipient: user, @@ -22,7 +22,7 @@ RSpec.describe "Notification center date alert and mention", actor:) end - shared_let(:notification_date_alert) do + let!(:notification_date_alert) do create(:notification, reason: :date_alert_due_date, recipient: user, @@ -32,11 +32,16 @@ RSpec.describe "Notification center date alert and mention", let(:center) { Pages::Notifications::Center.new } before do + travel_to(reference_time) login_as user visit notifications_center_path wait_for_reload end + after do + travel_back + end + context "with date alerts ee", with_ee: %i[date_alerts] do it "shows only the date alert time, not the mentioned author" do center.within_item(notification_date_alert) do diff --git a/spec/features/notifications/notification_center/notification_center_reminder_spec.rb b/spec/features/notifications/notification_center/notification_center_reminder_spec.rb index f2d9ddb7abd..f7b0d877061 100644 --- a/spec/features/notifications/notification_center/notification_center_reminder_spec.rb +++ b/spec/features/notifications/notification_center/notification_center_reminder_spec.rb @@ -13,10 +13,11 @@ RSpec.describe "Notification center reminder, mention and date alert", create(:user, member_with_permissions: { project => %w[view_work_packages] }) end - shared_let(:work_package) { create(:work_package, project:, due_date: 1.day.ago) } - shared_let(:work_package2) { create(:work_package, project:) } + let(:reference_time) { Time.zone.local(2025, 1, 8, 12, 0, 0) } + let(:work_package) { create(:work_package, project:, due_date: 1.day.ago.to_date) } + let(:work_package2) { create(:work_package, project:) } - shared_let(:notification_mentions) do + let!(:notification_mentions) do [create(:notification, reason: :mentioned, recipient: user, @@ -29,29 +30,34 @@ RSpec.describe "Notification center reminder, mention and date alert", actor: actor)] end - shared_let(:notification_date_alert) do + let!(:notification_date_alert) do create(:notification, reason: :date_alert_due_date, recipient: user, resource: work_package) end - shared_let(:notification_reminder) do + let!(:notification_reminder) do create_reminder_notification_for(work_package: work_package, user: user) end - shared_let(:notification_reminder2) do + let!(:notification_reminder2) do create_reminder_notification_for(work_package: work_package2, user: user) end let(:center) { Pages::Notifications::Center.new } before do + travel_to(reference_time) login_as user visit notifications_center_path wait_for_reload end + after do + travel_back + end + context "with a reminder, mention and date alert" do it "shows the reminder alert within aggregation with date alert + reminder note" do center.within_item(notification_reminder) do diff --git a/spec/features/versions/edit_spec.rb b/spec/features/versions/edit_spec.rb index dfdab37ba8e..9c9993b29fd 100644 --- a/spec/features/versions/edit_spec.rb +++ b/spec/features/versions/edit_spec.rb @@ -31,13 +31,11 @@ require "spec_helper" RSpec.describe "version edit", :js do - let(:user) do - create(:user, - member_with_permissions: { version.project => %i[manage_versions view_work_packages] }) - end - let(:version) { create(:version) } - let(:project) { version.project } + let(:project) { create(:project, enabled_module_names: %w[backlogs work_package_tracking]) } + let(:version) { create(:version, project:, sharing: "descendants") } let(:new_version_name) { "A new version name" } + let(:permissions) { { project => %i[manage_versions view_work_packages] } } + let(:user) { create(:user, member_with_permissions: permissions) } before do login_as(user) @@ -59,6 +57,51 @@ RSpec.describe "version edit", :js do .to have_content new_version_name end + context "when editing a shared version from a subproject with backlogs enabled", :js do + let(:child_project) do + create(:project, parent: project, enabled_module_names: %w[backlogs work_package_tracking]) + end + let(:permissions) do + { project => %i[manage_versions view_work_packages], + child_project => %i[manage_versions view_work_packages] } + end + + it "persists the version setting scoped to the subproject, not the parent project (Regression#73187)" do + visit edit_version_path(version, project_id: child_project.id) + + select I18n.t(:version_settings_display_option_right), + from: I18n.t(:label_column_in_backlog) + + click_button I18n.t(:button_save) + + expect(page).to have_text(I18n.t(:notice_successful_update)) + + # it creates a version setting for the child project + setting = VersionSetting.find_by(version:, project: child_project) + expect(setting).not_to be_nil + expect(setting).to be_display_right + + # it does not create a version setting for the parent project + expect(VersionSetting.exists?(version:, project:)).to be false + + # visiting the parent project shows the default version setting + visit edit_version_path(version, project_id: project.id) + + expect(page).to have_select( + I18n.t(:label_column_in_backlog), + selected: I18n.t(:version_settings_display_option_left) + ) + + # revisiting the settings page shows the correct version setting + visit edit_version_path(version, project_id: child_project.id) + + expect(page).to have_select( + I18n.t(:label_column_in_backlog), + selected: I18n.t(:version_settings_display_option_right) + ) + end + end + context "with a custom field" do let!(:custom_field) do create(:version_custom_field, :string, diff --git a/spec/features/work_packages/reminders_spec.rb b/spec/features/work_packages/reminders_spec.rb index 9fd51cab04c..ad0b68b9eb1 100644 --- a/spec/features/work_packages/reminders_spec.rb +++ b/spec/features/work_packages/reminders_spec.rb @@ -32,6 +32,7 @@ require "spec_helper" RSpec.describe "Work package reminder modal", :js do + let(:reference_time) { Time.find_zone!("Europe/Berlin").local(2025, 1, 8, 12, 0, 0) } let!(:project) { create(:project) } let!(:work_package) { create(:work_package, project:) } let!(:role_that_allows_managing_own_reminders) do @@ -54,6 +55,14 @@ RSpec.describe "Work package reminder modal", let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:center) { Pages::Notifications::Center.new } + before do + travel_to(reference_time) + end + + after do + travel_back + end + context "with permissions to manage own reminders" do current_user { user_with_permissions } diff --git a/spec/features/work_packages/table/queries/filter_spec.rb b/spec/features/work_packages/table/queries/filter_spec.rb index 5e70bdda107..0e4ab78b8fb 100644 --- a/spec/features/work_packages/table/queries/filter_spec.rb +++ b/spec/features/work_packages/table/queries/filter_spec.rb @@ -556,26 +556,36 @@ RSpec.describe "filter work packages", :js do end describe "datetime filters" do + shared_let(:business_day_at_noon) { Time.find_zone!("Europe/Kyiv").local(2025, 1, 8, 12, 0, 0) } + + before do + travel_to(business_day_at_noon) + end + + after do + travel_back + end + shared_let(:wp_updated_today) do create(:work_package, subject: "Created today", project:, - created_at: Time.current.change(hour: 12), - updated_at: Time.current.change(hour: 12)) + created_at: business_day_at_noon, + updated_at: business_day_at_noon) end shared_let(:wp_updated_3d_ago) do create(:work_package, subject: "Created 3d ago", project:, - created_at: 3.days.ago, - updated_at: 3.days.ago) + created_at: business_day_at_noon - 3.days, + updated_at: business_day_at_noon - 3.days) end shared_let(:wp_updated_5d_ago) do create(:work_package, subject: "Created 5d ago", project:, - created_at: 5.days.ago, - updated_at: 5.days.ago) + created_at: business_day_at_noon - 5.days, + updated_at: business_day_at_noon - 5.days) end it "filters on date by created_at (Regression #28459)" do diff --git a/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb b/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb index 9f09f6e18c2..7cf0cdabc96 100644 --- a/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb +++ b/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb @@ -36,17 +36,23 @@ RSpec.describe "mobile date filter work packages", :js do shared_let(:wp_table) { Pages::WorkPackagesTable.new(project) } shared_let(:wp_cards) { Pages::WorkPackageCards.new(project) } shared_let(:filters) { Components::WorkPackages::Filters.new } - shared_let(:work_package_with_due_date) { create(:work_package, project:, due_date: Date.current) } - shared_let(:work_package_without_due_date) { create(:work_package, project:, due_date: 5.days.from_now) } + shared_let(:business_day_at_noon) { Time.zone.local(2025, 1, 8, 12, 0, 0) } + shared_let(:work_package_with_due_date) { create(:work_package, project:, due_date: business_day_at_noon.to_date) } + shared_let(:work_package_without_due_date) { create(:work_package, project:, due_date: business_day_at_noon.to_date + 5.days) } current_user { user } include_context "with mobile screen size" before do + travel_to(business_day_at_noon) wp_table.visit! end + after do + travel_back + end + context "when filtering between finish date" do it "allows filtering, saving and retrieving and altering the saved filter" do filters.open @@ -59,9 +65,9 @@ RSpec.describe "mobile date filter work packages", :js do clear_input_field_contents(start_field) clear_input_field_contents(end_field) - start_field.set 1.day.ago.to_date + start_field.set business_day_at_noon.to_date - 1.day start_field.send_keys :tab - end_field.set Date.current + end_field.set business_day_at_noon.to_date end_field.send_keys :tab wait_for_reload @@ -76,7 +82,7 @@ RSpec.describe "mobile date filter work packages", :js do last_query = Query.last date_filter = last_query.filters.last - expect(date_filter.values).to eq [1.day.ago.to_date.iso8601, Date.current.iso8601] + expect(date_filter.values).to eq [(business_day_at_noon.to_date - 1.day).iso8601, business_day_at_noon.to_date.iso8601] end end @@ -90,7 +96,7 @@ RSpec.describe "mobile date filter work packages", :js do expect(date_field["type"]).to eq "date" clear_input_field_contents(date_field) - date_field.set Date.current + date_field.set business_day_at_noon.to_date wait_for_reload loading_indicator_saveguard @@ -104,7 +110,7 @@ RSpec.describe "mobile date filter work packages", :js do last_query = Query.last date_filter = last_query.filters.last - expect(date_filter.values).to eq [Date.current.iso8601] + expect(date_filter.values).to eq [business_day_at_noon.to_date.iso8601] end end end diff --git a/spec/fixtures/import/jira/issue.json b/spec/fixtures/import/jira/issue.json new file mode 100644 index 00000000000..3068393a935 --- /dev/null +++ b/spec/fixtures/import/jira/issue.json @@ -0,0 +1,92 @@ +{ + "id": "10100", + "key": "DYX-1", + "self": "https://jira-software.local/rest/api/2/issue/10100", + "fields": { + "summary": "Kanban cards represent work items", + "description": "*About Kanban*\n\nKanban is part of the Toyota Lean Manufacturing methodology.", + "created": "2026-02-04T09:51:03.000+0000", + "updated": "2026-03-10T12:00:59.000+0000", + "creator": { + "key": "JIRAUSER10000", + "name": "p.balashou", + "displayName": "Pavel Balashou", + "emailAddress": "p.balashou@openproject.com", + "active": true + }, + "assignee": { + "key": "JIRAUSER10000", + "name": "p.balashou", + "displayName": "Pavel Balashou", + "emailAddress": "p.balashou@openproject.com", + "active": true + }, + "issuetype": { + "id": "10100", + "name": "Task", + "description": "A task that needs to be done.", + "subtask": false + }, + "status": { + "id": "3", + "name": "In Progress", + "description": "This issue is being actively worked on." + }, + "priority": { + "id": "1", + "name": "Highest" + }, + "comment": { + "total": 1, + "comments": [ + { + "id": "10100", + "body": "Created 2 hours 36 minutes ago", + "author": { + "key": "JIRAUSER10000", + "name": "p.balashou", + "displayName": "Pavel Balashou", + "emailAddress": "p.balashou@openproject.com" + }, + "created": "2026-02-04T09:51:03.503+0000", + "updated": "2026-02-04T09:51:03.503+0000" + } + ] + }, + "attachment": [ + { + "id": "10000", + "filename": "solid-color-image.png", + "content": "https://jira-software.local/secure/attachment/10000/solid-color-image.png", + "mimeType": "image/png", + "size": 38697, + "author": { + "key": "JIRAUSER10000", + "name": "p.balashou", + "displayName": "Pavel Balashou", + "emailAddress": "p.balashou@openproject.com" + }, + "created": "2026-02-05T12:29:19.045+0000" + } + ] + }, + "changelog": { + "total": 1, + "histories": [ + { + "id": "10133", + "items": [ + { + "field": "Attachment", + "toString": "solid-color-image.png" + } + ], + "author": { + "key": "JIRAUSER10000", + "name": "p.balashou" + }, + "created": "2026-02-05T12:29:19.257+0000" + } + ] + } +} diff --git a/spec/fixtures/import/jira/project.json b/spec/fixtures/import/jira/project.json new file mode 100644 index 00000000000..bee84e91bd1 --- /dev/null +++ b/spec/fixtures/import/jira/project.json @@ -0,0 +1,23 @@ +{ + "id": "10242", + "key": "DYX", + "name": "Zombie Engine", + "self": "https://jira-software.local/rest/api/2/project/10242", + "expand": "description,lead,createdAt,createdBy,lastUpdatedAt,lastUpdatedBy,url,projectKeys", + "archived": false, + "avatarUrls": { + "16x16": "https://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", + "24x24": "https://jira-software.local/secure/projectavatar?size=small&avatarId=10324", + "32x32": "https://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", + "48x48": "https://jira-software.local/secure/projectavatar?avatarId=10324" + }, + "description": "Test project created by jira_projects.rb script at 2026-02-13 09:32:25 UTC", + "projectKeys": ["DYX"], + "projectTypeKey": "software", + "projectCategory": { + "id": "10008", + "name": "Legacy", + "self": "https://jira-software.local/rest/api/2/projectCategory/10008", + "description": "Maintenance and migration projects" + } +} diff --git a/spec/fixtures/import/jira/user.json b/spec/fixtures/import/jira/user.json new file mode 100644 index 00000000000..6d025e3505d --- /dev/null +++ b/spec/fixtures/import/jira/user.json @@ -0,0 +1,10 @@ +{ + "key": "JIRAUSER10000", + "name": "p.balashou", + "displayName": "Pavel Balashou", + "emailAddress": "p.balashou@openproject.com", + "active": true, + "groups": { + "items": [] + } +} diff --git a/spec/helpers/repositories_helper_spec.rb b/spec/helpers/repositories_helper_spec.rb new file mode 100644 index 00000000000..9d6c9ec630b --- /dev/null +++ b/spec/helpers/repositories_helper_spec.rb @@ -0,0 +1,278 @@ +# 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. +#++ + +require "spec_helper" + +RSpec.describe RepositoriesHelper do + let(:project) { build_stubbed(:project) } + let(:repository) { build_stubbed(:repository_subversion, project:) } + let(:changeset) { build_stubbed(:changeset, repository:, revision: "42") } + + before do + assign(:project, project) + assign(:repository, repository) + assign(:changeset, changeset) + + allow(repository).to receive(:relative_path) { |path| path } + + allow(helper).to receive_messages( + show_revisions_path_project_repository_path: "/revisions", + entry_revision_project_repository_path: "/entry", + diff_revision_project_repository_path: "/diff" + ) + end + + describe "#changes_tree_li_element" do + it "escapes plain text content" do + malicious_text = '' + result = helper.changes_tree_li_element("D", malicious_text, "change change-D") + + expect(result).not_to include("') + } + } + end + + it "escapes the revision" do + result = helper.render_changes_tree(tree) + + expect(result).not_to include("